@scryan7371/sdr-security 0.1.3 → 0.1.4
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/dist/api/migrations/1700000000001-add-refresh-tokens.js +4 -2
- package/dist/api/migrations/1739500000000-create-security-identity.js +3 -1
- package/dist/api/migrations/1739510000000-create-security-roles.js +2 -1
- package/dist/api/migrations/1739515000000-create-security-user-roles.js +4 -1
- package/dist/api/migrations/1739520000000-create-password-reset-tokens.js +3 -1
- package/dist/api/migrations/1739530000000-create-security-user.js +2 -1
- package/dist/integration/database.integration.test.js +1 -1
- package/dist/nest/entities/app-user.entity.js +1 -1
- package/dist/nest/entities/password-reset-token.entity.d.ts +1 -0
- package/dist/nest/entities/password-reset-token.entity.js +14 -2
- package/dist/nest/entities/refresh-token.entity.js +2 -2
- package/dist/nest/entities/security-role.entity.d.ts +1 -0
- package/dist/nest/entities/security-role.entity.js +13 -1
- package/dist/nest/entities/security-user-role.entity.d.ts +1 -0
- package/dist/nest/entities/security-user-role.entity.js +14 -2
- package/dist/nest/entities/security-user.entity.js +1 -1
- package/dist/nest/security-auth.service.js +4 -1
- package/dist/nest/security-auth.service.test.js +3 -1
- package/dist/nest/security-workflows.service.js +4 -0
- package/package.json +3 -2
- package/src/api/migrations/1700000000001-add-refresh-tokens.ts +4 -2
- package/src/api/migrations/1739500000000-create-security-identity.ts +3 -1
- package/src/api/migrations/1739510000000-create-security-roles.ts +2 -1
- package/src/api/migrations/1739515000000-create-security-user-roles.ts +4 -1
- package/src/api/migrations/1739520000000-create-password-reset-tokens.ts +3 -1
- package/src/api/migrations/1739530000000-create-security-user.ts +2 -1
- package/src/integration/database.integration.test.ts +1 -1
- package/src/nest/entities/app-user.entity.ts +2 -2
- package/src/nest/entities/password-reset-token.entity.ts +12 -3
- package/src/nest/entities/refresh-token.entity.ts +2 -2
- package/src/nest/entities/security-role.entity.ts +10 -2
- package/src/nest/entities/security-user-role.entity.ts +11 -3
- package/src/nest/entities/security-user.entity.ts +1 -1
- package/src/nest/security-auth.service.test.ts +4 -1
- package/src/nest/security-auth.service.ts +5 -2
- package/src/nest/security-workflows.service.ts +4 -0
|
@@ -7,12 +7,14 @@ class AddRefreshTokens1700000000001 {
|
|
|
7
7
|
const userTableRef = getUserTableReference();
|
|
8
8
|
await queryRunner.query(`
|
|
9
9
|
CREATE TABLE "refresh_token" (
|
|
10
|
-
"id"
|
|
10
|
+
"id" uuid PRIMARY KEY NOT NULL DEFAULT uuidv7(),
|
|
11
11
|
"token_hash" varchar NOT NULL,
|
|
12
12
|
"expires_at" timestamptz NOT NULL,
|
|
13
13
|
"revoked_at" timestamptz,
|
|
14
|
-
"userId"
|
|
14
|
+
"userId" uuid,
|
|
15
15
|
"created_at" timestamptz NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
|
16
|
+
CONSTRAINT "CHK_refresh_token_id_uuidv7" CHECK ("id"::text ~* '^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'),
|
|
17
|
+
CONSTRAINT "CHK_refresh_token_userId_uuidv7" CHECK ("userId" IS NULL OR "userId"::text ~* '^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'),
|
|
16
18
|
CONSTRAINT "FK_refresh_token_user" FOREIGN KEY ("userId") REFERENCES ${userTableRef} ("id") ON DELETE CASCADE ON UPDATE NO ACTION
|
|
17
19
|
)
|
|
18
20
|
`);
|
|
@@ -8,11 +8,13 @@ class CreateSecurityIdentity1739500000000 {
|
|
|
8
8
|
await queryRunner.query(`
|
|
9
9
|
CREATE TABLE IF NOT EXISTS "security_identity" (
|
|
10
10
|
"id" uuid PRIMARY KEY NOT NULL DEFAULT uuidv7(),
|
|
11
|
-
"user_id"
|
|
11
|
+
"user_id" uuid NOT NULL,
|
|
12
12
|
"provider" varchar NOT NULL,
|
|
13
13
|
"provider_subject" varchar NOT NULL,
|
|
14
14
|
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
15
15
|
"updated_at" timestamptz NOT NULL DEFAULT now(),
|
|
16
|
+
CONSTRAINT "CHK_security_identity_id_uuidv7" CHECK ("id"::text ~* '^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'),
|
|
17
|
+
CONSTRAINT "CHK_security_identity_user_id_uuidv7" CHECK ("user_id"::text ~* '^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'),
|
|
16
18
|
CONSTRAINT "FK_security_identity_user_id" FOREIGN KEY ("user_id") REFERENCES ${userTableRef} ("id") ON DELETE CASCADE
|
|
17
19
|
)
|
|
18
20
|
`);
|
|
@@ -11,7 +11,8 @@ class CreateSecurityRoles1739510000000 {
|
|
|
11
11
|
"description" text,
|
|
12
12
|
"is_system" boolean NOT NULL DEFAULT false,
|
|
13
13
|
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
14
|
-
"updated_at" timestamptz NOT NULL DEFAULT now()
|
|
14
|
+
"updated_at" timestamptz NOT NULL DEFAULT now(),
|
|
15
|
+
CONSTRAINT "CHK_security_role_id_uuidv7" CHECK ("id"::text ~* '^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$')
|
|
15
16
|
)
|
|
16
17
|
`);
|
|
17
18
|
await queryRunner.query(`CREATE UNIQUE INDEX IF NOT EXISTS "IDX_security_role_key" ON "security_role" ("role_key")`);
|
|
@@ -8,9 +8,12 @@ class CreateSecurityUserRoles1739515000000 {
|
|
|
8
8
|
await queryRunner.query(`
|
|
9
9
|
CREATE TABLE IF NOT EXISTS "security_user_role" (
|
|
10
10
|
"id" uuid PRIMARY KEY NOT NULL DEFAULT uuidv7(),
|
|
11
|
-
"user_id"
|
|
11
|
+
"user_id" uuid NOT NULL,
|
|
12
12
|
"role_id" uuid NOT NULL,
|
|
13
13
|
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
14
|
+
CONSTRAINT "CHK_security_user_role_id_uuidv7" CHECK ("id"::text ~* '^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'),
|
|
15
|
+
CONSTRAINT "CHK_security_user_role_user_id_uuidv7" CHECK ("user_id"::text ~* '^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'),
|
|
16
|
+
CONSTRAINT "CHK_security_user_role_role_id_uuidv7" CHECK ("role_id"::text ~* '^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'),
|
|
14
17
|
CONSTRAINT "FK_security_user_role_user_id" FOREIGN KEY ("user_id") REFERENCES ${userTableRef} ("id") ON DELETE CASCADE,
|
|
15
18
|
CONSTRAINT "FK_security_user_role_role_id" FOREIGN KEY ("role_id") REFERENCES "security_role" ("id") ON DELETE CASCADE
|
|
16
19
|
)
|
|
@@ -8,11 +8,13 @@ class CreatePasswordResetTokens1739520000000 {
|
|
|
8
8
|
await queryRunner.query(`
|
|
9
9
|
CREATE TABLE IF NOT EXISTS "security_password_reset_token" (
|
|
10
10
|
"id" uuid PRIMARY KEY NOT NULL DEFAULT uuidv7(),
|
|
11
|
-
"user_id"
|
|
11
|
+
"user_id" uuid NOT NULL,
|
|
12
12
|
"token" varchar NOT NULL,
|
|
13
13
|
"expires_at" timestamptz NOT NULL,
|
|
14
14
|
"used_at" timestamptz,
|
|
15
15
|
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
16
|
+
CONSTRAINT "CHK_security_password_reset_token_id_uuidv7" CHECK ("id"::text ~* '^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'),
|
|
17
|
+
CONSTRAINT "CHK_security_password_reset_token_user_id_uuidv7" CHECK ("user_id"::text ~* '^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'),
|
|
16
18
|
CONSTRAINT "FK_security_password_reset_token_user_id" FOREIGN KEY ("user_id") REFERENCES ${userTableRef} ("id") ON DELETE CASCADE
|
|
17
19
|
)
|
|
18
20
|
`);
|
|
@@ -7,13 +7,14 @@ class CreateSecurityUser1739530000000 {
|
|
|
7
7
|
const userTableRef = getUserTableReference();
|
|
8
8
|
await queryRunner.query(`
|
|
9
9
|
CREATE TABLE IF NOT EXISTS "security_user" (
|
|
10
|
-
"user_id"
|
|
10
|
+
"user_id" uuid PRIMARY KEY NOT NULL,
|
|
11
11
|
"password_hash" varchar NOT NULL,
|
|
12
12
|
"email_verified_at" timestamptz,
|
|
13
13
|
"email_verification_token" varchar,
|
|
14
14
|
"admin_approved_at" timestamptz,
|
|
15
15
|
"is_active" boolean NOT NULL DEFAULT true,
|
|
16
16
|
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
17
|
+
CONSTRAINT "CHK_security_user_user_id_uuidv7" CHECK ("user_id"::text ~* '^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'),
|
|
17
18
|
CONSTRAINT "FK_security_user_user_id" FOREIGN KEY ("user_id") REFERENCES ${userTableRef} ("id") ON DELETE CASCADE
|
|
18
19
|
)
|
|
19
20
|
`);
|
|
@@ -97,7 +97,7 @@ const resetSchemaBeforeRun = process.env.SECURITY_TEST_RESET_SCHEMA !== "false";
|
|
|
97
97
|
await client.query(`SET search_path TO "${schema}", public`);
|
|
98
98
|
await client.query(`
|
|
99
99
|
CREATE TABLE IF NOT EXISTS "${schema}"."app_user" (
|
|
100
|
-
"id"
|
|
100
|
+
"id" uuid PRIMARY KEY NOT NULL,
|
|
101
101
|
"email" varchar NOT NULL
|
|
102
102
|
)
|
|
103
103
|
`);
|
|
@@ -17,7 +17,7 @@ let AppUserEntity = class AppUserEntity {
|
|
|
17
17
|
};
|
|
18
18
|
exports.AppUserEntity = AppUserEntity;
|
|
19
19
|
__decorate([
|
|
20
|
-
(0, typeorm_1.
|
|
20
|
+
(0, typeorm_1.PrimaryColumn)({ type: "uuid" }),
|
|
21
21
|
__metadata("design:type", String)
|
|
22
22
|
], AppUserEntity.prototype, "id", void 0);
|
|
23
23
|
__decorate([
|
|
@@ -11,6 +11,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.PasswordResetTokenEntity = void 0;
|
|
13
13
|
const typeorm_1 = require("typeorm");
|
|
14
|
+
const uuid_1 = require("uuid");
|
|
14
15
|
let PasswordResetTokenEntity = class PasswordResetTokenEntity {
|
|
15
16
|
id;
|
|
16
17
|
userId;
|
|
@@ -18,14 +19,19 @@ let PasswordResetTokenEntity = class PasswordResetTokenEntity {
|
|
|
18
19
|
expiresAt;
|
|
19
20
|
usedAt;
|
|
20
21
|
createdAt;
|
|
22
|
+
ensureId() {
|
|
23
|
+
if (!this.id) {
|
|
24
|
+
this.id = (0, uuid_1.v7)();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
21
27
|
};
|
|
22
28
|
exports.PasswordResetTokenEntity = PasswordResetTokenEntity;
|
|
23
29
|
__decorate([
|
|
24
|
-
(0, typeorm_1.
|
|
30
|
+
(0, typeorm_1.PrimaryColumn)({ type: "uuid" }),
|
|
25
31
|
__metadata("design:type", String)
|
|
26
32
|
], PasswordResetTokenEntity.prototype, "id", void 0);
|
|
27
33
|
__decorate([
|
|
28
|
-
(0, typeorm_1.Column)({ type: "
|
|
34
|
+
(0, typeorm_1.Column)({ type: "uuid", name: "user_id" }),
|
|
29
35
|
__metadata("design:type", String)
|
|
30
36
|
], PasswordResetTokenEntity.prototype, "userId", void 0);
|
|
31
37
|
__decorate([
|
|
@@ -44,6 +50,12 @@ __decorate([
|
|
|
44
50
|
(0, typeorm_1.CreateDateColumn)({ name: "created_at" }),
|
|
45
51
|
__metadata("design:type", Date)
|
|
46
52
|
], PasswordResetTokenEntity.prototype, "createdAt", void 0);
|
|
53
|
+
__decorate([
|
|
54
|
+
(0, typeorm_1.BeforeInsert)(),
|
|
55
|
+
__metadata("design:type", Function),
|
|
56
|
+
__metadata("design:paramtypes", []),
|
|
57
|
+
__metadata("design:returntype", void 0)
|
|
58
|
+
], PasswordResetTokenEntity.prototype, "ensureId", null);
|
|
47
59
|
exports.PasswordResetTokenEntity = PasswordResetTokenEntity = __decorate([
|
|
48
60
|
(0, typeorm_1.Entity)({ name: "security_password_reset_token" })
|
|
49
61
|
], PasswordResetTokenEntity);
|
|
@@ -21,7 +21,7 @@ let RefreshTokenEntity = class RefreshTokenEntity {
|
|
|
21
21
|
};
|
|
22
22
|
exports.RefreshTokenEntity = RefreshTokenEntity;
|
|
23
23
|
__decorate([
|
|
24
|
-
(0, typeorm_1.PrimaryColumn)({ type: "
|
|
24
|
+
(0, typeorm_1.PrimaryColumn)({ type: "uuid" }),
|
|
25
25
|
__metadata("design:type", String)
|
|
26
26
|
], RefreshTokenEntity.prototype, "id", void 0);
|
|
27
27
|
__decorate([
|
|
@@ -37,7 +37,7 @@ __decorate([
|
|
|
37
37
|
__metadata("design:type", Object)
|
|
38
38
|
], RefreshTokenEntity.prototype, "revokedAt", void 0);
|
|
39
39
|
__decorate([
|
|
40
|
-
(0, typeorm_1.Column)({ type: "
|
|
40
|
+
(0, typeorm_1.Column)({ type: "uuid", name: "userId", nullable: true }),
|
|
41
41
|
__metadata("design:type", Object)
|
|
42
42
|
], RefreshTokenEntity.prototype, "userId", void 0);
|
|
43
43
|
__decorate([
|
|
@@ -10,16 +10,22 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.SecurityRoleEntity = void 0;
|
|
13
|
+
const uuid_1 = require("uuid");
|
|
13
14
|
const typeorm_1 = require("typeorm");
|
|
14
15
|
let SecurityRoleEntity = class SecurityRoleEntity {
|
|
15
16
|
id;
|
|
16
17
|
roleKey;
|
|
17
18
|
description;
|
|
18
19
|
isSystem;
|
|
20
|
+
ensureId() {
|
|
21
|
+
if (!this.id) {
|
|
22
|
+
this.id = (0, uuid_1.v7)();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
19
25
|
};
|
|
20
26
|
exports.SecurityRoleEntity = SecurityRoleEntity;
|
|
21
27
|
__decorate([
|
|
22
|
-
(0, typeorm_1.
|
|
28
|
+
(0, typeorm_1.PrimaryColumn)({ type: "uuid" }),
|
|
23
29
|
__metadata("design:type", String)
|
|
24
30
|
], SecurityRoleEntity.prototype, "id", void 0);
|
|
25
31
|
__decorate([
|
|
@@ -34,6 +40,12 @@ __decorate([
|
|
|
34
40
|
(0, typeorm_1.Column)({ type: "boolean", name: "is_system", default: false }),
|
|
35
41
|
__metadata("design:type", Boolean)
|
|
36
42
|
], SecurityRoleEntity.prototype, "isSystem", void 0);
|
|
43
|
+
__decorate([
|
|
44
|
+
(0, typeorm_1.BeforeInsert)(),
|
|
45
|
+
__metadata("design:type", Function),
|
|
46
|
+
__metadata("design:paramtypes", []),
|
|
47
|
+
__metadata("design:returntype", void 0)
|
|
48
|
+
], SecurityRoleEntity.prototype, "ensureId", null);
|
|
37
49
|
exports.SecurityRoleEntity = SecurityRoleEntity = __decorate([
|
|
38
50
|
(0, typeorm_1.Entity)({ name: "security_role" })
|
|
39
51
|
], SecurityRoleEntity);
|
|
@@ -10,25 +10,37 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.SecurityUserRoleEntity = void 0;
|
|
13
|
+
const uuid_1 = require("uuid");
|
|
13
14
|
const typeorm_1 = require("typeorm");
|
|
14
15
|
let SecurityUserRoleEntity = class SecurityUserRoleEntity {
|
|
15
16
|
id;
|
|
16
17
|
userId;
|
|
17
18
|
roleId;
|
|
19
|
+
ensureId() {
|
|
20
|
+
if (!this.id) {
|
|
21
|
+
this.id = (0, uuid_1.v7)();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
18
24
|
};
|
|
19
25
|
exports.SecurityUserRoleEntity = SecurityUserRoleEntity;
|
|
20
26
|
__decorate([
|
|
21
|
-
(0, typeorm_1.
|
|
27
|
+
(0, typeorm_1.PrimaryColumn)({ type: "uuid" }),
|
|
22
28
|
__metadata("design:type", String)
|
|
23
29
|
], SecurityUserRoleEntity.prototype, "id", void 0);
|
|
24
30
|
__decorate([
|
|
25
|
-
(0, typeorm_1.Column)({ type: "
|
|
31
|
+
(0, typeorm_1.Column)({ type: "uuid", name: "user_id" }),
|
|
26
32
|
__metadata("design:type", String)
|
|
27
33
|
], SecurityUserRoleEntity.prototype, "userId", void 0);
|
|
28
34
|
__decorate([
|
|
29
35
|
(0, typeorm_1.Column)({ type: "uuid", name: "role_id" }),
|
|
30
36
|
__metadata("design:type", String)
|
|
31
37
|
], SecurityUserRoleEntity.prototype, "roleId", void 0);
|
|
38
|
+
__decorate([
|
|
39
|
+
(0, typeorm_1.BeforeInsert)(),
|
|
40
|
+
__metadata("design:type", Function),
|
|
41
|
+
__metadata("design:paramtypes", []),
|
|
42
|
+
__metadata("design:returntype", void 0)
|
|
43
|
+
], SecurityUserRoleEntity.prototype, "ensureId", null);
|
|
32
44
|
exports.SecurityUserRoleEntity = SecurityUserRoleEntity = __decorate([
|
|
33
45
|
(0, typeorm_1.Entity)({ name: "security_user_role" })
|
|
34
46
|
], SecurityUserRoleEntity);
|
|
@@ -22,7 +22,7 @@ let SecurityUserEntity = class SecurityUserEntity {
|
|
|
22
22
|
};
|
|
23
23
|
exports.SecurityUserEntity = SecurityUserEntity;
|
|
24
24
|
__decorate([
|
|
25
|
-
(0, typeorm_1.PrimaryColumn)({ type: "
|
|
25
|
+
(0, typeorm_1.PrimaryColumn)({ type: "uuid", name: "user_id" }),
|
|
26
26
|
__metadata("design:type", String)
|
|
27
27
|
], SecurityUserEntity.prototype, "userId", void 0);
|
|
28
28
|
__decorate([
|
|
@@ -17,6 +17,7 @@ const common_1 = require("@nestjs/common");
|
|
|
17
17
|
const crypto_1 = require("crypto");
|
|
18
18
|
const bcryptjs_1 = require("bcryptjs");
|
|
19
19
|
const jsonwebtoken_1 = require("jsonwebtoken");
|
|
20
|
+
const uuid_1 = require("uuid");
|
|
20
21
|
const typeorm_1 = require("@nestjs/typeorm");
|
|
21
22
|
const typeorm_2 = require("typeorm");
|
|
22
23
|
const roles_1 = require("../api/roles");
|
|
@@ -58,6 +59,7 @@ let SecurityAuthService = class SecurityAuthService {
|
|
|
58
59
|
throw new common_1.BadRequestException("Email already in use");
|
|
59
60
|
}
|
|
60
61
|
const appUser = await this.appUsersRepo.save(this.appUsersRepo.create({
|
|
62
|
+
id: (0, uuid_1.v7)(),
|
|
61
63
|
email,
|
|
62
64
|
}));
|
|
63
65
|
const securityUser = await this.securityUsersRepo.save(this.securityUsersRepo.create({
|
|
@@ -161,6 +163,7 @@ let SecurityAuthService = class SecurityAuthService {
|
|
|
161
163
|
const expiresAt = new Date(Date.now() +
|
|
162
164
|
(this.options.passwordResetTokenExpiresInMinutes ?? 30) * 60_000);
|
|
163
165
|
await this.passwordResetRepo.save(this.passwordResetRepo.create({
|
|
166
|
+
id: (0, uuid_1.v7)(),
|
|
164
167
|
userId: appUser.id,
|
|
165
168
|
token,
|
|
166
169
|
expiresAt,
|
|
@@ -220,7 +223,7 @@ let SecurityAuthService = class SecurityAuthService {
|
|
|
220
223
|
const refreshTokenExpiresAt = new Date(Date.now() +
|
|
221
224
|
(this.options.refreshTokenExpiresInDays ?? 30) * 24 * 60 * 60 * 1000);
|
|
222
225
|
await this.refreshTokenRepo.save(this.refreshTokenRepo.create({
|
|
223
|
-
id: (0,
|
|
226
|
+
id: (0, uuid_1.v7)(),
|
|
224
227
|
userId: appUser.id,
|
|
225
228
|
tokenHash: refreshTokenHash,
|
|
226
229
|
expiresAt: refreshTokenExpiresAt,
|
|
@@ -8,11 +8,13 @@ vitest_1.vi.mock("bcryptjs", () => ({
|
|
|
8
8
|
}));
|
|
9
9
|
vitest_1.vi.mock("crypto", () => ({
|
|
10
10
|
randomBytes: vitest_1.vi.fn(() => ({ toString: () => "token-bytes" })),
|
|
11
|
-
randomUUID: vitest_1.vi.fn(() => "uuid-1"),
|
|
12
11
|
}));
|
|
13
12
|
vitest_1.vi.mock("jsonwebtoken", () => ({
|
|
14
13
|
sign: vitest_1.vi.fn(() => "signed-access-token"),
|
|
15
14
|
}));
|
|
15
|
+
vitest_1.vi.mock("uuid", () => ({
|
|
16
|
+
v7: vitest_1.vi.fn(() => "uuid-1"),
|
|
17
|
+
}));
|
|
16
18
|
const bcryptjs_1 = require("bcryptjs");
|
|
17
19
|
const jsonwebtoken_1 = require("jsonwebtoken");
|
|
18
20
|
const security_auth_service_1 = require("./security-auth.service");
|
|
@@ -16,6 +16,7 @@ exports.SecurityWorkflowsService = void 0;
|
|
|
16
16
|
const common_1 = require("@nestjs/common");
|
|
17
17
|
const typeorm_1 = require("@nestjs/typeorm");
|
|
18
18
|
const typeorm_2 = require("typeorm");
|
|
19
|
+
const uuid_1 = require("uuid");
|
|
19
20
|
const contracts_1 = require("../api/contracts");
|
|
20
21
|
const roles_1 = require("../api/roles");
|
|
21
22
|
const app_user_entity_1 = require("./entities/app-user.entity");
|
|
@@ -94,6 +95,7 @@ let SecurityWorkflowsService = class SecurityWorkflowsService {
|
|
|
94
95
|
let role = await this.rolesRepo.findOne({ where: { roleKey } });
|
|
95
96
|
if (!role) {
|
|
96
97
|
role = this.rolesRepo.create({
|
|
98
|
+
id: (0, uuid_1.v7)(),
|
|
97
99
|
roleKey,
|
|
98
100
|
description: description?.trim() || null,
|
|
99
101
|
isSystem: roleKey === contracts_1.ADMIN_ROLE,
|
|
@@ -139,6 +141,7 @@ let SecurityWorkflowsService = class SecurityWorkflowsService {
|
|
|
139
141
|
await this.userRolesRepo.delete({ userId });
|
|
140
142
|
if (roles.length > 0) {
|
|
141
143
|
await this.userRolesRepo.save(roles.map((role) => this.userRolesRepo.create({
|
|
144
|
+
id: (0, uuid_1.v7)(),
|
|
142
145
|
userId,
|
|
143
146
|
roleId: role.id,
|
|
144
147
|
})));
|
|
@@ -182,6 +185,7 @@ let SecurityWorkflowsService = class SecurityWorkflowsService {
|
|
|
182
185
|
return;
|
|
183
186
|
}
|
|
184
187
|
await this.rolesRepo.save(missing.map((roleKey) => this.rolesRepo.create({
|
|
188
|
+
id: (0, uuid_1.v7)(),
|
|
185
189
|
roleKey,
|
|
186
190
|
description: null,
|
|
187
191
|
isSystem: roleKey === contracts_1.ADMIN_ROLE,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scryan7371/sdr-security",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Reusable auth/security capability for API and app clients.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -34,7 +34,8 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@babel/runtime": "7.28.6",
|
|
36
36
|
"bcryptjs": "3.0.3",
|
|
37
|
-
"jsonwebtoken": "9.0.3"
|
|
37
|
+
"jsonwebtoken": "9.0.3",
|
|
38
|
+
"uuid": "11.1.0"
|
|
38
39
|
},
|
|
39
40
|
"peerDependencies": {
|
|
40
41
|
"@nestjs/common": "^11.0.0",
|
|
@@ -8,12 +8,14 @@ export class AddRefreshTokens1700000000001 {
|
|
|
8
8
|
|
|
9
9
|
await queryRunner.query(`
|
|
10
10
|
CREATE TABLE "refresh_token" (
|
|
11
|
-
"id"
|
|
11
|
+
"id" uuid PRIMARY KEY NOT NULL DEFAULT uuidv7(),
|
|
12
12
|
"token_hash" varchar NOT NULL,
|
|
13
13
|
"expires_at" timestamptz NOT NULL,
|
|
14
14
|
"revoked_at" timestamptz,
|
|
15
|
-
"userId"
|
|
15
|
+
"userId" uuid,
|
|
16
16
|
"created_at" timestamptz NOT NULL DEFAULT (CURRENT_TIMESTAMP),
|
|
17
|
+
CONSTRAINT "CHK_refresh_token_id_uuidv7" CHECK ("id"::text ~* '^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'),
|
|
18
|
+
CONSTRAINT "CHK_refresh_token_userId_uuidv7" CHECK ("userId" IS NULL OR "userId"::text ~* '^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'),
|
|
17
19
|
CONSTRAINT "FK_refresh_token_user" FOREIGN KEY ("userId") REFERENCES ${userTableRef} ("id") ON DELETE CASCADE ON UPDATE NO ACTION
|
|
18
20
|
)
|
|
19
21
|
`);
|
|
@@ -9,11 +9,13 @@ export class CreateSecurityIdentity1739500000000 {
|
|
|
9
9
|
await queryRunner.query(`
|
|
10
10
|
CREATE TABLE IF NOT EXISTS "security_identity" (
|
|
11
11
|
"id" uuid PRIMARY KEY NOT NULL DEFAULT uuidv7(),
|
|
12
|
-
"user_id"
|
|
12
|
+
"user_id" uuid NOT NULL,
|
|
13
13
|
"provider" varchar NOT NULL,
|
|
14
14
|
"provider_subject" varchar NOT NULL,
|
|
15
15
|
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
16
16
|
"updated_at" timestamptz NOT NULL DEFAULT now(),
|
|
17
|
+
CONSTRAINT "CHK_security_identity_id_uuidv7" CHECK ("id"::text ~* '^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'),
|
|
18
|
+
CONSTRAINT "CHK_security_identity_user_id_uuidv7" CHECK ("user_id"::text ~* '^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'),
|
|
17
19
|
CONSTRAINT "FK_security_identity_user_id" FOREIGN KEY ("user_id") REFERENCES ${userTableRef} ("id") ON DELETE CASCADE
|
|
18
20
|
)
|
|
19
21
|
`);
|
|
@@ -11,7 +11,8 @@ export class CreateSecurityRoles1739510000000 {
|
|
|
11
11
|
"description" text,
|
|
12
12
|
"is_system" boolean NOT NULL DEFAULT false,
|
|
13
13
|
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
14
|
-
"updated_at" timestamptz NOT NULL DEFAULT now()
|
|
14
|
+
"updated_at" timestamptz NOT NULL DEFAULT now(),
|
|
15
|
+
CONSTRAINT "CHK_security_role_id_uuidv7" CHECK ("id"::text ~* '^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$')
|
|
15
16
|
)
|
|
16
17
|
`);
|
|
17
18
|
|
|
@@ -9,9 +9,12 @@ export class CreateSecurityUserRoles1739515000000 {
|
|
|
9
9
|
await queryRunner.query(`
|
|
10
10
|
CREATE TABLE IF NOT EXISTS "security_user_role" (
|
|
11
11
|
"id" uuid PRIMARY KEY NOT NULL DEFAULT uuidv7(),
|
|
12
|
-
"user_id"
|
|
12
|
+
"user_id" uuid NOT NULL,
|
|
13
13
|
"role_id" uuid NOT NULL,
|
|
14
14
|
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
15
|
+
CONSTRAINT "CHK_security_user_role_id_uuidv7" CHECK ("id"::text ~* '^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'),
|
|
16
|
+
CONSTRAINT "CHK_security_user_role_user_id_uuidv7" CHECK ("user_id"::text ~* '^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'),
|
|
17
|
+
CONSTRAINT "CHK_security_user_role_role_id_uuidv7" CHECK ("role_id"::text ~* '^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'),
|
|
15
18
|
CONSTRAINT "FK_security_user_role_user_id" FOREIGN KEY ("user_id") REFERENCES ${userTableRef} ("id") ON DELETE CASCADE,
|
|
16
19
|
CONSTRAINT "FK_security_user_role_role_id" FOREIGN KEY ("role_id") REFERENCES "security_role" ("id") ON DELETE CASCADE
|
|
17
20
|
)
|
|
@@ -9,11 +9,13 @@ export class CreatePasswordResetTokens1739520000000 {
|
|
|
9
9
|
await queryRunner.query(`
|
|
10
10
|
CREATE TABLE IF NOT EXISTS "security_password_reset_token" (
|
|
11
11
|
"id" uuid PRIMARY KEY NOT NULL DEFAULT uuidv7(),
|
|
12
|
-
"user_id"
|
|
12
|
+
"user_id" uuid NOT NULL,
|
|
13
13
|
"token" varchar NOT NULL,
|
|
14
14
|
"expires_at" timestamptz NOT NULL,
|
|
15
15
|
"used_at" timestamptz,
|
|
16
16
|
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
17
|
+
CONSTRAINT "CHK_security_password_reset_token_id_uuidv7" CHECK ("id"::text ~* '^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'),
|
|
18
|
+
CONSTRAINT "CHK_security_password_reset_token_user_id_uuidv7" CHECK ("user_id"::text ~* '^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'),
|
|
17
19
|
CONSTRAINT "FK_security_password_reset_token_user_id" FOREIGN KEY ("user_id") REFERENCES ${userTableRef} ("id") ON DELETE CASCADE
|
|
18
20
|
)
|
|
19
21
|
`);
|
|
@@ -8,13 +8,14 @@ export class CreateSecurityUser1739530000000 {
|
|
|
8
8
|
|
|
9
9
|
await queryRunner.query(`
|
|
10
10
|
CREATE TABLE IF NOT EXISTS "security_user" (
|
|
11
|
-
"user_id"
|
|
11
|
+
"user_id" uuid PRIMARY KEY NOT NULL,
|
|
12
12
|
"password_hash" varchar NOT NULL,
|
|
13
13
|
"email_verified_at" timestamptz,
|
|
14
14
|
"email_verification_token" varchar,
|
|
15
15
|
"admin_approved_at" timestamptz,
|
|
16
16
|
"is_active" boolean NOT NULL DEFAULT true,
|
|
17
17
|
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
18
|
+
CONSTRAINT "CHK_security_user_user_id_uuidv7" CHECK ("user_id"::text ~* '^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$'),
|
|
18
19
|
CONSTRAINT "FK_security_user_user_id" FOREIGN KEY ("user_id") REFERENCES ${userTableRef} ("id") ON DELETE CASCADE
|
|
19
20
|
)
|
|
20
21
|
`);
|
|
@@ -121,7 +121,7 @@ describe("database integration", () => {
|
|
|
121
121
|
await client.query(`SET search_path TO "${schema}", public`);
|
|
122
122
|
await client.query(`
|
|
123
123
|
CREATE TABLE IF NOT EXISTS "${schema}"."app_user" (
|
|
124
|
-
"id"
|
|
124
|
+
"id" uuid PRIMARY KEY NOT NULL,
|
|
125
125
|
"email" varchar NOT NULL
|
|
126
126
|
)
|
|
127
127
|
`);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Column, Entity,
|
|
1
|
+
import { Column, Entity, PrimaryColumn } from "typeorm";
|
|
2
2
|
|
|
3
3
|
@Entity({ name: "app_user" })
|
|
4
4
|
export class AppUserEntity {
|
|
5
|
-
@
|
|
5
|
+
@PrimaryColumn({ type: "uuid" })
|
|
6
6
|
id!: string;
|
|
7
7
|
|
|
8
8
|
@Column({ type: "varchar" })
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
|
+
BeforeInsert,
|
|
2
3
|
Column,
|
|
3
4
|
CreateDateColumn,
|
|
4
5
|
Entity,
|
|
5
|
-
|
|
6
|
+
PrimaryColumn,
|
|
6
7
|
} from "typeorm";
|
|
8
|
+
import { v7 as uuidv7 } from "uuid";
|
|
7
9
|
|
|
8
10
|
@Entity({ name: "security_password_reset_token" })
|
|
9
11
|
export class PasswordResetTokenEntity {
|
|
10
|
-
@
|
|
12
|
+
@PrimaryColumn({ type: "uuid" })
|
|
11
13
|
id!: string;
|
|
12
14
|
|
|
13
|
-
@Column({ type: "
|
|
15
|
+
@Column({ type: "uuid", name: "user_id" })
|
|
14
16
|
userId!: string;
|
|
15
17
|
|
|
16
18
|
@Column({ type: "varchar", unique: true })
|
|
@@ -24,4 +26,11 @@ export class PasswordResetTokenEntity {
|
|
|
24
26
|
|
|
25
27
|
@CreateDateColumn({ name: "created_at" })
|
|
26
28
|
createdAt!: Date;
|
|
29
|
+
|
|
30
|
+
@BeforeInsert()
|
|
31
|
+
ensureId() {
|
|
32
|
+
if (!this.id) {
|
|
33
|
+
this.id = uuidv7();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
27
36
|
}
|
|
@@ -2,7 +2,7 @@ import { Column, CreateDateColumn, Entity, PrimaryColumn } from "typeorm";
|
|
|
2
2
|
|
|
3
3
|
@Entity({ name: "refresh_token" })
|
|
4
4
|
export class RefreshTokenEntity {
|
|
5
|
-
@PrimaryColumn({ type: "
|
|
5
|
+
@PrimaryColumn({ type: "uuid" })
|
|
6
6
|
id!: string;
|
|
7
7
|
|
|
8
8
|
@Column({ type: "varchar", name: "token_hash" })
|
|
@@ -14,7 +14,7 @@ export class RefreshTokenEntity {
|
|
|
14
14
|
@Column({ type: "timestamptz", name: "revoked_at", nullable: true })
|
|
15
15
|
revokedAt!: Date | null;
|
|
16
16
|
|
|
17
|
-
@Column({ type: "
|
|
17
|
+
@Column({ type: "uuid", name: "userId", nullable: true })
|
|
18
18
|
userId!: string | null;
|
|
19
19
|
|
|
20
20
|
@CreateDateColumn({ name: "created_at" })
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { v7 as uuidv7 } from "uuid";
|
|
2
|
+
import { BeforeInsert, Column, Entity, PrimaryColumn } from "typeorm";
|
|
2
3
|
|
|
3
4
|
@Entity({ name: "security_role" })
|
|
4
5
|
export class SecurityRoleEntity {
|
|
5
|
-
@
|
|
6
|
+
@PrimaryColumn({ type: "uuid" })
|
|
6
7
|
id!: string;
|
|
7
8
|
|
|
8
9
|
@Column({ type: "varchar", name: "role_key", unique: true })
|
|
@@ -13,4 +14,11 @@ export class SecurityRoleEntity {
|
|
|
13
14
|
|
|
14
15
|
@Column({ type: "boolean", name: "is_system", default: false })
|
|
15
16
|
isSystem!: boolean;
|
|
17
|
+
|
|
18
|
+
@BeforeInsert()
|
|
19
|
+
ensureId() {
|
|
20
|
+
if (!this.id) {
|
|
21
|
+
this.id = uuidv7();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
16
24
|
}
|
|
@@ -1,13 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { v7 as uuidv7 } from "uuid";
|
|
2
|
+
import { BeforeInsert, Column, Entity, PrimaryColumn } from "typeorm";
|
|
2
3
|
|
|
3
4
|
@Entity({ name: "security_user_role" })
|
|
4
5
|
export class SecurityUserRoleEntity {
|
|
5
|
-
@
|
|
6
|
+
@PrimaryColumn({ type: "uuid" })
|
|
6
7
|
id!: string;
|
|
7
8
|
|
|
8
|
-
@Column({ type: "
|
|
9
|
+
@Column({ type: "uuid", name: "user_id" })
|
|
9
10
|
userId!: string;
|
|
10
11
|
|
|
11
12
|
@Column({ type: "uuid", name: "role_id" })
|
|
12
13
|
roleId!: string;
|
|
14
|
+
|
|
15
|
+
@BeforeInsert()
|
|
16
|
+
ensureId() {
|
|
17
|
+
if (!this.id) {
|
|
18
|
+
this.id = uuidv7();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
13
21
|
}
|
|
@@ -2,7 +2,7 @@ import { Column, CreateDateColumn, Entity, PrimaryColumn } from "typeorm";
|
|
|
2
2
|
|
|
3
3
|
@Entity({ name: "security_user" })
|
|
4
4
|
export class SecurityUserEntity {
|
|
5
|
-
@PrimaryColumn({ type: "
|
|
5
|
+
@PrimaryColumn({ type: "uuid", name: "user_id" })
|
|
6
6
|
userId!: string;
|
|
7
7
|
|
|
8
8
|
@Column({ type: "varchar", name: "password_hash" })
|
|
@@ -10,13 +10,16 @@ vi.mock("bcryptjs", () => ({
|
|
|
10
10
|
|
|
11
11
|
vi.mock("crypto", () => ({
|
|
12
12
|
randomBytes: vi.fn(() => ({ toString: () => "token-bytes" })),
|
|
13
|
-
randomUUID: vi.fn(() => "uuid-1"),
|
|
14
13
|
}));
|
|
15
14
|
|
|
16
15
|
vi.mock("jsonwebtoken", () => ({
|
|
17
16
|
sign: vi.fn(() => "signed-access-token"),
|
|
18
17
|
}));
|
|
19
18
|
|
|
19
|
+
vi.mock("uuid", () => ({
|
|
20
|
+
v7: vi.fn(() => "uuid-1"),
|
|
21
|
+
}));
|
|
22
|
+
|
|
20
23
|
import { compare } from "bcryptjs";
|
|
21
24
|
import { sign } from "jsonwebtoken";
|
|
22
25
|
import { SecurityAuthService } from "./security-auth.service";
|
|
@@ -4,9 +4,10 @@ import {
|
|
|
4
4
|
Injectable,
|
|
5
5
|
UnauthorizedException,
|
|
6
6
|
} from "@nestjs/common";
|
|
7
|
-
import { randomBytes
|
|
7
|
+
import { randomBytes } from "crypto";
|
|
8
8
|
import { compare, hash } from "bcryptjs";
|
|
9
9
|
import { sign, type SignOptions } from "jsonwebtoken";
|
|
10
|
+
import { v7 as uuidv7 } from "uuid";
|
|
10
11
|
import { InjectRepository } from "@nestjs/typeorm";
|
|
11
12
|
import { In, IsNull, Repository } from "typeorm";
|
|
12
13
|
import { AuthResponse, RegisterResponse } from "../api/contracts";
|
|
@@ -60,6 +61,7 @@ export class SecurityAuthService {
|
|
|
60
61
|
|
|
61
62
|
const appUser = await this.appUsersRepo.save(
|
|
62
63
|
this.appUsersRepo.create({
|
|
64
|
+
id: uuidv7(),
|
|
63
65
|
email,
|
|
64
66
|
}),
|
|
65
67
|
);
|
|
@@ -195,6 +197,7 @@ export class SecurityAuthService {
|
|
|
195
197
|
);
|
|
196
198
|
await this.passwordResetRepo.save(
|
|
197
199
|
this.passwordResetRepo.create({
|
|
200
|
+
id: uuidv7(),
|
|
198
201
|
userId: appUser.id,
|
|
199
202
|
token,
|
|
200
203
|
expiresAt,
|
|
@@ -283,7 +286,7 @@ export class SecurityAuthService {
|
|
|
283
286
|
|
|
284
287
|
await this.refreshTokenRepo.save(
|
|
285
288
|
this.refreshTokenRepo.create({
|
|
286
|
-
id:
|
|
289
|
+
id: uuidv7(),
|
|
287
290
|
userId: appUser.id,
|
|
288
291
|
tokenHash: refreshTokenHash,
|
|
289
292
|
expiresAt: refreshTokenExpiresAt,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Inject, Injectable, NotFoundException } from "@nestjs/common";
|
|
2
2
|
import { InjectRepository } from "@nestjs/typeorm";
|
|
3
3
|
import { In, Repository } from "typeorm";
|
|
4
|
+
import { v7 as uuidv7 } from "uuid";
|
|
4
5
|
import { ADMIN_ROLE } from "../api/contracts";
|
|
5
6
|
import { normalizeRoleName } from "../api/roles";
|
|
6
7
|
import { AppUserEntity } from "./entities/app-user.entity";
|
|
@@ -106,6 +107,7 @@ export class SecurityWorkflowsService {
|
|
|
106
107
|
let role = await this.rolesRepo.findOne({ where: { roleKey } });
|
|
107
108
|
if (!role) {
|
|
108
109
|
role = this.rolesRepo.create({
|
|
110
|
+
id: uuidv7(),
|
|
109
111
|
roleKey,
|
|
110
112
|
description: description?.trim() || null,
|
|
111
113
|
isSystem: roleKey === ADMIN_ROLE,
|
|
@@ -158,6 +160,7 @@ export class SecurityWorkflowsService {
|
|
|
158
160
|
await this.userRolesRepo.save(
|
|
159
161
|
roles.map((role) =>
|
|
160
162
|
this.userRolesRepo.create({
|
|
163
|
+
id: uuidv7(),
|
|
161
164
|
userId,
|
|
162
165
|
roleId: role.id,
|
|
163
166
|
}),
|
|
@@ -210,6 +213,7 @@ export class SecurityWorkflowsService {
|
|
|
210
213
|
await this.rolesRepo.save(
|
|
211
214
|
missing.map((roleKey) =>
|
|
212
215
|
this.rolesRepo.create({
|
|
216
|
+
id: uuidv7(),
|
|
213
217
|
roleKey,
|
|
214
218
|
description: null,
|
|
215
219
|
isSystem: roleKey === ADMIN_ROLE,
|