1 | 'use strict';
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | var regexps = require('./lib/regexps');
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | var osparsers = regexps.os
|
13 | , osparserslength = osparsers.length;
|
14 |
|
15 |
|
16 | var agentparsers = regexps.browser
|
17 | , agentparserslength = agentparsers.length;
|
18 |
|
19 |
|
20 | var deviceparsers = regexps.device
|
21 | , deviceparserslength = deviceparsers.length;
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 | function Agent(family, major, minor, patch, source) {
|
35 | this.family = family || 'Other';
|
36 | this.major = major || '0';
|
37 | this.minor = minor || '0';
|
38 | this.patch = patch || '0';
|
39 | this.source = source || '';
|
40 | }
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 | Object.defineProperty(Agent.prototype, 'os', {
|
49 | get: function lazyparse() {
|
50 | var userAgent = this.source
|
51 | , length = osparserslength
|
52 | , parsers = osparsers
|
53 | , i = 0
|
54 | , parser
|
55 | , res;
|
56 |
|
57 | for (; i < length; i++) {
|
58 | if (res = parsers[i][0].exec(userAgent)) {
|
59 | parser = parsers[i];
|
60 |
|
61 | if (parser[1]) res[1] = parser[1].replace('$1', res[1]);
|
62 | break;
|
63 | }
|
64 | }
|
65 |
|
66 | return Object.defineProperty(this, 'os', {
|
67 | value: !parser || !res
|
68 | ? new OperatingSystem()
|
69 | : new OperatingSystem(
|
70 | res[1]
|
71 | , parser[2] || res[2]
|
72 | , parser[3] || res[3]
|
73 | , parser[4] || res[4]
|
74 | )
|
75 | }).os;
|
76 | },
|
77 |
|
78 | |
79 |
|
80 |
|
81 |
|
82 |
|
83 |
|
84 | set: function set(os) {
|
85 | if (!(os instanceof OperatingSystem)) return false;
|
86 |
|
87 | return Object.defineProperty(this, 'os', {
|
88 | value: os
|
89 | }).os;
|
90 | }
|
91 | });
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 | Object.defineProperty(Agent.prototype, 'device', {
|
100 | get: function lazyparse() {
|
101 | var userAgent = this.source
|
102 | , length = deviceparserslength
|
103 | , parsers = deviceparsers
|
104 | , i = 0
|
105 | , parser
|
106 | , res;
|
107 |
|
108 | for (; i < length; i++) {
|
109 | if (res = parsers[i][0].exec(userAgent)) {
|
110 | parser = parsers[i];
|
111 |
|
112 | if (parser[1]) res[1] = parser[1].replace('$1', res[1]);
|
113 | break;
|
114 | }
|
115 | }
|
116 |
|
117 | return Object.defineProperty(this, 'device', {
|
118 | value: !parser || !res
|
119 | ? new Device()
|
120 | : new Device(
|
121 | res[1]
|
122 | , parser[2] || res[2]
|
123 | , parser[3] || res[3]
|
124 | , parser[4] || res[4]
|
125 | )
|
126 | }).device;
|
127 | },
|
128 |
|
129 | |
130 |
|
131 |
|
132 |
|
133 |
|
134 |
|
135 | set: function set(device) {
|
136 | if (!(device instanceof Device)) return false;
|
137 |
|
138 | return Object.defineProperty(this, 'device', {
|
139 | value: device
|
140 | }).device;
|
141 | }
|
142 | });
|
143 |
|
144 |
|
145 |
|
146 |
|
147 |
|
148 | Agent.prototype.toAgent = function toAgent() {
|
149 | var output = this.family
|
150 | , version = this.toVersion();
|
151 |
|
152 | if (version) output += ' '+ version;
|
153 | return output;
|
154 | };
|
155 |
|
156 |
|
157 |
|
158 |
|
159 |
|
160 |
|
161 |
|
162 | Agent.prototype.toString = function toString() {
|
163 | var agent = this.toAgent()
|
164 | , os = this.os !== 'Other' ? this.os : false;
|
165 |
|
166 | return agent + (os ? ' / ' + os : '');
|
167 | };
|
168 |
|
169 |
|
170 |
|
171 |
|
172 |
|
173 |
|
174 |
|
175 | Agent.prototype.toVersion = function toVersion() {
|
176 | var version = '';
|
177 |
|
178 | if (this.major) {
|
179 | version += this.major;
|
180 |
|
181 | if (this.minor) {
|
182 | version += '.' + this.minor;
|
183 |
|
184 |
|
185 |
|
186 | if (this.patch) {
|
187 | version += (isNaN(+this.patch) ? ' ' : '.') + this.patch;
|
188 | }
|
189 | }
|
190 | }
|
191 |
|
192 | return version;
|
193 | };
|
194 |
|
195 |
|
196 |
|
197 |
|
198 |
|
199 |
|
200 |
|
201 | Agent.prototype.toJSON = function toJSON() {
|
202 | return {
|
203 | family: this.family
|
204 | , major: this.major
|
205 | , minor: this.minor
|
206 | , patch: this.patch
|
207 | , device: this.device
|
208 | , os: this.os
|
209 | };
|
210 | };
|
211 |
|
212 |
|
213 |
|
214 |
|
215 |
|
216 |
|
217 |
|
218 |
|
219 |
|
220 |
|
221 |
|
222 | function OperatingSystem(family, major, minor, patch) {
|
223 | this.family = family || 'Other';
|
224 | this.major = major || '0';
|
225 | this.minor = minor || '0';
|
226 | this.patch = patch || '0';
|
227 | }
|
228 |
|
229 |
|
230 |
|
231 |
|
232 |
|
233 |
|
234 |
|
235 | OperatingSystem.prototype.toString = function toString() {
|
236 | var output = this.family
|
237 | , version = this.toVersion();
|
238 |
|
239 | if (version) output += ' '+ version;
|
240 | return output;
|
241 | };
|
242 |
|
243 |
|
244 |
|
245 |
|
246 |
|
247 |
|
248 |
|
249 | OperatingSystem.prototype.toVersion = function toVersion() {
|
250 | var version = '';
|
251 |
|
252 | if (this.major) {
|
253 | version += this.major;
|
254 |
|
255 | if (this.minor) {
|
256 | version += '.' + this.minor;
|
257 |
|
258 |
|
259 |
|
260 | if (this.patch) {
|
261 | version += (isNaN(+this.patch) ? ' ' : '.') + this.patch;
|
262 | }
|
263 | }
|
264 | }
|
265 |
|
266 | return version;
|
267 | };
|
268 |
|
269 |
|
270 |
|
271 |
|
272 |
|
273 |
|
274 |
|
275 |
|
276 | OperatingSystem.prototype.toJSON = function toJSON(){
|
277 | return {
|
278 | family: this.family
|
279 | , major: this.major || undefined
|
280 | , minor: this.minor || undefined
|
281 | , patch: this.patch || undefined
|
282 | };
|
283 | };
|
284 |
|
285 |
|
286 |
|
287 |
|
288 |
|
289 |
|
290 |
|
291 |
|
292 |
|
293 |
|
294 |
|
295 | function Device(family, major, minor, patch) {
|
296 | this.family = family || 'Other';
|
297 | this.major = major || '0';
|
298 | this.minor = minor || '0';
|
299 | this.patch = patch || '0';
|
300 | }
|
301 |
|
302 |
|
303 |
|
304 |
|
305 |
|
306 |
|
307 |
|
308 | Device.prototype.toString = function toString() {
|
309 | var output = this.family
|
310 | , version = this.toVersion();
|
311 |
|
312 | if (version) output += ' '+ version;
|
313 | return output;
|
314 | };
|
315 |
|
316 |
|
317 |
|
318 |
|
319 |
|
320 |
|
321 |
|
322 | Device.prototype.toVersion = function toVersion() {
|
323 | var version = '';
|
324 |
|
325 | if (this.major) {
|
326 | version += this.major;
|
327 |
|
328 | if (this.minor) {
|
329 | version += '.' + this.minor;
|
330 |
|
331 |
|
332 |
|
333 | if (this.patch) {
|
334 | version += (isNaN(+this.patch) ? ' ' : '.') + this.patch;
|
335 | }
|
336 | }
|
337 | }
|
338 |
|
339 | return version;
|
340 | };
|
341 |
|
342 |
|
343 |
|
344 |
|
345 |
|
346 |
|
347 |
|
348 |
|
349 | Device.prototype.toJSON = function toJSON() {
|
350 | return {
|
351 | family: this.family
|
352 | , major: this.major || undefined
|
353 | , minor: this.minor || undefined
|
354 | , patch: this.patch || undefined
|
355 | };
|
356 | };
|
357 |
|
358 |
|
359 |
|
360 |
|
361 |
|
362 |
|
363 |
|
364 |
|
365 |
|
366 | module.exports = function updater() {
|
367 | try {
|
368 | require('./lib/update').update(function updating(err, results) {
|
369 | if (err) {
|
370 | console.log('[useragent] Failed to update the parsed due to an error:');
|
371 | console.log('[useragent] '+ (err.message ? err.message : err));
|
372 | return;
|
373 | }
|
374 |
|
375 | regexps = results;
|
376 |
|
377 |
|
378 | osparsers = regexps.os;
|
379 | osparserslength = osparsers.length;
|
380 |
|
381 |
|
382 | agentparsers = regexps.browser;
|
383 | agentparserslength = agentparsers.length;
|
384 |
|
385 |
|
386 | deviceparsers = regexps.device;
|
387 | deviceparserslength = deviceparsers.length;
|
388 | });
|
389 | } catch (e) {
|
390 | console.error('[useragent] If you want to use automatic updating, please add:');
|
391 | console.error('[useragent] - request (npm install request --save)');
|
392 | console.error('[useragent] - yamlparser (npm install yamlparser --save)');
|
393 | console.error('[useragent] To your own package.json');
|
394 | }
|
395 | };
|
396 |
|
397 |
|
398 | exports = module.exports;
|
399 |
|
400 |
|
401 |
|
402 |
|
403 |
|
404 | exports.Device = Device;
|
405 | exports.OperatingSystem = OperatingSystem;
|
406 | exports.Agent = Agent;
|
407 |
|
408 |
|
409 |
|
410 |
|
411 |
|
412 |
|
413 |
|
414 |
|
415 |
|
416 |
|
417 | exports.parse = function parse(userAgent, jsAgent) {
|
418 | if (!userAgent) return new Agent();
|
419 |
|
420 | var length = agentparserslength
|
421 | , parsers = agentparsers
|
422 | , i = 0
|
423 | , parser
|
424 | , res;
|
425 |
|
426 | for (; i < length; i++) {
|
427 | if (res = parsers[i][0].exec(userAgent)) {
|
428 | parser = parsers[i];
|
429 |
|
430 | if (parser[1]) res[1] = parser[1].replace('$1', res[1]);
|
431 | if (!jsAgent) return new Agent(
|
432 | res[1]
|
433 | , parser[2] || res[2]
|
434 | , parser[3] || res[3]
|
435 | , parser[4] || res[4]
|
436 | , userAgent
|
437 | );
|
438 |
|
439 | break;
|
440 | }
|
441 | }
|
442 |
|
443 |
|
444 |
|
445 | if (!parser || !res) return new Agent('', '', '', '', userAgent);
|
446 |
|
447 |
|
448 |
|
449 | if (jsAgent && ~jsAgent.indexOf('Chrome/') && ~userAgent.indexOf('chromeframe')) {
|
450 | res[1] = 'Chrome Frame (IE '+ res[1] +'.'+ res[2] +')';
|
451 |
|
452 |
|
453 |
|
454 | parser = parse(jsAgent);
|
455 | parser[2] = parser.major;
|
456 | parser[3] = parser.minor;
|
457 | parser[4] = parser.patch;
|
458 | }
|
459 |
|
460 | return new Agent(
|
461 | res[1]
|
462 | , parser[2] || res[2]
|
463 | , parser[3] || res[3]
|
464 | , parser[4] || res[4]
|
465 | , userAgent
|
466 | );
|
467 | };
|
468 |
|
469 |
|
470 |
|
471 |
|
472 |
|
473 |
|
474 |
|
475 |
|
476 |
|
477 |
|
478 |
|
479 |
|
480 |
|
481 | var LRU = require('lru-cache')(5000);
|
482 | exports.lookup = function lookup(userAgent, jsAgent) {
|
483 | var key = (userAgent || '')+(jsAgent || '')
|
484 | , cached = LRU.get(key);
|
485 |
|
486 | if (cached) return cached;
|
487 | LRU.set(key, (cached = exports.parse(userAgent, jsAgent)));
|
488 |
|
489 | return cached;
|
490 | };
|
491 |
|
492 |
|
493 |
|
494 |
|
495 |
|
496 |
|
497 |
|
498 |
|
499 |
|
500 |
|
501 | exports.is = function is(useragent) {
|
502 | var ua = (useragent || '').toLowerCase()
|
503 | , details = {
|
504 | chrome: false
|
505 | , firefox: false
|
506 | , ie: false
|
507 | , mobile_safari: false
|
508 | , mozilla: false
|
509 | , opera: false
|
510 | , safari: false
|
511 | , webkit: false
|
512 | , android: false
|
513 | , version: (ua.match(exports.is.versionRE) || [0, "0"])[1]
|
514 | };
|
515 |
|
516 | if (~ua.indexOf('webkit')) {
|
517 | details.webkit = true;
|
518 |
|
519 | if (~ua.indexOf('android')){
|
520 | details.android = true;
|
521 | }
|
522 |
|
523 | if (~ua.indexOf('chrome')) {
|
524 | details.chrome = true;
|
525 | } else if (~ua.indexOf('safari')) {
|
526 | details.safari = true;
|
527 |
|
528 | if (~ua.indexOf('mobile') && ~ua.indexOf('apple')) {
|
529 | details.mobile_safari = true;
|
530 | }
|
531 | }
|
532 | } else if (~ua.indexOf('opera')) {
|
533 | details.opera = true;
|
534 | } else if (~ua.indexOf('trident') || ~ua.indexOf('msie')) {
|
535 | details.ie = true;
|
536 | } else if (~ua.indexOf('mozilla') && !~ua.indexOf('compatible')) {
|
537 | details.mozilla = true;
|
538 |
|
539 | if (~ua.indexOf('firefox')) details.firefox = true;
|
540 | }
|
541 |
|
542 |
|
543 | return details;
|
544 | };
|
545 |
|
546 |
|
547 |
|
548 |
|
549 |
|
550 |
|
551 |
|
552 | exports.is.versionRE = /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/;
|
553 |
|
554 |
|
555 |
|
556 |
|
557 |
|
558 |
|
559 |
|
560 | exports.fromJSON = function fromJSON(details) {
|
561 | if (typeof details === 'string') details = JSON.parse(details);
|
562 |
|
563 | var agent = new Agent(details.family, details.major, details.minor, details.patch)
|
564 | , os = details.os;
|
565 |
|
566 |
|
567 | if ('device' in details) {
|
568 | agent.device = new Device(details.device.family);
|
569 | } else {
|
570 | agent.device = new Device();
|
571 | }
|
572 |
|
573 | if ('os' in details && os) {
|
574 |
|
575 |
|
576 |
|
577 | if (typeof os === 'string') {
|
578 | agent.os = new OperatingSystem(os);
|
579 | } else {
|
580 | agent.os = new OperatingSystem(os.family, os.major, os.minor, os.patch);
|
581 | }
|
582 | }
|
583 |
|
584 | return agent;
|
585 | };
|
586 |
|
587 |
|
588 |
|
589 |
|
590 |
|
591 |
|
592 |
|
593 | exports.version = require('./package.json').version;
|