@lenne.tech/nest-server 11.6.2 → 11.7.1
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/config.env.js +19 -12
- package/dist/config.env.js.map +1 -1
- package/dist/core/common/helpers/filter.helper.d.ts +9 -9
- package/dist/core/common/helpers/filter.helper.js +2 -4
- package/dist/core/common/helpers/filter.helper.js.map +1 -1
- package/dist/core/common/helpers/gridfs.helper.js +3 -3
- package/dist/core/common/helpers/gridfs.helper.js.map +1 -1
- package/dist/core/common/interfaces/server-options.interface.d.ts +21 -3
- package/dist/core/common/services/crud.service.d.ts +16 -16
- package/dist/core/common/services/crud.service.js +1 -1
- package/dist/core/common/services/crud.service.js.map +1 -1
- package/dist/core/modules/auth/core-auth.controller.d.ts +1 -0
- package/dist/core/modules/auth/core-auth.controller.js +28 -2
- package/dist/core/modules/auth/core-auth.controller.js.map +1 -1
- package/dist/core/modules/auth/core-auth.module.js +14 -1
- package/dist/core/modules/auth/core-auth.module.js.map +1 -1
- package/dist/core/modules/auth/core-auth.resolver.d.ts +1 -0
- package/dist/core/modules/auth/core-auth.resolver.js +20 -2
- package/dist/core/modules/auth/core-auth.resolver.js.map +1 -1
- package/dist/core/modules/auth/exceptions/legacy-auth-disabled.exception.d.ts +4 -0
- package/dist/core/modules/auth/exceptions/legacy-auth-disabled.exception.js +17 -0
- package/dist/core/modules/auth/exceptions/legacy-auth-disabled.exception.js.map +1 -0
- package/dist/core/modules/auth/guards/legacy-auth-rate-limit.guard.d.ts +9 -0
- package/dist/core/modules/auth/guards/legacy-auth-rate-limit.guard.js +74 -0
- package/dist/core/modules/auth/guards/legacy-auth-rate-limit.guard.js.map +1 -0
- package/dist/core/modules/auth/interfaces/auth-provider.interface.d.ts +7 -0
- package/dist/core/modules/auth/interfaces/auth-provider.interface.js +5 -0
- package/dist/core/modules/auth/interfaces/auth-provider.interface.js.map +1 -0
- package/dist/core/modules/auth/interfaces/core-auth-user.interface.d.ts +1 -0
- package/dist/core/modules/auth/services/core-auth.service.d.ts +10 -1
- package/dist/core/modules/auth/services/core-auth.service.js +141 -9
- package/dist/core/modules/auth/services/core-auth.service.js.map +1 -1
- package/dist/core/modules/auth/services/legacy-auth-rate-limiter.service.d.ts +31 -0
- package/dist/core/modules/auth/services/legacy-auth-rate-limiter.service.js +153 -0
- package/dist/core/modules/auth/services/legacy-auth-rate-limiter.service.js.map +1 -0
- package/dist/core/modules/better-auth/better-auth-migration-status.model.d.ts +10 -0
- package/dist/core/modules/better-auth/better-auth-migration-status.model.js +57 -0
- package/dist/core/modules/better-auth/better-auth-migration-status.model.js.map +1 -0
- package/dist/core/modules/better-auth/better-auth-models.d.ts +0 -1
- package/dist/core/modules/better-auth/better-auth-models.js +0 -4
- package/dist/core/modules/better-auth/better-auth-models.js.map +1 -1
- package/dist/core/modules/better-auth/better-auth-user.mapper.d.ts +33 -0
- package/dist/core/modules/better-auth/better-auth-user.mapper.js +443 -0
- package/dist/core/modules/better-auth/better-auth-user.mapper.js.map +1 -1
- package/dist/core/modules/better-auth/better-auth.config.js +3 -0
- package/dist/core/modules/better-auth/better-auth.config.js.map +1 -1
- package/dist/core/modules/better-auth/better-auth.module.d.ts +10 -2
- package/dist/core/modules/better-auth/better-auth.module.js +40 -52
- package/dist/core/modules/better-auth/better-auth.module.js.map +1 -1
- package/dist/core/modules/better-auth/better-auth.resolver.d.ts +8 -12
- package/dist/core/modules/better-auth/better-auth.resolver.js +33 -351
- package/dist/core/modules/better-auth/better-auth.resolver.js.map +1 -1
- package/dist/core/modules/better-auth/better-auth.service.d.ts +0 -1
- package/dist/core/modules/better-auth/better-auth.service.js +0 -3
- package/dist/core/modules/better-auth/better-auth.service.js.map +1 -1
- package/dist/core/modules/better-auth/better-auth.types.d.ts +9 -8
- package/dist/core/modules/better-auth/better-auth.types.js +14 -3
- package/dist/core/modules/better-auth/better-auth.types.js.map +1 -1
- package/dist/core/modules/better-auth/core-better-auth.controller.d.ts +67 -0
- package/dist/core/modules/better-auth/core-better-auth.controller.js +504 -0
- package/dist/core/modules/better-auth/core-better-auth.controller.js.map +1 -0
- package/dist/core/modules/better-auth/core-better-auth.resolver.d.ts +61 -0
- package/dist/core/modules/better-auth/core-better-auth.resolver.js +552 -0
- package/dist/core/modules/better-auth/core-better-auth.resolver.js.map +1 -0
- package/dist/core/modules/better-auth/index.d.ts +3 -0
- package/dist/core/modules/better-auth/index.js +3 -0
- package/dist/core/modules/better-auth/index.js.map +1 -1
- package/dist/core/modules/user/core-user.service.d.ts +7 -1
- package/dist/core/modules/user/core-user.service.js +57 -3
- package/dist/core/modules/user/core-user.service.js.map +1 -1
- package/dist/core/modules/user/interfaces/core-user-service-options.interface.d.ts +4 -0
- package/dist/core/modules/user/interfaces/core-user-service-options.interface.js +3 -0
- package/dist/core/modules/user/interfaces/core-user-service-options.interface.js.map +1 -0
- package/dist/core.module.d.ts +3 -0
- package/dist/core.module.js +132 -54
- package/dist/core.module.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/server/modules/auth/auth.resolver.js +2 -0
- package/dist/server/modules/auth/auth.resolver.js.map +1 -1
- package/dist/server/modules/better-auth/better-auth.controller.d.ts +10 -0
- package/dist/server/modules/better-auth/better-auth.controller.js +36 -0
- package/dist/server/modules/better-auth/better-auth.controller.js.map +1 -0
- package/dist/server/modules/better-auth/better-auth.module.d.ts +9 -0
- package/dist/server/modules/better-auth/better-auth.module.js +44 -0
- package/dist/server/modules/better-auth/better-auth.module.js.map +1 -0
- package/dist/server/modules/better-auth/better-auth.resolver.d.ts +47 -0
- package/dist/server/modules/better-auth/better-auth.resolver.js +234 -0
- package/dist/server/modules/better-auth/better-auth.resolver.js.map +1 -0
- package/dist/server/modules/file/file-info.model.d.ts +71 -3
- package/dist/server/modules/user/user.model.d.ts +169 -3
- package/dist/server/modules/user/user.service.d.ts +3 -1
- package/dist/server/modules/user/user.service.js +7 -3
- package/dist/server/modules/user/user.service.js.map +1 -1
- package/dist/server/server.module.js +6 -1
- package/dist/server/server.module.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +20 -29
- package/src/config.env.ts +34 -13
- package/src/core/common/helpers/filter.helper.ts +15 -17
- package/src/core/common/helpers/gridfs.helper.ts +5 -5
- package/src/core/common/interfaces/server-options.interface.ts +222 -14
- package/src/core/common/services/crud.service.ts +22 -22
- package/src/core/modules/auth/core-auth.controller.ts +93 -5
- package/src/core/modules/auth/core-auth.module.ts +15 -1
- package/src/core/modules/auth/core-auth.resolver.ts +70 -2
- package/src/core/modules/auth/exceptions/legacy-auth-disabled.exception.ts +35 -0
- package/src/core/modules/auth/guards/legacy-auth-rate-limit.guard.ts +109 -0
- package/src/core/modules/auth/interfaces/auth-provider.interface.ts +86 -0
- package/src/core/modules/auth/interfaces/core-auth-user.interface.ts +6 -0
- package/src/core/modules/auth/services/core-auth.service.ts +245 -6
- package/src/core/modules/auth/services/legacy-auth-rate-limiter.service.ts +283 -0
- package/src/core/modules/better-auth/INTEGRATION-CHECKLIST.md +254 -0
- package/src/core/modules/better-auth/README.md +698 -54
- package/src/core/modules/better-auth/better-auth-migration-status.model.ts +73 -0
- package/src/core/modules/better-auth/better-auth-models.ts +0 -3
- package/src/core/modules/better-auth/better-auth-user.mapper.ts +805 -0
- package/src/core/modules/better-auth/better-auth.config.ts +5 -0
- package/src/core/modules/better-auth/better-auth.module.ts +107 -66
- package/src/core/modules/better-auth/better-auth.resolver.ts +88 -553
- package/src/core/modules/better-auth/better-auth.service.ts +0 -9
- package/src/core/modules/better-auth/better-auth.types.ts +25 -10
- package/src/core/modules/better-auth/core-better-auth.controller.ts +646 -0
- package/src/core/modules/better-auth/core-better-auth.resolver.ts +730 -0
- package/src/core/modules/better-auth/index.ts +9 -1
- package/src/core/modules/user/core-user.service.ts +131 -4
- package/src/core/modules/user/interfaces/core-user-service-options.interface.ts +15 -0
- package/src/core.module.ts +257 -74
- package/src/index.ts +5 -0
- package/src/server/modules/auth/auth.resolver.ts +8 -0
- package/src/server/modules/better-auth/better-auth.controller.ts +41 -0
- package/src/server/modules/better-auth/better-auth.module.ts +88 -0
- package/src/server/modules/better-auth/better-auth.resolver.ts +210 -0
- package/src/server/modules/user/user.service.ts +4 -2
- package/src/server/server.module.ts +10 -1
|
@@ -2,10 +2,10 @@ import { NotFoundException } from '@nestjs/common';
|
|
|
2
2
|
import {
|
|
3
3
|
AggregateOptions,
|
|
4
4
|
Document,
|
|
5
|
-
FilterQuery,
|
|
6
5
|
Model as MongooseModel,
|
|
7
6
|
PipelineStage,
|
|
8
7
|
Query,
|
|
8
|
+
QueryFilter,
|
|
9
9
|
QueryOptions,
|
|
10
10
|
} from 'mongoose';
|
|
11
11
|
|
|
@@ -147,7 +147,7 @@ export abstract class CrudService<
|
|
|
147
147
|
* Get items via filter
|
|
148
148
|
*/
|
|
149
149
|
async find(
|
|
150
|
-
filter?: FilterArgs | { filterQuery?:
|
|
150
|
+
filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
|
|
151
151
|
serviceOptions?: ServiceOptions,
|
|
152
152
|
): Promise<Model[]> {
|
|
153
153
|
// If filter is not instance of FilterArgs a simple form with filterQuery and queryOptions is set
|
|
@@ -191,7 +191,7 @@ export abstract class CrudService<
|
|
|
191
191
|
* Warning: Disables the handling of rights and restrictions!
|
|
192
192
|
*/
|
|
193
193
|
async findForce(
|
|
194
|
-
filter?: FilterArgs | { filterQuery?:
|
|
194
|
+
filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
|
|
195
195
|
serviceOptions: ServiceOptions = {},
|
|
196
196
|
): Promise<Model[]> {
|
|
197
197
|
serviceOptions = serviceOptions || {};
|
|
@@ -204,7 +204,7 @@ export abstract class CrudService<
|
|
|
204
204
|
* Warning: Disables the handling of rights and restrictions! The raw data may contain secrets (such as passwords).
|
|
205
205
|
*/
|
|
206
206
|
async findRaw(
|
|
207
|
-
filter?: FilterArgs | { filterQuery?:
|
|
207
|
+
filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
|
|
208
208
|
serviceOptions: ServiceOptions = {},
|
|
209
209
|
): Promise<Model[]> {
|
|
210
210
|
serviceOptions = serviceOptions || {};
|
|
@@ -216,7 +216,7 @@ export abstract class CrudService<
|
|
|
216
216
|
* Get items and total count via filter
|
|
217
217
|
*/
|
|
218
218
|
async findAndCount(
|
|
219
|
-
filter?: FilterArgs | { filterQuery?:
|
|
219
|
+
filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
|
|
220
220
|
serviceOptions?: ServiceOptions,
|
|
221
221
|
): Promise<{ items: Model[]; totalCount: number }> {
|
|
222
222
|
// If filter is not instance of FilterArgs a simple form with filterQuery and queryOptions is set
|
|
@@ -280,10 +280,10 @@ export abstract class CrudService<
|
|
|
280
280
|
|
|
281
281
|
// Find and process db items
|
|
282
282
|
const collation = serviceOptions?.collation || ConfigService.get('mongoose.collation');
|
|
283
|
-
const dbResult
|
|
284
|
-
|
|
283
|
+
const dbResult =
|
|
284
|
+
(await this.mainDbModel.aggregate(aggregation, collation ? { collation } : {}).exec())[0] || {};
|
|
285
285
|
dbResult.totalCount = dbResult.totalCount?.[0]?.total || 0;
|
|
286
|
-
dbResult.items = dbResult.items?.map(item => this.mainDbModel.hydrate(item)) || [];
|
|
286
|
+
dbResult.items = dbResult.items?.map((item) => this.mainDbModel.hydrate(item)) || [];
|
|
287
287
|
return dbResult;
|
|
288
288
|
},
|
|
289
289
|
{ input: filter, outputPath: 'items', serviceOptions },
|
|
@@ -295,7 +295,7 @@ export abstract class CrudService<
|
|
|
295
295
|
* Warning: Disables the handling of rights and restrictions!
|
|
296
296
|
*/
|
|
297
297
|
async findAndCountForce(
|
|
298
|
-
filter?: FilterArgs | { filterQuery?:
|
|
298
|
+
filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
|
|
299
299
|
serviceOptions: ServiceOptions = {},
|
|
300
300
|
): Promise<{ items: Model[]; totalCount: number }> {
|
|
301
301
|
serviceOptions.raw = true;
|
|
@@ -307,7 +307,7 @@ export abstract class CrudService<
|
|
|
307
307
|
* Warning: Disables the handling of rights and restrictions! The raw data may contain secrets (such as passwords).
|
|
308
308
|
*/
|
|
309
309
|
async findAndCountRaw(
|
|
310
|
-
filter?: FilterArgs | { filterQuery?:
|
|
310
|
+
filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
|
|
311
311
|
serviceOptions: ServiceOptions = {},
|
|
312
312
|
): Promise<{ items: Model[]; totalCount: number }> {
|
|
313
313
|
serviceOptions = serviceOptions || {};
|
|
@@ -319,7 +319,7 @@ export abstract class CrudService<
|
|
|
319
319
|
* Find and update
|
|
320
320
|
*/
|
|
321
321
|
async findAndUpdate(
|
|
322
|
-
filter: FilterArgs | { filterQuery?:
|
|
322
|
+
filter: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
|
|
323
323
|
update: PlainObject<UpdateInput>,
|
|
324
324
|
serviceOptions?: ServiceOptions,
|
|
325
325
|
): Promise<Model[]> {
|
|
@@ -348,7 +348,7 @@ export abstract class CrudService<
|
|
|
348
348
|
* Warning: Disables the handling of rights and restrictions!
|
|
349
349
|
*/
|
|
350
350
|
async findAndUpdateForce(
|
|
351
|
-
filter: FilterArgs | { filterQuery?:
|
|
351
|
+
filter: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
|
|
352
352
|
update: PlainObject<UpdateInput>,
|
|
353
353
|
serviceOptions: ServiceOptions = {},
|
|
354
354
|
): Promise<Model[]> {
|
|
@@ -362,7 +362,7 @@ export abstract class CrudService<
|
|
|
362
362
|
* Warning: Disables the handling of rights and restrictions! The raw data may contain secrets (such as passwords).
|
|
363
363
|
*/
|
|
364
364
|
async findAndUpdateRaw(
|
|
365
|
-
filter: FilterArgs | { filterQuery?:
|
|
365
|
+
filter: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
|
|
366
366
|
update: PlainObject<UpdateInput>,
|
|
367
367
|
serviceOptions: ServiceOptions = {},
|
|
368
368
|
): Promise<Model[]> {
|
|
@@ -375,7 +375,7 @@ export abstract class CrudService<
|
|
|
375
375
|
* Find one item via filter
|
|
376
376
|
*/
|
|
377
377
|
async findOne(
|
|
378
|
-
filter?: FilterArgs | { filterQuery?:
|
|
378
|
+
filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions },
|
|
379
379
|
serviceOptions?: ServiceOptions,
|
|
380
380
|
): Promise<Model> {
|
|
381
381
|
// If filter is not instance of FilterArgs a simple form with filterQuery and queryOptions is set
|
|
@@ -414,7 +414,7 @@ export abstract class CrudService<
|
|
|
414
414
|
* Warning: Disables the handling of rights and restrictions!
|
|
415
415
|
*/
|
|
416
416
|
async findOneForce(
|
|
417
|
-
filter?: FilterArgs | { filterQuery?:
|
|
417
|
+
filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
|
|
418
418
|
serviceOptions: ServiceOptions = {},
|
|
419
419
|
): Promise<Model> {
|
|
420
420
|
serviceOptions = serviceOptions || {};
|
|
@@ -427,7 +427,7 @@ export abstract class CrudService<
|
|
|
427
427
|
* Warning: Disables the handling of rights and restrictions! The raw data may contain secrets (such as passwords).
|
|
428
428
|
*/
|
|
429
429
|
async findOneRaw(
|
|
430
|
-
filter?: FilterArgs | { filterQuery?:
|
|
430
|
+
filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
|
|
431
431
|
serviceOptions: ServiceOptions = {},
|
|
432
432
|
): Promise<Model> {
|
|
433
433
|
serviceOptions = serviceOptions || {};
|
|
@@ -452,7 +452,7 @@ export abstract class CrudService<
|
|
|
452
452
|
* CRUD alias for find
|
|
453
453
|
*/
|
|
454
454
|
async read(
|
|
455
|
-
filter: FilterArgs | { filterQuery?:
|
|
455
|
+
filter: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions },
|
|
456
456
|
serviceOptions?: ServiceOptions,
|
|
457
457
|
): Promise<Model[]>;
|
|
458
458
|
|
|
@@ -460,7 +460,7 @@ export abstract class CrudService<
|
|
|
460
460
|
* CRUD alias for get or find
|
|
461
461
|
*/
|
|
462
462
|
async read(
|
|
463
|
-
input: FilterArgs | string | { filterQuery?:
|
|
463
|
+
input: FilterArgs | string | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions },
|
|
464
464
|
serviceOptions?: ServiceOptions,
|
|
465
465
|
): Promise<Model | Model[]> {
|
|
466
466
|
if (typeof input === 'string') {
|
|
@@ -481,7 +481,7 @@ export abstract class CrudService<
|
|
|
481
481
|
* Warning: Disables the handling of rights and restrictions!
|
|
482
482
|
*/
|
|
483
483
|
async readForce(
|
|
484
|
-
filter: FilterArgs | { filterQuery?:
|
|
484
|
+
filter: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions },
|
|
485
485
|
serviceOptions?: ServiceOptions,
|
|
486
486
|
): Promise<Model[]>;
|
|
487
487
|
|
|
@@ -490,7 +490,7 @@ export abstract class CrudService<
|
|
|
490
490
|
* Warning: Disables the handling of rights and restrictions!
|
|
491
491
|
*/
|
|
492
492
|
async readForce(
|
|
493
|
-
input: FilterArgs | string | { filterQuery?:
|
|
493
|
+
input: FilterArgs | string | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions },
|
|
494
494
|
serviceOptions?: ServiceOptions,
|
|
495
495
|
): Promise<Model | Model[]> {
|
|
496
496
|
if (typeof input === 'string') {
|
|
@@ -511,7 +511,7 @@ export abstract class CrudService<
|
|
|
511
511
|
* Warning: Disables the handling of rights and restrictions! The raw data may contain secrets (such as passwords).
|
|
512
512
|
*/
|
|
513
513
|
async readRaw(
|
|
514
|
-
filter: FilterArgs | { filterQuery?:
|
|
514
|
+
filter: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions },
|
|
515
515
|
serviceOptions?: ServiceOptions,
|
|
516
516
|
): Promise<Model[]>;
|
|
517
517
|
|
|
@@ -520,7 +520,7 @@ export abstract class CrudService<
|
|
|
520
520
|
* Warning: Disables the handling of rights and restrictions! The raw data may contain secrets (such as passwords).
|
|
521
521
|
*/
|
|
522
522
|
async readRaw(
|
|
523
|
-
input: FilterArgs | string | { filterQuery?:
|
|
523
|
+
input: FilterArgs | string | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions },
|
|
524
524
|
serviceOptions?: ServiceOptions,
|
|
525
525
|
): Promise<Model | Model[]> {
|
|
526
526
|
if (typeof input === 'string') {
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { Body, Controller, Get, ParseBoolPipe, Post, Query, Res, UseGuards } from '@nestjs/common';
|
|
2
2
|
import {
|
|
3
|
-
ApiBody,
|
|
3
|
+
ApiBody,
|
|
4
|
+
ApiCreatedResponse,
|
|
5
|
+
ApiGoneResponse,
|
|
4
6
|
ApiOkResponse,
|
|
5
7
|
ApiOperation,
|
|
6
8
|
ApiQuery,
|
|
9
|
+
ApiTooManyRequestsResponse,
|
|
7
10
|
} from '@nestjs/swagger';
|
|
8
11
|
import { Response as ResponseType } from 'express';
|
|
9
12
|
|
|
@@ -14,13 +17,38 @@ import { RoleEnum } from '../../common/enums/role.enum';
|
|
|
14
17
|
import { ConfigService } from '../../common/services/config.service';
|
|
15
18
|
import { AuthGuardStrategy } from './auth-guard-strategy.enum';
|
|
16
19
|
import { CoreAuthModel } from './core-auth.model';
|
|
20
|
+
import { LegacyAuthDisabledException } from './exceptions/legacy-auth-disabled.exception';
|
|
17
21
|
import { AuthGuard } from './guards/auth.guard';
|
|
22
|
+
import { LegacyAuthRateLimitGuard } from './guards/legacy-auth-rate-limit.guard';
|
|
18
23
|
import { CoreAuthSignInInput } from './inputs/core-auth-sign-in.input';
|
|
19
24
|
import { CoreAuthSignUpInput } from './inputs/core-auth-sign-up.input';
|
|
20
25
|
import { ICoreAuthUser } from './interfaces/core-auth-user.interface';
|
|
21
26
|
import { CoreAuthService } from './services/core-auth.service';
|
|
22
27
|
import { Tokens } from './tokens.decorator';
|
|
23
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Authentication controller for REST endpoints
|
|
31
|
+
*
|
|
32
|
+
* This controller provides Legacy Auth endpoints via REST.
|
|
33
|
+
* In a future version, BetterAuth (IAM) will become the default.
|
|
34
|
+
*
|
|
35
|
+
* ## Disabling Legacy Endpoints
|
|
36
|
+
*
|
|
37
|
+
* After all users have migrated to BetterAuth (IAM), these endpoints
|
|
38
|
+
* can be disabled via configuration:
|
|
39
|
+
*
|
|
40
|
+
* ```typescript
|
|
41
|
+
* auth: {
|
|
42
|
+
* legacyEndpoints: {
|
|
43
|
+
* enabled: false, // Disable all legacy endpoints
|
|
44
|
+
* // or
|
|
45
|
+
* rest: false // Disable only REST endpoints
|
|
46
|
+
* }
|
|
47
|
+
* }
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @see https://github.com/lenneTech/nest-server/blob/develop/.claude/rules/module-deprecation.md
|
|
51
|
+
*/
|
|
24
52
|
@ApiCommonErrorResponses()
|
|
25
53
|
@Controller('auth')
|
|
26
54
|
@Roles(RoleEnum.ADMIN)
|
|
@@ -33,63 +61,123 @@ export class CoreAuthController {
|
|
|
33
61
|
protected readonly configService: ConfigService,
|
|
34
62
|
) {}
|
|
35
63
|
|
|
64
|
+
// ===========================================================================
|
|
65
|
+
// Helper - Legacy Endpoint Check
|
|
66
|
+
// ===========================================================================
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Check if legacy REST endpoints are enabled
|
|
70
|
+
*
|
|
71
|
+
* Throws LegacyAuthDisabledException if:
|
|
72
|
+
* - config.auth.legacyEndpoints.enabled is false
|
|
73
|
+
* - config.auth.legacyEndpoints.rest is false
|
|
74
|
+
*
|
|
75
|
+
* @throws LegacyAuthDisabledException
|
|
76
|
+
*/
|
|
77
|
+
protected checkLegacyRESTEnabled(endpointName: string): void {
|
|
78
|
+
const authConfig = this.configService.getFastButReadOnly('auth');
|
|
79
|
+
const legacyConfig = authConfig?.legacyEndpoints;
|
|
80
|
+
|
|
81
|
+
// Check if legacy endpoints are globally disabled
|
|
82
|
+
if (legacyConfig?.enabled === false) {
|
|
83
|
+
throw new LegacyAuthDisabledException(endpointName);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Check if REST endpoints specifically are disabled
|
|
87
|
+
if (legacyConfig?.rest === false) {
|
|
88
|
+
throw new LegacyAuthDisabledException(endpointName);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
36
92
|
/**
|
|
37
93
|
* Logout user (from specific device)
|
|
94
|
+
*
|
|
95
|
+
* @deprecated Will be replaced by BetterAuth signOut in a future version
|
|
96
|
+
* @throws LegacyAuthDisabledException if legacy endpoints are disabled
|
|
38
97
|
*/
|
|
98
|
+
@ApiGoneResponse({ description: 'Legacy Auth endpoints are disabled' })
|
|
39
99
|
@ApiOkResponse({ type: Boolean })
|
|
40
100
|
@ApiOperation({ description: 'Logs a user out from a specific device' })
|
|
41
101
|
@ApiQuery({ description: 'If all devices should be logged out,', name: 'allDevices', required: false, type: Boolean })
|
|
102
|
+
@ApiTooManyRequestsResponse({ description: 'Rate limit exceeded' })
|
|
42
103
|
@Get('logout')
|
|
43
104
|
@Roles(RoleEnum.S_EVERYONE)
|
|
44
|
-
@UseGuards(AuthGuard(AuthGuardStrategy.JWT))
|
|
105
|
+
@UseGuards(LegacyAuthRateLimitGuard, AuthGuard(AuthGuardStrategy.JWT))
|
|
45
106
|
async logout(
|
|
46
107
|
@CurrentUser() currentUser: ICoreAuthUser,
|
|
47
108
|
@Tokens('token') token: string,
|
|
48
109
|
@Res({ passthrough: true }) res: ResponseType,
|
|
49
110
|
@Query('allDevices', new ParseBoolPipe({ optional: true })) allDevices?: boolean,
|
|
50
111
|
): Promise<boolean> {
|
|
112
|
+
this.checkLegacyRESTEnabled('logout');
|
|
51
113
|
const result = await this.authService.logout(token, { allDevices, currentUser });
|
|
52
114
|
return this.processCookies(res, result);
|
|
53
115
|
}
|
|
54
116
|
|
|
55
117
|
/**
|
|
56
118
|
* Refresh token (for specific device)
|
|
119
|
+
*
|
|
120
|
+
* @deprecated Will be replaced by BetterAuth session refresh in a future version
|
|
121
|
+
* @throws LegacyAuthDisabledException if legacy endpoints are disabled
|
|
57
122
|
*/
|
|
123
|
+
@ApiGoneResponse({ description: 'Legacy Auth endpoints are disabled' })
|
|
58
124
|
@ApiOkResponse({ type: CoreAuthModel })
|
|
59
125
|
@ApiOperation({ description: 'Refresh token (for specific device)' })
|
|
126
|
+
@ApiTooManyRequestsResponse({ description: 'Rate limit exceeded' })
|
|
60
127
|
@Get('refresh-token')
|
|
61
128
|
@Roles(RoleEnum.S_EVERYONE)
|
|
62
|
-
@UseGuards(AuthGuard(AuthGuardStrategy.JWT_REFRESH))
|
|
129
|
+
@UseGuards(LegacyAuthRateLimitGuard, AuthGuard(AuthGuardStrategy.JWT_REFRESH))
|
|
63
130
|
async refreshToken(
|
|
64
131
|
@CurrentUser() user: ICoreAuthUser,
|
|
65
132
|
@Tokens('refreshToken') refreshToken: string,
|
|
66
133
|
@Res({ passthrough: true }) res: ResponseType,
|
|
67
134
|
): Promise<CoreAuthModel> {
|
|
135
|
+
this.checkLegacyRESTEnabled('refresh-token');
|
|
68
136
|
const result = await this.authService.refreshTokens(user, refreshToken);
|
|
69
137
|
return this.processCookies(res, result);
|
|
70
138
|
}
|
|
71
139
|
|
|
72
140
|
/**
|
|
73
141
|
* Sign in user via email and password (on specific device)
|
|
142
|
+
*
|
|
143
|
+
* @deprecated Will be replaced by BetterAuth signIn in a future version
|
|
144
|
+
* @throws LegacyAuthDisabledException if legacy endpoints are disabled
|
|
74
145
|
*/
|
|
75
146
|
@ApiCreatedResponse({ description: 'Signed in successfully', type: CoreAuthModel })
|
|
147
|
+
@ApiGoneResponse({ description: 'Legacy Auth endpoints are disabled' })
|
|
76
148
|
@ApiOperation({ description: 'Sign in via email and password' })
|
|
149
|
+
@ApiTooManyRequestsResponse({ description: 'Rate limit exceeded' })
|
|
77
150
|
@Post('signin')
|
|
78
151
|
@Roles(RoleEnum.S_EVERYONE)
|
|
79
|
-
|
|
152
|
+
@UseGuards(LegacyAuthRateLimitGuard)
|
|
153
|
+
async signIn(
|
|
154
|
+
@Res({ passthrough: true }) res: ResponseType,
|
|
155
|
+
@Body() input: CoreAuthSignInInput,
|
|
156
|
+
): Promise<CoreAuthModel> {
|
|
157
|
+
this.checkLegacyRESTEnabled('signin');
|
|
80
158
|
const result = await this.authService.signIn(input);
|
|
81
159
|
return this.processCookies(res, result);
|
|
82
160
|
}
|
|
83
161
|
|
|
84
162
|
/**
|
|
85
163
|
* Register a new user account (on specific device)
|
|
164
|
+
*
|
|
165
|
+
* @deprecated Will be replaced by BetterAuth signUp in a future version
|
|
166
|
+
* @throws LegacyAuthDisabledException if legacy endpoints are disabled
|
|
86
167
|
*/
|
|
87
168
|
@ApiBody({ type: CoreAuthSignUpInput })
|
|
88
169
|
@ApiCreatedResponse({ type: CoreAuthSignUpInput })
|
|
170
|
+
@ApiGoneResponse({ description: 'Legacy Auth endpoints are disabled' })
|
|
89
171
|
@ApiOperation({ description: 'Sign up via email and password' })
|
|
172
|
+
@ApiTooManyRequestsResponse({ description: 'Rate limit exceeded' })
|
|
90
173
|
@Post('signup')
|
|
91
174
|
@Roles(RoleEnum.S_EVERYONE)
|
|
92
|
-
|
|
175
|
+
@UseGuards(LegacyAuthRateLimitGuard)
|
|
176
|
+
async signUp(
|
|
177
|
+
@Res({ passthrough: true }) res: ResponseType,
|
|
178
|
+
@Body() input: CoreAuthSignUpInput,
|
|
179
|
+
): Promise<CoreAuthModel> {
|
|
180
|
+
this.checkLegacyRESTEnabled('signup');
|
|
93
181
|
const result = await this.authService.signUp(input);
|
|
94
182
|
return this.processCookies(res, result);
|
|
95
183
|
}
|
|
@@ -5,9 +5,11 @@ import { PassportModule } from '@nestjs/passport';
|
|
|
5
5
|
import { PubSub } from 'graphql-subscriptions';
|
|
6
6
|
|
|
7
7
|
import { AuthGuardStrategy } from './auth-guard-strategy.enum';
|
|
8
|
+
import { LegacyAuthRateLimitGuard } from './guards/legacy-auth-rate-limit.guard';
|
|
8
9
|
import { RolesGuard } from './guards/roles.guard';
|
|
9
10
|
import { CoreAuthUserService } from './services/core-auth-user.service';
|
|
10
11
|
import { CoreAuthService } from './services/core-auth.service';
|
|
12
|
+
import { LegacyAuthRateLimiter } from './services/legacy-auth-rate-limiter.service';
|
|
11
13
|
import { JwtRefreshStrategy } from './strategies/jwt-refresh.strategy';
|
|
12
14
|
import { JwtStrategy } from './strategies/jwt.strategy';
|
|
13
15
|
|
|
@@ -68,6 +70,9 @@ export class CoreAuthModule {
|
|
|
68
70
|
provide: JwtRefreshStrategy,
|
|
69
71
|
useClass: options.jwtRefreshStrategy || JwtRefreshStrategy,
|
|
70
72
|
},
|
|
73
|
+
// Rate limiting for Legacy Auth endpoints (disabled by default, configure via auth.rateLimit)
|
|
74
|
+
LegacyAuthRateLimiter,
|
|
75
|
+
LegacyAuthRateLimitGuard,
|
|
71
76
|
];
|
|
72
77
|
if (Array.isArray(options?.providers)) {
|
|
73
78
|
providers = imports.concat(options.providers);
|
|
@@ -75,7 +80,16 @@ export class CoreAuthModule {
|
|
|
75
80
|
|
|
76
81
|
// Return CoreAuthModule
|
|
77
82
|
return {
|
|
78
|
-
exports: [
|
|
83
|
+
exports: [
|
|
84
|
+
CoreAuthService,
|
|
85
|
+
JwtModule,
|
|
86
|
+
JwtStrategy,
|
|
87
|
+
JwtRefreshStrategy,
|
|
88
|
+
LegacyAuthRateLimiter,
|
|
89
|
+
LegacyAuthRateLimitGuard,
|
|
90
|
+
PassportModule,
|
|
91
|
+
UserModule,
|
|
92
|
+
],
|
|
79
93
|
imports,
|
|
80
94
|
module: CoreAuthModule,
|
|
81
95
|
providers,
|
|
@@ -10,7 +10,9 @@ import { ServiceOptions } from '../../common/interfaces/service-options.interfac
|
|
|
10
10
|
import { ConfigService } from '../../common/services/config.service';
|
|
11
11
|
import { AuthGuardStrategy } from './auth-guard-strategy.enum';
|
|
12
12
|
import { CoreAuthModel } from './core-auth.model';
|
|
13
|
+
import { LegacyAuthDisabledException } from './exceptions/legacy-auth-disabled.exception';
|
|
13
14
|
import { AuthGuard } from './guards/auth.guard';
|
|
15
|
+
import { LegacyAuthRateLimitGuard } from './guards/legacy-auth-rate-limit.guard';
|
|
14
16
|
import { CoreAuthSignInInput } from './inputs/core-auth-sign-in.input';
|
|
15
17
|
import { CoreAuthSignUpInput } from './inputs/core-auth-sign-up.input';
|
|
16
18
|
import { ICoreAuthUser } from './interfaces/core-auth-user.interface';
|
|
@@ -19,6 +21,26 @@ import { Tokens } from './tokens.decorator';
|
|
|
19
21
|
|
|
20
22
|
/**
|
|
21
23
|
* Authentication resolver for the sign in
|
|
24
|
+
*
|
|
25
|
+
* This resolver provides Legacy Auth endpoints via GraphQL.
|
|
26
|
+
* In a future version, BetterAuth (IAM) will become the default.
|
|
27
|
+
*
|
|
28
|
+
* ## Disabling Legacy Endpoints
|
|
29
|
+
*
|
|
30
|
+
* After all users have migrated to BetterAuth (IAM), these endpoints
|
|
31
|
+
* can be disabled via configuration:
|
|
32
|
+
*
|
|
33
|
+
* ```typescript
|
|
34
|
+
* auth: {
|
|
35
|
+
* legacyEndpoints: {
|
|
36
|
+
* enabled: false, // Disable all legacy endpoints
|
|
37
|
+
* // or
|
|
38
|
+
* graphql: false // Disable only GraphQL endpoints
|
|
39
|
+
* }
|
|
40
|
+
* }
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* @see https://github.com/lenneTech/nest-server/blob/develop/.claude/rules/module-deprecation.md
|
|
22
44
|
*/
|
|
23
45
|
@Resolver(() => CoreAuthModel, { isAbstract: true })
|
|
24
46
|
@Roles(RoleEnum.ADMIN)
|
|
@@ -31,67 +53,113 @@ export class CoreAuthResolver {
|
|
|
31
53
|
protected readonly configService: ConfigService,
|
|
32
54
|
) {}
|
|
33
55
|
|
|
56
|
+
// ===========================================================================
|
|
57
|
+
// Helper - Legacy Endpoint Check
|
|
58
|
+
// ===========================================================================
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Check if legacy GraphQL endpoints are enabled
|
|
62
|
+
*
|
|
63
|
+
* Throws LegacyAuthDisabledException if:
|
|
64
|
+
* - config.auth.legacyEndpoints.enabled is false
|
|
65
|
+
* - config.auth.legacyEndpoints.graphql is false
|
|
66
|
+
*
|
|
67
|
+
* @throws LegacyAuthDisabledException
|
|
68
|
+
*/
|
|
69
|
+
protected checkLegacyGraphQLEnabled(endpointName: string): void {
|
|
70
|
+
const authConfig = this.configService.getFastButReadOnly('auth');
|
|
71
|
+
const legacyConfig = authConfig?.legacyEndpoints;
|
|
72
|
+
|
|
73
|
+
// Check if legacy endpoints are globally disabled
|
|
74
|
+
if (legacyConfig?.enabled === false) {
|
|
75
|
+
throw new LegacyAuthDisabledException(endpointName);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Check if GraphQL endpoints specifically are disabled
|
|
79
|
+
if (legacyConfig?.graphql === false) {
|
|
80
|
+
throw new LegacyAuthDisabledException(endpointName);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
34
84
|
// ===========================================================================
|
|
35
85
|
// Mutations
|
|
36
86
|
// ===========================================================================
|
|
37
87
|
|
|
38
88
|
/**
|
|
39
89
|
* Logout user (from specific device)
|
|
90
|
+
*
|
|
91
|
+
* @deprecated Will be replaced by BetterAuth signOut in a future version
|
|
92
|
+
* @throws LegacyAuthDisabledException if legacy endpoints are disabled
|
|
40
93
|
*/
|
|
41
94
|
@Mutation(() => Boolean, { description: 'Logout user (from specific device)' })
|
|
42
95
|
@Roles(RoleEnum.S_EVERYONE)
|
|
43
|
-
@UseGuards(AuthGuard(AuthGuardStrategy.JWT))
|
|
96
|
+
@UseGuards(LegacyAuthRateLimitGuard, AuthGuard(AuthGuardStrategy.JWT))
|
|
44
97
|
async logout(
|
|
45
98
|
@CurrentUser() currentUser: ICoreAuthUser,
|
|
46
99
|
@Context() ctx: { res: ResponseType },
|
|
47
100
|
@Tokens('token') token: string,
|
|
48
101
|
@Args('allDevices', { nullable: true }) allDevices?: boolean,
|
|
49
102
|
): Promise<boolean> {
|
|
103
|
+
this.checkLegacyGraphQLEnabled('logout');
|
|
50
104
|
const result = await this.authService.logout(token, { allDevices, currentUser });
|
|
51
105
|
return this.processCookies(ctx, result);
|
|
52
106
|
}
|
|
53
107
|
|
|
54
108
|
/**
|
|
55
109
|
* Refresh token (for specific device)
|
|
110
|
+
*
|
|
111
|
+
* @deprecated Will be replaced by BetterAuth session refresh in a future version
|
|
112
|
+
* @throws LegacyAuthDisabledException if legacy endpoints are disabled
|
|
56
113
|
*/
|
|
57
114
|
@Mutation(() => CoreAuthModel, { description: 'Refresh tokens (for specific device)' })
|
|
58
115
|
@Roles(RoleEnum.S_EVERYONE)
|
|
59
|
-
@UseGuards(AuthGuard(AuthGuardStrategy.JWT_REFRESH))
|
|
116
|
+
@UseGuards(LegacyAuthRateLimitGuard, AuthGuard(AuthGuardStrategy.JWT_REFRESH))
|
|
60
117
|
async refreshToken(
|
|
61
118
|
@CurrentUser() user: ICoreAuthUser,
|
|
62
119
|
@Tokens('refreshToken') refreshToken: string,
|
|
63
120
|
@Context() ctx: { res: ResponseType },
|
|
64
121
|
): Promise<CoreAuthModel> {
|
|
122
|
+
this.checkLegacyGraphQLEnabled('refreshToken');
|
|
65
123
|
const result = await this.authService.refreshTokens(user, refreshToken);
|
|
66
124
|
return this.processCookies(ctx, result);
|
|
67
125
|
}
|
|
68
126
|
|
|
69
127
|
/**
|
|
70
128
|
* Sign in user via email and password (on specific device)
|
|
129
|
+
*
|
|
130
|
+
* @deprecated Will be replaced by BetterAuth signIn in a future version
|
|
131
|
+
* @throws LegacyAuthDisabledException if legacy endpoints are disabled
|
|
71
132
|
*/
|
|
72
133
|
@Mutation(() => CoreAuthModel, {
|
|
73
134
|
description: 'Sign in user via email and password and get JWT tokens (for specific device)',
|
|
74
135
|
})
|
|
75
136
|
@Roles(RoleEnum.S_EVERYONE)
|
|
137
|
+
@UseGuards(LegacyAuthRateLimitGuard)
|
|
76
138
|
async signIn(
|
|
77
139
|
@GraphQLServiceOptions({ gqlPath: 'signIn.user' }) serviceOptions: ServiceOptions,
|
|
78
140
|
@Context() ctx: { res: ResponseType },
|
|
79
141
|
@Args('input') input: CoreAuthSignInInput,
|
|
80
142
|
): Promise<CoreAuthModel> {
|
|
143
|
+
this.checkLegacyGraphQLEnabled('signIn');
|
|
81
144
|
const result = await this.authService.signIn(input, serviceOptions);
|
|
82
145
|
return this.processCookies(ctx, result);
|
|
83
146
|
}
|
|
84
147
|
|
|
85
148
|
/**
|
|
86
149
|
* Register a new user account (on specific device)
|
|
150
|
+
*
|
|
151
|
+
* @deprecated Will be replaced by BetterAuth signUp in a future version
|
|
152
|
+
* @throws LegacyAuthDisabledException if legacy endpoints are disabled
|
|
87
153
|
*/
|
|
88
154
|
@Mutation(() => CoreAuthModel, { description: 'Register a new user account (on specific device)' })
|
|
89
155
|
@Roles(RoleEnum.S_EVERYONE)
|
|
156
|
+
@UseGuards(LegacyAuthRateLimitGuard)
|
|
90
157
|
async signUp(
|
|
91
158
|
@GraphQLServiceOptions({ gqlPath: 'signUp.user' }) serviceOptions: ServiceOptions,
|
|
92
159
|
@Context() ctx: { res: ResponseType },
|
|
93
160
|
@Args('input') input: CoreAuthSignUpInput,
|
|
94
161
|
): Promise<CoreAuthModel> {
|
|
162
|
+
this.checkLegacyGraphQLEnabled('signUp');
|
|
95
163
|
const result = await this.authService.signUp(input, serviceOptions);
|
|
96
164
|
return this.processCookies(ctx, result);
|
|
97
165
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { GoneException } from '@nestjs/common';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Exception thrown when Legacy Auth endpoints are accessed but disabled
|
|
5
|
+
*
|
|
6
|
+
* This exception is thrown when:
|
|
7
|
+
* - config.auth.legacyEndpoints.enabled is false
|
|
8
|
+
* - config.auth.legacyEndpoints.graphql is false (for GraphQL endpoints)
|
|
9
|
+
* - config.auth.legacyEndpoints.rest is false (for REST endpoints)
|
|
10
|
+
*
|
|
11
|
+
* HTTP Status: 410 Gone
|
|
12
|
+
*
|
|
13
|
+
* This status code indicates that the resource is no longer available
|
|
14
|
+
* and will not be available again - appropriate for deprecated endpoints.
|
|
15
|
+
*
|
|
16
|
+
* @since 11.7.1
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* if (!this.isLegacyEndpointEnabled()) {
|
|
21
|
+
* throw new LegacyAuthDisabledException();
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export class LegacyAuthDisabledException extends GoneException {
|
|
26
|
+
constructor(endpoint?: string) {
|
|
27
|
+
super({
|
|
28
|
+
error: 'Legacy Auth Disabled',
|
|
29
|
+
message: endpoint
|
|
30
|
+
? `Legacy Auth endpoint '${endpoint}' is disabled. Use BetterAuth (IAM) endpoints instead.`
|
|
31
|
+
: 'Legacy Auth endpoints are disabled. Use BetterAuth (IAM) endpoints instead.',
|
|
32
|
+
statusCode: 410,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|