PageRenderTime 41ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/node_modules/useragent/index.js

https://gitlab.com/JuanCalcagnoDev/CertFront
JavaScript | 593 lines | 310 code | 78 blank | 205 comment | 92 complexity | 52622042eb9c2a2ef06d24f7ffb8177e MD5 | raw file
  1. 'use strict';
  2. /**
  3. * This is where all the magic comes from, specially crafted for `useragent`.
  4. */
  5. var regexps = require('./lib/regexps');
  6. /**
  7. * Reduce references by storing the lookups.
  8. */
  9. // OperatingSystem parsers:
  10. var osparsers = regexps.os
  11. , osparserslength = osparsers.length;
  12. // UserAgent parsers:
  13. var agentparsers = regexps.browser
  14. , agentparserslength = agentparsers.length;
  15. // Device parsers:
  16. var deviceparsers = regexps.device
  17. , deviceparserslength = deviceparsers.length;
  18. /**
  19. * The representation of a parsed user agent.
  20. *
  21. * @constructor
  22. * @param {String} family The name of the browser
  23. * @param {String} major Major version of the browser
  24. * @param {String} minor Minor version of the browser
  25. * @param {String} patch Patch version of the browser
  26. * @param {String} source The actual user agent string
  27. * @api public
  28. */
  29. function Agent(family, major, minor, patch, source) {
  30. this.family = family || 'Other';
  31. this.major = major || '0';
  32. this.minor = minor || '0';
  33. this.patch = patch || '0';
  34. this.source = source || '';
  35. }
  36. /**
  37. * OnDemand parsing of the Operating System.
  38. *
  39. * @type {OperatingSystem}
  40. * @api public
  41. */
  42. Object.defineProperty(Agent.prototype, 'os', {
  43. get: function lazyparse() {
  44. var userAgent = this.source
  45. , length = osparserslength
  46. , parsers = osparsers
  47. , i = 0
  48. , parser
  49. , res;
  50. for (; i < length; i++) {
  51. if (res = parsers[i][0].exec(userAgent)) {
  52. parser = parsers[i];
  53. if (parser[1]) res[1] = parser[1].replace('$1', res[1]);
  54. break;
  55. }
  56. }
  57. return Object.defineProperty(this, 'os', {
  58. value: !parser || !res
  59. ? new OperatingSystem()
  60. : new OperatingSystem(
  61. res[1]
  62. , parser[2] || res[2]
  63. , parser[3] || res[3]
  64. , parser[4] || res[4]
  65. )
  66. }).os;
  67. },
  68. /**
  69. * Bypass the OnDemand parsing and set an OperatingSystem instance.
  70. *
  71. * @param {OperatingSystem} os
  72. * @api public
  73. */
  74. set: function set(os) {
  75. if (!(os instanceof OperatingSystem)) return false;
  76. return Object.defineProperty(this, 'os', {
  77. value: os
  78. }).os;
  79. }
  80. });
  81. /**
  82. * OnDemand parsing of the Device type.
  83. *
  84. * @type {Device}
  85. * @api public
  86. */
  87. Object.defineProperty(Agent.prototype, 'device', {
  88. get: function lazyparse() {
  89. var userAgent = this.source
  90. , length = deviceparserslength
  91. , parsers = deviceparsers
  92. , i = 0
  93. , parser
  94. , res;
  95. for (; i < length; i++) {
  96. if (res = parsers[i][0].exec(userAgent)) {
  97. parser = parsers[i];
  98. if (parser[1]) res[1] = parser[1].replace('$1', res[1]);
  99. break;
  100. }
  101. }
  102. return Object.defineProperty(this, 'device', {
  103. value: !parser || !res
  104. ? new Device()
  105. : new Device(
  106. res[1]
  107. , parser[2] || res[2]
  108. , parser[3] || res[3]
  109. , parser[4] || res[4]
  110. )
  111. }).device;
  112. },
  113. /**
  114. * Bypass the OnDemand parsing and set an Device instance.
  115. *
  116. * @param {Device} device
  117. * @api public
  118. */
  119. set: function set(device) {
  120. if (!(device instanceof Device)) return false;
  121. return Object.defineProperty(this, 'device', {
  122. value: device
  123. }).device;
  124. }
  125. });
  126. /*** Generates a string output of the parsed user agent.
  127. *
  128. * @returns {String}
  129. * @api public
  130. */
  131. Agent.prototype.toAgent = function toAgent() {
  132. var output = this.family
  133. , version = this.toVersion();
  134. if (version) output += ' '+ version;
  135. return output;
  136. };
  137. /**
  138. * Generates a string output of the parser user agent and operating system.
  139. *
  140. * @returns {String} "UserAgent 0.0.0 / OS"
  141. * @api public
  142. */
  143. Agent.prototype.toString = function toString() {
  144. var agent = this.toAgent()
  145. , os = this.os !== 'Other' ? this.os : false;
  146. return agent + (os ? ' / ' + os : '');
  147. };
  148. /**
  149. * Outputs a compiled veersion number of the user agent.
  150. *
  151. * @returns {String}
  152. * @api public
  153. */
  154. Agent.prototype.toVersion = function toVersion() {
  155. var version = '';
  156. if (this.major) {
  157. version += this.major;
  158. if (this.minor) {
  159. version += '.' + this.minor;
  160. // Special case here, the patch can also be Alpha, Beta etc so we need
  161. // to check if it's a string or not.
  162. if (this.patch) {
  163. version += (isNaN(+this.patch) ? ' ' : '.') + this.patch;
  164. }
  165. }
  166. }
  167. return version;
  168. };
  169. /**
  170. * Outputs a JSON string of the Agent.
  171. *
  172. * @returns {String}
  173. * @api public
  174. */
  175. Agent.prototype.toJSON = function toJSON() {
  176. return {
  177. family: this.family
  178. , major: this.major
  179. , minor: this.minor
  180. , patch: this.patch
  181. , device: this.device
  182. , os: this.os
  183. };
  184. };
  185. /**
  186. * The representation of a parsed Operating System.
  187. *
  188. * @constructor
  189. * @param {String} family The name of the os
  190. * @param {String} major Major version of the os
  191. * @param {String} minor Minor version of the os
  192. * @param {String} patch Patch version of the os
  193. * @api public
  194. */
  195. function OperatingSystem(family, major, minor, patch) {
  196. this.family = family || 'Other';
  197. this.major = major || '0';
  198. this.minor = minor || '0';
  199. this.patch = patch || '0';
  200. }
  201. /**
  202. * Generates a stringified version of the Operating System.
  203. *
  204. * @returns {String} "Operating System 0.0.0"
  205. * @api public
  206. */
  207. OperatingSystem.prototype.toString = function toString() {
  208. var output = this.family
  209. , version = this.toVersion();
  210. if (version) output += ' '+ version;
  211. return output;
  212. };
  213. /**
  214. * Generates the version of the Operating System.
  215. *
  216. * @returns {String}
  217. * @api public
  218. */
  219. OperatingSystem.prototype.toVersion = function toVersion() {
  220. var version = '';
  221. if (this.major) {
  222. version += this.major;
  223. if (this.minor) {
  224. version += '.' + this.minor;
  225. // Special case here, the patch can also be Alpha, Beta etc so we need
  226. // to check if it's a string or not.
  227. if (this.patch) {
  228. version += (isNaN(+this.patch) ? ' ' : '.') + this.patch;
  229. }
  230. }
  231. }
  232. return version;
  233. };
  234. /**
  235. * Outputs a JSON string of the OS, values are defaulted to undefined so they
  236. * are not outputed in the stringify.
  237. *
  238. * @returns {String}
  239. * @api public
  240. */
  241. OperatingSystem.prototype.toJSON = function toJSON(){
  242. return {
  243. family: this.family
  244. , major: this.major || undefined
  245. , minor: this.minor || undefined
  246. , patch: this.patch || undefined
  247. };
  248. };
  249. /**
  250. * The representation of a parsed Device.
  251. *
  252. * @constructor
  253. * @param {String} family The name of the device
  254. * @param {String} major Major version of the device
  255. * @param {String} minor Minor version of the device
  256. * @param {String} patch Patch version of the device
  257. * @api public
  258. */
  259. function Device(family, major, minor, patch) {
  260. this.family = family || 'Other';
  261. this.major = major || '0';
  262. this.minor = minor || '0';
  263. this.patch = patch || '0';
  264. }
  265. /**
  266. * Generates a stringified version of the Device.
  267. *
  268. * @returns {String} "Device 0.0.0"
  269. * @api public
  270. */
  271. Device.prototype.toString = function toString() {
  272. var output = this.family
  273. , version = this.toVersion();
  274. if (version) output += ' '+ version;
  275. return output;
  276. };
  277. /**
  278. * Generates the version of the Device.
  279. *
  280. * @returns {String}
  281. * @api public
  282. */
  283. Device.prototype.toVersion = function toVersion() {
  284. var version = '';
  285. if (this.major) {
  286. version += this.major;
  287. if (this.minor) {
  288. version += '.' + this.minor;
  289. // Special case here, the patch can also be Alpha, Beta etc so we need
  290. // to check if it's a string or not.
  291. if (this.patch) {
  292. version += (isNaN(+this.patch) ? ' ' : '.') + this.patch;
  293. }
  294. }
  295. }
  296. return version;
  297. };
  298. /**
  299. * Outputs a JSON string of the Device, values are defaulted to undefined so they
  300. * are not outputed in the stringify.
  301. *
  302. * @returns {String}
  303. * @api public
  304. */
  305. Device.prototype.toJSON = function toJSON() {
  306. return {
  307. family: this.family
  308. , major: this.major || undefined
  309. , minor: this.minor || undefined
  310. , patch: this.patch || undefined
  311. };
  312. };
  313. /**
  314. * Small nifty thick that allows us to download a fresh set regexs from t3h
  315. * Int3rNetz when we want to. We will be using the compiled version by default
  316. * but users can opt-in for updates.
  317. *
  318. * @param {Boolean} refresh Refresh the dataset from the remote
  319. * @api public
  320. */
  321. module.exports = function updater() {
  322. try {
  323. require('./lib/update').update(function updating(err, results) {
  324. if (err) {
  325. console.log('[useragent] Failed to update the parsed due to an error:');
  326. console.log('[useragent] '+ (err.message ? err.message : err));
  327. return;
  328. }
  329. regexps = results;
  330. // OperatingSystem parsers:
  331. osparsers = regexps.os;
  332. osparserslength = osparsers.length;
  333. // UserAgent parsers:
  334. agentparsers = regexps.browser;
  335. agentparserslength = agentparsers.length;
  336. // Device parsers:
  337. deviceparsers = regexps.device;
  338. deviceparserslength = deviceparsers.length;
  339. });
  340. } catch (e) {
  341. console.error('[useragent] If you want to use automatic updating, please add:');
  342. console.error('[useragent] - request (npm install request --save)');
  343. console.error('[useragent] - yamlparser (npm install yamlparser --save)');
  344. console.error('[useragent] To your own package.json');
  345. }
  346. };
  347. // Override the exports with our newly set module.exports
  348. exports = module.exports;
  349. /**
  350. * Nao that we have setup all the different classes and configured it we can
  351. * actually start assembling and exposing everything.
  352. */
  353. exports.Device = Device;
  354. exports.OperatingSystem = OperatingSystem;
  355. exports.Agent = Agent;
  356. /**
  357. * Parses the user agent string with the generated parsers from the
  358. * ua-parser project on google code.
  359. *
  360. * @param {String} userAgent The user agent string
  361. * @param {String} jsAgent Optional UA from js to detect chrome frame
  362. * @returns {Agent}
  363. * @api public
  364. */
  365. exports.parse = function parse(userAgent, jsAgent) {
  366. if (!userAgent) return new Agent();
  367. var length = agentparserslength
  368. , parsers = agentparsers
  369. , i = 0
  370. , parser
  371. , res;
  372. for (; i < length; i++) {
  373. if (res = parsers[i][0].exec(userAgent)) {
  374. parser = parsers[i];
  375. if (parser[1]) res[1] = parser[1].replace('$1', res[1]);
  376. if (!jsAgent) return new Agent(
  377. res[1]
  378. , parser[2] || res[2]
  379. , parser[3] || res[3]
  380. , parser[4] || res[4]
  381. , userAgent
  382. );
  383. break;
  384. }
  385. }
  386. // Return early if we didn't find an match, but might still be able to parse
  387. // the os and device, so make sure we supply it with the source
  388. if (!parser || !res) return new Agent('', '', '', '', userAgent);
  389. // Detect Chrome Frame, but make sure it's enabled! So we need to check for
  390. // the Chrome/ so we know that it's actually using Chrome under the hood.
  391. if (jsAgent && ~jsAgent.indexOf('Chrome/') && ~userAgent.indexOf('chromeframe')) {
  392. res[1] = 'Chrome Frame (IE '+ res[1] +'.'+ res[2] +')';
  393. // Run the JavaScripted userAgent string through the parser again so we can
  394. // update the version numbers;
  395. parser = parse(jsAgent);
  396. parser[2] = parser.major;
  397. parser[3] = parser.minor;
  398. parser[4] = parser.patch;
  399. }
  400. return new Agent(
  401. res[1]
  402. , parser[2] || res[2]
  403. , parser[3] || res[3]
  404. , parser[4] || res[4]
  405. , userAgent
  406. );
  407. };
  408. /**
  409. * If you are doing a lot of lookups you might want to cache the results of the
  410. * parsed user agent string instead, in memory.
  411. *
  412. * @TODO We probably want to create 2 dictionary's here 1 for the Agent
  413. * instances and one for the userAgent instance mapping so we can re-use simular
  414. * Agent instance and lower our memory consumption.
  415. *
  416. * @param {String} userAgent The user agent string
  417. * @param {String} jsAgent Optional UA from js to detect chrome frame
  418. * @api public
  419. */
  420. var LRU = require('lru-cache')(5000);
  421. exports.lookup = function lookup(userAgent, jsAgent) {
  422. var key = (userAgent || '')+(jsAgent || '')
  423. , cached = LRU.get(key);
  424. if (cached) return cached;
  425. LRU.set(key, (cached = exports.parse(userAgent, jsAgent)));
  426. return cached;
  427. };
  428. /**
  429. * Does a more inaccurate but more common check for useragents identification.
  430. * The version detection is from the jQuery.com library and is licensed under
  431. * MIT.
  432. *
  433. * @param {String} useragent The user agent
  434. * @returns {Object} matches
  435. * @api public
  436. */
  437. exports.is = function is(useragent) {
  438. var ua = (useragent || '').toLowerCase()
  439. , details = {
  440. chrome: false
  441. , firefox: false
  442. , ie: false
  443. , mobile_safari: false
  444. , mozilla: false
  445. , opera: false
  446. , safari: false
  447. , webkit: false
  448. , android: false
  449. , version: (ua.match(exports.is.versionRE) || [0, "0"])[1]
  450. };
  451. if (~ua.indexOf('webkit')) {
  452. details.webkit = true;
  453. if (~ua.indexOf('android')){
  454. details.android = true;
  455. }
  456. if (~ua.indexOf('chrome')) {
  457. details.chrome = true;
  458. } else if (~ua.indexOf('safari')) {
  459. details.safari = true;
  460. if (~ua.indexOf('mobile') && ~ua.indexOf('apple')) {
  461. details.mobile_safari = true;
  462. }
  463. }
  464. } else if (~ua.indexOf('opera')) {
  465. details.opera = true;
  466. } else if (~ua.indexOf('trident') || ~ua.indexOf('msie')) {
  467. details.ie = true;
  468. } else if (~ua.indexOf('mozilla') && !~ua.indexOf('compatible')) {
  469. details.mozilla = true;
  470. if (~ua.indexOf('firefox')) details.firefox = true;
  471. }
  472. return details;
  473. };
  474. /**
  475. * Parses out the version numbers.
  476. *
  477. * @type {RegExp}
  478. * @api private
  479. */
  480. exports.is.versionRE = /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/;
  481. /**
  482. * Transform a JSON object back to a valid userAgent string
  483. *
  484. * @param {Object} details
  485. * @returns {Agent}
  486. */
  487. exports.fromJSON = function fromJSON(details) {
  488. if (typeof details === 'string') details = JSON.parse(details);
  489. var agent = new Agent(details.family, details.major, details.minor, details.patch)
  490. , os = details.os;
  491. // The device family was added in v2.0
  492. if ('device' in details) {
  493. agent.device = new Device(details.device.family);
  494. } else {
  495. agent.device = new Device();
  496. }
  497. if ('os' in details && os) {
  498. // In v1.1.0 we only parsed out the Operating System name, not the full
  499. // version which we added in v2.0. To provide backwards compatible we should
  500. // we should set the details.os as family
  501. if (typeof os === 'string') {
  502. agent.os = new OperatingSystem(os);
  503. } else {
  504. agent.os = new OperatingSystem(os.family, os.major, os.minor, os.patch);
  505. }
  506. }
  507. return agent;
  508. };
  509. /**
  510. * Library version.
  511. *
  512. * @type {String}
  513. * @api public
  514. */
  515. exports.version = require('./package.json').version;