diff options
| author | Shinigami <[email protected]> | 2022-05-03 15:48:20 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-05-03 15:48:20 +0200 |
| commit | a2da7c496e9a3741d165ddfe6128b50837fec361 (patch) | |
| tree | 88d371bc19487bc8a34d9043035aed8e4fedd7d5 /src/modules/internet | |
| parent | cc46a0c19af2752b6210c24b715fcce20197b6d9 (diff) | |
| download | faker-a2da7c496e9a3741d165ddfe6128b50837fec361.tar.xz faker-a2da7c496e9a3741d165ddfe6128b50837fec361.zip | |
refactor!: reorganize src folder (#909)
Diffstat (limited to 'src/modules/internet')
| -rw-r--r-- | src/modules/internet/index.ts | 458 | ||||
| -rw-r--r-- | src/modules/internet/user-agent.ts | 345 |
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]); +} |
