Skip to content

Commit 19ffcc0

Browse files
committed
feat: introduces security module
1 parent 3c108b4 commit 19ffcc0

File tree

8 files changed

+184
-0
lines changed

8 files changed

+184
-0
lines changed

scripts/generateLocales.ts

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ const definitionsTypes: DefinitionsType = {
5959
music: 'MusicDefinitions',
6060
name: 'NameDefinitions',
6161
phone_number: 'PhoneNumberDefinitions',
62+
security: 'SecurityDefinitions',
6263
science: 'ScienceDefinitions',
6364
system: 'SystemDefinitions',
6465
vehicle: 'VehicleDefinitions',

src/definitions/definitions.ts

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import type { MusicDefinitions } from './music';
1313
import type { NameDefinitions } from './name';
1414
import type { PhoneNumberDefinitions } from './phone_number';
1515
import type { ScienceDefinitions } from './science';
16+
import type { SecurityDefinitions } from './security';
1617
import type { SystemDefinitions } from './system';
1718
import type { VehicleDefinitions } from './vehicle';
1819
import type { WordDefinitions } from './word';
@@ -40,6 +41,7 @@ export interface Definitions {
4041
music: MusicDefinitions;
4142
name: NameDefinitions;
4243
phone_number: PhoneNumberDefinitions;
44+
security: SecurityDefinitions;
4345
science: ScienceDefinitions;
4446
system: SystemDefinitions;
4547
vehicle: VehicleDefinitions;

src/definitions/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export type { MusicDefinitions } from './music';
2020
export type { NameDefinitions, NameTitleDefinitions } from './name';
2121
export type { PhoneNumberDefinitions } from './phone_number';
2222
export type { ScienceDefinitions } from './science';
23+
export type { SecurityDefinitions } from './security';
2324
export type {
2425
SystemDefinitions,
2526
SystemMimeTypeEntryDefinitions,

src/definitions/security.ts

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import type { Cvss } from '../modules/security';
2+
import type { LocaleEntry } from './definitions';
3+
4+
/**
5+
* The possible definitions related to security.
6+
*/
7+
export type SecurityDefinitions = LocaleEntry<{
8+
/**
9+
* CVE definition.
10+
*/
11+
cve: string[];
12+
13+
/**
14+
* CWE definition.
15+
*/
16+
cwe: string[];
17+
18+
/**
19+
* CVSS object
20+
*/
21+
cvss: Cvss;
22+
}>;

src/faker.ts

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { Name } from './modules/name';
2323
import { Phone } from './modules/phone';
2424
import { Random } from './modules/random';
2525
import { Science } from './modules/science';
26+
import { Security } from './modules/security';
2627
import { System } from './modules/system';
2728
import { Unique } from './modules/unique';
2829
import { Vehicle } from './modules/vehicle';
@@ -102,6 +103,7 @@ export class Faker {
102103
readonly music: Music = new Music(this);
103104
readonly name: Name = new Name(this);
104105
readonly phone: Phone = new Phone(this);
106+
readonly security: Security = new Security(this);
105107
readonly science: Science = new Science(this);
106108
readonly system: System = new System(this);
107109
readonly vehicle: Vehicle = new Vehicle(this);

src/modules/security/index.ts

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import type { Faker } from '../..';
2+
3+
export interface Cvss {
4+
score: number;
5+
vector: string;
6+
rating: 'none' | 'low' | 'medium' | 'high' | 'critical';
7+
}
8+
9+
export class Security {
10+
constructor(private readonly faker: Faker) {
11+
// Bind `this` so namespaced is working correctly
12+
for (const name of Object.getOwnPropertyNames(Security.prototype)) {
13+
if (name === 'constructor' || typeof this[name] !== 'function') {
14+
continue;
15+
}
16+
this[name] = this[name].bind(this);
17+
}
18+
}
19+
20+
/**
21+
* Generates a random CVE
22+
*
23+
* @example
24+
* faker.security.cve() // 'CVE-2011-0762'
25+
*/
26+
cve(): string {
27+
return [
28+
'CVE',
29+
// Year
30+
this.faker.date
31+
.between('1999-01-01T00:00:00.000Z', '2022-01-01T00:00:00.000Z')
32+
.getFullYear(),
33+
// Sequence in the year
34+
this.faker.random.numeric(5, { allowLeadingZeros: true }),
35+
].join('-');
36+
}
37+
38+
/**
39+
* Generates a random CWE
40+
*
41+
* @example
42+
* faker.security.cwe() // 'CWE-####'
43+
*/
44+
cwe(): string {
45+
return ['CWE', this.faker.random.numeric(4)].join('-');
46+
}
47+
48+
/**
49+
* Generates a random CVSS return
50+
* Based on:
51+
* https://www.first.org/cvss/calculator/3.1
52+
*
53+
* @example
54+
* faker.security.cvss()
55+
*/
56+
cvss(): Cvss {
57+
return {
58+
score: 0.5,
59+
vector: [
60+
'CVSS:3.1',
61+
`AV:${this.faker.helpers.arrayElement('NALP'.split(''))}`,
62+
`AC:${this.faker.helpers.arrayElement('LH'.split(''))}`,
63+
`PR:${this.faker.helpers.arrayElement('NLH'.split(''))}`,
64+
`UI:${this.faker.helpers.arrayElement('NR'.split(''))}`,
65+
`S:${this.faker.helpers.arrayElement('UC'.split(''))}`,
66+
`C:${this.faker.helpers.arrayElement('NLH'.split(''))}`,
67+
`I:${this.faker.helpers.arrayElement('NLH'.split(''))}`,
68+
`A:${this.faker.helpers.arrayElement('NLH'.split(''))}`,
69+
].join('/'),
70+
rating: this.faker.helpers.arrayElement([
71+
'none',
72+
'low',
73+
'medium',
74+
'high',
75+
'critical',
76+
]),
77+
};
78+
}
79+
}
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Vitest Snapshot v1
2+
3+
exports[`security > seed: 42 > cve() 1`] = `"CVE-2007-79177"`;
4+
5+
exports[`security > seed: 42 > cwe() 1`] = `"CWE-4791"`;
6+
7+
exports[`security > seed: 1211 > cve() 1`] = `"CVE-2020-48721"`;
8+
9+
exports[`security > seed: 1211 > cwe() 1`] = `"CWE-9487"`;
10+
11+
exports[`security > seed: 1337 > cve() 1`] = `"CVE-2005-51225"`;
12+
13+
exports[`security > seed: 1337 > cwe() 1`] = `"CWE-3512"`;

test/security.spec.ts

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { afterEach, describe, expect, it } from 'vitest';
2+
import { faker } from '../src';
3+
import { seededRuns } from './support/seededRuns';
4+
5+
const NON_SEEDED_BASED_RUN = 5;
6+
7+
const functionNames = ['cve', 'cwe'];
8+
9+
describe('security', () => {
10+
afterEach(() => {
11+
faker.locale = 'en';
12+
});
13+
14+
for (const seed of seededRuns) {
15+
describe(`seed: ${seed}`, () => {
16+
for (const functionName of functionNames) {
17+
it(`${functionName}()`, () => {
18+
faker.seed(seed);
19+
20+
const actual = faker.security[functionName]();
21+
expect(actual).toMatchSnapshot();
22+
});
23+
}
24+
});
25+
}
26+
27+
// Create and log-back the seed for debug purposes
28+
faker.seed(Math.ceil(Math.random() * 1_000_000_000));
29+
30+
describe(`random seeded tests for seed ${JSON.stringify(
31+
faker.seed()
32+
)}`, () => {
33+
for (let i = 1; i <= NON_SEEDED_BASED_RUN; i++) {
34+
describe('cve()', () => {
35+
it('should return a well formed string', () => {
36+
expect(faker.security.cve()).toMatch(/^CVE-[0-9]{4}-[0-9]{4}/);
37+
});
38+
});
39+
40+
describe('cwe()', () => {
41+
it('should return a well formed string', () => {
42+
expect(faker.security.cwe()).toMatch(/^CWE-[0-9]{4}/);
43+
});
44+
});
45+
46+
describe('cvss()', () => {
47+
it('should return an object', () => {
48+
const cvss = faker.security.cvss();
49+
expect(cvss).toBeTypeOf('object');
50+
});
51+
52+
it('should return a numeric value', () => {
53+
expect(faker.security.cvss().score).toEqual(expect.any(Number));
54+
});
55+
56+
it('should return a well formed string', () => {
57+
expect(faker.security.cvss().vector).toMatch(
58+
/^CVSS:3.1\/AV:[NALP]\/AC:[LH]\/PR:[NLH]\/UI:[NR]\/S:[UC]\/C:[NLH]\/I:[NLH]\/A:[NLH]/
59+
);
60+
});
61+
});
62+
}
63+
});
64+
});

0 commit comments

Comments
 (0)