@scryan7371/sdr-security 0.1.6 → 0.1.9
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/contracts.d.ts +4 -0
- package/dist/api/migrations/1739490000000-create-app-user.js +3 -1
- package/dist/nest/entities/app-user.entity.d.ts +2 -0
- package/dist/nest/entities/app-user.entity.js +10 -0
- package/dist/nest/security-auth.controller.d.ts +0 -4
- package/dist/nest/security-auth.controller.js +0 -13
- package/dist/nest/security-auth.controller.test.js +0 -5
- package/dist/nest/security-auth.module.js +8 -1
- package/dist/nest/security-auth.service.js +6 -1
- package/package.json +15 -7
- package/src/api/contracts.ts +4 -0
- package/src/api/migrations/1739490000000-create-app-user.ts +3 -1
- package/src/nest/entities/app-user.entity.ts +6 -0
- package/src/nest/security-auth.controller.test.ts +0 -8
- package/src/nest/security-auth.controller.ts +0 -8
- package/src/nest/security-auth.module.ts +9 -2
- package/src/nest/security-auth.service.ts +6 -1
package/dist/api/contracts.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ export type UserRole = string;
|
|
|
3
3
|
export type SafeUser = {
|
|
4
4
|
id: string;
|
|
5
5
|
email: string;
|
|
6
|
+
firstName: string | null;
|
|
7
|
+
lastName: string | null;
|
|
6
8
|
phone: string | null;
|
|
7
9
|
roles: UserRole[];
|
|
8
10
|
emailVerifiedAt: string | Date | null;
|
|
@@ -27,6 +29,8 @@ export type AuthResponse = {
|
|
|
27
29
|
accessTokenExpiresIn: string;
|
|
28
30
|
refreshToken: string;
|
|
29
31
|
refreshTokenExpiresAt: string | Date;
|
|
32
|
+
userId: string;
|
|
33
|
+
roles: UserRole[];
|
|
30
34
|
user: SafeUser;
|
|
31
35
|
};
|
|
32
36
|
export type RegisterResponse = {
|
|
@@ -8,7 +8,9 @@ class CreateAppUser1739490000000 {
|
|
|
8
8
|
await queryRunner.query(`
|
|
9
9
|
CREATE TABLE IF NOT EXISTS ${userTableRef} (
|
|
10
10
|
"id" uuid PRIMARY KEY NOT NULL,
|
|
11
|
-
"email" varchar NOT NULL
|
|
11
|
+
"email" varchar NOT NULL,
|
|
12
|
+
"first_name" varchar,
|
|
13
|
+
"last_name" varchar
|
|
12
14
|
)
|
|
13
15
|
`);
|
|
14
16
|
}
|
|
@@ -14,6 +14,8 @@ const typeorm_1 = require("typeorm");
|
|
|
14
14
|
let AppUserEntity = class AppUserEntity {
|
|
15
15
|
id;
|
|
16
16
|
email;
|
|
17
|
+
firstName;
|
|
18
|
+
lastName;
|
|
17
19
|
};
|
|
18
20
|
exports.AppUserEntity = AppUserEntity;
|
|
19
21
|
__decorate([
|
|
@@ -24,6 +26,14 @@ __decorate([
|
|
|
24
26
|
(0, typeorm_1.Column)({ type: "varchar" }),
|
|
25
27
|
__metadata("design:type", String)
|
|
26
28
|
], AppUserEntity.prototype, "email", void 0);
|
|
29
|
+
__decorate([
|
|
30
|
+
(0, typeorm_1.Column)({ type: "varchar", nullable: true, name: "first_name" }),
|
|
31
|
+
__metadata("design:type", Object)
|
|
32
|
+
], AppUserEntity.prototype, "firstName", void 0);
|
|
33
|
+
__decorate([
|
|
34
|
+
(0, typeorm_1.Column)({ type: "varchar", nullable: true, name: "last_name" }),
|
|
35
|
+
__metadata("design:type", Object)
|
|
36
|
+
], AppUserEntity.prototype, "lastName", void 0);
|
|
27
37
|
exports.AppUserEntity = AppUserEntity = __decorate([
|
|
28
38
|
(0, typeorm_1.Entity)({ name: "app_user" })
|
|
29
39
|
], AppUserEntity);
|
|
@@ -78,9 +78,6 @@ let SecurityAuthController = class SecurityAuthController {
|
|
|
78
78
|
}
|
|
79
79
|
return this.authService.verifyEmailByToken(token);
|
|
80
80
|
}
|
|
81
|
-
async getMyRoles(request) {
|
|
82
|
-
return this.authService.getMyRoles(request.user.sub);
|
|
83
|
-
}
|
|
84
81
|
};
|
|
85
82
|
exports.SecurityAuthController = SecurityAuthController;
|
|
86
83
|
__decorate([
|
|
@@ -160,16 +157,6 @@ __decorate([
|
|
|
160
157
|
__metadata("design:paramtypes", [String]),
|
|
161
158
|
__metadata("design:returntype", Promise)
|
|
162
159
|
], SecurityAuthController.prototype, "verifyEmail", null);
|
|
163
|
-
__decorate([
|
|
164
|
-
(0, common_1.UseGuards)(security_jwt_guard_1.SecurityJwtGuard),
|
|
165
|
-
(0, common_1.Get)("me/roles"),
|
|
166
|
-
(0, swagger_1.ApiOperation)({ summary: "Get roles for authenticated user" }),
|
|
167
|
-
(0, swagger_1.ApiBearerAuth)(),
|
|
168
|
-
__param(0, (0, common_1.Req)()),
|
|
169
|
-
__metadata("design:type", Function),
|
|
170
|
-
__metadata("design:paramtypes", [Object]),
|
|
171
|
-
__metadata("design:returntype", Promise)
|
|
172
|
-
], SecurityAuthController.prototype, "getMyRoles", null);
|
|
173
160
|
exports.SecurityAuthController = SecurityAuthController = __decorate([
|
|
174
161
|
(0, common_1.Controller)("security/auth"),
|
|
175
162
|
(0, swagger_1.ApiTags)("security-auth"),
|
|
@@ -12,7 +12,6 @@ const makeAuthService = () => ({
|
|
|
12
12
|
requestForgotPassword: vitest_1.vi.fn(),
|
|
13
13
|
resetPassword: vitest_1.vi.fn(),
|
|
14
14
|
verifyEmailByToken: vitest_1.vi.fn(),
|
|
15
|
-
getMyRoles: vitest_1.vi.fn(),
|
|
16
15
|
});
|
|
17
16
|
(0, vitest_1.describe)("SecurityAuthController", () => {
|
|
18
17
|
let service;
|
|
@@ -80,8 +79,4 @@ const makeAuthService = () => ({
|
|
|
80
79
|
});
|
|
81
80
|
(0, vitest_1.expect)(service.verifyEmailByToken).toHaveBeenCalledWith("token-1");
|
|
82
81
|
});
|
|
83
|
-
(0, vitest_1.it)("delegates getMyRoles", async () => {
|
|
84
|
-
service.getMyRoles.mockResolvedValue({ userId: "u1", roles: ["ADMIN"] });
|
|
85
|
-
await (0, vitest_1.expect)(controller.getMyRoles({ user: { sub: "u1" } })).resolves.toEqual({ userId: "u1", roles: ["ADMIN"] });
|
|
86
|
-
});
|
|
87
82
|
});
|
|
@@ -60,11 +60,18 @@ let SecurityAuthModule = SecurityAuthModule_1 = class SecurityAuthModule {
|
|
|
60
60
|
security_admin_guard_1.SecurityAdminGuard,
|
|
61
61
|
notifierProvider,
|
|
62
62
|
],
|
|
63
|
-
exports: [
|
|
63
|
+
exports: [
|
|
64
|
+
security_auth_constants_1.SECURITY_AUTH_OPTIONS,
|
|
65
|
+
security_auth_service_1.SecurityAuthService,
|
|
66
|
+
security_workflows_service_1.SecurityWorkflowsService,
|
|
67
|
+
security_jwt_guard_1.SecurityJwtGuard,
|
|
68
|
+
security_admin_guard_1.SecurityAdminGuard,
|
|
69
|
+
],
|
|
64
70
|
};
|
|
65
71
|
}
|
|
66
72
|
};
|
|
67
73
|
exports.SecurityAuthModule = SecurityAuthModule;
|
|
68
74
|
exports.SecurityAuthModule = SecurityAuthModule = SecurityAuthModule_1 = __decorate([
|
|
75
|
+
(0, common_1.Global)(),
|
|
69
76
|
(0, common_1.Module)({})
|
|
70
77
|
], SecurityAuthModule);
|
|
@@ -229,12 +229,15 @@ let SecurityAuthService = class SecurityAuthService {
|
|
|
229
229
|
expiresAt: refreshTokenExpiresAt,
|
|
230
230
|
revokedAt: null,
|
|
231
231
|
}));
|
|
232
|
+
const user = await this.toSafeUser(appUser, securityUser);
|
|
232
233
|
return {
|
|
233
234
|
accessToken,
|
|
234
235
|
accessTokenExpiresIn,
|
|
235
236
|
refreshToken,
|
|
236
237
|
refreshTokenExpiresAt,
|
|
237
|
-
|
|
238
|
+
userId: appUser.id,
|
|
239
|
+
roles,
|
|
240
|
+
user,
|
|
238
241
|
};
|
|
239
242
|
}
|
|
240
243
|
async createEmailVerificationToken(userId) {
|
|
@@ -273,6 +276,8 @@ let SecurityAuthService = class SecurityAuthService {
|
|
|
273
276
|
return {
|
|
274
277
|
id: appUser.id,
|
|
275
278
|
email: appUser.email,
|
|
279
|
+
firstName: appUser.firstName ?? null,
|
|
280
|
+
lastName: appUser.lastName ?? null,
|
|
276
281
|
phone: null,
|
|
277
282
|
roles: await this.getUserRoleKeys(appUser.id),
|
|
278
283
|
emailVerifiedAt: securityUser.emailVerifiedAt,
|
package/package.json
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scryan7371/sdr-security",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "Reusable auth/security capability for API and app clients.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"exports": {
|
|
7
|
-
".":
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"require": "./dist/index.js",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
},
|
|
8
12
|
"./nest": {
|
|
9
13
|
"types": "./dist/nest/index.d.ts",
|
|
14
|
+
"require": "./dist/nest/index.js",
|
|
10
15
|
"default": "./dist/nest/index.js"
|
|
11
|
-
}
|
|
16
|
+
},
|
|
17
|
+
"./package.json": "./package.json"
|
|
12
18
|
},
|
|
13
19
|
"types": "dist/index.d.ts",
|
|
14
20
|
"publishConfig": {
|
|
@@ -23,16 +29,18 @@
|
|
|
23
29
|
"build": "tsc -p tsconfig.json",
|
|
24
30
|
"clean": "rm -rf dist",
|
|
25
31
|
"prepublishOnly": "npm run clean && npm run build",
|
|
26
|
-
"lint": "eslint \"src/**/*.ts\"",
|
|
27
|
-
"
|
|
32
|
+
"lint": "eslint \"src/**/*.ts\" --max-warnings=0",
|
|
33
|
+
"format": "prettier --write \"src/**/*.ts\" \"README.md\"",
|
|
28
34
|
"test": "vitest run",
|
|
29
35
|
"test:db": "vitest run --config vitest.db.config.ts",
|
|
30
|
-
"
|
|
36
|
+
"coverage": "vitest run --coverage",
|
|
31
37
|
"test:db:keep": "SECURITY_TEST_KEEP_SCHEMA=true SECURITY_TEST_SCHEMA=sdr_security_it_debug npm run test:db",
|
|
32
38
|
"test:db:teardown": "SECURITY_TEST_SCHEMA=sdr_security_it_debug npm run test:db",
|
|
33
39
|
"release:patch": "bash ./scripts/release.sh patch",
|
|
34
40
|
"release:minor": "bash ./scripts/release.sh minor",
|
|
35
|
-
"release:major": "bash ./scripts/release.sh major"
|
|
41
|
+
"release:major": "bash ./scripts/release.sh major",
|
|
42
|
+
"ci:prepush": "npm run lint && npm run test",
|
|
43
|
+
"prepush": "npm run ci:prepush"
|
|
36
44
|
},
|
|
37
45
|
"dependencies": {
|
|
38
46
|
"@babel/runtime": "7.28.6",
|
package/src/api/contracts.ts
CHANGED
|
@@ -4,6 +4,8 @@ export type UserRole = string;
|
|
|
4
4
|
export type SafeUser = {
|
|
5
5
|
id: string;
|
|
6
6
|
email: string;
|
|
7
|
+
firstName: string | null;
|
|
8
|
+
lastName: string | null;
|
|
7
9
|
phone: string | null;
|
|
8
10
|
roles: UserRole[];
|
|
9
11
|
emailVerifiedAt: string | Date | null;
|
|
@@ -32,6 +34,8 @@ export type AuthResponse = {
|
|
|
32
34
|
accessTokenExpiresIn: string;
|
|
33
35
|
refreshToken: string;
|
|
34
36
|
refreshTokenExpiresAt: string | Date;
|
|
37
|
+
userId: string;
|
|
38
|
+
roles: UserRole[];
|
|
35
39
|
user: SafeUser;
|
|
36
40
|
};
|
|
37
41
|
|
|
@@ -9,7 +9,9 @@ export class CreateAppUser1739490000000 {
|
|
|
9
9
|
await queryRunner.query(`
|
|
10
10
|
CREATE TABLE IF NOT EXISTS ${userTableRef} (
|
|
11
11
|
"id" uuid PRIMARY KEY NOT NULL,
|
|
12
|
-
"email" varchar NOT NULL
|
|
12
|
+
"email" varchar NOT NULL,
|
|
13
|
+
"first_name" varchar,
|
|
14
|
+
"last_name" varchar
|
|
13
15
|
)
|
|
14
16
|
`);
|
|
15
17
|
}
|
|
@@ -7,4 +7,10 @@ export class AppUserEntity {
|
|
|
7
7
|
|
|
8
8
|
@Column({ type: "varchar" })
|
|
9
9
|
email!: string;
|
|
10
|
+
|
|
11
|
+
@Column({ type: "varchar", nullable: true, name: "first_name" })
|
|
12
|
+
firstName!: string | null;
|
|
13
|
+
|
|
14
|
+
@Column({ type: "varchar", nullable: true, name: "last_name" })
|
|
15
|
+
lastName!: string | null;
|
|
10
16
|
}
|
|
@@ -11,7 +11,6 @@ const makeAuthService = () => ({
|
|
|
11
11
|
requestForgotPassword: vi.fn(),
|
|
12
12
|
resetPassword: vi.fn(),
|
|
13
13
|
verifyEmailByToken: vi.fn(),
|
|
14
|
-
getMyRoles: vi.fn(),
|
|
15
14
|
});
|
|
16
15
|
|
|
17
16
|
describe("SecurityAuthController", () => {
|
|
@@ -118,11 +117,4 @@ describe("SecurityAuthController", () => {
|
|
|
118
117
|
});
|
|
119
118
|
expect(service.verifyEmailByToken).toHaveBeenCalledWith("token-1");
|
|
120
119
|
});
|
|
121
|
-
|
|
122
|
-
it("delegates getMyRoles", async () => {
|
|
123
|
-
service.getMyRoles.mockResolvedValue({ userId: "u1", roles: ["ADMIN"] });
|
|
124
|
-
await expect(
|
|
125
|
-
controller.getMyRoles({ user: { sub: "u1" } }),
|
|
126
|
-
).resolves.toEqual({ userId: "u1", roles: ["ADMIN"] });
|
|
127
|
-
});
|
|
128
120
|
});
|
|
@@ -137,12 +137,4 @@ export class SecurityAuthController {
|
|
|
137
137
|
}
|
|
138
138
|
return this.authService.verifyEmailByToken(token);
|
|
139
139
|
}
|
|
140
|
-
|
|
141
|
-
@UseGuards(SecurityJwtGuard)
|
|
142
|
-
@Get("me/roles")
|
|
143
|
-
@ApiOperation({ summary: "Get roles for authenticated user" })
|
|
144
|
-
@ApiBearerAuth()
|
|
145
|
-
async getMyRoles(@Req() request: AuthedRequest) {
|
|
146
|
-
return this.authService.getMyRoles(request.user.sub);
|
|
147
|
-
}
|
|
148
140
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DynamicModule, Module, Provider } from "@nestjs/common";
|
|
1
|
+
import { DynamicModule, Global, Module, Provider } from "@nestjs/common";
|
|
2
2
|
import { TypeOrmModule } from "@nestjs/typeorm";
|
|
3
3
|
import { SecurityWorkflowNotifier } from "./contracts";
|
|
4
4
|
import { AppUserEntity } from "./entities/app-user.entity";
|
|
@@ -24,6 +24,7 @@ const noopNotifier: SecurityWorkflowNotifier = {
|
|
|
24
24
|
sendUserAccountApproved: async () => undefined,
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
+
@Global()
|
|
27
28
|
@Module({})
|
|
28
29
|
export class SecurityAuthModule {
|
|
29
30
|
static forRoot(options: {
|
|
@@ -59,7 +60,13 @@ export class SecurityAuthModule {
|
|
|
59
60
|
SecurityAdminGuard,
|
|
60
61
|
notifierProvider,
|
|
61
62
|
],
|
|
62
|
-
exports: [
|
|
63
|
+
exports: [
|
|
64
|
+
SECURITY_AUTH_OPTIONS,
|
|
65
|
+
SecurityAuthService,
|
|
66
|
+
SecurityWorkflowsService,
|
|
67
|
+
SecurityJwtGuard,
|
|
68
|
+
SecurityAdminGuard,
|
|
69
|
+
],
|
|
63
70
|
};
|
|
64
71
|
}
|
|
65
72
|
}
|
|
@@ -294,12 +294,15 @@ export class SecurityAuthService {
|
|
|
294
294
|
}),
|
|
295
295
|
);
|
|
296
296
|
|
|
297
|
+
const user = await this.toSafeUser(appUser, securityUser);
|
|
297
298
|
return {
|
|
298
299
|
accessToken,
|
|
299
300
|
accessTokenExpiresIn,
|
|
300
301
|
refreshToken,
|
|
301
302
|
refreshTokenExpiresAt,
|
|
302
|
-
|
|
303
|
+
userId: appUser.id,
|
|
304
|
+
roles,
|
|
305
|
+
user,
|
|
303
306
|
};
|
|
304
307
|
}
|
|
305
308
|
|
|
@@ -348,6 +351,8 @@ export class SecurityAuthService {
|
|
|
348
351
|
return {
|
|
349
352
|
id: appUser.id,
|
|
350
353
|
email: appUser.email,
|
|
354
|
+
firstName: appUser.firstName ?? null,
|
|
355
|
+
lastName: appUser.lastName ?? null,
|
|
351
356
|
phone: null,
|
|
352
357
|
roles: await this.getUserRoleKeys(appUser.id),
|
|
353
358
|
emailVerifiedAt: securityUser.emailVerifiedAt,
|