Skip to content

Commit

Permalink
feat: introduces security module
Browse files Browse the repository at this point in the history
  • Loading branch information
thisislawatts committed Jul 13, 2022
1 parent 3c108b4 commit 19ffcc0
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 0 deletions.
1 change: 1 addition & 0 deletions scripts/generateLocales.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ const definitionsTypes: DefinitionsType = {
music: 'MusicDefinitions',
name: 'NameDefinitions',
phone_number: 'PhoneNumberDefinitions',
security: 'SecurityDefinitions',
science: 'ScienceDefinitions',
system: 'SystemDefinitions',
vehicle: 'VehicleDefinitions',
Expand Down
2 changes: 2 additions & 0 deletions src/definitions/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type { MusicDefinitions } from './music';
import type { NameDefinitions } from './name';
import type { PhoneNumberDefinitions } from './phone_number';
import type { ScienceDefinitions } from './science';
import type { SecurityDefinitions } from './security';
import type { SystemDefinitions } from './system';
import type { VehicleDefinitions } from './vehicle';
import type { WordDefinitions } from './word';
Expand Down Expand Up @@ -40,6 +41,7 @@ export interface Definitions {
music: MusicDefinitions;
name: NameDefinitions;
phone_number: PhoneNumberDefinitions;
security: SecurityDefinitions;
science: ScienceDefinitions;
system: SystemDefinitions;
vehicle: VehicleDefinitions;
Expand Down
1 change: 1 addition & 0 deletions src/definitions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export type { MusicDefinitions } from './music';
export type { NameDefinitions, NameTitleDefinitions } from './name';
export type { PhoneNumberDefinitions } from './phone_number';
export type { ScienceDefinitions } from './science';
export type { SecurityDefinitions } from './security';
export type {
SystemDefinitions,
SystemMimeTypeEntryDefinitions,
Expand Down
22 changes: 22 additions & 0 deletions src/definitions/security.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { Cvss } from '../modules/security';
import type { LocaleEntry } from './definitions';

/**
* The possible definitions related to security.
*/
export type SecurityDefinitions = LocaleEntry<{
/**
* CVE definition.
*/
cve: string[];

/**
* CWE definition.
*/
cwe: string[];

/**
* CVSS object
*/
cvss: Cvss;
}>;
2 changes: 2 additions & 0 deletions src/faker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { Name } from './modules/name';
import { Phone } from './modules/phone';
import { Random } from './modules/random';
import { Science } from './modules/science';
import { Security } from './modules/security';
import { System } from './modules/system';
import { Unique } from './modules/unique';
import { Vehicle } from './modules/vehicle';
Expand Down Expand Up @@ -102,6 +103,7 @@ export class Faker {
readonly music: Music = new Music(this);
readonly name: Name = new Name(this);
readonly phone: Phone = new Phone(this);
readonly security: Security = new Security(this);
readonly science: Science = new Science(this);
readonly system: System = new System(this);
readonly vehicle: Vehicle = new Vehicle(this);
Expand Down
79 changes: 79 additions & 0 deletions src/modules/security/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import type { Faker } from '../..';

export interface Cvss {
score: number;
vector: string;
rating: 'none' | 'low' | 'medium' | 'high' | 'critical';
}

export class Security {
constructor(private readonly faker: Faker) {
// Bind `this` so namespaced is working correctly
for (const name of Object.getOwnPropertyNames(Security.prototype)) {
if (name === 'constructor' || typeof this[name] !== 'function') {
continue;
}
this[name] = this[name].bind(this);
}
}

/**
* Generates a random CVE
*
* @example
* faker.security.cve() // 'CVE-2011-0762'
*/
cve(): string {
return [
'CVE',
// Year
this.faker.date
.between('1999-01-01T00:00:00.000Z', '2022-01-01T00:00:00.000Z')
.getFullYear(),
// Sequence in the year
this.faker.random.numeric(5, { allowLeadingZeros: true }),
].join('-');
}

/**
* Generates a random CWE
*
* @example
* faker.security.cwe() // 'CWE-####'
*/
cwe(): string {
return ['CWE', this.faker.random.numeric(4)].join('-');
}

/**
* Generates a random CVSS return
* Based on:
* https://www.first.org/cvss/calculator/3.1
*
* @example
* faker.security.cvss()
*/
cvss(): Cvss {
return {
score: 0.5,
vector: [
'CVSS:3.1',
`AV:${this.faker.helpers.arrayElement('NALP'.split(''))}`,
`AC:${this.faker.helpers.arrayElement('LH'.split(''))}`,
`PR:${this.faker.helpers.arrayElement('NLH'.split(''))}`,
`UI:${this.faker.helpers.arrayElement('NR'.split(''))}`,
`S:${this.faker.helpers.arrayElement('UC'.split(''))}`,
`C:${this.faker.helpers.arrayElement('NLH'.split(''))}`,
`I:${this.faker.helpers.arrayElement('NLH'.split(''))}`,
`A:${this.faker.helpers.arrayElement('NLH'.split(''))}`,
].join('/'),
rating: this.faker.helpers.arrayElement([
'none',
'low',
'medium',
'high',
'critical',
]),
};
}
}
13 changes: 13 additions & 0 deletions test/__snapshots__/security.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Vitest Snapshot v1

exports[`security > seed: 42 > cve() 1`] = `"CVE-2007-79177"`;

exports[`security > seed: 42 > cwe() 1`] = `"CWE-4791"`;

exports[`security > seed: 1211 > cve() 1`] = `"CVE-2020-48721"`;

exports[`security > seed: 1211 > cwe() 1`] = `"CWE-9487"`;

exports[`security > seed: 1337 > cve() 1`] = `"CVE-2005-51225"`;

exports[`security > seed: 1337 > cwe() 1`] = `"CWE-3512"`;
64 changes: 64 additions & 0 deletions test/security.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { afterEach, describe, expect, it } from 'vitest';
import { faker } from '../src';
import { seededRuns } from './support/seededRuns';

const NON_SEEDED_BASED_RUN = 5;

const functionNames = ['cve', 'cwe'];

describe('security', () => {
afterEach(() => {
faker.locale = 'en';
});

for (const seed of seededRuns) {
describe(`seed: ${seed}`, () => {
for (const functionName of functionNames) {
it(`${functionName}()`, () => {
faker.seed(seed);

const actual = faker.security[functionName]();
expect(actual).toMatchSnapshot();
});
}
});
}

// Create and log-back the seed for debug purposes
faker.seed(Math.ceil(Math.random() * 1_000_000_000));

describe(`random seeded tests for seed ${JSON.stringify(
faker.seed()
)}`, () => {
for (let i = 1; i <= NON_SEEDED_BASED_RUN; i++) {
describe('cve()', () => {
it('should return a well formed string', () => {
expect(faker.security.cve()).toMatch(/^CVE-[0-9]{4}-[0-9]{4}/);
});
});

describe('cwe()', () => {
it('should return a well formed string', () => {
expect(faker.security.cwe()).toMatch(/^CWE-[0-9]{4}/);
});
});

describe('cvss()', () => {
it('should return an object', () => {
const cvss = faker.security.cvss();
expect(cvss).toBeTypeOf('object');
});

it('should return a numeric value', () => {
expect(faker.security.cvss().score).toEqual(expect.any(Number));
});

it('should return a well formed string', () => {
expect(faker.security.cvss().vector).toMatch(
/^CVSS:3.1\/AV:[NALP]\/AC:[LH]\/PR:[NLH]\/UI:[NR]\/S:[UC]\/C:[NLH]\/I:[NLH]\/A:[NLH]/
);
});
});
}
});
});

0 comments on commit 19ffcc0

Please sign in to comment.