aboutsummaryrefslogtreecommitdiff
path: root/src/modules/internet
diff options
context:
space:
mode:
authorShinigami <[email protected]>2022-05-03 15:48:20 +0200
committerGitHub <[email protected]>2022-05-03 15:48:20 +0200
commita2da7c496e9a3741d165ddfe6128b50837fec361 (patch)
tree88d371bc19487bc8a34d9043035aed8e4fedd7d5 /src/modules/internet
parentcc46a0c19af2752b6210c24b715fcce20197b6d9 (diff)
downloadfaker-a2da7c496e9a3741d165ddfe6128b50837fec361.tar.xz
faker-a2da7c496e9a3741d165ddfe6128b50837fec361.zip
refactor!: reorganize src folder (#909)
Diffstat (limited to 'src/modules/internet')
-rw-r--r--src/modules/internet/index.ts458
-rw-r--r--src/modules/internet/user-agent.ts345
2 files changed, 803 insertions, 0 deletions
diff --git a/src/modules/internet/index.ts b/src/modules/internet/index.ts
new file mode 100644
index 00000000..bcc5daf3
--- /dev/null
+++ b/src/modules/internet/index.ts
@@ -0,0 +1,458 @@
+import type { Faker } from '../..';
+import * as random_ua from './user-agent';
+
+export type EmojiType =
+ | 'smiley'
+ | 'body'
+ | 'person'
+ | 'nature'
+ | 'food'
+ | 'travel'
+ | 'activity'
+ | 'object'
+ | 'symbol'
+ | 'flag';
+
+/**
+ * Module to generate internet related entries.
+ */
+export class Internet {
+ constructor(private readonly faker: Faker) {
+ // Bind `this` so namespaced is working correctly
+ for (const name of Object.getOwnPropertyNames(Internet.prototype)) {
+ if (name === 'constructor' || typeof this[name] !== 'function') {
+ continue;
+ }
+ this[name] = this[name].bind(this);
+ }
+ }
+
+ /**
+ * Returns a random avatar url.
+ *
+ * @example
+ * faker.internet.avatar()
+ * // 'https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/315.jpg'
+ */
+ avatar(): string {
+ return `https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/${this.faker.datatype.number(
+ 1249
+ )}.jpg`;
+ }
+
+ /**
+ * Generates an email address using the given person's name as base.
+ *
+ * @param firstName The optional first name to use. If not specified, a random one will be chosen.
+ * @param lastName The optional last name to use. If not specified, a random one will be chosen.
+ * @param provider The mail provider domain to use. If not specified, a random free mail provider will be chosen.
+ * @param options The options to use. Defaults to `{ allowSpecialCharacters: false }`.
+ * @param options.allowSpecialCharacters Whether special characters such as ``.!#$%&'*+-/=?^_`{|}~`` should be included
+ * in the email address. Defaults to `false`.
+ *
+ * @example
+ * faker.internet.email() // '[email protected]'
+ * faker.internet.email('Jeanne', 'Doe') // '[email protected]'
+ * faker.internet.email('Jeanne', 'Doe', 'example.fakerjs.dev') // '[email protected]'
+ * faker.internet.email('Jeanne', 'Doe', 'example.fakerjs.dev', { allowSpecialCharacters: true }) // 'Jeanne%[email protected]'
+ */
+ email(
+ firstName?: string,
+ lastName?: string,
+ provider?: string,
+ options?: { allowSpecialCharacters?: boolean }
+ ): string {
+ provider =
+ provider ||
+ this.faker.helpers.arrayElement(
+ this.faker.definitions.internet.free_email
+ );
+
+ let localPart: string = this.faker.helpers.slugify(
+ this.userName(firstName, lastName)
+ );
+
+ if (options?.allowSpecialCharacters) {
+ const usernameChars: string[] = '._-'.split('');
+ const specialChars: string[] = ".!#$%&'*+-/=?^_`{|}~".split('');
+ localPart = localPart.replace(
+ this.faker.helpers.arrayElement(usernameChars),
+ this.faker.helpers.arrayElement(specialChars)
+ );
+ }
+
+ return `${localPart}@${provider}`;
+ }
+
+ /**
+ * Generates an email address using an example mail provider using the given person's name as base.
+ *
+ * @param firstName The optional first name to use. If not specified, a random one will be chosen.
+ * @param lastName The optional last name to use. If not specified, a random one will be chosen.
+ * @param options The options to use. Defaults to `{ allowSpecialCharacters: false }`.
+ * @param options.allowSpecialCharacters Whether special characters such as ``.!#$%&'*+-/=?^_`{|}~`` should be included
+ * in the email address. Defaults to `false`.
+ *
+ * @example
+ * faker.internet.exampleEmail() // '[email protected]'
+ * faker.internet.exampleEmail('Jeanne', 'Doe') // '[email protected]'
+ * faker.internet.exampleEmail('Jeanne', 'Doe', { allowSpecialCharacters: true }) // 'Jeanne%[email protected]'
+ */
+ exampleEmail(
+ firstName?: string,
+ lastName?: string,
+ options?: { allowSpecialCharacters?: boolean }
+ ): string {
+ const provider = this.faker.helpers.arrayElement(
+ this.faker.definitions.internet.example_email
+ );
+ return this.email(firstName, lastName, provider, options);
+ }
+
+ /**
+ * Generates a username using the given person's name as base.
+ *
+ * @param firstName The optional first name to use. If not specified, a random one will be chosen.
+ * @param lastName The optional last name to use. If not specified, a random one will be chosen.
+ *
+ * @example
+ * faker.internet.userName() // 'Nettie_Zboncak40'
+ * faker.internet.userName('Jeanne', 'Doe') // 'Jeanne98'
+ */
+ userName(firstName?: string, lastName?: string): string {
+ let result: string;
+ firstName = firstName || this.faker.name.firstName();
+ lastName = lastName || this.faker.name.lastName();
+ switch (this.faker.datatype.number(2)) {
+ case 0:
+ result = `${firstName}${this.faker.datatype.number(99)}`;
+ break;
+ case 1:
+ result =
+ firstName + this.faker.helpers.arrayElement(['.', '_']) + lastName;
+ break;
+ case 2:
+ result = `${firstName}${this.faker.helpers.arrayElement([
+ '.',
+ '_',
+ ])}${lastName}${this.faker.datatype.number(99)}`;
+ break;
+ }
+ result = result.toString().replace(/'/g, '');
+ result = result.replace(/ /g, '');
+ return result;
+ }
+
+ /**
+ * Returns a random web protocol. Either `http` or `https`.
+ *
+ * @example
+ * faker.internet.protocol() // 'http'
+ * faker.internet.protocol() // 'https'
+ */
+ protocol(): 'http' | 'https' {
+ const protocols: ['http', 'https'] = ['http', 'https'];
+ return this.faker.helpers.arrayElement(protocols);
+ }
+
+ /**
+ * Returns a random http method.
+ *
+ * Can be either of the following:
+ *
+ * - `GET`
+ * - `POST`
+ * - `PUT`
+ * - `DELETE`
+ * - `PATCH`
+ *
+ * @example
+ * faker.internet.httpMethod() // 'PATCH'
+ */
+ httpMethod(): 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' {
+ const httpMethods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'] = [
+ 'GET',
+ 'POST',
+ 'PUT',
+ 'DELETE',
+ 'PATCH',
+ ];
+ return this.faker.helpers.arrayElement(httpMethods);
+ }
+
+ /**
+ * Generates a random url.
+ *
+ * @example
+ * faker.internet.url() // 'https://remarkable-hackwork.info'
+ */
+ url(): string {
+ return `${this.protocol()}://${this.domainName()}`;
+ }
+
+ /**
+ * Generates a random domain name.
+ *
+ * @example
+ * faker.internet.domainName() // 'slow-timer.info'
+ */
+ domainName(): string {
+ return `${this.domainWord()}.${this.domainSuffix()}`;
+ }
+
+ /**
+ * Returns a random domain suffix.
+ *
+ * @example
+ * faker.internet.domainSuffix() // 'com'
+ * faker.internet.domainSuffix() // 'name'
+ */
+ domainSuffix(): string {
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.internet.domain_suffix
+ );
+ }
+
+ /**
+ * Generates a random domain word.
+ *
+ * @example
+ * faker.internet.domainWord() // 'close-reality'
+ * faker.internet.domainWord() // 'weird-cytoplasm'
+ */
+ domainWord(): string {
+ return `${this.faker.word.adjective()}-${this.faker.word.noun()}`
+ .replace(/([\\~#&*{}/:<>?|\"'])/gi, '')
+ .replace(/\s/g, '-')
+ .replace(/-{2,}/g, '-')
+ .toLowerCase();
+ }
+
+ /**
+ * Generates a random IPv4 address.
+ *
+ * @example
+ * faker.internet.ip() // '245.108.222.0'
+ */
+ ip(): string {
+ // TODO @Shinigami92 2022-03-21: We may want to return a IPv4 or IPv6 address here in a later major release
+ return this.ipv4();
+ }
+
+ /**
+ * Generates a random IPv4 address.
+ *
+ * @example
+ * faker.internet.ipv4() // '245.108.222.0'
+ */
+ ipv4(): string {
+ const randNum = () => {
+ return this.faker.datatype.number(255).toFixed(0);
+ };
+
+ const result: string[] = [];
+ for (let i = 0; i < 4; i++) {
+ result[i] = randNum();
+ }
+
+ return result.join('.');
+ }
+
+ /**
+ * Generates a random IPv6 address.
+ *
+ * @example
+ * faker.internet.ipv6() // '269f:1230:73e3:318d:842b:daab:326d:897b'
+ */
+ ipv6(): string {
+ const randHash = () => {
+ let result = '';
+ for (let i = 0; i < 4; i++) {
+ result += this.faker.helpers.arrayElement([
+ '0',
+ '1',
+ '2',
+ '3',
+ '4',
+ '5',
+ '6',
+ '7',
+ '8',
+ '9',
+ 'a',
+ 'b',
+ 'c',
+ 'd',
+ 'e',
+ 'f',
+ ]);
+ }
+ return result;
+ };
+
+ const result: string[] = [];
+ for (let i = 0; i < 8; i++) {
+ result[i] = randHash();
+ }
+ return result.join(':');
+ }
+
+ /**
+ * Generates a random port number.
+ *
+ * @example
+ * faker.internet.port() // '9414'
+ */
+ port(): number {
+ return this.faker.datatype.number({ min: 0, max: 65535 });
+ }
+
+ /**
+ * Generates a random user agent string.
+ *
+ * @example
+ * faker.internet.userAgent()
+ * // 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_8_8) AppleWebKit/536.0.2 (KHTML, like Gecko) Chrome/27.0.849.0 Safari/536.0.2'
+ */
+ userAgent(): string {
+ return random_ua.generate(this.faker);
+ }
+
+ /**
+ * Generates a random css hex color code in aesthetically pleasing color palette.
+ *
+ * Based on
+ * http://stackoverflow.com/questions/43044/algorithm-to-randomly-generate-an-aesthetically-pleasing-color-palette
+ *
+ * @param redBase The optional base red in range between `0` and `255`. Defaults to `0`.
+ * @param greenBase The optional base green in range between `0` and `255`. Defaults to `0`.
+ * @param blueBase The optional base blue in range between `0` and `255`. Defaults to `0`.
+ *
+ * @example
+ * faker.internet.color() // '#30686e'
+ * faker.internet.color(100, 100, 100) // '#4e5f8b'
+ */
+ color(
+ redBase: number = 0,
+ greenBase: number = 0,
+ blueBase: number = 0
+ ): string {
+ const colorFromBase = (base: number): string =>
+ Math.floor((this.faker.datatype.number(256) + base) / 2)
+ .toString(16)
+ .padStart(2, '0');
+
+ const red = colorFromBase(redBase);
+ const green = colorFromBase(greenBase);
+ const blue = colorFromBase(blueBase);
+
+ return `#${red}${green}${blue}`;
+ }
+
+ /**
+ * Generates a random mac address.
+ *
+ * @param sep The optional separator to use. Can be either `':'`, `'-'` or `''`. Defaults to `':'`.
+ *
+ * @example
+ * faker.internet.mac() // '32:8e:2e:09:c6:05'
+ */
+ mac(sep?: string): string {
+ let i: number;
+ let mac = '';
+ let validSep = ':';
+
+ // if the client passed in a different separator than `:`,
+ // we will use it if it is in the list of acceptable separators (dash or no separator)
+ if (['-', ''].indexOf(sep) !== -1) {
+ validSep = sep;
+ }
+
+ for (i = 0; i < 12; i++) {
+ mac += this.faker.datatype.number(15).toString(16);
+ if (i % 2 === 1 && i !== 11) {
+ mac += validSep;
+ }
+ }
+ return mac;
+ }
+
+ /**
+ * Generates a random password.
+ *
+ * @param len The length of the password to generate. Defaults to `15`.
+ * @param memorable Whether the generated password should be memorable. Defaults to `false`.
+ * @param pattern The pattern that all chars should match should match.
+ * This option will be ignored, if `memorable` is `true`. Defaults to `/\w/`.
+ * @param prefix The prefix to use. Defaults to `''`.
+ *
+ * @example
+ * faker.internet.password() // '89G1wJuBLbGziIs'
+ * faker.internet.password(20) // 'aF55c_8O9kZaPOrysFB_'
+ * faker.internet.password(20, true) // 'lawetimufozujosodedi'
+ * faker.internet.password(20, true, /[A-Z]/) // 'HMAQDFFYLDDUTBKVNFVS'
+ * faker.internet.password(20, true, /[A-Z]/, 'Hello ') // 'Hello IREOXTDWPERQSB'
+ */
+ password(
+ len: number = 15,
+ memorable: boolean = false,
+ pattern: RegExp = /\w/,
+ prefix: string = ''
+ ): string {
+ /*
+ * password-generator ( function )
+ * Copyright(c) 2011-2013 Bermi Ferrer <[email protected]>
+ * MIT Licensed
+ */
+ const vowel = /[aeiouAEIOU]$/;
+ const consonant = /[bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ]$/;
+ const _password = (
+ length: number,
+ memorable: boolean,
+ pattern: RegExp,
+ prefix: string
+ ): string => {
+ if (prefix.length >= length) {
+ return prefix;
+ }
+ if (memorable) {
+ if (prefix.match(consonant)) {
+ pattern = vowel;
+ } else {
+ pattern = consonant;
+ }
+ }
+ const n = this.faker.datatype.number(94) + 33;
+ let char = String.fromCharCode(n);
+ if (memorable) {
+ char = char.toLowerCase();
+ }
+ if (!char.match(pattern)) {
+ return _password(length, memorable, pattern, prefix);
+ }
+ return _password(length, memorable, pattern, prefix + char);
+ };
+ return _password(len, memorable, pattern, prefix);
+ }
+
+ /**
+ * Generates a random emoji.
+ *
+ * @param options Options object.
+ * @param options.types A list of the emoji types that should be used.
+ * @example
+ * faker.internet.emoji() // '🥰'
+ * faker.internet.emoji({ types: ['food', 'nature'] }) // '🥐'
+ */
+ emoji(options: { types?: ReadonlyArray<EmojiType> } = {}): string {
+ const {
+ types = Object.keys(
+ this.faker.definitions.internet.emoji
+ ) as Array<EmojiType>,
+ } = options;
+ const emojiType = this.faker.helpers.arrayElement(types);
+ return this.faker.helpers.arrayElement(
+ this.faker.definitions.internet.emoji[emojiType]
+ );
+ }
+}
diff --git a/src/modules/internet/user-agent.ts b/src/modules/internet/user-agent.ts
new file mode 100644
index 00000000..046758d4
--- /dev/null
+++ b/src/modules/internet/user-agent.ts
@@ -0,0 +1,345 @@
+/**
+ * Copyright (c) 2022 Faker
+ *
+ * This is a version of the original code migrated to TypeScript and modified
+ * by the Faker team.
+ *
+ * Check LICENSE for more details about the copyright.
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (c) 2012-2014 Jeffrey Mealo
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Based loosely on Luka Pusic's PHP Script:
+ * http://360percents.com/posts/php-random-user-agent-generator/
+ *
+ * The license for that script is as follows:
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ *
+ * <[email protected]> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Luka Pusic
+ */
+
+import type { Faker } from '../..';
+
+export type Arch = '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 });
+ }
+
+ 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;
+
+ 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];
+ }
+ }
+
+ return return_val;
+ })(a);
+ }
+
+ throw new TypeError(
+ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
+ `Invalid arguments passed to rnd. (${b ? `${a}, ${b}` : a})`
+ );
+ }
+
+ function randomLang(): string | number {
+ return rnd([
+ 'AB',
+ 'AF',
+ 'AN',
+ 'AR',
+ 'AS',
+ 'AZ',
+ 'BE',
+ 'BG',
+ 'BN',
+ 'BO',
+ 'BR',
+ 'BS',
+ 'CA',
+ 'CE',
+ 'CO',
+ 'CS',
+ 'CU',
+ 'CY',
+ 'DA',
+ 'DE',
+ 'EL',
+ 'EN',
+ 'EO',
+ 'ES',
+ 'ET',
+ 'EU',
+ 'FA',
+ 'FI',
+ 'FJ',
+ 'FO',
+ 'FR',
+ 'FY',
+ 'GA',
+ 'GD',
+ 'GL',
+ 'GV',
+ 'HE',
+ 'HI',
+ 'HR',
+ 'HT',
+ 'HU',
+ 'HY',
+ 'ID',
+ 'IS',
+ 'IT',
+ 'JA',
+ 'JV',
+ 'KA',
+ 'KG',
+ 'KO',
+ 'KU',
+ 'KW',
+ 'KY',
+ 'LA',
+ 'LB',
+ 'LI',
+ 'LN',
+ 'LT',
+ 'LV',
+ 'MG',
+ 'MK',
+ 'MN',
+ 'MO',
+ 'MS',
+ 'MT',
+ 'MY',
+ 'NB',
+ 'NE',
+ 'NL',
+ 'NN',
+ 'NO',
+ 'OC',
+ 'PL',
+ 'PT',
+ 'RM',
+ 'RO',
+ 'RU',
+ 'SC',
+ 'SE',
+ 'SK',
+ 'SL',
+ 'SO',
+ 'SQ',
+ 'SR',
+ 'SV',
+ 'SW',
+ 'TK',
+ 'TR',
+ 'TY',
+ 'UK',
+ 'UR',
+ 'UZ',
+ 'VI',
+ 'VO',
+ 'YI',
+ 'ZH',
+ ]);
+ }
+
+ function randomBrowserAndOS(): Array<string | number> {
+ const browser = rnd({
+ 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'],
+ };
+
+ return [browser, rnd(os[browser])];
+ }
+
+ function randomProc(arch: Arch): string | number {
+ 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]);
+ }
+
+ function 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 return_val;
+ }
+
+ const version_string = {
+ net() {
+ return [rnd(1, 4), rnd(0, 9), rnd(10000, 99999), rnd(0, 9)].join('.');
+ },
+ nt() {
+ return `${rnd(5, 6)}.${rnd(0, 3)}`;
+ },
+ ie() {
+ return rnd(7, 11);
+ },
+ trident() {
+ return `${rnd(3, 7)}.${rnd(0, 1)}`;
+ },
+ osx(delim?: string) {
+ return [10, rnd(5, 10), rnd(0, 9)].join(delim || '.');
+ },
+ chrome() {
+ return [rnd(13, 39), 0, rnd(800, 899), 0].join('.');
+ },
+ presto() {
+ return `2.9.${rnd(160, 190)}`;
+ },
+ presto2() {
+ return `${rnd(10, 12)}.00`;
+ },
+ safari() {
+ return `${rnd(531, 538)}.${rnd(0, 2)}.${rnd(0, 2)}`;
+ },
+ };
+
+ const browser = {
+ firefox(arch: Arch): string {
+ //https://developer.mozilla.org/en-US/docs/Gecko_user_agent_string_reference
+ const firefox_ver = `${rnd(5, 15)}${randomRevision(2)}`,
+ gecko_ver = `Gecko/20100101 Firefox/${firefox_ver}`,
+ proc = randomProc(arch),
+ os_ver =
+ arch === 'win'
+ ? `(Windows NT ${version_string.nt()}${proc ? `; ${proc}` : ''}`
+ : arch === 'mac'
+ ? `(Macintosh; ${proc} Mac OS X ${version_string.osx()}`
+ : `(X11; Linux ${proc}`;
+
+ return `Mozilla/5.0 ${os_ver}; rv:${firefox_ver.slice(
+ 0,
+ -2
+ )}) ${gecko_ver}`;
+ },
+
+ iexplorer(): string {
+ const ver = version_string.ie();
+
+ 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`;
+ }
+
+ //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()}` : ''
+ })`;
+ },
+
+ opera(arch: Arch): string {
+ //http://www.opera.com/docs/history/
+ const presto_ver = ` Presto/${version_string.presto()} Version/${version_string.presto2()})`,
+ os_ver =
+ arch === 'win'
+ ? `(Windows NT ${version_string.nt()}; U; ${randomLang()}${presto_ver}`
+ : arch === 'lin'
+ ? `(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}`;
+ },
+
+ safari(arch: Arch): string {
+ const safari = version_string.safari(),
+ ver = `${rnd(4, 7)}.${rnd(0, 1)}.${rnd(0, 10)}`,
+ os_ver =
+ arch === 'mac'
+ ? `(Macintosh; ${randomProc('mac')} Mac OS X ${version_string.osx(
+ '_'
+ )} rv:${rnd(2, 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 {
+ const safari = version_string.safari(),
+ os_ver =
+ arch === 'mac'
+ ? `(Macintosh; ${randomProc('mac')} Mac OS X ${version_string.osx(
+ '_'
+ )}) `
+ : arch === 'win'
+ ? `(Windows; U; Windows NT ${version_string.nt()})`
+ : `(X11; Linux ${randomProc(arch)}`;
+
+ return `Mozilla/5.0 ${os_ver} AppleWebKit/${safari} (KHTML, like Gecko) Chrome/${version_string.chrome()} Safari/${safari}`;
+ },
+ };
+
+ const random = randomBrowserAndOS();
+ return browser[random[0]](random[1]);
+}