44
44
45
45
import type { Faker } from '../..' ;
46
46
47
- export type Arch = 'lin' | 'mac' | 'win' ;
47
+ type OS = 'lin' | 'mac' | 'win' ;
48
48
49
- export function generate ( faker : Faker ) : string {
50
- function rnd (
51
- a ?: string [ ] | number | Record < string , number > ,
52
- b ?: number
53
- ) : string | number {
54
- //calling rnd() with no arguments is identical to rnd(0, 100)
55
- a = a || 0 ;
56
- b = b || 100 ;
57
-
58
- if ( typeof b === 'number' && typeof a === 'number' ) {
59
- // 9/2018 - Added faker random to ensure mersenne and seed
60
- return faker . datatype . number ( { min : a , max : b } ) ;
61
- }
49
+ type Browser = 'chrome' | 'iexplorer' | 'firefox' | 'safari' | 'opera' ;
62
50
63
- if ( Array . isArray ( a ) ) {
64
- //returns a random element from array (a), even weighting
65
- return faker . helpers . arrayElement ( a ) ;
66
- }
67
-
68
- if ( a && typeof a === 'object' ) {
69
- //returns a random key from the passed object; keys are weighted by the decimal probability in their value
70
- return ( ( obj ) => {
71
- const rand = ( rnd ( 0 , 100 ) as number ) / 100 ;
72
- let min = 0 ;
73
- let max = 0 ;
74
- let return_val : string ;
51
+ /**
52
+ * Generates a random user-agent.
53
+ *
54
+ * @param faker An existing faker instance.
55
+ */
56
+ export function generate ( faker : Faker ) : string {
57
+ const weightedKeyFromObject = < T extends Record < string , number > > (
58
+ obj : T
59
+ ) : keyof T => {
60
+ //returns a random key from the passed object; keys are weighted by the decimal probability in their value
61
+ const rand = faker . datatype . number ( { min : 0 , max : 100 } ) / 100 ;
62
+ let min = 0 ;
63
+ let max = 0 ;
64
+ let return_val : string ;
75
65
76
- for ( const key in obj ) {
77
- if ( Object . prototype . hasOwnProperty . call ( obj , key ) ) {
78
- max = obj [ key ] + min ;
79
- return_val = key ;
80
- if ( rand >= min && rand <= max ) {
81
- break ;
82
- }
83
- min = min + obj [ key ] ;
84
- }
66
+ for ( const key in obj ) {
67
+ if ( Object . prototype . hasOwnProperty . call ( obj , key ) ) {
68
+ max = obj [ key ] + min ;
69
+ return_val = key ;
70
+ if ( rand >= min && rand <= max ) {
71
+ break ;
85
72
}
86
-
87
- return return_val ;
88
- } ) ( a ) ;
73
+ min = min + obj [ key ] ;
74
+ }
89
75
}
90
76
91
- throw new TypeError (
92
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
93
- `Invalid arguments passed to rnd. (${ b ? `${ a } , ${ b } ` : a } )`
94
- ) ;
95
- }
77
+ return return_val ;
78
+ } ;
96
79
97
- function randomLang ( ) : string | number {
98
- return rnd ( [
80
+ const randomLang = ( ) : string =>
81
+ faker . helpers . arrayElement ( [
99
82
'AB' ,
100
83
'AF' ,
101
84
'AN' ,
@@ -193,80 +176,113 @@ export function generate(faker: Faker): string {
193
176
'YI' ,
194
177
'ZH' ,
195
178
] ) ;
196
- }
197
179
198
- function randomBrowserAndOS ( ) : Array < string | number > {
199
- const browser = rnd ( {
180
+ const randomBrowserAndOS = ( ) : [ Browser , OS ] = > {
181
+ const browser : Browser = weightedKeyFromObject ( {
200
182
chrome : 0.45132810566 ,
201
183
iexplorer : 0.27477061836 ,
202
184
firefox : 0.19384170608 ,
203
185
safari : 0.06186781118 ,
204
186
opera : 0.01574236955 ,
205
187
} ) ;
206
- const os = {
207
- chrome : { win : 0.89 , mac : 0.09 , lin : 0.02 } ,
208
- firefox : { win : 0.83 , mac : 0.16 , lin : 0.01 } ,
209
- opera : { win : 0.91 , mac : 0.03 , lin : 0.06 } ,
210
- safari : { win : 0.04 , mac : 0.96 } ,
211
- iexplorer : [ 'win' ] ,
212
- } ;
188
+ const os : OS = weightedKeyFromObject (
189
+ {
190
+ chrome : { win : 0.89 , mac : 0.09 , lin : 0.02 } ,
191
+ firefox : { win : 0.83 , mac : 0.16 , lin : 0.01 } ,
192
+ opera : { win : 0.91 , mac : 0.03 , lin : 0.06 } ,
193
+ safari : { win : 0.04 , mac : 0.96 } ,
194
+ iexplorer : { win : 1 } ,
195
+ } [ browser ]
196
+ ) ;
213
197
214
- return [ browser , rnd ( os [ browser ] ) ] ;
215
- }
198
+ return [ browser , os ] ;
199
+ } ;
216
200
217
- function randomProc ( arch : Arch ) : string | number {
201
+ const randomProc = ( arch : OS ) : string => {
218
202
const procs = {
219
203
lin : [ 'i686' , 'x86_64' ] ,
220
204
mac : { Intel : 0.48 , PPC : 0.01 , 'U; Intel' : 0.48 , 'U; PPC' : 0.01 } ,
221
205
win : [ '' , 'WOW64' , 'Win64; x64' ] ,
222
206
} ;
223
- return rnd ( procs [ arch ] ) ;
224
- }
207
+ const archValue = procs [ arch ] ;
208
+ const proc = Array . isArray ( archValue )
209
+ ? faker . helpers . arrayElement ( archValue )
210
+ : weightedKeyFromObject ( archValue ) ;
225
211
226
- function randomRevision ( dots : number ) : string {
212
+ return proc ;
213
+ } ;
214
+
215
+ const randomRevision = ( dots : number ) : string => {
227
216
let return_val = '' ;
228
217
//generate a random revision
229
218
//dots = 2 returns .x.y where x & y are between 0 and 9
230
219
for ( let x = 0 ; x < dots ; x ++ ) {
231
- return_val += `.${ rnd ( 0 , 9 ) } ` ;
220
+ return_val += `.${ faker . datatype . number ( { min : 0 , max : 9 } ) } ` ;
232
221
}
233
222
return return_val ;
234
- }
223
+ } ;
235
224
236
225
const version_string = {
237
226
net ( ) {
238
- return [ rnd ( 1 , 4 ) , rnd ( 0 , 9 ) , rnd ( 10000 , 99999 ) , rnd ( 0 , 9 ) ] . join ( '.' ) ;
227
+ return [
228
+ faker . datatype . number ( { min : 1 , max : 4 } ) ,
229
+ faker . datatype . number ( { min : 0 , max : 9 } ) ,
230
+ faker . datatype . number ( { min : 10000 , max : 99999 } ) ,
231
+ faker . datatype . number ( { min : 0 , max : 9 } ) ,
232
+ ] . join ( '.' ) ;
239
233
} ,
240
234
nt ( ) {
241
- return `${ rnd ( 5 , 6 ) } .${ rnd ( 0 , 3 ) } ` ;
235
+ return [
236
+ faker . datatype . number ( { min : 5 , max : 6 } ) ,
237
+ faker . datatype . number ( { min : 0 , max : 3 } ) ,
238
+ ] . join ( '.' ) ;
242
239
} ,
243
240
ie ( ) {
244
- return rnd ( 7 , 11 ) ;
241
+ return faker . datatype . number ( { min : 7 , max : 11 } ) ;
245
242
} ,
246
243
trident ( ) {
247
- return `${ rnd ( 3 , 7 ) } .${ rnd ( 0 , 1 ) } ` ;
244
+ return [
245
+ faker . datatype . number ( { min : 3 , max : 7 } ) ,
246
+ faker . datatype . number ( { min : 0 , max : 1 } ) ,
247
+ ] . join ( '.' ) ;
248
248
} ,
249
249
osx ( delim ?: string ) {
250
- return [ 10 , rnd ( 5 , 10 ) , rnd ( 0 , 9 ) ] . join ( delim || '.' ) ;
250
+ return [
251
+ 10 ,
252
+ faker . datatype . number ( { min : 5 , max : 10 } ) ,
253
+ faker . datatype . number ( { min : 0 , max : 9 } ) ,
254
+ ] . join ( delim || '.' ) ;
251
255
} ,
252
256
chrome ( ) {
253
- return [ rnd ( 13 , 39 ) , 0 , rnd ( 800 , 899 ) , 0 ] . join ( '.' ) ;
257
+ return [
258
+ faker . datatype . number ( { min : 13 , max : 39 } ) ,
259
+ 0 ,
260
+ faker . datatype . number ( { min : 800 , max : 899 } ) ,
261
+ 0 ,
262
+ ] . join ( '.' ) ;
254
263
} ,
255
264
presto ( ) {
256
- return `2.9.${ rnd ( 160 , 190 ) } ` ;
265
+ return `2.9.${ faker . datatype . number ( { min : 160 , max : 190 } ) } ` ;
257
266
} ,
258
267
presto2 ( ) {
259
- return `${ rnd ( 10 , 12 ) } .00` ;
268
+ return `${ faker . datatype . number ( { min : 10 , max : 12 } ) } .00` ;
260
269
} ,
261
270
safari ( ) {
262
- return `${ rnd ( 531 , 538 ) } .${ rnd ( 0 , 2 ) } .${ rnd ( 0 , 2 ) } ` ;
271
+ return [
272
+ faker . datatype . number ( { min : 531 , max : 538 } ) ,
273
+ faker . datatype . number ( { min : 0 , max : 2 } ) ,
274
+ faker . datatype . number ( { min : 0 , max : 2 } ) ,
275
+ ] . join ( '.' ) ;
263
276
} ,
264
277
} ;
265
278
266
- const browser = {
267
- firefox ( arch : Arch ) : string {
279
+ const browserMap = {
280
+ firefox ( arch : OS ) : string {
268
281
//https://developer.mozilla.org/en-US/docs/Gecko_user_agent_string_reference
269
- const firefox_ver = `${ rnd ( 5 , 15 ) } ${ randomRevision ( 2 ) } ` ,
282
+ const firefox_ver = `${ faker . datatype . number ( {
283
+ min : 5 ,
284
+ max : 15 ,
285
+ } ) } ${ randomRevision ( 2 ) } `,
270
286
gecko_ver = `Gecko/20100101 Firefox/${ firefox_ver } ` ,
271
287
proc = randomProc ( arch ) ,
272
288
os_ver =
@@ -287,19 +303,21 @@ export function generate(faker: Faker): string {
287
303
288
304
if ( ver >= 11 ) {
289
305
//http://msdn.microsoft.com/en-us/library/ie/hh869301(v=vs.85).aspx
290
- return `Mozilla/5.0 (Windows NT 6.${ rnd ( 1 , 3 ) } ; Trident/7.0; ${ rnd ( [
291
- 'Touch; ' ,
292
- '' ,
293
- ] ) } rv:11.0) like Gecko`;
306
+ return `Mozilla/5.0 (Windows NT 6.${ faker . datatype . number ( {
307
+ min : 1 ,
308
+ max : 3 ,
309
+ } ) } ; Trident/7.0; ${
310
+ faker . datatype . boolean ( ) ? 'Touch; ' : ''
311
+ } rv:11.0) like Gecko`;
294
312
}
295
313
296
314
//http://msdn.microsoft.com/en-us/library/ie/ms537503(v=vs.85).aspx
297
315
return `Mozilla/5.0 (compatible; MSIE ${ ver } .0; Windows NT ${ version_string . nt ( ) } ; Trident/${ version_string . trident ( ) } ${
298
- rnd ( 0 , 1 ) === 1 ? `; .NET CLR ${ version_string . net ( ) } ` : ''
316
+ faker . datatype . boolean ( ) ? `; .NET CLR ${ version_string . net ( ) } ` : ''
299
317
} )`;
300
318
} ,
301
319
302
- opera ( arch : Arch ) : string {
320
+ opera ( arch : OS ) : string {
303
321
//http://www.opera.com/docs/history/
304
322
const presto_ver = ` Presto/${ version_string . presto ( ) } Version/${ version_string . presto2 ( ) } )` ,
305
323
os_ver =
@@ -309,23 +327,38 @@ export function generate(faker: Faker): string {
309
327
? `(X11; Linux ${ randomProc ( arch ) } ; U; ${ randomLang ( ) } ${ presto_ver } `
310
328
: `(Macintosh; Intel Mac OS X ${ version_string . osx ( ) } U; ${ randomLang ( ) } Presto/${ version_string . presto ( ) } Version/${ version_string . presto2 ( ) } )` ;
311
329
312
- return `Opera/${ rnd ( 9 , 14 ) } .${ rnd ( 0 , 99 ) } ${ os_ver } ` ;
330
+ return `Opera/${ faker . datatype . number ( {
331
+ min : 9 ,
332
+ max : 14 ,
333
+ } ) } .${ faker . datatype . number ( {
334
+ min : 0 ,
335
+ max : 99 ,
336
+ } ) } ${ os_ver } `;
313
337
} ,
314
338
315
- safari ( arch : Arch ) : string {
339
+ safari ( arch : OS ) : string {
316
340
const safari = version_string . safari ( ) ,
317
- ver = `${ rnd ( 4 , 7 ) } .${ rnd ( 0 , 1 ) } .${ rnd ( 0 , 10 ) } ` ,
341
+ ver = `${ faker . datatype . number ( {
342
+ min : 4 ,
343
+ max : 7 ,
344
+ } ) } .${ faker . datatype . number ( {
345
+ min : 0 ,
346
+ max : 1 ,
347
+ } ) } .${ faker . datatype . number ( { min : 0 , max : 10 } ) } `,
318
348
os_ver =
319
349
arch === 'mac'
320
350
? `(Macintosh; ${ randomProc ( 'mac' ) } Mac OS X ${ version_string . osx (
321
351
'_'
322
- ) } rv:${ rnd ( 2 , 6 ) } .0; ${ randomLang ( ) } ) `
352
+ ) } rv:${ faker . datatype . number ( {
353
+ min : 2 ,
354
+ max : 6 ,
355
+ } ) } .0; ${ randomLang ( ) } ) `
323
356
: `(Windows; U; Windows NT ${ version_string . nt ( ) } )` ;
324
357
325
358
return `Mozilla/5.0 ${ os_ver } AppleWebKit/${ safari } (KHTML, like Gecko) Version/${ ver } Safari/${ safari } ` ;
326
359
} ,
327
360
328
- chrome ( arch : Arch ) : string {
361
+ chrome ( arch : OS ) : string {
329
362
const safari = version_string . safari ( ) ,
330
363
os_ver =
331
364
arch === 'mac'
@@ -340,6 +373,6 @@ export function generate(faker: Faker): string {
340
373
} ,
341
374
} ;
342
375
343
- const random = randomBrowserAndOS ( ) ;
344
- return browser [ random [ 0 ] ] ( random [ 1 ] ) ;
376
+ const [ browser , arch ] = randomBrowserAndOS ( ) ;
377
+ return browserMap [ browser ] ( arch ) ;
345
378
}
0 commit comments