Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(user-agent): fix linter warnings #1174

Merged
merged 11 commits into from
Jul 30, 2022
209 changes: 121 additions & 88 deletions src/modules/internet/user-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,58 +44,41 @@

import type { Faker } from '../..';

export type Arch = 'lin' | 'mac' | 'win';
type OS = 'lin' | 'mac' | 'win';

export function generate(faker: Faker): string {
function rnd(
a?: string[] | number | Record<string, number>,
b?: number
): string | number {
//calling rnd() with no arguments is identical to rnd(0, 100)
a = a || 0;
b = b || 100;

if (typeof b === 'number' && typeof a === 'number') {
// 9/2018 - Added faker random to ensure mersenne and seed
return faker.datatype.number({ min: a, max: b });
}
type Browser = 'chrome' | 'iexplorer' | 'firefox' | 'safari' | 'opera';

if (Array.isArray(a)) {
//returns a random element from array (a), even weighting
return faker.helpers.arrayElement(a);
}

if (a && typeof a === 'object') {
//returns a random key from the passed object; keys are weighted by the decimal probability in their value
return ((obj) => {
const rand = (rnd(0, 100) as number) / 100;
let min = 0;
let max = 0;
let return_val: string;
/**
* Generates a random user-agent.
*
* @param faker An existing faker instance.
*/
export function generate(faker: Faker): string {
const weightedKeyFromObject = <T extends Record<string, number>>(
xDivisionByZerox marked this conversation as resolved.
Show resolved Hide resolved
obj: T
): keyof T => {
//returns a random key from the passed object; keys are weighted by the decimal probability in their value
const rand = faker.datatype.number({ min: 0, max: 100 }) / 100;
let min = 0;
let max = 0;
let return_val: string;

for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
max = obj[key] + min;
return_val = key;
if (rand >= min && rand <= max) {
break;
}
min = min + obj[key];
}
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
max = obj[key] + min;
return_val = key;
if (rand >= min && rand <= max) {
break;
}

return return_val;
})(a);
min = min + obj[key];
}
}

throw new TypeError(
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
`Invalid arguments passed to rnd. (${b ? `${a}, ${b}` : a})`
);
}
return return_val;
};

