backend-test-tools 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +51 -0
- package/.mocharc.js +9 -0
- package/.prettierrc +7 -0
- package/README.md +271 -0
- package/babel.config.json +33 -0
- package/dist/factory/factory.d.ts +11 -0
- package/dist/factory/factory.js +39 -0
- package/dist/factory/factory.js.map +1 -0
- package/dist/factory/factory.types.d.ts +38 -0
- package/dist/factory/factory.types.js +2 -0
- package/dist/factory/factory.types.js.map +1 -0
- package/dist/factory/index.d.ts +2 -0
- package/dist/factory/index.js +28 -0
- package/dist/factory/index.js.map +1 -0
- package/dist/factory/workers/connection.d.ts +3 -0
- package/dist/factory/workers/connection.js +25 -0
- package/dist/factory/workers/connection.js.map +1 -0
- package/dist/factory/workers/connection.types.d.ts +28 -0
- package/dist/factory/workers/connection.types.js +2 -0
- package/dist/factory/workers/connection.types.js.map +1 -0
- package/dist/factory/workers/index.d.ts +6 -0
- package/dist/factory/workers/index.js +72 -0
- package/dist/factory/workers/index.js.map +1 -0
- package/dist/factory/workers/organization.d.ts +3 -0
- package/dist/factory/workers/organization.js +36 -0
- package/dist/factory/workers/organization.js.map +1 -0
- package/dist/factory/workers/organization.types.d.ts +51 -0
- package/dist/factory/workers/organization.types.js +2 -0
- package/dist/factory/workers/organization.types.js.map +1 -0
- package/dist/factory/workers/user.d.ts +5 -0
- package/dist/factory/workers/user.js +60 -0
- package/dist/factory/workers/user.js.map +1 -0
- package/dist/factory/workers/user.types.d.ts +76 -0
- package/dist/factory/workers/user.types.js +2 -0
- package/dist/factory/workers/user.types.js.map +1 -0
- package/dist/generators/generateAccessToken.d.ts +3 -0
- package/dist/generators/generateAccessToken.js +27 -0
- package/dist/generators/generateAccessToken.js.map +1 -0
- package/dist/generators/generateChatId.d.ts +2 -0
- package/dist/generators/generateChatId.js +13 -0
- package/dist/generators/generateChatId.js.map +1 -0
- package/dist/generators/generateEcdsaKeyPair.d.ts +2 -0
- package/dist/generators/generateEcdsaKeyPair.js +31 -0
- package/dist/generators/generateEcdsaKeyPair.js.map +1 -0
- package/dist/generators/generateImageBuffer.d.ts +3 -0
- package/dist/generators/generateImageBuffer.js +23 -0
- package/dist/generators/generateImageBuffer.js.map +1 -0
- package/dist/generators/generateImageBuffer.types.d.ts +7 -0
- package/dist/generators/generateImageBuffer.types.js +2 -0
- package/dist/generators/generateImageBuffer.types.js.map +1 -0
- package/dist/generators/generateKeyPair.d.ts +6 -0
- package/dist/generators/generateKeyPair.js +36 -0
- package/dist/generators/generateKeyPair.js.map +1 -0
- package/dist/generators/generateKeyPair.types.d.ts +9 -0
- package/dist/generators/generateKeyPair.types.js +2 -0
- package/dist/generators/generateKeyPair.types.js.map +1 -0
- package/dist/generators/generateLocale.d.ts +5 -0
- package/dist/generators/generateLocale.js +16 -0
- package/dist/generators/generateLocale.js.map +1 -0
- package/dist/generators/generateRegId.d.ts +4 -0
- package/dist/generators/generateRegId.js +14 -0
- package/dist/generators/generateRegId.js.map +1 -0
- package/dist/generators/generateRsaKeyPair.d.ts +2 -0
- package/dist/generators/generateRsaKeyPair.js +22 -0
- package/dist/generators/generateRsaKeyPair.js.map +1 -0
- package/dist/generators/generateUserCrypto.d.ts +15 -0
- package/dist/generators/generateUserCrypto.js +33 -0
- package/dist/generators/generateUserCrypto.js.map +1 -0
- package/dist/generators/index.d.ts +9 -0
- package/dist/generators/index.js +105 -0
- package/dist/generators/index.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +50 -0
- package/dist/index.js.map +1 -0
- package/dist/stubs/index.d.ts +1 -0
- package/dist/stubs/index.js +17 -0
- package/dist/stubs/index.js.map +1 -0
- package/dist/stubs/server-engine/Leader.types.d.ts +8 -0
- package/dist/stubs/server-engine/Leader.types.js +2 -0
- package/dist/stubs/server-engine/Leader.types.js.map +1 -0
- package/dist/stubs/server-engine/Localizator.d.ts +3 -0
- package/dist/stubs/server-engine/Localizator.js +34 -0
- package/dist/stubs/server-engine/Localizator.js.map +1 -0
- package/dist/stubs/server-engine/Localizator.types.d.ts +22 -0
- package/dist/stubs/server-engine/Localizator.types.js +2 -0
- package/dist/stubs/server-engine/Localizator.types.js.map +1 -0
- package/dist/stubs/server-engine/PubSub.d.ts +3 -0
- package/dist/stubs/server-engine/PubSub.js +24 -0
- package/dist/stubs/server-engine/PubSub.js.map +1 -0
- package/dist/stubs/server-engine/PubSub.types.d.ts +14 -0
- package/dist/stubs/server-engine/PubSub.types.js +2 -0
- package/dist/stubs/server-engine/PubSub.types.js.map +1 -0
- package/dist/stubs/server-engine/PushNotification.d.ts +3 -0
- package/dist/stubs/server-engine/PushNotification.js +18 -0
- package/dist/stubs/server-engine/PushNotification.js.map +1 -0
- package/dist/stubs/server-engine/PushNotification.types.d.ts +8 -0
- package/dist/stubs/server-engine/PushNotification.types.js +2 -0
- package/dist/stubs/server-engine/PushNotification.types.js.map +1 -0
- package/dist/stubs/server-engine/index.d.ts +4 -0
- package/dist/stubs/server-engine/index.js +50 -0
- package/dist/stubs/server-engine/index.js.map +1 -0
- package/dist/stubs/server-engine/sendPush.d.ts +3 -0
- package/dist/stubs/server-engine/sendPush.js +15 -0
- package/dist/stubs/server-engine/sendPush.js.map +1 -0
- package/dist/utils/generateCerts/generateCerts.const.d.ts +5 -0
- package/dist/utils/generateCerts/generateCerts.const.js +35 -0
- package/dist/utils/generateCerts/generateCerts.const.js.map +1 -0
- package/dist/utils/generateCerts/generateCerts.d.ts +9 -0
- package/dist/utils/generateCerts/generateCerts.js +108 -0
- package/dist/utils/generateCerts/generateCerts.js.map +1 -0
- package/dist/utils/generateCerts/generateCerts.types.d.ts +19 -0
- package/dist/utils/generateCerts/generateCerts.types.js +2 -0
- package/dist/utils/generateCerts/generateCerts.types.js.map +1 -0
- package/dist/utils/generateCerts/index.d.ts +1 -0
- package/dist/utils/generateCerts/index.js +17 -0
- package/dist/utils/generateCerts/index.js.map +1 -0
- package/dist/utils/getAdminApiBearer.d.ts +2 -0
- package/dist/utils/getAdminApiBearer.js +19 -0
- package/dist/utils/getAdminApiBearer.js.map +1 -0
- package/dist/utils/getBearer.d.ts +3 -0
- package/dist/utils/getBearer.js +12 -0
- package/dist/utils/getBearer.js.map +1 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.js +72 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/jwtRequest.d.ts +9 -0
- package/dist/utils/jwtRequest.js +29 -0
- package/dist/utils/jwtRequest.js.map +1 -0
- package/dist/utils/staticRequest.d.ts +10 -0
- package/dist/utils/staticRequest.js +24 -0
- package/dist/utils/staticRequest.js.map +1 -0
- package/dist/utils/tlsRequest.d.ts +6 -0
- package/dist/utils/tlsRequest.js +44 -0
- package/dist/utils/tlsRequest.js.map +1 -0
- package/dist/utils/tlsRequest.types.d.ts +9 -0
- package/dist/utils/tlsRequest.types.js +2 -0
- package/dist/utils/tlsRequest.types.js.map +1 -0
- package/eslint.config.mjs +11 -0
- package/jsconfig.json +14 -0
- package/package.json +83 -0
- package/src/factory/factory.ts +51 -0
- package/src/factory/factory.types.ts +50 -0
- package/src/factory/index.ts +2 -0
- package/src/factory/workers/connection.ts +22 -0
- package/src/factory/workers/connection.types.ts +29 -0
- package/src/factory/workers/index.ts +6 -0
- package/src/factory/workers/organization.ts +35 -0
- package/src/factory/workers/organization.types.ts +53 -0
- package/src/factory/workers/user.ts +57 -0
- package/src/factory/workers/user.types.ts +77 -0
- package/src/generators/generateAccessToken.ts +24 -0
- package/src/generators/generateChatId.ts +6 -0
- package/src/generators/generateEcdsaKeyPair.ts +16 -0
- package/src/generators/generateImageBuffer.ts +19 -0
- package/src/generators/generateImageBuffer.types.ts +7 -0
- package/src/generators/generateKeyPair.ts +24 -0
- package/src/generators/generateKeyPair.types.ts +9 -0
- package/src/generators/generateLocale.ts +28 -0
- package/src/generators/generateRegId.ts +9 -0
- package/src/generators/generateRsaKeyPair.ts +12 -0
- package/src/generators/generateUserCrypto.ts +24 -0
- package/src/generators/index.ts +9 -0
- package/src/index.ts +4 -0
- package/src/stubs/index.ts +1 -0
- package/src/stubs/server-engine/Leader.types.ts +9 -0
- package/src/stubs/server-engine/Localizator.ts +25 -0
- package/src/stubs/server-engine/Localizator.types.ts +24 -0
- package/src/stubs/server-engine/PubSub.ts +13 -0
- package/src/stubs/server-engine/PubSub.types.ts +15 -0
- package/src/stubs/server-engine/PushNotification.ts +11 -0
- package/src/stubs/server-engine/PushNotification.types.ts +9 -0
- package/src/stubs/server-engine/index.ts +4 -0
- package/src/stubs/server-engine/sendPush.ts +7 -0
- package/src/utils/generateCerts/generateCerts.const.ts +48 -0
- package/src/utils/generateCerts/generateCerts.ts +108 -0
- package/src/utils/generateCerts/generateCerts.types.ts +21 -0
- package/src/utils/generateCerts/index.ts +1 -0
- package/src/utils/getAdminApiBearer.ts +17 -0
- package/src/utils/getBearer.ts +11 -0
- package/src/utils/index.ts +6 -0
- package/src/utils/jwtRequest.ts +25 -0
- package/src/utils/staticRequest.ts +22 -0
- package/src/utils/tlsRequest.ts +41 -0
- package/src/utils/tlsRequest.types.ts +9 -0
- package/test/env.ts +10 -0
- package/tsconfig.build.json +4 -0
- package/tsconfig.json +30 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {randomUUID} from 'crypto';
|
|
2
|
+
import {
|
|
3
|
+
FactoryModel,
|
|
4
|
+
FactoryBuildOptions,
|
|
5
|
+
FactoryModelOverride,
|
|
6
|
+
FactoryReturnType,
|
|
7
|
+
ModelsMap,
|
|
8
|
+
} from './factory.types';
|
|
9
|
+
import {connectionFactoryWorker, organizationFactoryWorker, userFactoryWorker} from './workers';
|
|
10
|
+
|
|
11
|
+
const modelsMap: ModelsMap = {
|
|
12
|
+
connection: connectionFactoryWorker,
|
|
13
|
+
organization: organizationFactoryWorker,
|
|
14
|
+
user: userFactoryWorker,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const factory = {
|
|
18
|
+
/**
|
|
19
|
+
* Build an object according to a defined model
|
|
20
|
+
*/
|
|
21
|
+
build: function <T extends FactoryModel>(
|
|
22
|
+
name: T,
|
|
23
|
+
attributes: FactoryModelOverride<T> = {},
|
|
24
|
+
buildOptions: FactoryBuildOptions<T> = {},
|
|
25
|
+
): FactoryReturnType<T> {
|
|
26
|
+
if (!Object.keys(modelsMap).includes(name)) throw new Error(`Factory: unknown model "${name}"`);
|
|
27
|
+
const worker = modelsMap[name];
|
|
28
|
+
const instance = worker(buildOptions);
|
|
29
|
+
return {
|
|
30
|
+
id: randomUUID(),
|
|
31
|
+
...instance,
|
|
32
|
+
...attributes,
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Build multiple objects according to a defined model
|
|
38
|
+
*/
|
|
39
|
+
buildMany: function <T extends FactoryModel>(
|
|
40
|
+
name: T,
|
|
41
|
+
count: number,
|
|
42
|
+
attributes: FactoryModelOverride<T> = {},
|
|
43
|
+
buildOptions: FactoryBuildOptions<T> = {},
|
|
44
|
+
): Array<FactoryReturnType<T>> {
|
|
45
|
+
const instances: Array<FactoryReturnType<T>> = [];
|
|
46
|
+
for (let i = 0; i < count; i++) {
|
|
47
|
+
instances.push(this.build(name, attributes, buildOptions));
|
|
48
|
+
}
|
|
49
|
+
return instances;
|
|
50
|
+
},
|
|
51
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import {
|
|
3
|
+
ConnectionModel,
|
|
4
|
+
ConnectionBuildOptions,
|
|
5
|
+
OrganizationModel,
|
|
6
|
+
UserModel,
|
|
7
|
+
UserBuildOptions,
|
|
8
|
+
} from './workers';
|
|
9
|
+
|
|
10
|
+
type FactoryTyping = {
|
|
11
|
+
/** Mapping for the connection model */
|
|
12
|
+
connection: {
|
|
13
|
+
/** Options for the connection model */
|
|
14
|
+
options: ConnectionBuildOptions;
|
|
15
|
+
/** Return type for the connection model */
|
|
16
|
+
return: ConnectionModel;
|
|
17
|
+
};
|
|
18
|
+
/** Mapping for the organization model */
|
|
19
|
+
organization: {
|
|
20
|
+
/** Options for the organization model */
|
|
21
|
+
options: any;
|
|
22
|
+
/** Return type for the organization model */
|
|
23
|
+
return: OrganizationModel;
|
|
24
|
+
};
|
|
25
|
+
/** Mapping for the user model */
|
|
26
|
+
user: {
|
|
27
|
+
/** Options for the user model */
|
|
28
|
+
options: UserBuildOptions;
|
|
29
|
+
/** Return type for the user model */
|
|
30
|
+
return: UserModel;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type FactoryModel = keyof FactoryTyping;
|
|
35
|
+
|
|
36
|
+
export type FactoryModelOverride<T extends FactoryModel> = Partial<FactoryTyping[T]['return']> & {
|
|
37
|
+
/** Id of the model */
|
|
38
|
+
id?: string;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export type FactoryBuildOptions<T extends FactoryModel> = FactoryTyping[T]['options'];
|
|
42
|
+
|
|
43
|
+
export type FactoryReturnType<T extends FactoryModel> = FactoryTyping[T]['return'] & {
|
|
44
|
+
/** Id of the model */
|
|
45
|
+
id: string;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export type ModelsMap = {
|
|
49
|
+
[T in FactoryModel]: (buildOptions: FactoryTyping[T]['options']) => FactoryTyping[T]['return'];
|
|
50
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {randomUUID} from 'crypto';
|
|
2
|
+
import { faker } from '@faker-js/faker';
|
|
3
|
+
import {ConnectionBuildOptions, ConnectionModel} from './connection.types';
|
|
4
|
+
|
|
5
|
+
/** Create a random connection */
|
|
6
|
+
export function connectionFactoryWorker(
|
|
7
|
+
buildOptions: ConnectionBuildOptions = {},
|
|
8
|
+
): ConnectionModel {
|
|
9
|
+
const accepted = buildOptions.accepted ?? true;
|
|
10
|
+
const blocked = buildOptions.blocked ?? false;
|
|
11
|
+
return {
|
|
12
|
+
ownerId: randomUUID(),
|
|
13
|
+
otherUserId: randomUUID(),
|
|
14
|
+
accepted,
|
|
15
|
+
acceptedAt: accepted ? faker.date.recent() : undefined,
|
|
16
|
+
blocked,
|
|
17
|
+
blockedAt: blocked ? faker.date.recent() : undefined,
|
|
18
|
+
initiator: true,
|
|
19
|
+
message: faker.lorem.sentence(),
|
|
20
|
+
note: faker.lorem.sentence(),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** Connection base model */
|
|
2
|
+
export interface ConnectionModel {
|
|
3
|
+
/** Owner of the connection */
|
|
4
|
+
ownerId: string;
|
|
5
|
+
/** USer with which the owner is connected */
|
|
6
|
+
otherUserId: string;
|
|
7
|
+
/** Wether the connection is accepted or not */
|
|
8
|
+
accepted: boolean;
|
|
9
|
+
/** Date at which the connection was accepted */
|
|
10
|
+
acceptedAt?: Date;
|
|
11
|
+
/** Wether the owner did block the other user */
|
|
12
|
+
blocked: boolean;
|
|
13
|
+
/** Date at which the connection was blocked */
|
|
14
|
+
blockedAt?: Date;
|
|
15
|
+
/** Did the owner initiate the connection */
|
|
16
|
+
initiator: boolean;
|
|
17
|
+
/** Message sent to the other user with the connection */
|
|
18
|
+
message: string;
|
|
19
|
+
/** Private note the user has on the connection */
|
|
20
|
+
note: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Build options for connections */
|
|
24
|
+
export interface ConnectionBuildOptions {
|
|
25
|
+
/** Wether the connection is accepted or not */
|
|
26
|
+
accepted?: boolean;
|
|
27
|
+
/** Wether the owner did block the other user */
|
|
28
|
+
blocked?: boolean;
|
|
29
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { faker } from '@faker-js/faker';
|
|
2
|
+
import {OrganizationModel} from './organization.types';
|
|
3
|
+
|
|
4
|
+
/** Create a random organization */
|
|
5
|
+
export function organizationFactoryWorker(): OrganizationModel {
|
|
6
|
+
return {
|
|
7
|
+
name: faker.company.name(),
|
|
8
|
+
territory: faker.address.countryCode(),
|
|
9
|
+
description: faker.company.catchPhrase(),
|
|
10
|
+
contactInfo: faker.address.streetAddress(),
|
|
11
|
+
productsInfo: faker.company.catchPhrase(),
|
|
12
|
+
avatarUrl: faker.internet.url(),
|
|
13
|
+
coverUrl: faker.internet.url(),
|
|
14
|
+
membersVisible: faker.datatype.boolean(),
|
|
15
|
+
searchable: faker.datatype.boolean(),
|
|
16
|
+
activities: [
|
|
17
|
+
{
|
|
18
|
+
id: faker.string.uuid(),
|
|
19
|
+
translationKey: faker.lorem.word(),
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
members: [
|
|
23
|
+
{
|
|
24
|
+
id: faker.string.uuid(),
|
|
25
|
+
organizationId: faker.string.uuid(),
|
|
26
|
+
userId: faker.string.uuid(),
|
|
27
|
+
requested: faker.datatype.boolean(),
|
|
28
|
+
requestedAt: faker.date.recent(),
|
|
29
|
+
invited: faker.datatype.boolean(),
|
|
30
|
+
invitedAt: faker.date.recent(),
|
|
31
|
+
admin: faker.datatype.boolean(),
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** Organization base model */
|
|
2
|
+
export interface OrganizationModel {
|
|
3
|
+
/** Name of the organization */
|
|
4
|
+
name: string;
|
|
5
|
+
/** ISO Code of the territory in which the organization is located */
|
|
6
|
+
territory: string;
|
|
7
|
+
/** Description of the organization */
|
|
8
|
+
description: string;
|
|
9
|
+
/** Contact information of the organization */
|
|
10
|
+
contactInfo: string;
|
|
11
|
+
/** Product information fo the organization */
|
|
12
|
+
productsInfo: string;
|
|
13
|
+
/** URL of the organization avatar */
|
|
14
|
+
avatarUrl: string;
|
|
15
|
+
/** URL of the organization cover picture */
|
|
16
|
+
coverUrl: string;
|
|
17
|
+
/** Indicates if organization members are visible publicly */
|
|
18
|
+
membersVisible: boolean;
|
|
19
|
+
/** Indicates if organization is searchable publicly */
|
|
20
|
+
searchable: boolean;
|
|
21
|
+
/** List of activities that the organization has */
|
|
22
|
+
activities: Array<OrganizationActivityModel>;
|
|
23
|
+
/** List of organization members */
|
|
24
|
+
members: Array<OrganizationMemberModel>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Organization activity template */
|
|
28
|
+
export interface OrganizationActivityModel {
|
|
29
|
+
/** ID of the activity */
|
|
30
|
+
id: string;
|
|
31
|
+
/** Translation key to display the activity name */
|
|
32
|
+
translationKey: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Organization member */
|
|
36
|
+
export interface OrganizationMemberModel {
|
|
37
|
+
/** ID of the membership */
|
|
38
|
+
id: string;
|
|
39
|
+
/** ID of the organization on which the user has membership */
|
|
40
|
+
organizationId: string;
|
|
41
|
+
/** ID of the user */
|
|
42
|
+
userId: string;
|
|
43
|
+
/** Did the user accept/request to join the organization */
|
|
44
|
+
requested: boolean;
|
|
45
|
+
/** Time at which the user accepted/requested to join the organization */
|
|
46
|
+
requestedAt: Date;
|
|
47
|
+
/** Did the user get accepted/invited by an organization admin */
|
|
48
|
+
invited: boolean;
|
|
49
|
+
/** Time at which the user got accepted/invited by an organization admin */
|
|
50
|
+
invitedAt: Date;
|
|
51
|
+
/** Is the user an admin of the organization */
|
|
52
|
+
admin: boolean;
|
|
53
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { randomUUID } from 'crypto';
|
|
2
|
+
import { faker } from '@faker-js/faker';
|
|
3
|
+
import { UserModel, UserBuildOptions } from './user.types';
|
|
4
|
+
import {
|
|
5
|
+
generateRegId,
|
|
6
|
+
generateLocale,
|
|
7
|
+
generateSignKeyPub,
|
|
8
|
+
generateSignKeyEncrypted,
|
|
9
|
+
generateBbEncrypted
|
|
10
|
+
} from 'generators';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Create a random user
|
|
14
|
+
*/
|
|
15
|
+
export function userFactoryWorker(
|
|
16
|
+
buildOptions: UserBuildOptions = {}
|
|
17
|
+
): UserModel {
|
|
18
|
+
const firstName = buildOptions.firstName ?? faker.person.firstName();
|
|
19
|
+
const lastName = buildOptions.lastName ?? faker.person.lastName();
|
|
20
|
+
const email = faker.internet.email({ firstName, lastName });
|
|
21
|
+
const userName = faker.internet.userName({ firstName, lastName });
|
|
22
|
+
const random = Math.random().toString(36).substring(7);
|
|
23
|
+
const organizationId = buildOptions.organizationId;
|
|
24
|
+
const organizationMember = buildOptions.member ?? false;
|
|
25
|
+
const organizationAdmin = buildOptions.admin ?? false;
|
|
26
|
+
return {
|
|
27
|
+
firstName,
|
|
28
|
+
lastName,
|
|
29
|
+
firstNameLastName: `${firstName}${lastName}`,
|
|
30
|
+
firstNameSpaceLastName: `${firstName} ${lastName}`,
|
|
31
|
+
lastNameFirstName: `${lastName}${firstName}`,
|
|
32
|
+
lastNameSpaceFirstName: `${lastName} ${firstName}`,
|
|
33
|
+
displayName: `${firstName} ${lastName}`,
|
|
34
|
+
casualName: `${firstName}`,
|
|
35
|
+
formalName: `${firstName}`,
|
|
36
|
+
email: buildOptions.moreRandom ? `${random}${email}` : email,
|
|
37
|
+
username: buildOptions.moreRandom ? `${random}${userName}` : userName,
|
|
38
|
+
regId: generateRegId(),
|
|
39
|
+
locale: generateLocale(),
|
|
40
|
+
pictureUrl: faker.image.avatar(),
|
|
41
|
+
organizationId,
|
|
42
|
+
joinedOrganizationAt: organizationId ? faker.date.recent() : null,
|
|
43
|
+
organizationAdmin: organizationAdmin,
|
|
44
|
+
requestedToJoinOrganization: organizationMember || organizationAdmin,
|
|
45
|
+
acceptedInOrganization: organizationMember || organizationAdmin,
|
|
46
|
+
linkId: randomUUID(),
|
|
47
|
+
bbId: randomUUID(),
|
|
48
|
+
bbEncrypted: generateBbEncrypted(),
|
|
49
|
+
signKeyEncrypted: generateSignKeyEncrypted(),
|
|
50
|
+
signKeyPub: generateSignKeyPub(),
|
|
51
|
+
autoConnect: true,
|
|
52
|
+
searchable: true,
|
|
53
|
+
enableUrlScan: true,
|
|
54
|
+
enableMessageTranslation: true,
|
|
55
|
+
emailVisibility: true
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/** User model template */
|
|
2
|
+
export interface UserModel {
|
|
3
|
+
/** User's first name */
|
|
4
|
+
firstName: string;
|
|
5
|
+
/** User's last name */
|
|
6
|
+
lastName: string;
|
|
7
|
+
/** @deprecated */
|
|
8
|
+
firstNameLastName: string;
|
|
9
|
+
/** @deprecated */
|
|
10
|
+
firstNameSpaceLastName: string;
|
|
11
|
+
/** @deprecated */
|
|
12
|
+
lastNameFirstName: string;
|
|
13
|
+
/** @deprecated */
|
|
14
|
+
lastNameSpaceFirstName: string;
|
|
15
|
+
/** User's regular display name */
|
|
16
|
+
displayName: string;
|
|
17
|
+
/** User's casual display name */
|
|
18
|
+
casualName: string;
|
|
19
|
+
/** User's formal display name */
|
|
20
|
+
formalName: string;
|
|
21
|
+
/** User's email address */
|
|
22
|
+
email: string;
|
|
23
|
+
/** @deprecated User's username */
|
|
24
|
+
username: string;
|
|
25
|
+
/** User's RegId */
|
|
26
|
+
regId: string;
|
|
27
|
+
/** User's locale */
|
|
28
|
+
locale: string;
|
|
29
|
+
/** URL opf the user's avatar */
|
|
30
|
+
pictureUrl: string;
|
|
31
|
+
/** @deprecated ID of the user's organization */
|
|
32
|
+
organizationId?: string;
|
|
33
|
+
/** @deprecated Date at which the user joined the organization */
|
|
34
|
+
joinedOrganizationAt?: Date | null;
|
|
35
|
+
/** @deprecated Admin status of the user in the organization */
|
|
36
|
+
organizationAdmin: boolean;
|
|
37
|
+
/** @deprecated */
|
|
38
|
+
requestedToJoinOrganization: boolean;
|
|
39
|
+
/** @deprecated */
|
|
40
|
+
acceptedInOrganization: boolean;
|
|
41
|
+
/** User's ID for QR codes */
|
|
42
|
+
linkId: string;
|
|
43
|
+
/** User's BlackBerry ID */
|
|
44
|
+
bbId: string;
|
|
45
|
+
/** User's BlackBerry encrypted key */
|
|
46
|
+
bbEncrypted: string;
|
|
47
|
+
/** User's signature keys */
|
|
48
|
+
signKeyEncrypted: string;
|
|
49
|
+
/** User's public key */
|
|
50
|
+
signKeyPub: string;
|
|
51
|
+
/** Enables auto-acceptance of contact requests */
|
|
52
|
+
autoConnect: boolean;
|
|
53
|
+
/** Is the user searchable publicly */
|
|
54
|
+
searchable: boolean;
|
|
55
|
+
/** Is URL scanning enabled for the user */
|
|
56
|
+
enableUrlScan: boolean;
|
|
57
|
+
/** Is message translation enabled for the user */
|
|
58
|
+
enableMessageTranslation: boolean;
|
|
59
|
+
/** Is the user's email visible publicly */
|
|
60
|
+
emailVisibility: boolean;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** User template build options */
|
|
64
|
+
export interface UserBuildOptions {
|
|
65
|
+
/** User's first name */
|
|
66
|
+
firstName?: string;
|
|
67
|
+
/** User's last name */
|
|
68
|
+
lastName?: string;
|
|
69
|
+
/** Id of the organization to which the user is affiliated */
|
|
70
|
+
organizationId?: string;
|
|
71
|
+
/** Admin status of the user in his organization */
|
|
72
|
+
admin?: boolean;
|
|
73
|
+
/** Membership status of the user in his organization */
|
|
74
|
+
member?: boolean;
|
|
75
|
+
/** Add randomness to avoid collisions when generating a large number of entities */
|
|
76
|
+
moreRandom?: boolean;
|
|
77
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { randomUUID } from 'crypto';
|
|
2
|
+
import { sign, SignOptions } from 'jsonwebtoken';
|
|
3
|
+
|
|
4
|
+
/** Returns an API access token valid in test environment */
|
|
5
|
+
export function generateAccessToken(
|
|
6
|
+
userId: string,
|
|
7
|
+
options: SignOptions = {},
|
|
8
|
+
payload: string | Buffer | object = {}
|
|
9
|
+
): string {
|
|
10
|
+
const id = userId ?? randomUUID();
|
|
11
|
+
if (!process.env.JWT_SECRET) throw new Error('Missing JWT signing secret');
|
|
12
|
+
return sign(
|
|
13
|
+
typeof payload === 'object' ? { ...payload, user: { id } } : payload,
|
|
14
|
+
process.env.JWT_SECRET,
|
|
15
|
+
{
|
|
16
|
+
expiresIn: '1d',
|
|
17
|
+
audience: process.env.ACCESS_TOKEN_AUDIENCE,
|
|
18
|
+
issuer: process.env.ACCESS_TOKEN_ISSUER,
|
|
19
|
+
subject: id,
|
|
20
|
+
jwtid: randomUUID(),
|
|
21
|
+
...options
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {generateKeyPairSync} from 'crypto';
|
|
2
|
+
import {writeFileSync, existsSync, mkdirSync} from 'fs';
|
|
3
|
+
import {resolve} from 'path';
|
|
4
|
+
|
|
5
|
+
/** Generate a signature key pair for ECDSA */
|
|
6
|
+
export function generateEcdsaKeyPair(): void {
|
|
7
|
+
const DIR = resolve('certs');
|
|
8
|
+
if (!existsSync(DIR)) mkdirSync(DIR);
|
|
9
|
+
const {privateKey, publicKey} = generateKeyPairSync('ec', {
|
|
10
|
+
namedCurve: 'prime256v1',
|
|
11
|
+
privateKeyEncoding: {type: 'pkcs8', format: 'pem'},
|
|
12
|
+
publicKeyEncoding: {type: 'spki', format: 'pem'},
|
|
13
|
+
});
|
|
14
|
+
writeFileSync(`${DIR}/ecdsa.key`, privateKey);
|
|
15
|
+
writeFileSync(`${DIR}/ecdsa.key.pub`, publicKey);
|
|
16
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import Jimp from 'jimp';
|
|
2
|
+
import {generateImageBufferOptions} from './generateImageBuffer.types';
|
|
3
|
+
|
|
4
|
+
/** Generate a binary buffer containing a PNG image */
|
|
5
|
+
export async function generateImageBuffer(
|
|
6
|
+
options: generateImageBufferOptions = {},
|
|
7
|
+
): Promise<Buffer> {
|
|
8
|
+
const image = await generateImage(options);
|
|
9
|
+
return image.getBufferAsync(Jimp.MIME_PNG);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Generate the asynchronously image using Jimp */
|
|
13
|
+
async function generateImage(options: generateImageBufferOptions = {}): Promise<Jimp> {
|
|
14
|
+
return new Promise<Jimp>((resolve) => {
|
|
15
|
+
new Jimp(options.width ?? 150, options.height ?? 150, function (err, image) {
|
|
16
|
+
resolve(image);
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {generateKeyPairSync, randomBytes} from 'crypto';
|
|
2
|
+
import {GeneratedKeyPair} from './generateKeyPair.types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Generate a RSA key pair
|
|
6
|
+
* @param pass - passphrase used to encrypt the private key (default: generates a random passphrase)
|
|
7
|
+
*/
|
|
8
|
+
export function generateKeyPair(pass: string): GeneratedKeyPair {
|
|
9
|
+
const passphrase = pass ?? process.env.ID_TOKEN_PASSPHRASE ?? randomBytes(32).toString('base64');
|
|
10
|
+
const {publicKey, privateKey} = generateKeyPairSync('rsa', {
|
|
11
|
+
modulusLength: 1024,
|
|
12
|
+
publicKeyEncoding: {
|
|
13
|
+
type: 'spki',
|
|
14
|
+
format: 'pem',
|
|
15
|
+
},
|
|
16
|
+
privateKeyEncoding: {
|
|
17
|
+
type: 'pkcs8',
|
|
18
|
+
format: 'pem',
|
|
19
|
+
cipher: 'aes-256-cbc',
|
|
20
|
+
passphrase,
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
return {passphrase, publicKey, privateKey};
|
|
24
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Key pair that was generated */
|
|
2
|
+
export interface GeneratedKeyPair {
|
|
3
|
+
/** PAssphrase used to encrypt the private key */
|
|
4
|
+
passphrase: string;
|
|
5
|
+
/** Public key generated, PEM encoded */
|
|
6
|
+
publicKey: string;
|
|
7
|
+
/** Private key generated, PEM encoded */
|
|
8
|
+
privateKey: string;
|
|
9
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export const TEST_LOCALES = [
|
|
2
|
+
'ar',
|
|
3
|
+
'en-US',
|
|
4
|
+
'es-ES',
|
|
5
|
+
'fr-FR',
|
|
6
|
+
'id-ID',
|
|
7
|
+
'it-IT',
|
|
8
|
+
'ja-JP',
|
|
9
|
+
'km-KH',
|
|
10
|
+
'ko-KR',
|
|
11
|
+
'ms-MY',
|
|
12
|
+
'my-MM',
|
|
13
|
+
'nl-NL',
|
|
14
|
+
'pt-PT',
|
|
15
|
+
'ry-RU',
|
|
16
|
+
'th-TH',
|
|
17
|
+
'uk-UA',
|
|
18
|
+
'vi-VN',
|
|
19
|
+
'zh-CN',
|
|
20
|
+
'zh-TW',
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Pick up a random locale from the list of testable ones
|
|
25
|
+
*/
|
|
26
|
+
export function generateLocale(): string {
|
|
27
|
+
return TEST_LOCALES[Math.floor(Math.random() * TEST_LOCALES.length)];
|
|
28
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {writeFileSync, mkdirSync, existsSync} from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import {generateKeyPair} from './generateKeyPair';
|
|
4
|
+
|
|
5
|
+
/** Generate a RSA key pair and store it under "{cwd}/certs/rsa.*" */
|
|
6
|
+
export function generateRsaKeyPair(passphrase: string): void {
|
|
7
|
+
const DIR = path.resolve('certs');
|
|
8
|
+
if (!existsSync(DIR)) mkdirSync(DIR);
|
|
9
|
+
const {publicKey, privateKey} = generateKeyPair(passphrase);
|
|
10
|
+
writeFileSync(`${DIR}/rsa.key`, privateKey);
|
|
11
|
+
writeFileSync(`${DIR}/rsa.pub.key`, publicKey);
|
|
12
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generates a fake base64 string that looks like a user public key
|
|
5
|
+
* /!\ This is not a valid crypto key
|
|
6
|
+
*/
|
|
7
|
+
export function generateSignKeyPub(): string {
|
|
8
|
+
return crypto.randomBytes(162).toString('base64');
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Generates a fake base64 string that looks like a user encrypted private key
|
|
12
|
+
* /!\ This is not a valid crypto key
|
|
13
|
+
*/
|
|
14
|
+
export function generateSignKeyEncrypted(): string {
|
|
15
|
+
return crypto.randomBytes(640).toString('base64');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Generates a fake base64 string that looks like a user encrypted Blackberry Passcode
|
|
20
|
+
* /!\ This is not a valid crypto key
|
|
21
|
+
*/
|
|
22
|
+
export function generateBbEncrypted(): string {
|
|
23
|
+
return crypto.randomBytes(80).toString('base64');
|
|
24
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './generateAccessToken';
|
|
2
|
+
export * from './generateImageBuffer';
|
|
3
|
+
export * from './generateKeyPair';
|
|
4
|
+
export * from './generateLocale';
|
|
5
|
+
export * from './generateRegId';
|
|
6
|
+
export * from './generateRsaKeyPair';
|
|
7
|
+
export * from './generateUserCrypto';
|
|
8
|
+
export * from './generateChatId';
|
|
9
|
+
export * from './generateEcdsaKeyPair';
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './server-engine';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {Localizator} from '@gwcdata/node-server-engine/dist/entities/Localizator/Localizator';
|
|
2
|
+
import {stub} from 'sinon';
|
|
3
|
+
import {LocalizatorStub, LocalizatorStubOptions} from './Localizator.types';
|
|
4
|
+
|
|
5
|
+
const DEFAULT_LOCALE_DATA = {
|
|
6
|
+
enabled: true,
|
|
7
|
+
display: 'English',
|
|
8
|
+
names: {
|
|
9
|
+
firstNameFirst: true,
|
|
10
|
+
spacing: true,
|
|
11
|
+
},
|
|
12
|
+
cloudTranslationKey: 'en',
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/** Stub the Localizator service */
|
|
16
|
+
export function stubLocalizator(overrides: LocalizatorStubOptions): LocalizatorStub {
|
|
17
|
+
const synchronize = stub(Localizator, 'synchronize').resolves();
|
|
18
|
+
const init = stub(Localizator, 'init').resolves();
|
|
19
|
+
const shutdown = stub(Localizator, 'shutdown').resolves();
|
|
20
|
+
const getLocaleData = stub(Localizator, 'getLocaleData').returns(
|
|
21
|
+
overrides?.localeData ?? DEFAULT_LOCALE_DATA,
|
|
22
|
+
);
|
|
23
|
+
const isValidLocale = stub(Localizator, 'isValidLocale').returns(overrides?.isValid ?? true);
|
|
24
|
+
return {synchronize, init, shutdown, getLocaleData, isValidLocale};
|
|
25
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {LocalizatorLocalizationDataElement} from '@gwcdata/node-server-engine';
|
|
2
|
+
import {SinonStub} from 'sinon';
|
|
3
|
+
|
|
4
|
+
/** Stubbing options for the Localizator */
|
|
5
|
+
export interface LocalizatorStubOptions {
|
|
6
|
+
/** Forces the return value of the isValidLocale functions */
|
|
7
|
+
isValid?: boolean;
|
|
8
|
+
/** Forces the return value of the getLocaleData functions */
|
|
9
|
+
localeData?: LocalizatorLocalizationDataElement;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Stubbed properties of the Localizator entity */
|
|
13
|
+
export interface LocalizatorStub {
|
|
14
|
+
/** Stub of the synchronize method */
|
|
15
|
+
synchronize: SinonStub;
|
|
16
|
+
/** Stub of the init method */
|
|
17
|
+
init: SinonStub;
|
|
18
|
+
/** Stub of the shutdown method */
|
|
19
|
+
shutdown: SinonStub;
|
|
20
|
+
/** Stub of the getLocaleData method */
|
|
21
|
+
getLocaleData: SinonStub;
|
|
22
|
+
/** Stub of the isValidLocale method */
|
|
23
|
+
isValidLocale: SinonStub;
|
|
24
|
+
}
|