Class: BrowserSniffer

Inherits:
Object
  • Object
show all
Defined in:
lib/browser_sniffer.rb,
lib/browser_sniffer/version.rb,
lib/browser_sniffer/patterns.rb

Constant Summary collapse

VERSION =
"2.4.0"
STRING_MAP =
{
  :browser => {
    :oldsafari => {
      :major => {
        '/85' => '1',
        '/125' => '1',
        '/312' => '1',
        '/412' => '2',
        '/416' => '2',
        '/417' => '2',
        '/419' => '2'
      },
      :version => {
        '/85' => '1.0',
        '/125' => '1.2',
        '/312' => '1.3',
        '/412' => '2.0',
        '/416' => '2.0.2',
        '/417' => '2.0.3',
        '/419' => '2.0.4'
      }
    }
  },
  :os => {
    :windows => {
      :version => {
        '4.90' => 'ME',
        'NT3.51' => 'NT 3.11',
        'NT4.0' => 'NT 4.0',
        'NT 5.0' => '2000',
        'NT 5.1' => 'XP',
        'NT 5.2' => 'XP',
        'NT 6.0' => 'Vista',
        'NT 6.1' => '7',
        'NT 6.2' => '8',
        'NT 6.3' => '8.1',
        'NT 10.0' => '10',
        'ARM' => 'RT'
      }
    }
  }
}
REGEX_MAP =
{
  :browser => [
    [
      # Shopify POS Go
      /WSC6X|WTH11/i
    ], [[:name, 'Shopify POS Go']],[
      # Shopify Mobile for iPhone or iPad
      %r{.*Shopify/\d+\s\((iPhone|iPad)\;\siOS\s[\d\.]+}i
    ], [[:name, 'Shopify Mobile']], [
      # Shopify Mobile for Android
      %r{.*Dalvik/[a-z0-9\.]+.*Shopify\s[\d+\.\/]+}i
    ], [[:name, 'Shopify Mobile']], [
      # Shopify POS for iOS
      %r{.*(Shopify\sPOS)\/([\d\.]+)\s\((iPhone|iPad|iPod\stouch)\;}i,
    ], [:name, :version], [
      # Old Shopify POS for Android
      %r{^Dalvik/[a-z0-9\.]+.*(Shopify\sPOS)\s(\d(?:\.\d+)*)(\/\d*)*}i,
    ], [:name, :version], [
      # Shopify POS for Android (Native App)
      %r{.*(\sPOS\s-).*\s([\d+\.]+)(\/\d*)*\s}i,
    ], [[:name, 'Shopify POS'], :version], [
      # Shopify POS for Android (React Native App)
      %r{(Shopify POS)\/([\d\.]+)[^\/]*\/(Android)\/(\d+)}i,
    ], [[:name, 'Shopify POS'], :version], [
      # Shopify POS for iOS (React Native App)
      %r{(Shopify POS)\/([\d\.]+)[^\/]*\/(iOS)\/([\d\.]+)}i,
    ], [[:name, 'Shopify POS'], :version], [
      # Shopify POS for Android (SmartWebView)
      %r{.*(Shopify\sPOS)\s.*Android.*\s([\d+\.]+)(\/\d*)*\s}i,
    ], [:name, :version], [
      # Shopify POS uses this user agent
      %r{^(okhttp)\/([\d\.]+)}i
    ], [:name, :version], [
      # Shopify Mobile for iPhone or iPad
      %r{.*(Shopify Mobile)\/(?:iPhone\sOS|iOS)\/([\d\.]+) \((iPhone|iPad|iPod)}i
    ], [[:name, 'Shopify Mobile'], :version], [
      # Shopify POS Next for iPhone or iPad
      %r{.*(Shopify POS Next|Shopify POS)\/(?:iOS)\/([\d\.]+) \((iPhone|iPad|iPod)}i
    ], [[:name, 'Shopify POS'], :version], [
      # Shopify Mobile for Android
      %r{.*(Shopify Mobile)\/Android\/([\d\.]+)(?: \((debug(?:|-push))\))? \(Build (\d+) with API (\d+)}i
    ], [[:name, 'Shopify Mobile'], :version, :debug_mode, :build, :sdk_version], [
      # ShopifyFoundation shared library
      /^(ShopifyFoundation)/i,
    ], [:name], [
      # Shopify Ping iOS
      %r{.*(Shopify Ping)\/(?:iPhone\sOS|iOS)\/([\d\.]+) \((iPhone|iPad|iPod)}i
    ], [[:name, 'Shopify Ping'], :version], [
      # Presto based
      /(opera\smini)\/((\d+)?[\w\.-]+)/i, # Opera Mini
      /(opera\s[mobiletab]+).+:version\/((\d+)?[\w\.-]+)/i, # Opera Mobi/Tablet
      /(opera).+:version\/((\d+)?[\w\.]+)/i, # Opera > 9.80
      /(opera)[\/\s]+((\d+)?[\w\.]+)/i # Opera < 9.80
    ], [:name, :version, :major, [:type, :opera]], [
      /\s(opr)\/((\d+)?[\w\.]+)/i # Opera Webkit
    ], [[:name, 'Opera'], :version, :major, [:type, :opera]], [
      # Mixed
      /(kindle)\/((\d+)?[\w\.]+)/i, # Kindle
      /(lunascape|maxthon|netfront|jasmine|blazer)[\/\s]?((\d+)?[\w\.]+)*/i, # Lunascape/Maxthon/Netfront/Jasmine/Blazer
      # Trident based
      /(avant\s|iemobile|slim|baidu)(?:browser)?[\/\s]?((\d+)?[\w\.]*)/i # Avant/IEMobile/SlimBrowser/Baidu
    ], [:name, :version, :major], [
      /(?:ms|\()(ie)\s((\d+)[\w\.]+)/i # Internet Explorer
    ], [:name, :version, :major, [:type, :ie]], [
      /Edge\/(\d+).\d+/i #Edge
    ], [:major, [:version, 10], [:name, 'Edge'], [:type, :edge]], [
      /Mozilla\/5.0.*Windows NT 6\.\d.*Trident\/7\.\d.*rv:(\d+)\.\d*/i #IE11 on Win7
    ], [:major, [:version, 7], [:name, 'Internet Explorer'], [:type, :ie]], [
      /Mozilla\/5.0.*Windows NT 10\.\d.*Trident\/7\.\d.*rv:(\d+)\.\d*.*like\sGecko/i #IE11 on Win10
    ], [:major, [:version, 10], [:name, 'Internet Explorer'], [:type, :ie]], [
      # Webkit/KHTML based
      /(rekonq)\/?((\d+)[\w\.]+)*/i, # Rekonq
      /(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt)\/((\d+)?[\w\.-]+)/i # Chromium/Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt
    ], [:name, :version, :major], [
      /(yabrowser)\/((\d+)?[\w\.]+)/i # Yandex
    ], [[:name, 'Yandex'], :version, :major], [
      /(comodo_dragon)\/((\d+)?[\w\.]+)/i # Comodo Dragon
    ], [[:name, 'Comodo Dragon'], :version, :major], [
      /(chromium)\/((\d+)?[\w\.-]+)/i, # Chromium
      /(chrome)\/v?((\d+)?[\w\.]+)/i # Chrome
    ], [:name, :version, :major, [:type, :chrome]], [
      /(omniweb|arora|[tizenoka]{5}\s?browser)\/v?((\d+)?[\w\.]+)/i # Chrome/OmniWeb/Arora/Tizen/Nokia
    ], [:name, :version, :major], [
      /(dolfin)\/((\d+)?[\w\.]+)/i # Dolphin
    ], [[:name, 'Dolphin'], :version, :major], [
      /((?:android.+)crmo|crios)\/((\d+)?[\w\.]+)/i # Chrome for Android/iOS
    ], [[:name, 'Chrome'], :version, :major, [:type, :chrome]], [
      /(FxiOS)\/((\d+)?[\w\.]+)/i # Firefox for iOS
    ], [[:name, 'Mobile Firefox'], :version, :major, [:type, :firefoxios]], [
      /version\/((\d+)?[\w\.]+).+?mobile\/\w+\s(safari)/i # Mobile Safari
    ], [:version, :major, [:name, 'Mobile Safari'], [:type, :safari]], [
      /Mozilla\/5.0 \((?:iPhone|iPad|iPod(?: Touch)?);(.*)AppleWebKit\/((\d+)?[\w\.]+).+?(mobile)\/\w?/i # ios webview
    ], [:version, :major, [:name, 'Mobile Safari'], [:type, :safari]], [
      /version\/((\d+)?[\w\.]+).+?(mobile\s?safari|safari)/i # Safari & Safari Mobile
    ], [:version, :major, :name, [:type, :safari]], [
      /webkit.+?(mobile\s?safari|safari)((\/[\w]+))/i # Safari < 3.0
    ], [:name, [:major, STRING_MAP[:browser][:oldsafari][:major]], [:version, STRING_MAP[:browser][:oldsafari][:version]], [:type, :safari]], [
      /(konqueror)\/((\d+)?[\w\.]+)/i, # Konqueror
      /(webkit|khtml)\/((\d+)?[\w\.]+)/i
    ], [:name, :version, :major], [
      # Gecko based
      /(navigator|netscape)\/((\d+)?[\w\.-]+)/i # Netscape
    ], [[:name, 'Netscape'], :version, :major], [
      /(swiftfox)/i, # Swiftfox
      /(iceweasel|camino|chimera|fennec|maemo\sbrowser|minimo|conkeror)[\/\s]?((\d+)?[\w\.\+]+)/i, # Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror
      /(seamonkey|k-meleon|icecat|iceape|firebird|phoenix)\/((\d+)?[\w\.-]+)/i # Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix
    ], [:name, :version, :major], [
      /(firefox)\/((\d+)?[\w\.-]+)/i, # Firefox
      /(mozilla)\/((\d+)?[\w\.]+).+rv\:.+gecko\/\d+/i, # Mozilla
    ], [:name, :version, :major, [:type, :firefox]], [
      # Other
      /(uc\s?browser|polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|word|excel)[\/\s]?((\d+)?[\w\.]+)/i, # UCBrowser/Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Word/Excel
      /(links)\s\(((\d+)?[\w\.]+)/i, # Links
      /(gobrowser)\/?((\d+)?[\w\.]+)*/i, # GoBrowser
      /(ice\s?browser)\/v?((\d+)?[\w\._]+)/i, # ICE Browser
      /(mosaic)[\/\s]((\d+)?[\w\.]+)/i # Mosaic
    ], [:name, :version, :major]
  ],
  :in_app_browser => [
    [
      /FBAN\/FBIOS/,
      /FB_IAB\/FB4A/,
      /FBAN\/MessengerForiOS/,
      /FB_IAB\/MESSENGER/,
    ], [[:type, :facebook]], [
      /Instagram/,
    ], [[:type, :instagram]],
  ],
  :device => [
    [
      # Shopify POS Go
      /WSC6X|WTH11/i
    ], [[:type, :handheld], [:name, 'Shopify POS Go']],[
      # Shopify Mobile for iPhone
      %r{.*Shopify Mobile/(?:iPhone\sOS|iOS)/[\d\.]+ \((iPhone)([\d,]+)}i
    ], [[:type, :handheld], :model], [
      # Shopify Mobile for iPad
      %r{.*Shopify Mobile/(?:iPhone\sOS|iOS)/[\d\.]+ \((iPad)([\d,]+)}i
    ], [[:type, :tablet], :model], [
      # Shopify Mobile for iPod touch
      %r{.*Shopify Mobile/(?:iPhone\sOS|iOS)/[\d\.]+ \((iPod)([\d,]+)}i
    ], [[:type, :handheld], :model], [
      # Shopify POS Next for iPhone
      %r{.*(?:Shopify POS Next|Shopify POS)/(?:iPhone\sOS|iOS)/[\d\.]+ \((iPhone)([\d,]+)}i
    ], [[:type, :handheld], :model], [
      # Shopify POS Next for iPad
      %r{.*(?:Shopify POS Next|Shopify POS)/(?:iPhone\sOS|iOS)/[\d\.]+ \((iPad)([\d,]+)}i
    ], [[:type, :tablet], :model], [
      # Shopify POS Next for iPod touch
      %r{.*(?:Shopify POS Next|Shopify POS)/(?:iPhone\sOS|iOS)/[\d\.]+ \((iPod)([\d,]+)}i
    ], [[:type, :handheld], :model], [
      # Shopify POS for iOS iPhone/iPod (React Native App)
      %r{.*Shopify POS\/[\d\.]+[^\/]*\/(iOS)\/[\d\.]+\/Apple\/((iPhone|iPod)[^\/]*)\/}i,
    ], [[:type, :handheld], :model], [
      # Shopify POS for iOS iPad (React Native App)
      %r{.*Shopify POS\/[\d\.]+[^\/]*\/(iOS)\/[\d\.]+\/Apple\/(iPad[^\/]*)\/}i,
    ], [[:type, :tablet], :model], [
      # Shopify Ping for iPhone
      %r{.*Shopify Ping/(?:iPhone\sOS|iOS)/[\d\.]+ \((iPhone)([\d,]+)}i
    ], [[:type, :handheld], :model], [
      # Shopify Mobile for Android
      %r{.*Shopify Mobile\/(Android)\/[\d\.]+(?: \(debug(?:|-push)\))? \(Build \d+ with API \d+ on (.*?) ([^\)]*)\)}i
    ], [[:type, :handheld], :vendor, :model], [
      # Shopify POS for iPhone
      %r{.*Shopify POS\/[\d\.]+ \((iPhone)\;.*Scale/([\d\.]+)}i,
    ], [[:type, :handheld], :scale], [
      # Shopify POS for iPad
      %r{.*Shopify POS\/[\d\.]+ \((iPad)\;.*Scale/([\d\.]+)}i,
    ], [[:type, :tablet], :scale], [
      # Shopify POS for iPod touch
      %r{.*Shopify POS\/[\d\.]+ \((iPod touch)\;.*Scale/([\d\.]+)}i,
    ], [[:type, :handheld], :scale], [
      # Shopify POS for Android (SmartWebView)
      %r{.*Shopify\sPOS.*\(.*(Android)\s[\d\.]+\;\s(.*)\sBuild/.*\)\sPOS.*[\d+\.]+}i,
    ], [[:type, :handheld], :model], [
      # Shopify POS for Android (Native App)
      %r{.*\(.*(Android)\s[\d\.]+\;\s(.*)\sBuild/.*\)\sPOS.*[\d+\.]+}i,
    ], [[:type, :handheld], :model], [
      /\((playbook);[\w\s\);-]+(rim)/i # PlayBook
    ], [:model, :vendor, [:type, :tablet]], [
      /\((ipad);[\w\s\);-]+(apple)/i # iPad
    ], [:model, :vendor, [:name, :ipad], [:type, :tablet]], [
      /(hp).+(touchpad)/i, # HP TouchPad
      /(kindle)\/([\w\.]+)/i, # Kindle
      /\s(nook)[\w\s]+build\/(\w+)/i, # Nook
      /(dell)\s(strea[kpr\s\d]*[\dko])/i # Dell Streak
    ], [:vendor, :model, [:type, :tablet]], [
      /\((?:iphone|ipod(?: touch)?);.+(apple)/i # iPod Touch/iPhone
    ], [:model, :vendor, [:name, :iphone], [:type, :handheld]], [
      /(blackberry)[\s-]?(\w+)/i, # BlackBerry
      /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|huawei|meizu|motorola)[\s_-]?([\w-]+)*/i, # BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Huawei/Meizu/Motorola
      /(hp)\s([\w\s]+\w)/i, # HP iPAQ
      /(asus)-?(\w+)/i # Asus
    ], [:vendor, :model, [:type, :handheld]], [
      /\((bb10);\s(\w+)/i # BlackBerry 10
    ], [[:vendor, 'BlackBerry'], :model, [:type, :handheld]], [
      /android.+((transfo[prime\s]{4,10}\s\w+|eeepc|slider\s\w+))/i # Asus Tablets
    ], [[:vendor, 'Asus'], :model, [:type, :tablet]], [
      /(sony)\s(tablet\s[ps])/i # Sony Tablets
    ], [:vendor, :model, [:type, :tablet]], [
      /(nintendo)\s([wids3u]+)/i # Nintendo
    ], [:vendor, :model, [:type, :console]], [
      /((playstation)\s[3portablevi]+)/i # Playstation
    ], [[:vendor, 'Sony'], :model, [:type, :console]], [
      /(sprint\s(\w+))/i # Sprint Phones
    ], [:vendor, :model, [:type, :handheld]], [
      /(htc)[;_\s-]+([\w\s_]+(?=\))|\w+)*/i, # HTC
      /(zte)-(\w+)*/i, # ZTE
      /(alcatel|geeksphone|huawei|lenovo|nexian|panasonic|(?=;\s)sony)[_\s-]?([\w-]+)*/i # Alcatel/GeeksPhone/Huawei/Lenovo/Nexian/Panasonic/Sony
    ], [:vendor, [:model, lambda {|str| str && str.gsub(/_/, ' ') }], [:type, :handheld]], [
      /\s((milestone|droid[2x]?))[globa\s]*\sbuild\//i, # Motorola
      /(mot)[\s-]?(\w+)*/i
    ], [[:vendor, 'Motorola'], :model, [:type, :handheld]], [
      /android.+\s((mz60\d|xoom[\s2]{0,2}))\sbuild\//i
    ], [[:vendor, 'Motorola'], :model, [:type, :tablet]], [
      /android.+((sch-i[89]0\d|shw-m380s|gt-p\d{4}|gt-n8000|sgh-t8[56]9))/i
    ], [[:vendor, 'Samsung'], :model, [:type, :tablet]], [
      # Samsung
      /((s[cgp]h-\w+|gt-\w+|galaxy\snexus))/i,
      /(sam[sung]*)[\s-]*(\w+-?[\w-]*)*/i,
      /sec-((sgh\w+))/i
    ], [[:vendor, 'Samsung'], :model, [:type, :handheld]], [
      /(sie)-(\w+)*/i # Siemens
    ], [[:vendor, 'Siemens'], :model, [:type, :handheld]], [
      /(maemo|nokia).*(n900|lumia\s\d+)/i, # Nokia
      /(nokia)[\s_-]?([\w-]+)*/i
    ], [[:vendor, 'Nokia'], :model, [:type, :handheld]], [
      /android\s3\.[-\s\w;]{10}((a\d{3}))/i # Acer
    ], [[:vendor, 'Acer'], :model, [:type, :tablet]], [
      /android\s3\.[-\s\w;]{10}(lg?)-([06cv9]{3,4})/i # LG
    ], [[:vendor, 'LG'], :model, [:type, :tablet]], [
      /((nexus\s4))/i,
      /(lg)[-e;\s\/]+(\w+)*/i
    ], [[:vendor, 'LG'], :model, [:type, :handheld]], [
      /opera\smobi/i,
      /android/i
    ], [[:type, :handheld]], [
      /nitro/i # Nintendo DS
    ], [[:type, :console]], [
      /(mobile|tablet);.+rv\:.+gecko\//i # Unidentifiable
    ], [:type, :vendor, :model]
  ],
  :engine => [
    [
      /(presto)\/((\d+)[\w\.]+)/i # Presto
    ], [:name, :version, :major, [:type, :presto]], [
      /(webkit)\/((\d+)[\w\.]+)/i # WebKit
    ], [:name, :version, :major, [:type, :webkit]], [
      /(trident)\/((\d+)[\w\.]+)/i # Trident
    ], [:name, :version, :major, [:type, :trident]], [
      /(netfront|netsurf|amaya|lynx|w3m)\/((\d+)[\w\.]+)/i, # NetFront/NetSurf/Amaya/Lynx/w3m
      /(khtml|tasman|links)[\/\s]\(?((\d+)[\w\.]+)/i, # KHTML/Tasman/Links
      /(icab)[\/\s]([23]\.(\d+)[\d\.]+)/i # iCab
    ], [:name, :version, :major], [
      /rv\:((\d+)[\w\.]+).*(gecko)/i # Gecko
    ], [:version, :major, :name, [:type, :gecko]]
  ],
  :os => [
    [
      # Shopify Retail OS on POS Go
      /WSC6X|WTH11/i
    ], [[:name, 'Shopify Retail OS']],[
      # Shopify Mobile for iOS
      %r{.*Shopify/\d+\s\((?:iPhone|iPad)\;\s(iOS)\s([\d\.]+)}i
    ], [[:type, :ios], :version, [:name, 'iOS']], [
      # Shopify POS for iOS
      %r{.*Shopify\sPOS/[\d\.]+\s\((?:iPhone|iPad|iPod\stouch)\;\s(iOS)\s([\d\.]+)}i,
    ], [[:type, :ios], :version, [:name, 'iOS']], [
      # Old Shopify POS for Android
      /^Dalvik.*(Android)\s([\d\.]+)\;\s.*\s[\d+\.]+/i,
    ], [[:type, :android], :version, [:name, 'Android']], [
      # Shopify POS for Android
      /.*Shopify\sPOS\s.*(Android)\s([\d\.]+)\;\s.*\s[\d+\.]+\s/i,
    ], [[:type, :android], :version, [:name, 'Android']], [
      # Shopify Mobile for iOS
      %r{.*Shopify Mobile\/(iPhone\sOS|iOS)\/[\d\.]+ \(.*\/OperatingSystemVersion\((.*)\)}i
    ], [[:type, :ios], [:version, lambda { |str| str && str.scan(/\d+/).join(".") }], [:name, 'iOS']], [
      # Shopify Mobile for iPhone or iPad
      %r{.*(Shopify Mobile)\/(?:iPhone\sOS|iOS)[\/\d\.]* \((iPhone|iPad|iPod).*\/([\d\.]+)\)}i
    ], [[:type, :ios], [:name, 'iOS'], :version], [
      # Shopify Mobile for iPhone or iPad with build number
      %r{.*(Shopify Mobile)\/(?:iPhone\sOS|iOS)[\/\d\.]* \((iPhone|iPad|iPod).*\/([\d\.]+) - Build [\d]*\)}i
    ], [[:type, :ios], [:name, 'iOS'], :version], [
      # Shopify POS Next for iPhone or iPad
      %r{.*(Shopify POS Next|Shopify POS)\/(?:iPhone\sOS|iOS)[\/\d\.]* \((iPhone|iPad|iPod).*\/([\d\.]+)\)}i
    ], [[:type, :ios], [:name, 'iOS'], :version], [
      # Shopify POS for iOS (React Native App)
      %r{.*Shopify POS\/[\d\.]+[^\/]*\/(iOS)\/([\d\.]+)\/(Apple)\/(iPhone|iPad|iPod)[^\/]*\/}i
    ], [[:type, :ios], :version, [:name, 'iOS']], [
      # Shopify Ping for iOS
      %r{.*Shopify Ping\/(iOS)\/[\d\.]+ \(.*\/([\d\.]+)\)}i
    ], [[:type, :ios], :version, [:name, 'iOS']], [
      # Shopify Mobile for Android
      %r{.*Shopify Mobile\/(Android)\/[\d\.]+ }i
    ], [:name, [:type, :android]], [
      # Windows based
      /(windows)\snt\s6\.2;\s(arm)/i, # Windows RT
      /(windows\sphone(?:\sos)*|windows\smobile|windows)[\s\/]?([ntce\d\.\s]+\w)/i,
      /(microsoft windows)/i
    ], [:name, [:version, STRING_MAP[:os][:windows][:version]], [:type, :windows]], [
      /(win(?=3|9|n)|win\s9x\s)([nt\d\.]+)/i
    ], [[:name, 'Windows'], [:version, STRING_MAP[:os][:windows][:version]], [:type, :windows]], [
      # Mobile/Embedded OS
      /\((bb)(10);/i # BlackBerry 10
    ], [[:name, 'BlackBerry'], :version, [:type, :blackberry]], [
      /(blackberry)\w*\/?([\w\.]+)*/i, # Blackberry
      /(rim\stablet\sos)[\/\s-]?([\w\.]+)*/i # RIM
    ], [:name, :version, [:type, :blackberry]], [
      /(android)[\/\s-]?([\w\.]+)*/i # Android
    ], [:name, :version, [:type, :android]], [
      /(tizen)\/([\w\.]+)/i, # Tizen
      /(webos|palm\os|qnx|bada|meego)[\/\s-]?([\w\.]+)*/i # WebOS/Palm/QNX/Bada/MeeGo
    ], [:name, :version], [
      /(symbian\s?os|symbos|s60(?=;))[\/\s-]?([\w\.]+)*/i # Symbian
    ], [[:name, 'Symbian'], :version],[
      /mozilla.+\(mobile;.+gecko.+firefox/i # Firefox OS
    ], [[:name, 'Firefox OS'], :version], [
      # Console
      /(nintendo|playstation)\s([wids3portablevu]+)/i, # Nintendo/Playstation
    ], [:name, :version], [
      # GNU/Linux based
      /(mint)[\/\s\(]?(\w+)*/i, # Mint
      /(joli|[kxln]?ubuntu|debian|[open]*suse|gentoo|arch|slackware|fedora|mandriva|centos|pclinuxos|redhat|zenwalk)[\/\s-]?([\w\.-]+)*/i, # Joli/Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware/Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk
      /(hurd|linux)\s?([\w\.]+)*/i, # Hurd/Linux
      /(gnu)\s?([\w\.]+)*/i # GNU
    ], [:name, :version, [:type, :linux]], [
      /(cros)\s[\w]+\s([\w\.]+\w)/i # Chromium OS
    ], [[:name, 'Chromium OS'], :version, [:type, :chromium_os]],[
      # Solaris
      /(sunos)\s?([\w\.]+\d)*/i # Solaris
    ], [[:name, 'Solaris'], :version], [
      # BSD based
      /\s([frentopc-]{0,4}bsd|dragonfly)\s?([\w\.]+)*/i # FreeBSD/NetBSD/OpenBSD/PC-BSD/DragonFly
    ], [:name, :version],[
      /(ip[honead]+)(?:.*os\s*([\w]+)*\slike\smac|;\sopera)/i # iOS
    ], [[:name, 'iOS'], [:version, lambda {|str| str && str.gsub(/_/, '.') }], [:type, :ios]], [
      /(mac\sos\sx)\s?([\w\s\.]+\w)*/i # Mac OS
    ], [:name, [:version, lambda {|str| str && str.gsub(/_/, '.') }], [:type, :mac]], [
      # Other
      /(haiku)\s(\w+)/i, # Haiku
      /(aix)\s((\d)(?=\.|\)|\s)[\w\.]*)*/i, # AIX
      /(macintosh|mac(?=_powerpc)|plan\s9|minix|beos|os\/2|amigaos|morphos|risc\sos)/i, # Plan9/Minix/BeOS/OS2/AmigaOS/MorphOS/RISCOS
      /(unix)\s?([\w\.]+)*/i # UNIX
    ], [:name, :version]
  ]
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(user_agent) ⇒ BrowserSniffer

Returns a new instance of BrowserSniffer.



7
8
9
# File 'lib/browser_sniffer.rb', line 7

def initialize(user_agent)
  @user_agent = user_agent
end

Instance Attribute Details

#user_agentObject (readonly)

Returns the value of attribute user_agent.



5
6
7
# File 'lib/browser_sniffer.rb', line 5

def user_agent
  @user_agent
end

Instance Method Details

#android?Boolean

Returns:

  • (Boolean)


15
16
17
# File 'lib/browser_sniffer.rb', line 15

def android?
  os == :android
end

#browserObject



73
74
75
# File 'lib/browser_sniffer.rb', line 73

def browser
  browser_info[:type]
end

#browser_infoObject



126
127
128
# File 'lib/browser_sniffer.rb', line 126

def browser_info
  @browser_info ||= parse_user_agent_for(BrowserSniffer::REGEX_MAP[:browser])
end

#browser_nameObject



77
78
79
# File 'lib/browser_sniffer.rb', line 77

def browser_name
  browser_info[:name]
end

#browser_versionObject



86
87
88
# File 'lib/browser_sniffer.rb', line 86

def browser_version
  browser_info[:version]
end

#chromium_based?Boolean

Returns:

  • (Boolean)


195
196
197
# File 'lib/browser_sniffer.rb', line 195

def chromium_based?
  browser_name ? browser_name.downcase.match(/chrom(e|ium)/) : false
end

#desktop?Boolean

Returns:

  • (Boolean)


44
45
46
# File 'lib/browser_sniffer.rb', line 44

def desktop?
  form_factor == :desktop
end

#deviceObject



98
99
100
# File 'lib/browser_sniffer.rb', line 98

def device
  device_info[:name]
end

#device_infoObject



138
139
140
# File 'lib/browser_sniffer.rb', line 138

def device_info
  @device_info ||= parse_user_agent_for(BrowserSniffer::REGEX_MAP[:device])
end

#device_nameObject



102
103
104
# File 'lib/browser_sniffer.rb', line 102

def device_name
  device_info[:model]
end

#device_vendorObject



106
107
108
# File 'lib/browser_sniffer.rb', line 106

def device_vendor
  device_info[:vendor]
end

#engineObject



54
55
56
# File 'lib/browser_sniffer.rb', line 54

def engine
  engine_info[:type]
end

#engine_infoObject



134
135
136
# File 'lib/browser_sniffer.rb', line 134

def engine_info
  @engine_info ||= parse_user_agent_for(BrowserSniffer::REGEX_MAP[:engine])
end

#engine_nameObject



58
59
60
# File 'lib/browser_sniffer.rb', line 58

def engine_name
  engine_info[:name]
end

#engine_versionObject



67
68
69
# File 'lib/browser_sniffer.rb', line 67

def engine_version
  engine_info[:version]
end

#form_factorObject



48
49
50
# File 'lib/browser_sniffer.rb', line 48

def form_factor
  device_info[:type] || :desktop
end

#handheld?Boolean

Returns:

  • (Boolean)


36
37
38
# File 'lib/browser_sniffer.rb', line 36

def handheld?
  form_factor == :handheld
end

#ie11?Boolean

Returns:

  • (Boolean)


23
24
25
# File 'lib/browser_sniffer.rb', line 23

def ie11?
  browser == :ie && major_browser_version == 11
end

#ie11_actual?Boolean

This method checks ie 11 mobile or ie11 rendering an older version in compatibility mode, in addition to ‘ie11?`. The `ie11?` method would return false in both those scenarios.

Returns:

  • (Boolean)


29
30
31
32
33
34
# File 'lib/browser_sniffer.rb', line 29

def ie11_actual?
  ie11_engine = major_engine_version == 7 && engine_name == 'Trident'
  ie_mobile11 = major_browser_version == 11 && browser_name == 'IEMobile'

  ie11? || ie11_engine || ie_mobile11
end

#ie8?Boolean

Returns:

  • (Boolean)


19
20
21
# File 'lib/browser_sniffer.rb', line 19

def ie8?
  browser == :ie && major_browser_version == 8
end

#in_app_browserObject



92
93
94
# File 'lib/browser_sniffer.rb', line 92

def in_app_browser
  in_app_browser_info[:type]
end

#in_app_browser_infoObject



130
131
132
# File 'lib/browser_sniffer.rb', line 130

def in_app_browser_info
  @in_app_browser_info = parse_user_agent_for(BrowserSniffer::REGEX_MAP[:in_app_browser])
end

#ios?Boolean

Returns:

  • (Boolean)


11
12
13
# File 'lib/browser_sniffer.rb', line 11

def ios?
  os == :ios
end

#major_browser_versionObject



81
82
83
84
# File 'lib/browser_sniffer.rb', line 81

def major_browser_version
  str = browser_info[:major]
  str && str.to_i
end

#major_engine_versionObject



62
63
64
65
# File 'lib/browser_sniffer.rb', line 62

def major_engine_version
  str = engine_info[:major]
  str && str.to_i
end

#osObject



112
113
114
# File 'lib/browser_sniffer.rb', line 112

def os
  os_info[:type]
end

#os_infoObject



142
143
144
# File 'lib/browser_sniffer.rb', line 142

def os_info
  @os_info ||= parse_user_agent_for(BrowserSniffer::REGEX_MAP[:os])
end

#os_nameObject



116
117
118
# File 'lib/browser_sniffer.rb', line 116

def os_name
  os_info[:name]
end

#os_versionObject



120
121
122
# File 'lib/browser_sniffer.rb', line 120

def os_version
  os_info[:version]
end

#parse_user_agent_for(type) ⇒ Object



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/browser_sniffer.rb', line 146

def parse_user_agent_for(type)
  result = {}
  type.each_slice(2) do |regexps, format|
    regexps.each do |regex|
      regex.match(user_agent) do |match|
        format.each_with_index do |field, index|
          if field.class == Symbol
            result[field] = match[index + 1]
          elsif field.class == Array
            if field[1].class == String || field[1].class == Symbol
              result[field[0]] = field[1]
            elsif field[1].class == Hash
              if field[1][match[index + 1]]
                result[field[0]] = field[1][match[index + 1]]
              else
                result[field[0]] = match[index + 1]
              end
            elsif field[1].class == Proc
              result[field[0]] = field[1].call(match[index + 1])
            end
          end
        end
        return result
      end
    end
  end
  result
end

#same_site_none_compatible?Boolean

Returns:

  • (Boolean)


175
176
177
178
179
# File 'lib/browser_sniffer.rb', line 175

def same_site_none_compatible?
  return false unless user_agent

  webkit_same_site_compatible? && same_site_recognized_browser?
end

#same_site_recognized_browser?Boolean

Returns:

  • (Boolean)


188
189
190
191
192
193
# File 'lib/browser_sniffer.rb', line 188

def same_site_recognized_browser?
  return false unless major_browser_version

  !(chromium_based? && major_browser_version >= 51 && major_browser_version <= 66) &&
    !(uc_browser? && !uc_browser_version_at_least?(12, 13, 2))
end

#tablet?Boolean

Returns:

  • (Boolean)


40
41
42
# File 'lib/browser_sniffer.rb', line 40

def tablet?
  form_factor == :tablet
end

#uc_browser?Boolean

Returns:

  • (Boolean)


199
200
201
# File 'lib/browser_sniffer.rb', line 199

def uc_browser?
  user_agent ? user_agent.downcase.match(/uc\s?browser/) : false
end

#uc_browser_version_at_least?(major, minor, build) ⇒ Boolean

Returns:

  • (Boolean)


203
204
205
206
207
208
209
210
211
# File 'lib/browser_sniffer.rb', line 203

def uc_browser_version_at_least?(major, minor, build)
  return false unless browser_version
  digits = browser_version.split('.').map(&:to_i)
  return false unless digits.count >= 3

  return digits[0] > major if digits[0] != major
  return digits[1] > minor if digits[1] != minor
  digits[2] >= build
end

#webkit_same_site_compatible?Boolean

Returns:

  • (Boolean)


181
182
183
184
185
186
# File 'lib/browser_sniffer.rb', line 181

def webkit_same_site_compatible?
  return false unless os && os_version && browser

  !(os == :ios && os_version.match(/^([0-9]|1[12])[\.\_]/)) &&
     !(os == :mac && browser == :safari && os_version.match(/^10[\.\_]14/))
end