function randomLang(): string | number {
return rnd([
const randomLang = (): string =>
faker.helpers.arrayElement([
'AB',
'AF',
'AN',
Expand Down Expand Up @@ -193,80 +176,113 @@ export function generate(faker: Faker): string {
'YI',
'ZH',
]);
}

function randomBrowserAndOS(): Array<string | number> {
const browser = rnd({
const randomBrowserAndOS = (): [Browser, OS] => {
const browser: Browser = weightedKeyFromObject({
chrome: 0.45132810566,
iexplorer: 0.27477061836,
firefox: 0.19384170608,
safari: 0.06186781118,
opera: 0.01574236955,
});
const os = {
chrome: { win: 0.89, mac: 0.09, lin: 0.02 },
firefox: { win: 0.83, mac: 0.16, lin: 0.01 },
opera: { win: 0.91, mac: 0.03, lin: 0.06 },
safari: { win: 0.04, mac: 0.96 },
iexplorer: ['win'],
};
const os: OS = weightedKeyFromObject(
{
chrome: { win: 0.89, mac: 0.09, lin: 0.02 },
firefox: { win: 0.83, mac: 0.16, lin: 0.01 },
opera: { win: 0.91, mac: 0.03, lin: 0.06 },
safari: { win: 0.04, mac: 0.96 },
iexplorer: { win: 1 },
}[browser]
);

return [browser, rnd(os[browser])];
}
return [browser, os];
};

function randomProc(arch: Arch): string | number {
const randomProc = (arch: OS): string => {
xDivisionByZerox marked this conversation as resolved.
Show resolved Hide resolved
const procs = {
lin: ['i686', 'x86_64'],
mac: { Intel: 0.48, PPC: 0.01, 'U; Intel': 0.48, 'U; PPC': 0.01 },
win: ['', 'WOW64', 'Win64; x64'],
};
return rnd(procs[arch]);
}
const archValue = procs[arch];
const proc = Array.isArray(archValue)
? faker.helpers.arrayElement(archValue)
: weightedKeyFromObject(archValue);

function randomRevision(dots: number): string {
return proc;
};

const randomRevision = (dots: number): string => {
let return_val = '';
//generate a random revision
//dots = 2 returns .x.y where x & y are between 0 and 9
for (let x = 0; x < dots; x++) {
return_val += `.${rnd(0, 9)}`;
return_val += `.${faker.datatype.number({ min: 0, max: 9 })}`;
}
return return_val;
}
};

const version_string = {
net() {
return [rnd(1, 4), rnd(0, 9), rnd(10000, 99999), rnd(0, 9)].join('.');
return [
faker.datatype.number({ min: 1, max: 4 }),
faker.datatype.number({ min: 0, max: 9 }),
faker.datatype.number({ min: 10000, max: 99999 }),
faker.datatype.number({ min: 0, max: 9 }),
].join('.');
},
nt() {
return `${rnd(5, 6)}.${rnd(0, 3)}`;
return [
faker.datatype.number({ min: 5, max: 6 }),
faker.datatype.number({ min: 0, max: 3 }),
].join('.');
},
ie() {
return rnd(7, 11);
return faker.datatype.number({ min: 7, max: 11 });
},
trident() {
return `${rnd(3, 7)}.${rnd(0, 1)}`;
return [
faker.datatype.number({ min: 3, max: 7 }),
faker.datatype.number({ min: 0, max: 1 }),
].join('.');
},
osx(delim?: string) {
return [10, rnd(5, 10), rnd(0, 9)].join(delim || '.');
return [
10,
faker.datatype.number({ min: 5, max: 10 }),
faker.datatype.number({ min: 0, max: 9 }),
].join(delim || '.');
},
chrome() {
return [rnd(13, 39), 0, rnd(800, 899), 0].join('.');
return [
faker.datatype.number({ min: 13, max: 39 }),
0,
faker.datatype.number({ min: 800, max: 899 }),
0,
].join('.');
},
presto() {
return `2.9.${rnd(160, 190)}`;
return `2.9.${faker.datatype.number({ min: 160, max: 190 })}`;
},
presto2() {
return `${rnd(10, 12)}.00`;
return `${faker.datatype.number({ min: 10, max: 12 })}.00`;
},
safari() {
return `${rnd(531, 538)}.${rnd(0, 2)}.${rnd(0, 2)}`;
return [
faker.datatype.number({ min: 531, max: 538 }),
faker.datatype.number({ min: 0, max: 2 }),
faker.datatype.number({ min: 0, max: 2 }),
].join('.');
},
};

const browser = {
firefox(arch: Arch): string {
const browserMap = {
firefox(arch: OS): string {
//https://developer.mozilla.org/en-US/docs/Gecko_user_agent_string_reference
const firefox_ver = `${rnd(5, 15)}${randomRevision(2)}`,
const firefox_ver = `${faker.datatype.number({
min: 5,
max: 15,
})}${randomRevision(2)}`,
gecko_ver = `Gecko/20100101 Firefox/${firefox_ver}`,
proc = randomProc(arch),
os_ver =
Expand All @@ -287,19 +303,21 @@ export function generate(faker: Faker): string {

if (ver >= 11) {
//http://msdn.microsoft.com/en-us/library/ie/hh869301(v=vs.85).aspx
return `Mozilla/5.0 (Windows NT 6.${rnd(1, 3)}; Trident/7.0; ${rnd([
'Touch; ',
'',
])}rv:11.0) like Gecko`;
return `Mozilla/5.0 (Windows NT 6.${faker.datatype.number({
min: 1,
max: 3,
})}; Trident/7.0; ${
faker.datatype.boolean() ? 'Touch; ' : ''
}rv:11.0) like Gecko`;
}

//http://msdn.microsoft.com/en-us/library/ie/ms537503(v=vs.85).aspx
return `Mozilla/5.0 (compatible; MSIE ${ver}.0; Windows NT ${version_string.nt()}; Trident/${version_string.trident()}${
rnd(0, 1) === 1 ? `; .NET CLR ${version_string.net()}` : ''
faker.datatype.boolean() ? `; .NET CLR ${version_string.net()}` : ''
})`;
},

opera(arch: Arch): string {
opera(arch: OS): string {
//http://www.opera.com/docs/history/
const presto_ver = ` Presto/${version_string.presto()} Version/${version_string.presto2()})`,
os_ver =
Expand All @@ -309,23 +327,38 @@ export function generate(faker: Faker): string {
? `(X11; Linux ${randomProc(arch)}; U; ${randomLang()}${presto_ver}`
: `(Macintosh; Intel Mac OS X ${version_string.osx()} U; ${randomLang()} Presto/${version_string.presto()} Version/${version_string.presto2()})`;

return `Opera/${rnd(9, 14)}.${rnd(0, 99)} ${os_ver}`;
return `Opera/${faker.datatype.number({
min: 9,
max: 14,
})}.${faker.datatype.number({
min: 0,
max: 99,
})} ${os_ver}`;
},

safari(arch: Arch): string {
safari(arch: OS): string {
const safari = version_string.safari(),
ver = `${rnd(4, 7)}.${rnd(0, 1)}.${rnd(0, 10)}`,
ver = `${faker.datatype.number({
min: 4,
max: 7,
})}.${faker.datatype.number({
min: 0,
max: 1,
})}.${faker.datatype.number({ min: 0, max: 10 })}`,
os_ver =
arch === 'mac'
? `(Macintosh; ${randomProc('mac')} Mac OS X ${version_string.osx(
'_'
)} rv:${rnd(2, 6)}.0; ${randomLang()}) `
)} rv:${faker.datatype.number({
min: 2,
max: 6,
})}.0; ${randomLang()}) `
: `(Windows; U; Windows NT ${version_string.nt()})`;

return `Mozilla/5.0 ${os_ver}AppleWebKit/${safari} (KHTML, like Gecko) Version/${ver} Safari/${safari}`;
},

chrome(arch: Arch): string {
chrome(arch: OS): string {
const safari = version_string.safari(),
os_ver =
arch === 'mac'
Expand All @@ -340,6 +373,6 @@ export function generate(faker: Faker): string {
},
};

const random = randomBrowserAndOS();
return browser[random[0]](random[1]);
const [browser, arch] = randomBrowserAndOS();
return browserMap[browser](arch);
}