@scryan7371/sdr-security 0.1.1 → 0.1.3
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/README.md +216 -13
- package/dist/api/contracts.d.ts +12 -2
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.js +1 -0
- package/dist/api/migrations/1739500000000-create-security-identity.d.ts +1 -1
- package/dist/api/migrations/1739500000000-create-security-identity.js +9 -35
- package/dist/api/migrations/1739510000000-create-security-roles.d.ts +1 -1
- package/dist/api/migrations/1739510000000-create-security-roles.js +1 -67
- package/dist/api/migrations/1739515000000-create-security-user-roles.d.ts +9 -0
- package/dist/api/migrations/1739515000000-create-security-user-roles.js +39 -0
- package/dist/api/migrations/1739520000000-create-password-reset-tokens.d.ts +9 -0
- package/dist/api/migrations/1739520000000-create-password-reset-tokens.js +42 -0
- package/dist/api/migrations/1739530000000-create-security-user.d.ts +9 -0
- package/dist/api/migrations/1739530000000-create-security-user.js +41 -0
- package/dist/api/migrations/index.d.ts +4 -2
- package/dist/api/migrations/index.js +10 -4
- package/dist/api/migrations/migrations.test.d.ts +1 -0
- package/dist/api/migrations/migrations.test.js +88 -0
- package/dist/api/notification-workflows.d.ts +31 -0
- package/dist/api/notification-workflows.js +22 -0
- package/dist/api/notification-workflows.test.d.ts +1 -0
- package/dist/api/notification-workflows.test.js +63 -0
- package/dist/api/validation.test.d.ts +1 -0
- package/dist/api/validation.test.js +20 -0
- package/dist/app/client.d.ts +17 -4
- package/dist/app/client.js +38 -11
- package/dist/app/client.test.d.ts +1 -0
- package/dist/app/client.test.js +130 -0
- package/dist/index.test.d.ts +1 -0
- package/dist/index.test.js +10 -0
- package/dist/integration/database.integration.test.d.ts +1 -0
- package/dist/integration/database.integration.test.js +158 -0
- package/dist/nest/contracts.d.ts +21 -0
- package/dist/nest/contracts.js +2 -0
- package/dist/nest/dto/auth.dto.d.ts +25 -0
- package/dist/nest/dto/auth.dto.js +89 -0
- package/dist/nest/dto/workflows.dto.d.ts +16 -0
- package/dist/nest/dto/workflows.dto.js +58 -0
- package/dist/nest/entities/app-user.entity.d.ts +4 -0
- package/dist/nest/entities/app-user.entity.js +29 -0
- package/dist/nest/entities/password-reset-token.entity.d.ts +8 -0
- package/dist/nest/entities/password-reset-token.entity.js +49 -0
- package/dist/nest/entities/refresh-token.entity.d.ts +8 -0
- package/dist/nest/entities/refresh-token.entity.js +49 -0
- package/dist/nest/entities/security-role.entity.d.ts +6 -0
- package/dist/nest/entities/security-role.entity.js +39 -0
- package/dist/nest/entities/security-user-role.entity.d.ts +5 -0
- package/dist/nest/entities/security-user-role.entity.js +34 -0
- package/dist/nest/entities/security-user.entity.d.ts +9 -0
- package/dist/nest/entities/security-user.entity.js +54 -0
- package/dist/nest/index.d.ts +19 -0
- package/dist/nest/index.js +35 -0
- package/dist/nest/index.test.d.ts +1 -0
- package/dist/nest/index.test.js +14 -0
- package/dist/nest/security-admin.guard.d.ts +4 -0
- package/dist/nest/security-admin.guard.js +25 -0
- package/dist/nest/security-admin.guard.test.d.ts +1 -0
- package/dist/nest/security-admin.guard.test.js +24 -0
- package/dist/nest/security-auth.constants.d.ts +1 -0
- package/dist/nest/security-auth.constants.js +4 -0
- package/dist/nest/security-auth.controller.d.ts +51 -0
- package/dist/nest/security-auth.controller.js +177 -0
- package/dist/nest/security-auth.controller.test.d.ts +1 -0
- package/dist/nest/security-auth.controller.test.js +87 -0
- package/dist/nest/security-auth.module.d.ts +9 -0
- package/dist/nest/security-auth.module.js +70 -0
- package/dist/nest/security-auth.options.d.ts +8 -0
- package/dist/nest/security-auth.options.js +2 -0
- package/dist/nest/security-auth.service.d.ts +60 -0
- package/dist/nest/security-auth.service.js +299 -0
- package/dist/nest/security-auth.service.test.d.ts +1 -0
- package/dist/nest/security-auth.service.test.js +249 -0
- package/dist/nest/security-jwt.guard.d.ts +7 -0
- package/dist/nest/security-jwt.guard.js +46 -0
- package/dist/nest/security-jwt.guard.test.d.ts +1 -0
- package/dist/nest/security-jwt.guard.test.js +51 -0
- package/dist/nest/security-modules.test.d.ts +1 -0
- package/dist/nest/security-modules.test.js +61 -0
- package/dist/nest/security-workflows.controller.d.ts +72 -0
- package/dist/nest/security-workflows.controller.js +187 -0
- package/dist/nest/security-workflows.controller.test.d.ts +1 -0
- package/dist/nest/security-workflows.controller.test.js +87 -0
- package/dist/nest/security-workflows.module.d.ts +9 -0
- package/dist/nest/security-workflows.module.js +61 -0
- package/dist/nest/security-workflows.service.d.ts +69 -0
- package/dist/nest/security-workflows.service.js +203 -0
- package/dist/nest/security-workflows.service.test.d.ts +1 -0
- package/dist/nest/security-workflows.service.test.js +178 -0
- package/dist/nest/swagger.d.ts +2 -0
- package/dist/nest/swagger.js +16 -0
- package/dist/nest/swagger.test.d.ts +1 -0
- package/dist/nest/swagger.test.js +21 -0
- package/dist/nest/tokens.d.ts +1 -0
- package/dist/nest/tokens.js +4 -0
- package/package.json +45 -4
- package/src/api/contracts.ts +11 -2
- package/src/api/index.ts +1 -0
- package/src/api/migrations/1739500000000-create-security-identity.ts +11 -50
- package/src/api/migrations/1739510000000-create-security-roles.ts +2 -89
- package/src/api/migrations/1739515000000-create-security-user-roles.ts +49 -0
- package/src/api/migrations/1739520000000-create-password-reset-tokens.ts +57 -0
- package/src/api/migrations/1739530000000-create-security-user.ts +51 -0
- package/src/api/migrations/index.ts +9 -3
- package/src/api/migrations/migrations.test.ts +145 -0
- package/src/api/notification-workflows.test.ts +78 -0
- package/src/api/notification-workflows.ts +38 -0
- package/src/api/validation.test.ts +21 -0
- package/src/app/client.test.ts +157 -0
- package/src/app/client.ts +74 -18
- package/src/index.test.ts +9 -0
- package/src/integration/database.integration.test.ts +205 -0
- package/src/nest/contracts.ts +20 -0
- package/src/nest/dto/auth.dto.ts +48 -0
- package/src/nest/dto/workflows.dto.ts +29 -0
- package/src/nest/entities/app-user.entity.ts +10 -0
- package/src/nest/entities/password-reset-token.entity.ts +27 -0
- package/src/nest/entities/refresh-token.entity.ts +22 -0
- package/src/nest/entities/security-role.entity.ts +16 -0
- package/src/nest/entities/security-user-role.entity.ts +13 -0
- package/src/nest/entities/security-user.entity.ts +25 -0
- package/src/nest/index.test.ts +20 -0
- package/src/nest/index.ts +19 -0
- package/src/nest/security-admin.guard.test.ts +31 -0
- package/src/nest/security-admin.guard.ts +21 -0
- package/src/nest/security-auth.constants.ts +1 -0
- package/src/nest/security-auth.controller.test.ts +128 -0
- package/src/nest/security-auth.controller.ts +148 -0
- package/src/nest/security-auth.module.ts +65 -0
- package/src/nest/security-auth.options.ts +8 -0
- package/src/nest/security-auth.service.test.ts +368 -0
- package/src/nest/security-auth.service.ts +356 -0
- package/src/nest/security-jwt.guard.test.ts +65 -0
- package/src/nest/security-jwt.guard.ts +47 -0
- package/src/nest/security-modules.test.ts +79 -0
- package/src/nest/security-workflows.controller.test.ts +119 -0
- package/src/nest/security-workflows.controller.ts +149 -0
- package/src/nest/security-workflows.module.ts +56 -0
- package/src/nest/security-workflows.service.test.ts +238 -0
- package/src/nest/security-workflows.service.ts +220 -0
- package/src/nest/swagger.test.ts +27 -0
- package/src/nest/swagger.ts +18 -0
- package/src/nest/tokens.ts +1 -0
- package/dist/api/migrations/1739490000000-add-google-subject-to-user.d.ts +0 -5
- package/dist/api/migrations/1739490000000-add-google-subject-to-user.js +0 -14
- package/src/api/migrations/1739490000000-add-google-subject-to-user.ts +0 -12
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const common_1 = require("@nestjs/common");
|
|
4
|
+
const vitest_1 = require("vitest");
|
|
5
|
+
vitest_1.vi.mock("jsonwebtoken", () => ({
|
|
6
|
+
verify: vitest_1.vi.fn(),
|
|
7
|
+
}));
|
|
8
|
+
const jsonwebtoken_1 = require("jsonwebtoken");
|
|
9
|
+
const security_jwt_guard_1 = require("./security-jwt.guard");
|
|
10
|
+
const mockedVerify = vitest_1.vi.mocked(jsonwebtoken_1.verify);
|
|
11
|
+
const makeContext = (headers) => ({
|
|
12
|
+
switchToHttp: () => ({
|
|
13
|
+
getRequest: () => ({ headers }),
|
|
14
|
+
}),
|
|
15
|
+
});
|
|
16
|
+
(0, vitest_1.describe)("SecurityJwtGuard", () => {
|
|
17
|
+
(0, vitest_1.it)("throws when header is missing", () => {
|
|
18
|
+
const guard = new security_jwt_guard_1.SecurityJwtGuard({ jwtSecret: "secret" });
|
|
19
|
+
(0, vitest_1.expect)(() => guard.canActivate(makeContext())).toThrow(common_1.UnauthorizedException);
|
|
20
|
+
});
|
|
21
|
+
(0, vitest_1.it)("throws when token is invalid", () => {
|
|
22
|
+
mockedVerify.mockImplementation(() => {
|
|
23
|
+
throw new Error("bad token");
|
|
24
|
+
});
|
|
25
|
+
const guard = new security_jwt_guard_1.SecurityJwtGuard({ jwtSecret: "secret" });
|
|
26
|
+
(0, vitest_1.expect)(() => guard.canActivate(makeContext({ authorization: "Bearer token" }))).toThrow("Invalid token");
|
|
27
|
+
});
|
|
28
|
+
(0, vitest_1.it)("attaches user payload on success", () => {
|
|
29
|
+
mockedVerify.mockReturnValue({
|
|
30
|
+
sub: "user-1",
|
|
31
|
+
email: "user@example.com",
|
|
32
|
+
roles: ["ADMIN"],
|
|
33
|
+
});
|
|
34
|
+
const request = {
|
|
35
|
+
headers: { Authorization: "Bearer good-token" },
|
|
36
|
+
user: undefined,
|
|
37
|
+
};
|
|
38
|
+
const context = {
|
|
39
|
+
switchToHttp: () => ({
|
|
40
|
+
getRequest: () => request,
|
|
41
|
+
}),
|
|
42
|
+
};
|
|
43
|
+
const guard = new security_jwt_guard_1.SecurityJwtGuard({ jwtSecret: "secret" });
|
|
44
|
+
(0, vitest_1.expect)(guard.canActivate(context)).toBe(true);
|
|
45
|
+
(0, vitest_1.expect)(request.user).toEqual({
|
|
46
|
+
sub: "user-1",
|
|
47
|
+
email: "user@example.com",
|
|
48
|
+
roles: ["ADMIN"],
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const security_auth_constants_1 = require("./security-auth.constants");
|
|
5
|
+
const security_auth_module_1 = require("./security-auth.module");
|
|
6
|
+
const security_workflows_module_1 = require("./security-workflows.module");
|
|
7
|
+
const tokens_1 = require("./tokens");
|
|
8
|
+
(0, vitest_1.describe)("Security module factories", () => {
|
|
9
|
+
(0, vitest_1.it)("builds auth module with custom notifier", () => {
|
|
10
|
+
const notifierProvider = {
|
|
11
|
+
provide: tokens_1.SECURITY_WORKFLOW_NOTIFIER,
|
|
12
|
+
useValue: {
|
|
13
|
+
sendAdminsUserEmailVerified: async () => undefined,
|
|
14
|
+
sendUserAccountApproved: async () => undefined,
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
const dynamicModule = security_auth_module_1.SecurityAuthModule.forRoot({
|
|
18
|
+
auth: { jwtSecret: "secret", requireAdminApproval: true },
|
|
19
|
+
notifierProvider,
|
|
20
|
+
});
|
|
21
|
+
(0, vitest_1.expect)(dynamicModule.module).toBe(security_auth_module_1.SecurityAuthModule);
|
|
22
|
+
(0, vitest_1.expect)(dynamicModule.controllers).toBeDefined();
|
|
23
|
+
(0, vitest_1.expect)(dynamicModule.providers).toEqual(vitest_1.expect.arrayContaining([
|
|
24
|
+
vitest_1.expect.objectContaining({ provide: security_auth_constants_1.SECURITY_AUTH_OPTIONS }),
|
|
25
|
+
notifierProvider,
|
|
26
|
+
]));
|
|
27
|
+
});
|
|
28
|
+
(0, vitest_1.it)("builds auth module with default notifier", () => {
|
|
29
|
+
const dynamicModule = security_auth_module_1.SecurityAuthModule.forRoot({
|
|
30
|
+
auth: { jwtSecret: "secret" },
|
|
31
|
+
});
|
|
32
|
+
const notifier = (dynamicModule.providers ?? []).find((provider) => typeof provider === "object" &&
|
|
33
|
+
provider !== null &&
|
|
34
|
+
"provide" in provider &&
|
|
35
|
+
provider.provide ===
|
|
36
|
+
tokens_1.SECURITY_WORKFLOW_NOTIFIER);
|
|
37
|
+
(0, vitest_1.expect)(notifier).toBeDefined();
|
|
38
|
+
});
|
|
39
|
+
(0, vitest_1.it)("builds workflows module with default auth options", () => {
|
|
40
|
+
const dynamicModule = security_workflows_module_1.SecurityWorkflowsModule.forRoot();
|
|
41
|
+
(0, vitest_1.expect)(dynamicModule.module).toBe(security_workflows_module_1.SecurityWorkflowsModule);
|
|
42
|
+
(0, vitest_1.expect)(dynamicModule.providers).toEqual(vitest_1.expect.arrayContaining([
|
|
43
|
+
vitest_1.expect.objectContaining({ provide: security_auth_constants_1.SECURITY_AUTH_OPTIONS }),
|
|
44
|
+
vitest_1.expect.objectContaining({ provide: tokens_1.SECURITY_WORKFLOW_NOTIFIER }),
|
|
45
|
+
]));
|
|
46
|
+
});
|
|
47
|
+
(0, vitest_1.it)("builds workflows module with custom options", () => {
|
|
48
|
+
const notifierProvider = {
|
|
49
|
+
provide: tokens_1.SECURITY_WORKFLOW_NOTIFIER,
|
|
50
|
+
useValue: {
|
|
51
|
+
sendAdminsUserEmailVerified: async () => undefined,
|
|
52
|
+
sendUserAccountApproved: async () => undefined,
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
const dynamicModule = security_workflows_module_1.SecurityWorkflowsModule.forRoot({
|
|
56
|
+
auth: { jwtSecret: "custom" },
|
|
57
|
+
notifierProvider,
|
|
58
|
+
});
|
|
59
|
+
(0, vitest_1.expect)(dynamicModule.providers).toEqual(vitest_1.expect.arrayContaining([notifierProvider]));
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { SecurityWorkflowsService } from "./security-workflows.service";
|
|
2
|
+
export declare class SecurityWorkflowsController {
|
|
3
|
+
private readonly workflowsService;
|
|
4
|
+
constructor(workflowsService: SecurityWorkflowsService);
|
|
5
|
+
markEmailVerified(id: string): Promise<{
|
|
6
|
+
success: true;
|
|
7
|
+
notified: false;
|
|
8
|
+
adminEmails: string[];
|
|
9
|
+
} | {
|
|
10
|
+
success: true;
|
|
11
|
+
notified: true;
|
|
12
|
+
adminEmails: string[];
|
|
13
|
+
}>;
|
|
14
|
+
setAdminApproval(id: string, body: {
|
|
15
|
+
approved?: boolean;
|
|
16
|
+
}): Promise<{
|
|
17
|
+
success: true;
|
|
18
|
+
notified: false;
|
|
19
|
+
} | {
|
|
20
|
+
success: true;
|
|
21
|
+
notified: true;
|
|
22
|
+
}>;
|
|
23
|
+
setUserActive(id: string, body: {
|
|
24
|
+
active?: boolean;
|
|
25
|
+
}): Promise<{
|
|
26
|
+
success: true;
|
|
27
|
+
userId: string;
|
|
28
|
+
active: boolean;
|
|
29
|
+
}>;
|
|
30
|
+
listRoles(): Promise<{
|
|
31
|
+
roles: {
|
|
32
|
+
role: string;
|
|
33
|
+
description: string | null;
|
|
34
|
+
isSystem: boolean;
|
|
35
|
+
}[];
|
|
36
|
+
}>;
|
|
37
|
+
createRole(body: {
|
|
38
|
+
role?: string;
|
|
39
|
+
description?: string | null;
|
|
40
|
+
}): Promise<{
|
|
41
|
+
roles: {
|
|
42
|
+
role: string;
|
|
43
|
+
description: string | null;
|
|
44
|
+
isSystem: boolean;
|
|
45
|
+
}[];
|
|
46
|
+
}>;
|
|
47
|
+
removeRole(role: string): Promise<{
|
|
48
|
+
success: false;
|
|
49
|
+
} | {
|
|
50
|
+
success: true;
|
|
51
|
+
}>;
|
|
52
|
+
getUserRoles(id: string): Promise<{
|
|
53
|
+
userId: string;
|
|
54
|
+
roles: string[];
|
|
55
|
+
}>;
|
|
56
|
+
setUserRoles(id: string, body: {
|
|
57
|
+
roles?: string[];
|
|
58
|
+
}): Promise<{
|
|
59
|
+
userId: string;
|
|
60
|
+
roles: string[];
|
|
61
|
+
}>;
|
|
62
|
+
assignUserRole(id: string, body: {
|
|
63
|
+
role?: string;
|
|
64
|
+
}): Promise<{
|
|
65
|
+
userId: string;
|
|
66
|
+
roles: string[];
|
|
67
|
+
}>;
|
|
68
|
+
removeUserRole(id: string, role: string): Promise<{
|
|
69
|
+
userId: string;
|
|
70
|
+
roles: string[];
|
|
71
|
+
}>;
|
|
72
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.SecurityWorkflowsController = void 0;
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
17
|
+
const swagger_1 = require("@nestjs/swagger");
|
|
18
|
+
const security_admin_guard_1 = require("./security-admin.guard");
|
|
19
|
+
const security_jwt_guard_1 = require("./security-jwt.guard");
|
|
20
|
+
const security_workflows_service_1 = require("./security-workflows.service");
|
|
21
|
+
const workflows_dto_1 = require("./dto/workflows.dto");
|
|
22
|
+
let SecurityWorkflowsController = class SecurityWorkflowsController {
|
|
23
|
+
workflowsService;
|
|
24
|
+
constructor(workflowsService) {
|
|
25
|
+
this.workflowsService = workflowsService;
|
|
26
|
+
}
|
|
27
|
+
async markEmailVerified(id) {
|
|
28
|
+
return this.workflowsService.markEmailVerifiedAndNotifyAdmins(id);
|
|
29
|
+
}
|
|
30
|
+
async setAdminApproval(id, body) {
|
|
31
|
+
if (typeof body.approved !== "boolean") {
|
|
32
|
+
throw new common_1.BadRequestException("approved is required");
|
|
33
|
+
}
|
|
34
|
+
return this.workflowsService.setAdminApprovalAndNotifyUser(id, body.approved);
|
|
35
|
+
}
|
|
36
|
+
async setUserActive(id, body) {
|
|
37
|
+
if (typeof body.active !== "boolean") {
|
|
38
|
+
throw new common_1.BadRequestException("active is required");
|
|
39
|
+
}
|
|
40
|
+
return this.workflowsService.setUserActive(id, body.active);
|
|
41
|
+
}
|
|
42
|
+
async listRoles() {
|
|
43
|
+
return { roles: await this.workflowsService.listRoles() };
|
|
44
|
+
}
|
|
45
|
+
async createRole(body) {
|
|
46
|
+
if (!body.role || !body.role.trim()) {
|
|
47
|
+
throw new common_1.BadRequestException("role is required");
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
roles: await this.workflowsService.createRole(body.role, body.description),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
async removeRole(role) {
|
|
54
|
+
return this.workflowsService.removeRole(role);
|
|
55
|
+
}
|
|
56
|
+
async getUserRoles(id) {
|
|
57
|
+
return this.workflowsService.getUserRoles(id);
|
|
58
|
+
}
|
|
59
|
+
async setUserRoles(id, body) {
|
|
60
|
+
if (!Array.isArray(body.roles)) {
|
|
61
|
+
throw new common_1.BadRequestException("roles must be an array");
|
|
62
|
+
}
|
|
63
|
+
return this.workflowsService.setUserRoles(id, body.roles);
|
|
64
|
+
}
|
|
65
|
+
async assignUserRole(id, body) {
|
|
66
|
+
if (!body.role || !body.role.trim()) {
|
|
67
|
+
throw new common_1.BadRequestException("role is required");
|
|
68
|
+
}
|
|
69
|
+
return this.workflowsService.assignRoleToUser(id, body.role);
|
|
70
|
+
}
|
|
71
|
+
async removeUserRole(id, role) {
|
|
72
|
+
return this.workflowsService.removeRoleFromUser(id, role);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
exports.SecurityWorkflowsController = SecurityWorkflowsController;
|
|
76
|
+
__decorate([
|
|
77
|
+
(0, common_1.Post)("users/:id/email-verified"),
|
|
78
|
+
(0, swagger_1.ApiOperation)({ summary: "Mark user email as verified and notify admins" }),
|
|
79
|
+
__param(0, (0, common_1.Param)("id")),
|
|
80
|
+
__metadata("design:type", Function),
|
|
81
|
+
__metadata("design:paramtypes", [String]),
|
|
82
|
+
__metadata("design:returntype", Promise)
|
|
83
|
+
], SecurityWorkflowsController.prototype, "markEmailVerified", null);
|
|
84
|
+
__decorate([
|
|
85
|
+
(0, common_1.Patch)("users/:id/admin-approval"),
|
|
86
|
+
(0, common_1.UseGuards)(security_jwt_guard_1.SecurityJwtGuard, security_admin_guard_1.SecurityAdminGuard),
|
|
87
|
+
(0, swagger_1.ApiOperation)({ summary: "Approve/unapprove user and notify on approval" }),
|
|
88
|
+
(0, swagger_1.ApiBearerAuth)(),
|
|
89
|
+
(0, swagger_1.ApiBody)({ type: workflows_dto_1.SetAdminApprovalDto }),
|
|
90
|
+
__param(0, (0, common_1.Param)("id")),
|
|
91
|
+
__param(1, (0, common_1.Body)()),
|
|
92
|
+
__metadata("design:type", Function),
|
|
93
|
+
__metadata("design:paramtypes", [String, Object]),
|
|
94
|
+
__metadata("design:returntype", Promise)
|
|
95
|
+
], SecurityWorkflowsController.prototype, "setAdminApproval", null);
|
|
96
|
+
__decorate([
|
|
97
|
+
(0, common_1.Patch)("users/:id/active"),
|
|
98
|
+
(0, common_1.UseGuards)(security_jwt_guard_1.SecurityJwtGuard, security_admin_guard_1.SecurityAdminGuard),
|
|
99
|
+
(0, swagger_1.ApiOperation)({ summary: "Activate/deactivate a user" }),
|
|
100
|
+
(0, swagger_1.ApiBearerAuth)(),
|
|
101
|
+
(0, swagger_1.ApiBody)({ type: workflows_dto_1.SetUserActiveDto }),
|
|
102
|
+
__param(0, (0, common_1.Param)("id")),
|
|
103
|
+
__param(1, (0, common_1.Body)()),
|
|
104
|
+
__metadata("design:type", Function),
|
|
105
|
+
__metadata("design:paramtypes", [String, Object]),
|
|
106
|
+
__metadata("design:returntype", Promise)
|
|
107
|
+
], SecurityWorkflowsController.prototype, "setUserActive", null);
|
|
108
|
+
__decorate([
|
|
109
|
+
(0, common_1.Get)("roles"),
|
|
110
|
+
(0, common_1.UseGuards)(security_jwt_guard_1.SecurityJwtGuard, security_admin_guard_1.SecurityAdminGuard),
|
|
111
|
+
(0, swagger_1.ApiOperation)({ summary: "List role catalog" }),
|
|
112
|
+
(0, swagger_1.ApiBearerAuth)(),
|
|
113
|
+
__metadata("design:type", Function),
|
|
114
|
+
__metadata("design:paramtypes", []),
|
|
115
|
+
__metadata("design:returntype", Promise)
|
|
116
|
+
], SecurityWorkflowsController.prototype, "listRoles", null);
|
|
117
|
+
__decorate([
|
|
118
|
+
(0, common_1.Post)("roles"),
|
|
119
|
+
(0, common_1.UseGuards)(security_jwt_guard_1.SecurityJwtGuard, security_admin_guard_1.SecurityAdminGuard),
|
|
120
|
+
(0, swagger_1.ApiOperation)({ summary: "Create or update a role" }),
|
|
121
|
+
(0, swagger_1.ApiBearerAuth)(),
|
|
122
|
+
(0, swagger_1.ApiBody)({ type: workflows_dto_1.CreateRoleDto }),
|
|
123
|
+
__param(0, (0, common_1.Body)()),
|
|
124
|
+
__metadata("design:type", Function),
|
|
125
|
+
__metadata("design:paramtypes", [Object]),
|
|
126
|
+
__metadata("design:returntype", Promise)
|
|
127
|
+
], SecurityWorkflowsController.prototype, "createRole", null);
|
|
128
|
+
__decorate([
|
|
129
|
+
(0, common_1.Delete)("roles/:role"),
|
|
130
|
+
(0, common_1.UseGuards)(security_jwt_guard_1.SecurityJwtGuard, security_admin_guard_1.SecurityAdminGuard),
|
|
131
|
+
(0, swagger_1.ApiOperation)({ summary: "Remove a role" }),
|
|
132
|
+
(0, swagger_1.ApiBearerAuth)(),
|
|
133
|
+
__param(0, (0, common_1.Param)("role")),
|
|
134
|
+
__metadata("design:type", Function),
|
|
135
|
+
__metadata("design:paramtypes", [String]),
|
|
136
|
+
__metadata("design:returntype", Promise)
|
|
137
|
+
], SecurityWorkflowsController.prototype, "removeRole", null);
|
|
138
|
+
__decorate([
|
|
139
|
+
(0, common_1.Get)("users/:id/roles"),
|
|
140
|
+
(0, common_1.UseGuards)(security_jwt_guard_1.SecurityJwtGuard, security_admin_guard_1.SecurityAdminGuard),
|
|
141
|
+
(0, swagger_1.ApiOperation)({ summary: "Get assigned roles for a user" }),
|
|
142
|
+
(0, swagger_1.ApiBearerAuth)(),
|
|
143
|
+
__param(0, (0, common_1.Param)("id")),
|
|
144
|
+
__metadata("design:type", Function),
|
|
145
|
+
__metadata("design:paramtypes", [String]),
|
|
146
|
+
__metadata("design:returntype", Promise)
|
|
147
|
+
], SecurityWorkflowsController.prototype, "getUserRoles", null);
|
|
148
|
+
__decorate([
|
|
149
|
+
(0, common_1.Put)("users/:id/roles"),
|
|
150
|
+
(0, common_1.UseGuards)(security_jwt_guard_1.SecurityJwtGuard, security_admin_guard_1.SecurityAdminGuard),
|
|
151
|
+
(0, swagger_1.ApiOperation)({ summary: "Replace user roles" }),
|
|
152
|
+
(0, swagger_1.ApiBearerAuth)(),
|
|
153
|
+
(0, swagger_1.ApiBody)({ type: workflows_dto_1.SetUserRolesDto }),
|
|
154
|
+
__param(0, (0, common_1.Param)("id")),
|
|
155
|
+
__param(1, (0, common_1.Body)()),
|
|
156
|
+
__metadata("design:type", Function),
|
|
157
|
+
__metadata("design:paramtypes", [String, Object]),
|
|
158
|
+
__metadata("design:returntype", Promise)
|
|
159
|
+
], SecurityWorkflowsController.prototype, "setUserRoles", null);
|
|
160
|
+
__decorate([
|
|
161
|
+
(0, common_1.Post)("users/:id/roles"),
|
|
162
|
+
(0, common_1.UseGuards)(security_jwt_guard_1.SecurityJwtGuard, security_admin_guard_1.SecurityAdminGuard),
|
|
163
|
+
(0, swagger_1.ApiOperation)({ summary: "Assign one role to a user" }),
|
|
164
|
+
(0, swagger_1.ApiBearerAuth)(),
|
|
165
|
+
(0, swagger_1.ApiBody)({ type: workflows_dto_1.AssignRoleDto }),
|
|
166
|
+
__param(0, (0, common_1.Param)("id")),
|
|
167
|
+
__param(1, (0, common_1.Body)()),
|
|
168
|
+
__metadata("design:type", Function),
|
|
169
|
+
__metadata("design:paramtypes", [String, Object]),
|
|
170
|
+
__metadata("design:returntype", Promise)
|
|
171
|
+
], SecurityWorkflowsController.prototype, "assignUserRole", null);
|
|
172
|
+
__decorate([
|
|
173
|
+
(0, common_1.Delete)("users/:id/roles/:role"),
|
|
174
|
+
(0, common_1.UseGuards)(security_jwt_guard_1.SecurityJwtGuard, security_admin_guard_1.SecurityAdminGuard),
|
|
175
|
+
(0, swagger_1.ApiOperation)({ summary: "Remove one role from a user" }),
|
|
176
|
+
(0, swagger_1.ApiBearerAuth)(),
|
|
177
|
+
__param(0, (0, common_1.Param)("id")),
|
|
178
|
+
__param(1, (0, common_1.Param)("role")),
|
|
179
|
+
__metadata("design:type", Function),
|
|
180
|
+
__metadata("design:paramtypes", [String, String]),
|
|
181
|
+
__metadata("design:returntype", Promise)
|
|
182
|
+
], SecurityWorkflowsController.prototype, "removeUserRole", null);
|
|
183
|
+
exports.SecurityWorkflowsController = SecurityWorkflowsController = __decorate([
|
|
184
|
+
(0, common_1.Controller)("security/workflows"),
|
|
185
|
+
(0, swagger_1.ApiTags)("security-workflows"),
|
|
186
|
+
__metadata("design:paramtypes", [security_workflows_service_1.SecurityWorkflowsService])
|
|
187
|
+
], SecurityWorkflowsController);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const common_1 = require("@nestjs/common");
|
|
4
|
+
const vitest_1 = require("vitest");
|
|
5
|
+
const security_workflows_controller_1 = require("./security-workflows.controller");
|
|
6
|
+
const makeService = () => ({
|
|
7
|
+
markEmailVerifiedAndNotifyAdmins: vitest_1.vi.fn(),
|
|
8
|
+
setAdminApprovalAndNotifyUser: vitest_1.vi.fn(),
|
|
9
|
+
setUserActive: vitest_1.vi.fn(),
|
|
10
|
+
listRoles: vitest_1.vi.fn(),
|
|
11
|
+
createRole: vitest_1.vi.fn(),
|
|
12
|
+
removeRole: vitest_1.vi.fn(),
|
|
13
|
+
getUserRoles: vitest_1.vi.fn(),
|
|
14
|
+
setUserRoles: vitest_1.vi.fn(),
|
|
15
|
+
assignRoleToUser: vitest_1.vi.fn(),
|
|
16
|
+
removeRoleFromUser: vitest_1.vi.fn(),
|
|
17
|
+
});
|
|
18
|
+
(0, vitest_1.describe)("SecurityWorkflowsController", () => {
|
|
19
|
+
let service;
|
|
20
|
+
let controller;
|
|
21
|
+
(0, vitest_1.beforeEach)(() => {
|
|
22
|
+
service = makeService();
|
|
23
|
+
controller = new security_workflows_controller_1.SecurityWorkflowsController(service);
|
|
24
|
+
});
|
|
25
|
+
(0, vitest_1.it)("marks email verified", async () => {
|
|
26
|
+
service.markEmailVerifiedAndNotifyAdmins.mockResolvedValue({
|
|
27
|
+
success: true,
|
|
28
|
+
});
|
|
29
|
+
await (0, vitest_1.expect)(controller.markEmailVerified("u1")).resolves.toEqual({
|
|
30
|
+
success: true,
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
(0, vitest_1.it)("validates admin approval and active payload", async () => {
|
|
34
|
+
await (0, vitest_1.expect)(controller.setAdminApproval("u1", {})).rejects.toBeInstanceOf(common_1.BadRequestException);
|
|
35
|
+
await (0, vitest_1.expect)(controller.setUserActive("u1", {})).rejects.toBeInstanceOf(common_1.BadRequestException);
|
|
36
|
+
});
|
|
37
|
+
(0, vitest_1.it)("delegates admin approval and active updates", async () => {
|
|
38
|
+
service.setAdminApprovalAndNotifyUser.mockResolvedValue({ success: true });
|
|
39
|
+
service.setUserActive.mockResolvedValue({ success: true });
|
|
40
|
+
await controller.setAdminApproval("u1", { approved: true });
|
|
41
|
+
await controller.setUserActive("u1", { active: false });
|
|
42
|
+
(0, vitest_1.expect)(service.setAdminApprovalAndNotifyUser).toHaveBeenCalledWith("u1", true);
|
|
43
|
+
(0, vitest_1.expect)(service.setUserActive).toHaveBeenCalledWith("u1", false);
|
|
44
|
+
});
|
|
45
|
+
(0, vitest_1.it)("lists and creates roles", async () => {
|
|
46
|
+
service.listRoles.mockResolvedValue([{ role: "ADMIN" }]);
|
|
47
|
+
service.createRole.mockResolvedValue([
|
|
48
|
+
{ role: "ADMIN" },
|
|
49
|
+
{ role: "COACH" },
|
|
50
|
+
]);
|
|
51
|
+
await (0, vitest_1.expect)(controller.listRoles()).resolves.toEqual({
|
|
52
|
+
roles: [{ role: "ADMIN" }],
|
|
53
|
+
});
|
|
54
|
+
await (0, vitest_1.expect)(controller.createRole({ role: "coach", description: null })).resolves.toEqual({ roles: [{ role: "ADMIN" }, { role: "COACH" }] });
|
|
55
|
+
await (0, vitest_1.expect)(controller.createRole({ role: " " })).rejects.toBeInstanceOf(common_1.BadRequestException);
|
|
56
|
+
});
|
|
57
|
+
(0, vitest_1.it)("delegates role assignment and removal", async () => {
|
|
58
|
+
service.removeRole.mockResolvedValue({ success: true });
|
|
59
|
+
service.getUserRoles.mockResolvedValue({ userId: "u1", roles: ["ADMIN"] });
|
|
60
|
+
service.setUserRoles.mockResolvedValue({ userId: "u1", roles: ["ADMIN"] });
|
|
61
|
+
service.assignRoleToUser.mockResolvedValue({
|
|
62
|
+
userId: "u1",
|
|
63
|
+
roles: ["ADMIN"],
|
|
64
|
+
});
|
|
65
|
+
service.removeRoleFromUser.mockResolvedValue({ userId: "u1", roles: [] });
|
|
66
|
+
await (0, vitest_1.expect)(controller.removeRole("ADMIN")).resolves.toEqual({
|
|
67
|
+
success: true,
|
|
68
|
+
});
|
|
69
|
+
await (0, vitest_1.expect)(controller.getUserRoles("u1")).resolves.toEqual({
|
|
70
|
+
userId: "u1",
|
|
71
|
+
roles: ["ADMIN"],
|
|
72
|
+
});
|
|
73
|
+
await (0, vitest_1.expect)(controller.setUserRoles("u1", { roles: ["ADMIN"] })).resolves.toEqual({
|
|
74
|
+
userId: "u1",
|
|
75
|
+
roles: ["ADMIN"],
|
|
76
|
+
});
|
|
77
|
+
await (0, vitest_1.expect)(controller.assignUserRole("u1", { role: "ADMIN" })).resolves.toEqual({ userId: "u1", roles: ["ADMIN"] });
|
|
78
|
+
await (0, vitest_1.expect)(controller.removeUserRole("u1", "ADMIN")).resolves.toEqual({
|
|
79
|
+
userId: "u1",
|
|
80
|
+
roles: [],
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
(0, vitest_1.it)("validates role array and role string", async () => {
|
|
84
|
+
await (0, vitest_1.expect)(controller.setUserRoles("u1", { roles: undefined })).rejects.toBeInstanceOf(common_1.BadRequestException);
|
|
85
|
+
await (0, vitest_1.expect)(controller.assignUserRole("u1", {})).rejects.toBeInstanceOf(common_1.BadRequestException);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { DynamicModule, Provider } from "@nestjs/common";
|
|
2
|
+
import { SecurityWorkflowNotifier } from "./contracts";
|
|
3
|
+
import { SecurityAuthModuleOptions } from "./security-auth.options";
|
|
4
|
+
export declare class SecurityWorkflowsModule {
|
|
5
|
+
static forRoot(options?: {
|
|
6
|
+
notifierProvider?: Provider<SecurityWorkflowNotifier>;
|
|
7
|
+
auth?: SecurityAuthModuleOptions;
|
|
8
|
+
}): DynamicModule;
|
|
9
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var SecurityWorkflowsModule_1;
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.SecurityWorkflowsModule = void 0;
|
|
11
|
+
const common_1 = require("@nestjs/common");
|
|
12
|
+
const typeorm_1 = require("@nestjs/typeorm");
|
|
13
|
+
const security_auth_constants_1 = require("./security-auth.constants");
|
|
14
|
+
const security_admin_guard_1 = require("./security-admin.guard");
|
|
15
|
+
const security_jwt_guard_1 = require("./security-jwt.guard");
|
|
16
|
+
const app_user_entity_1 = require("./entities/app-user.entity");
|
|
17
|
+
const security_role_entity_1 = require("./entities/security-role.entity");
|
|
18
|
+
const security_user_entity_1 = require("./entities/security-user.entity");
|
|
19
|
+
const security_user_role_entity_1 = require("./entities/security-user-role.entity");
|
|
20
|
+
const security_workflows_controller_1 = require("./security-workflows.controller");
|
|
21
|
+
const security_workflows_service_1 = require("./security-workflows.service");
|
|
22
|
+
const tokens_1 = require("./tokens");
|
|
23
|
+
const noopNotifier = {
|
|
24
|
+
sendAdminsUserEmailVerified: async () => undefined,
|
|
25
|
+
sendUserAccountApproved: async () => undefined,
|
|
26
|
+
};
|
|
27
|
+
let SecurityWorkflowsModule = SecurityWorkflowsModule_1 = class SecurityWorkflowsModule {
|
|
28
|
+
static forRoot(options) {
|
|
29
|
+
const notifierProvider = options?.notifierProvider ?? {
|
|
30
|
+
provide: tokens_1.SECURITY_WORKFLOW_NOTIFIER,
|
|
31
|
+
useValue: noopNotifier,
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
module: SecurityWorkflowsModule_1,
|
|
35
|
+
imports: [
|
|
36
|
+
typeorm_1.TypeOrmModule.forFeature([
|
|
37
|
+
app_user_entity_1.AppUserEntity,
|
|
38
|
+
security_user_entity_1.SecurityUserEntity,
|
|
39
|
+
security_role_entity_1.SecurityRoleEntity,
|
|
40
|
+
security_user_role_entity_1.SecurityUserRoleEntity,
|
|
41
|
+
]),
|
|
42
|
+
],
|
|
43
|
+
controllers: [security_workflows_controller_1.SecurityWorkflowsController],
|
|
44
|
+
providers: [
|
|
45
|
+
{
|
|
46
|
+
provide: security_auth_constants_1.SECURITY_AUTH_OPTIONS,
|
|
47
|
+
useValue: options?.auth ?? { jwtSecret: "dev-secret" },
|
|
48
|
+
},
|
|
49
|
+
security_workflows_service_1.SecurityWorkflowsService,
|
|
50
|
+
security_jwt_guard_1.SecurityJwtGuard,
|
|
51
|
+
security_admin_guard_1.SecurityAdminGuard,
|
|
52
|
+
notifierProvider,
|
|
53
|
+
],
|
|
54
|
+
exports: [security_workflows_service_1.SecurityWorkflowsService],
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
exports.SecurityWorkflowsModule = SecurityWorkflowsModule;
|
|
59
|
+
exports.SecurityWorkflowsModule = SecurityWorkflowsModule = SecurityWorkflowsModule_1 = __decorate([
|
|
60
|
+
(0, common_1.Module)({})
|
|
61
|
+
], SecurityWorkflowsModule);
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Repository } from "typeorm";
|
|
2
|
+
import { AppUserEntity } from "./entities/app-user.entity";
|
|
3
|
+
import { SecurityRoleEntity } from "./entities/security-role.entity";
|
|
4
|
+
import { SecurityUserEntity } from "./entities/security-user.entity";
|
|
5
|
+
import { SecurityUserRoleEntity } from "./entities/security-user-role.entity";
|
|
6
|
+
import { SecurityWorkflowNotifier } from "./contracts";
|
|
7
|
+
export declare class SecurityWorkflowsService {
|
|
8
|
+
private readonly appUsersRepo;
|
|
9
|
+
private readonly securityUsersRepo;
|
|
10
|
+
private readonly rolesRepo;
|
|
11
|
+
private readonly userRolesRepo;
|
|
12
|
+
private readonly notifier;
|
|
13
|
+
constructor(appUsersRepo: Repository<AppUserEntity>, securityUsersRepo: Repository<SecurityUserEntity>, rolesRepo: Repository<SecurityRoleEntity>, userRolesRepo: Repository<SecurityUserRoleEntity>, notifier: SecurityWorkflowNotifier);
|
|
14
|
+
markEmailVerifiedAndNotifyAdmins(userId: string): Promise<{
|
|
15
|
+
success: true;
|
|
16
|
+
notified: false;
|
|
17
|
+
adminEmails: string[];
|
|
18
|
+
} | {
|
|
19
|
+
success: true;
|
|
20
|
+
notified: true;
|
|
21
|
+
adminEmails: string[];
|
|
22
|
+
}>;
|
|
23
|
+
setAdminApprovalAndNotifyUser(userId: string, approved: boolean): Promise<{
|
|
24
|
+
success: true;
|
|
25
|
+
notified: false;
|
|
26
|
+
} | {
|
|
27
|
+
success: true;
|
|
28
|
+
notified: true;
|
|
29
|
+
}>;
|
|
30
|
+
listAdminEmails(): Promise<string[]>;
|
|
31
|
+
listRoles(): Promise<{
|
|
32
|
+
role: string;
|
|
33
|
+
description: string | null;
|
|
34
|
+
isSystem: boolean;
|
|
35
|
+
}[]>;
|
|
36
|
+
createRole(roleName: string, description?: string | null): Promise<{
|
|
37
|
+
role: string;
|
|
38
|
+
description: string | null;
|
|
39
|
+
isSystem: boolean;
|
|
40
|
+
}[]>;
|
|
41
|
+
removeRole(roleName: string): Promise<{
|
|
42
|
+
success: false;
|
|
43
|
+
} | {
|
|
44
|
+
success: true;
|
|
45
|
+
}>;
|
|
46
|
+
getUserRoles(userId: string): Promise<{
|
|
47
|
+
userId: string;
|
|
48
|
+
roles: string[];
|
|
49
|
+
}>;
|
|
50
|
+
setUserRoles(userId: string, roleNames: string[]): Promise<{
|
|
51
|
+
userId: string;
|
|
52
|
+
roles: string[];
|
|
53
|
+
}>;
|
|
54
|
+
assignRoleToUser(userId: string, roleName: string): Promise<{
|
|
55
|
+
userId: string;
|
|
56
|
+
roles: string[];
|
|
57
|
+
}>;
|
|
58
|
+
removeRoleFromUser(userId: string, roleName: string): Promise<{
|
|
59
|
+
userId: string;
|
|
60
|
+
roles: string[];
|
|
61
|
+
}>;
|
|
62
|
+
setUserActive(userId: string, active: boolean): Promise<{
|
|
63
|
+
success: true;
|
|
64
|
+
userId: string;
|
|
65
|
+
active: boolean;
|
|
66
|
+
}>;
|
|
67
|
+
private assertUserExists;
|
|
68
|
+
private ensureRoles;
|
|
69
|
+
}
|