mongodb-dynamic-api 2.3.17 → 2.4.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/CHANGELOG.md +9 -0
- package/package.json +5 -2
- package/src/adapters/socket-adapter.d.ts +8 -0
- package/src/adapters/socket-adapter.js +11 -0
- package/src/adapters/socket-adapter.js.map +1 -0
- package/src/builders/route-decorators/auth-decorators.builder.d.ts +4 -4
- package/src/builders/route-decorators/auth-decorators.builder.js +9 -6
- package/src/builders/route-decorators/auth-decorators.builder.js.map +1 -1
- package/src/dtos/index.d.ts +1 -1
- package/src/dtos/index.js +1 -1
- package/src/dtos/index.js.map +1 -1
- package/src/dtos/many-entity.query.d.ts +3 -0
- package/src/dtos/{delete-many-entity.query.js → many-entity.query.js} +5 -5
- package/src/dtos/many-entity.query.js.map +1 -0
- package/src/dynamic-api.module.d.ts +2 -2
- package/src/dynamic-api.module.js +10 -7
- package/src/dynamic-api.module.js.map +1 -1
- package/src/filters/ws-exception/dynamic-api-ws-exception.filter.d.ts +5 -0
- package/src/filters/ws-exception/dynamic-api-ws-exception.filter.js +29 -0
- package/src/filters/ws-exception/dynamic-api-ws-exception.filter.js.map +1 -0
- package/src/gateways/base.gateway.d.ts +10 -0
- package/src/gateways/base.gateway.js +45 -0
- package/src/gateways/base.gateway.js.map +1 -0
- package/src/gateways/index.d.ts +1 -0
- package/src/gateways/index.js +18 -0
- package/src/gateways/index.js.map +1 -0
- package/src/helpers/controller-mixin.helper.js +2 -20
- package/src/helpers/controller-mixin.helper.js.map +1 -1
- package/src/helpers/format.helper.d.ts +7 -4
- package/src/helpers/format.helper.js +12 -4
- package/src/helpers/format.helper.js.map +1 -1
- package/src/helpers/index.d.ts +1 -0
- package/src/helpers/index.js +1 -0
- package/src/helpers/index.js.map +1 -1
- package/src/helpers/socket-config.helper.d.ts +5 -0
- package/src/helpers/socket-config.helper.js +30 -0
- package/src/helpers/socket-config.helper.js.map +1 -0
- package/src/index.d.ts +1 -0
- package/src/index.js +1 -0
- package/src/index.js.map +1 -1
- package/src/interfaces/dynamic-api-global-state.interface.d.ts +3 -0
- package/src/interfaces/dynamic-api-options.interface.d.ts +3 -0
- package/src/interfaces/dynamic-api-options.interface.js.map +1 -1
- package/src/interfaces/dynamic-api-policy-handler.interface.d.ts +2 -2
- package/src/interfaces/dynamic-api-route-config.interface.d.ts +2 -0
- package/src/interfaces/dynamic-api-web-socket.interface.d.ts +13 -0
- package/src/interfaces/dynamic-api-web-socket.interface.js +3 -0
- package/src/interfaces/dynamic-api-web-socket.interface.js.map +1 -0
- package/src/interfaces/index.d.ts +1 -0
- package/src/interfaces/index.js +1 -0
- package/src/interfaces/index.js.map +1 -1
- package/src/modules/auth/auth.helper.d.ts +7 -5
- package/src/modules/auth/auth.helper.js +29 -5
- package/src/modules/auth/auth.helper.js.map +1 -1
- package/src/modules/auth/auth.module.js +26 -8
- package/src/modules/auth/auth.module.js.map +1 -1
- package/src/modules/auth/guards/index.d.ts +4 -2
- package/src/modules/auth/guards/index.js +4 -2
- package/src/modules/auth/guards/index.js.map +1 -1
- package/src/modules/auth/guards/jwt-auth/jwt-auth.guard.js.map +1 -0
- package/src/modules/auth/guards/jwt-socket-auth/jwt-socket-auth.guard.d.ts +5 -0
- package/src/modules/auth/guards/jwt-socket-auth/jwt-socket-auth.guard.js +57 -0
- package/src/modules/auth/guards/jwt-socket-auth/jwt-socket-auth.guard.js.map +1 -0
- package/src/modules/auth/guards/local-auth/local-auth.guard.js.map +1 -0
- package/src/modules/auth/guards/reset-password/reset-password.guard.d.ts +6 -0
- package/src/modules/auth/guards/reset-password/reset-password.guard.js +30 -0
- package/src/modules/auth/guards/reset-password/reset-password.guard.js.map +1 -0
- package/src/modules/auth/interfaces/auth-controller.interface.d.ts +3 -0
- package/src/modules/auth/interfaces/auth-gateway.interface.d.ts +16 -0
- package/src/modules/auth/interfaces/auth-gateway.interface.js +3 -0
- package/src/modules/auth/interfaces/auth-gateway.interface.js.map +1 -0
- package/src/modules/auth/interfaces/auth-options.interface.d.ts +14 -7
- package/src/modules/auth/interfaces/auth-service.interface.d.ts +1 -0
- package/src/modules/auth/interfaces/index.d.ts +1 -0
- package/src/modules/auth/interfaces/index.js +1 -0
- package/src/modules/auth/interfaces/index.js.map +1 -1
- package/src/modules/auth/mixins/auth-controller.mixin.d.ts +2 -2
- package/src/modules/auth/mixins/auth-controller.mixin.js +31 -5
- package/src/modules/auth/mixins/auth-controller.mixin.js.map +1 -1
- package/src/modules/auth/mixins/auth-gateway.mixin.d.ts +5 -0
- package/src/modules/auth/mixins/auth-gateway.mixin.js +191 -0
- package/src/modules/auth/mixins/auth-gateway.mixin.js.map +1 -0
- package/src/modules/auth/mixins/auth-policies-guard.mixin.d.ts +6 -0
- package/src/modules/auth/mixins/auth-policies-guard.mixin.js +52 -0
- package/src/modules/auth/mixins/auth-policies-guard.mixin.js.map +1 -0
- package/src/modules/auth/mixins/index.d.ts +2 -1
- package/src/modules/auth/mixins/index.js +2 -1
- package/src/modules/auth/mixins/index.js.map +1 -1
- package/src/modules/auth/services/base-auth.service.d.ts +2 -0
- package/src/modules/auth/services/base-auth.service.js +17 -1
- package/src/modules/auth/services/base-auth.service.js.map +1 -1
- package/src/routes/create-many/create-many-body-dto.mixin.d.ts +7 -0
- package/src/routes/create-many/create-many-body-dto.mixin.js +30 -0
- package/src/routes/create-many/create-many-body-dto.mixin.js.map +1 -0
- package/src/routes/create-many/create-many-controller.interface.d.ts +5 -4
- package/src/routes/create-many/create-many-gateway.interface.d.ts +10 -0
- package/src/routes/create-many/create-many-gateway.interface.js +3 -0
- package/src/routes/create-many/create-many-gateway.interface.js.map +1 -0
- package/src/routes/create-many/create-many-gateway.mixin.d.ts +6 -0
- package/src/routes/create-many/create-many-gateway.mixin.js +60 -0
- package/src/routes/create-many/create-many-gateway.mixin.js.map +1 -0
- package/src/routes/create-many/create-many.helper.d.ts +4 -2
- package/src/routes/create-many/create-many.helper.js +21 -1
- package/src/routes/create-many/create-many.helper.js.map +1 -1
- package/src/routes/create-many/create-many.module.d.ts +2 -2
- package/src/routes/create-many/create-many.module.js +12 -2
- package/src/routes/create-many/create-many.module.js.map +1 -1
- package/src/routes/create-many/index.d.ts +3 -0
- package/src/routes/create-many/index.js +3 -0
- package/src/routes/create-many/index.js.map +1 -1
- package/src/routes/create-one/create-one-gateway.interface.d.ts +9 -0
- package/src/routes/create-one/create-one-gateway.interface.js +3 -0
- package/src/routes/create-one/create-one-gateway.interface.js.map +1 -0
- package/src/routes/create-one/create-one-gateway.mixin.d.ts +6 -0
- package/src/routes/create-one/create-one-gateway.mixin.js +61 -0
- package/src/routes/create-one/create-one-gateway.mixin.js.map +1 -0
- package/src/routes/create-one/create-one.helper.d.ts +4 -2
- package/src/routes/create-one/create-one.helper.js +21 -1
- package/src/routes/create-one/create-one.helper.js.map +1 -1
- package/src/routes/create-one/create-one.module.d.ts +2 -2
- package/src/routes/create-one/create-one.module.js +12 -2
- package/src/routes/create-one/create-one.module.js.map +1 -1
- package/src/routes/create-one/index.d.ts +2 -0
- package/src/routes/create-one/index.js +2 -0
- package/src/routes/create-one/index.js.map +1 -1
- package/src/routes/delete-many/delete-many-controller.interface.d.ts +2 -2
- package/src/routes/delete-many/delete-many-controller.mixin.js +1 -1
- package/src/routes/delete-many/delete-many-controller.mixin.js.map +1 -1
- package/src/routes/delete-many/delete-many-gateway.interface.d.ts +10 -0
- package/src/routes/delete-many/delete-many-gateway.interface.js +3 -0
- package/src/routes/delete-many/delete-many-gateway.interface.js.map +1 -0
- package/src/routes/delete-many/delete-many-gateway.mixin.d.ts +6 -0
- package/src/routes/delete-many/delete-many-gateway.mixin.js +60 -0
- package/src/routes/delete-many/delete-many-gateway.mixin.js.map +1 -0
- package/src/routes/delete-many/delete-many.helper.d.ts +4 -2
- package/src/routes/delete-many/delete-many.helper.js +21 -1
- package/src/routes/delete-many/delete-many.helper.js.map +1 -1
- package/src/routes/delete-many/delete-many.module.d.ts +2 -2
- package/src/routes/delete-many/delete-many.module.js +12 -2
- package/src/routes/delete-many/delete-many.module.js.map +1 -1
- package/src/routes/delete-many/index.d.ts +2 -0
- package/src/routes/delete-many/index.js +2 -0
- package/src/routes/delete-many/index.js.map +1 -1
- package/src/routes/delete-one/delete-one-gateway.interface.d.ts +10 -0
- package/src/routes/delete-one/delete-one-gateway.interface.js +3 -0
- package/src/routes/delete-one/delete-one-gateway.interface.js.map +1 -0
- package/src/routes/delete-one/delete-one-gateway.mixin.d.ts +6 -0
- package/src/routes/delete-one/delete-one-gateway.mixin.js +60 -0
- package/src/routes/delete-one/delete-one-gateway.mixin.js.map +1 -0
- package/src/routes/delete-one/delete-one.helper.d.ts +4 -2
- package/src/routes/delete-one/delete-one.helper.js +21 -1
- package/src/routes/delete-one/delete-one.helper.js.map +1 -1
- package/src/routes/delete-one/delete-one.module.d.ts +2 -2
- package/src/routes/delete-one/delete-one.module.js +12 -2
- package/src/routes/delete-one/delete-one.module.js.map +1 -1
- package/src/routes/delete-one/index.d.ts +2 -0
- package/src/routes/delete-one/index.js +2 -0
- package/src/routes/delete-one/index.js.map +1 -1
- package/src/routes/duplicate-many/base-duplicate-many.service.js +1 -1
- package/src/routes/duplicate-many/base-duplicate-many.service.js.map +1 -1
- package/src/routes/duplicate-many/duplicate-many-gateway.interface.d.ts +10 -0
- package/src/routes/duplicate-many/duplicate-many-gateway.interface.js +3 -0
- package/src/routes/duplicate-many/duplicate-many-gateway.interface.js.map +1 -0
- package/src/routes/duplicate-many/duplicate-many-gateway.mixin.d.ts +6 -0
- package/src/routes/duplicate-many/duplicate-many-gateway.mixin.js +60 -0
- package/src/routes/duplicate-many/duplicate-many-gateway.mixin.js.map +1 -0
- package/src/routes/duplicate-many/duplicate-many.helper.d.ts +4 -2
- package/src/routes/duplicate-many/duplicate-many.helper.js +21 -1
- package/src/routes/duplicate-many/duplicate-many.helper.js.map +1 -1
- package/src/routes/duplicate-many/duplicate-many.module.d.ts +2 -2
- package/src/routes/duplicate-many/duplicate-many.module.js +12 -2
- package/src/routes/duplicate-many/duplicate-many.module.js.map +1 -1
- package/src/routes/duplicate-many/index.d.ts +2 -0
- package/src/routes/duplicate-many/index.js +2 -0
- package/src/routes/duplicate-many/index.js.map +1 -1
- package/src/routes/duplicate-one/duplicate-one-gateway.interface.d.ts +10 -0
- package/src/routes/duplicate-one/duplicate-one-gateway.interface.js +3 -0
- package/src/routes/duplicate-one/duplicate-one-gateway.interface.js.map +1 -0
- package/src/routes/duplicate-one/duplicate-one-gateway.mixin.d.ts +6 -0
- package/src/routes/duplicate-one/duplicate-one-gateway.mixin.js +60 -0
- package/src/routes/duplicate-one/duplicate-one-gateway.mixin.js.map +1 -0
- package/src/routes/duplicate-one/duplicate-one.helper.d.ts +4 -2
- package/src/routes/duplicate-one/duplicate-one.helper.js +21 -1
- package/src/routes/duplicate-one/duplicate-one.helper.js.map +1 -1
- package/src/routes/duplicate-one/duplicate-one.module.d.ts +2 -2
- package/src/routes/duplicate-one/duplicate-one.module.js +12 -2
- package/src/routes/duplicate-one/duplicate-one.module.js.map +1 -1
- package/src/routes/duplicate-one/index.d.ts +2 -0
- package/src/routes/duplicate-one/index.js +2 -0
- package/src/routes/duplicate-one/index.js.map +1 -1
- package/src/routes/get-many/get-many-gateway.interface.d.ts +9 -0
- package/src/routes/get-many/get-many-gateway.interface.js +3 -0
- package/src/routes/get-many/get-many-gateway.interface.js.map +1 -0
- package/src/routes/get-many/get-many-gateway.mixin.d.ts +6 -0
- package/src/routes/get-many/get-many-gateway.mixin.js +56 -0
- package/src/routes/get-many/get-many-gateway.mixin.js.map +1 -0
- package/src/routes/get-many/get-many.helper.d.ts +4 -2
- package/src/routes/get-many/get-many.helper.js +21 -1
- package/src/routes/get-many/get-many.helper.js.map +1 -1
- package/src/routes/get-many/get-many.module.d.ts +2 -2
- package/src/routes/get-many/get-many.module.js +12 -2
- package/src/routes/get-many/get-many.module.js.map +1 -1
- package/src/routes/get-many/index.d.ts +2 -0
- package/src/routes/get-many/index.js +2 -0
- package/src/routes/get-many/index.js.map +1 -1
- package/src/routes/get-one/get-one-gateway.interface.d.ts +10 -0
- package/src/routes/get-one/get-one-gateway.interface.js +3 -0
- package/src/routes/get-one/get-one-gateway.interface.js.map +1 -0
- package/src/routes/get-one/get-one-gateway.mixin.d.ts +6 -0
- package/src/routes/get-one/get-one-gateway.mixin.js +60 -0
- package/src/routes/get-one/get-one-gateway.mixin.js.map +1 -0
- package/src/routes/get-one/get-one.helper.d.ts +4 -2
- package/src/routes/get-one/get-one.helper.js +21 -1
- package/src/routes/get-one/get-one.helper.js.map +1 -1
- package/src/routes/get-one/get-one.module.d.ts +2 -2
- package/src/routes/get-one/get-one.module.js +12 -2
- package/src/routes/get-one/get-one.module.js.map +1 -1
- package/src/routes/get-one/index.d.ts +2 -0
- package/src/routes/get-one/index.js +2 -0
- package/src/routes/get-one/index.js.map +1 -1
- package/src/routes/replace-one/index.d.ts +2 -0
- package/src/routes/replace-one/index.js +2 -0
- package/src/routes/replace-one/index.js.map +1 -1
- package/src/routes/replace-one/replace-one-gateway.interface.d.ts +10 -0
- package/src/routes/replace-one/replace-one-gateway.interface.js +3 -0
- package/src/routes/replace-one/replace-one-gateway.interface.js.map +1 -0
- package/src/routes/replace-one/replace-one-gateway.mixin.d.ts +6 -0
- package/src/routes/replace-one/replace-one-gateway.mixin.js +60 -0
- package/src/routes/replace-one/replace-one-gateway.mixin.js.map +1 -0
- package/src/routes/replace-one/replace-one.helper.d.ts +4 -2
- package/src/routes/replace-one/replace-one.helper.js +21 -1
- package/src/routes/replace-one/replace-one.helper.js.map +1 -1
- package/src/routes/replace-one/replace-one.module.d.ts +2 -2
- package/src/routes/replace-one/replace-one.module.js +12 -2
- package/src/routes/replace-one/replace-one.module.js.map +1 -1
- package/src/routes/update-many/index.d.ts +2 -0
- package/src/routes/update-many/index.js +2 -0
- package/src/routes/update-many/index.js.map +1 -1
- package/src/routes/update-many/update-many-gateway.interface.d.ts +10 -0
- package/src/routes/update-many/update-many-gateway.interface.js +3 -0
- package/src/routes/update-many/update-many-gateway.interface.js.map +1 -0
- package/src/routes/update-many/update-many-gateway.mixin.d.ts +6 -0
- package/src/routes/update-many/update-many-gateway.mixin.js +63 -0
- package/src/routes/update-many/update-many-gateway.mixin.js.map +1 -0
- package/src/routes/update-many/update-many.helper.d.ts +4 -2
- package/src/routes/update-many/update-many.helper.js +21 -1
- package/src/routes/update-many/update-many.helper.js.map +1 -1
- package/src/routes/update-many/update-many.module.d.ts +2 -2
- package/src/routes/update-many/update-many.module.js +12 -2
- package/src/routes/update-many/update-many.module.js.map +1 -1
- package/src/routes/update-one/update-one-gateway.interface.d.ts +10 -0
- package/src/routes/update-one/update-one-gateway.interface.js +3 -0
- package/src/routes/update-one/update-one-gateway.interface.js.map +1 -0
- package/src/routes/update-one/update-one-gateway.mixin.d.ts +6 -0
- package/src/routes/update-one/update-one-gateway.mixin.js +60 -0
- package/src/routes/update-one/update-one-gateway.mixin.js.map +1 -0
- package/src/routes/update-one/update-one.helper.d.ts +4 -2
- package/src/routes/update-one/update-one.helper.js +21 -1
- package/src/routes/update-one/update-one.helper.js.map +1 -1
- package/src/routes/update-one/update-one.module.d.ts +2 -2
- package/src/routes/update-one/update-one.module.js +12 -2
- package/src/routes/update-one/update-one.module.js.map +1 -1
- package/src/services/base/base.service.d.ts +1 -0
- package/src/services/base/base.service.js +5 -0
- package/src/services/base/base.service.js.map +1 -1
- package/src/services/dynamic-api-global-state/dynamic-api-global-state.service.js +1 -0
- package/src/services/dynamic-api-global-state/dynamic-api-global-state.service.js.map +1 -1
- package/src/version.json +1 -1
- package/test/dynamic-api-for-root.e2e-spec.js +976 -641
- package/test/dynamic-api-for-root.e2e-spec.js.map +1 -1
- package/test/e2e.setup.d.ts +16 -1
- package/test/e2e.setup.js +62 -7
- package/test/e2e.setup.js.map +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/src/dtos/delete-many-entity.query.d.ts +0 -3
- package/src/dtos/delete-many-entity.query.js.map +0 -1
- package/src/modules/auth/guards/jwt-auth.guard.js.map +0 -1
- package/src/modules/auth/guards/local-auth.guard.js.map +0 -1
- package/src/modules/auth/mixins/auth-register-policies-guard.mixin.d.ts +0 -5
- package/src/modules/auth/mixins/auth-register-policies-guard.mixin.js +0 -31
- package/src/modules/auth/mixins/auth-register-policies-guard.mixin.js.map +0 -1
- /package/src/modules/auth/guards/{jwt-auth.guard.d.ts → jwt-auth/jwt-auth.guard.d.ts} +0 -0
- /package/src/modules/auth/guards/{jwt-auth.guard.js → jwt-auth/jwt-auth.guard.js} +0 -0
- /package/src/modules/auth/guards/{local-auth.guard.d.ts → local-auth/local-auth.guard.d.ts} +0 -0
- /package/src/modules/auth/guards/{local-auth.guard.js → local-auth/local-auth.guard.js} +0 -0
|
@@ -16,16 +16,18 @@ const testing_1 = require("@nestjs/testing");
|
|
|
16
16
|
const class_validator_1 = require("class-validator");
|
|
17
17
|
const mongoose_2 = require("mongoose");
|
|
18
18
|
const src_1 = require("../src");
|
|
19
|
+
const socket_adapter_1 = require("../src/adapters/socket-adapter");
|
|
19
20
|
const e2e_setup_1 = require("./e2e.setup");
|
|
20
21
|
require("dotenv/config");
|
|
21
22
|
const utils_1 = require("./utils");
|
|
22
23
|
describe('DynamicApiModule forRoot (e2e)', () => {
|
|
23
24
|
const uri = process.env.MONGO_DB_URL;
|
|
24
|
-
const initModule = async (dynamicApiForRootOptions, initFixtures) => {
|
|
25
|
+
const initModule = async (dynamicApiForRootOptions, initFixtures, initMainCb, testGateway) => {
|
|
25
26
|
const moduleRef = await testing_1.Test.createTestingModule({
|
|
26
27
|
imports: [src_1.DynamicApiModule.forRoot(uri, dynamicApiForRootOptions)],
|
|
28
|
+
providers: testGateway ? [e2e_setup_1.TestGateway] : [],
|
|
27
29
|
}).compile();
|
|
28
|
-
return (0, e2e_setup_1.createTestingApp)(moduleRef, initFixtures);
|
|
30
|
+
return (0, e2e_setup_1.createTestingApp)(moduleRef, initFixtures, initMainCb);
|
|
29
31
|
};
|
|
30
32
|
beforeEach(() => {
|
|
31
33
|
src_1.DynamicApiModule.state['resetState']();
|
|
@@ -44,6 +46,7 @@ describe('DynamicApiModule forRoot (e2e)', () => {
|
|
|
44
46
|
cacheExcludedPaths: [],
|
|
45
47
|
credentials: null,
|
|
46
48
|
isAuthEnabled: false,
|
|
49
|
+
jwtExpirationTime: undefined,
|
|
47
50
|
jwtSecret: undefined,
|
|
48
51
|
routesConfig: {
|
|
49
52
|
defaults: [
|
|
@@ -61,6 +64,7 @@ describe('DynamicApiModule forRoot (e2e)', () => {
|
|
|
61
64
|
],
|
|
62
65
|
excluded: [],
|
|
63
66
|
},
|
|
67
|
+
gatewayOptions: undefined,
|
|
64
68
|
});
|
|
65
69
|
});
|
|
66
70
|
it('should initialize dynamic api module state with custom options', async () => {
|
|
@@ -83,733 +87,1064 @@ describe('DynamicApiModule forRoot (e2e)', () => {
|
|
|
83
87
|
cacheExcludedPaths: ['/fake-path'],
|
|
84
88
|
credentials: null,
|
|
85
89
|
isAuthEnabled: false,
|
|
90
|
+
jwtExpirationTime: undefined,
|
|
86
91
|
jwtSecret: undefined,
|
|
87
92
|
routesConfig: {
|
|
88
93
|
defaults: ['GetMany', 'GetOne', 'CreateOne', 'UpdateOne', 'DeleteOne'],
|
|
89
94
|
excluded: ['CreateMany', 'UpdateMany', 'DeleteMany'],
|
|
90
95
|
},
|
|
96
|
+
gatewayOptions: undefined,
|
|
91
97
|
});
|
|
92
98
|
});
|
|
93
|
-
describe('
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
(
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
(
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
it('should initialize dynamic api module state and authentication API with default options', async () => {
|
|
112
|
-
expect(app).toBeDefined();
|
|
113
|
-
expect(src_1.DynamicApiModule.state.get()).toStrictEqual({
|
|
114
|
-
uri,
|
|
115
|
-
initialized: true,
|
|
116
|
-
isGlobalCacheEnabled: true,
|
|
117
|
-
connectionName: 'dynamic-api-connection',
|
|
118
|
-
cacheExcludedPaths: [],
|
|
119
|
-
credentials: {
|
|
120
|
-
loginField: 'email',
|
|
121
|
-
passwordField: 'password',
|
|
122
|
-
},
|
|
123
|
-
isAuthEnabled: true,
|
|
124
|
-
jwtSecret: 'dynamic-api-jwt-secret',
|
|
125
|
-
routesConfig: {
|
|
126
|
-
defaults: [
|
|
127
|
-
'GetMany',
|
|
128
|
-
'GetOne',
|
|
129
|
-
'CreateMany',
|
|
130
|
-
'CreateOne',
|
|
131
|
-
'UpdateMany',
|
|
132
|
-
'UpdateOne',
|
|
133
|
-
'ReplaceOne',
|
|
134
|
-
'DuplicateMany',
|
|
135
|
-
'DuplicateOne',
|
|
136
|
-
'DeleteMany',
|
|
137
|
-
'DeleteOne',
|
|
138
|
-
],
|
|
139
|
-
excluded: [],
|
|
140
|
-
},
|
|
99
|
+
describe('Authentication API', () => {
|
|
100
|
+
describe('useAuth when only userEntity is provided', () => {
|
|
101
|
+
let UserEntity = class UserEntity extends src_1.BaseEntity {
|
|
102
|
+
};
|
|
103
|
+
__decorate([
|
|
104
|
+
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
105
|
+
__metadata("design:type", String)
|
|
106
|
+
], UserEntity.prototype, "email", void 0);
|
|
107
|
+
__decorate([
|
|
108
|
+
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
109
|
+
__metadata("design:type", String)
|
|
110
|
+
], UserEntity.prototype, "password", void 0);
|
|
111
|
+
UserEntity = __decorate([
|
|
112
|
+
(0, mongoose_1.Schema)({ collection: 'users' })
|
|
113
|
+
], UserEntity);
|
|
114
|
+
let app;
|
|
115
|
+
beforeEach(async () => {
|
|
116
|
+
app = await initModule({ useAuth: { userEntity: UserEntity } });
|
|
141
117
|
});
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
118
|
+
it('should initialize dynamic api module state and authentication API with default options', async () => {
|
|
119
|
+
expect(app).toBeDefined();
|
|
120
|
+
expect(src_1.DynamicApiModule.state.get()).toStrictEqual({
|
|
121
|
+
uri,
|
|
122
|
+
initialized: true,
|
|
123
|
+
isGlobalCacheEnabled: true,
|
|
124
|
+
connectionName: 'dynamic-api-connection',
|
|
125
|
+
cacheExcludedPaths: [],
|
|
126
|
+
credentials: {
|
|
127
|
+
loginField: 'email',
|
|
128
|
+
passwordField: 'password',
|
|
129
|
+
},
|
|
130
|
+
isAuthEnabled: true,
|
|
131
|
+
jwtExpirationTime: '1d',
|
|
132
|
+
jwtSecret: 'dynamic-api-jwt-secret',
|
|
133
|
+
routesConfig: {
|
|
134
|
+
defaults: [
|
|
135
|
+
'GetMany',
|
|
136
|
+
'GetOne',
|
|
137
|
+
'CreateMany',
|
|
138
|
+
'CreateOne',
|
|
139
|
+
'UpdateMany',
|
|
140
|
+
'UpdateOne',
|
|
141
|
+
'ReplaceOne',
|
|
142
|
+
'DuplicateMany',
|
|
143
|
+
'DuplicateOne',
|
|
144
|
+
'DeleteMany',
|
|
145
|
+
'DeleteOne',
|
|
146
|
+
],
|
|
147
|
+
excluded: [],
|
|
148
|
+
},
|
|
149
|
+
gatewayOptions: undefined,
|
|
151
150
|
});
|
|
152
151
|
});
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
152
|
+
describe('POST /auth/register', () => {
|
|
153
|
+
it('should throw a bad request exception if email is missing', async () => {
|
|
154
|
+
const { body, status } = await e2e_setup_1.server.post('/auth/register', { username: 'unit-test', password: 'test-2' });
|
|
155
|
+
expect(status).toBe(400);
|
|
156
|
+
expect(body).toEqual({
|
|
157
|
+
error: 'Bad Request',
|
|
158
|
+
message: ['email property is required'],
|
|
159
|
+
statusCode: 400,
|
|
160
|
+
});
|
|
160
161
|
});
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
it('should throw an unauthorized exception if email is missing', async () => {
|
|
170
|
-
const { body, status } = await e2e_setup_1.server.post('/auth/login', { pass: 'test-2' });
|
|
171
|
-
expect(status).toBe(401);
|
|
172
|
-
expect(body).toEqual({
|
|
173
|
-
message: 'Unauthorized',
|
|
174
|
-
statusCode: 401,
|
|
162
|
+
it('should throw a bad request exception if password is missing', async () => {
|
|
163
|
+
const { body, status } = await e2e_setup_1.server.post('/auth/register', { email: 'unit@test.co', pass: 'test-2' });
|
|
164
|
+
expect(status).toBe(400);
|
|
165
|
+
expect(body).toEqual({
|
|
166
|
+
error: 'Bad Request',
|
|
167
|
+
message: ['password property is required'],
|
|
168
|
+
statusCode: 400,
|
|
169
|
+
});
|
|
175
170
|
});
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
expect(body).toEqual({
|
|
181
|
-
message: 'Unauthorized',
|
|
182
|
-
statusCode: 401,
|
|
171
|
+
it('should create a new user and return access token', async () => {
|
|
172
|
+
const { body, status } = await e2e_setup_1.server.post('/auth/register', { email: 'unit@test.co', password: 'test' });
|
|
173
|
+
expect(status).toBe(201);
|
|
174
|
+
expect(body).toEqual({ accessToken: expect.any(String) });
|
|
183
175
|
});
|
|
184
176
|
});
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
177
|
+
describe('POST /auth/login', () => {
|
|
178
|
+
it('should throw an unauthorized exception if email is missing', async () => {
|
|
179
|
+
const { body, status } = await e2e_setup_1.server.post('/auth/login', { pass: 'test-2' });
|
|
180
|
+
expect(status).toBe(401);
|
|
181
|
+
expect(body).toEqual({
|
|
182
|
+
message: 'Unauthorized',
|
|
183
|
+
statusCode: 401,
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
it('should throw an unauthorized exception if password is missing', async () => {
|
|
187
|
+
const { body, status } = await e2e_setup_1.server.post('/auth/login', { email: 'unit@test.co' });
|
|
188
|
+
expect(status).toBe(401);
|
|
189
|
+
expect(body).toEqual({
|
|
190
|
+
message: 'Unauthorized',
|
|
191
|
+
statusCode: 401,
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
it('should return access token', async () => {
|
|
195
|
+
await e2e_setup_1.server.post('/auth/register', { email: 'unit@test.co', password: 'test' });
|
|
196
|
+
const { body, status } = await e2e_setup_1.server.post('/auth/login', { email: 'unit@test.co', password: 'test' });
|
|
197
|
+
expect(status).toBe(200);
|
|
198
|
+
expect(body).toEqual({ accessToken: expect.any(String) });
|
|
199
199
|
});
|
|
200
200
|
});
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
219
|
-
__metadata("design:type", String)
|
|
220
|
-
], UserEntity.prototype, "email", void 0);
|
|
221
|
-
__decorate([
|
|
222
|
-
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
223
|
-
__metadata("design:type", String)
|
|
224
|
-
], UserEntity.prototype, "password", void 0);
|
|
225
|
-
UserEntity = __decorate([
|
|
226
|
-
(0, mongoose_1.Schema)({ collection: 'users' })
|
|
227
|
-
], UserEntity);
|
|
228
|
-
beforeEach(async () => {
|
|
229
|
-
app = await initModule({
|
|
230
|
-
useAuth: {
|
|
231
|
-
userEntity: UserEntity,
|
|
232
|
-
jwt: {
|
|
233
|
-
secret: 'test-secret',
|
|
234
|
-
expiresIn: '4s',
|
|
235
|
-
},
|
|
236
|
-
},
|
|
237
|
-
});
|
|
238
|
-
jwtService = app.get(jwt_1.JwtService);
|
|
239
|
-
const { body: { accessToken } } = await e2e_setup_1.server.post('/auth/register', { email: 'unit@test.co', password: 'test' });
|
|
240
|
-
token = accessToken;
|
|
241
|
-
});
|
|
242
|
-
it('should initialize dynamic api module state and authentication API with jwt options', async () => {
|
|
243
|
-
expect(app).toBeDefined();
|
|
244
|
-
expect(src_1.DynamicApiModule.state.get()).toStrictEqual({
|
|
245
|
-
uri,
|
|
246
|
-
initialized: true,
|
|
247
|
-
isGlobalCacheEnabled: true,
|
|
248
|
-
connectionName: 'dynamic-api-connection',
|
|
249
|
-
cacheExcludedPaths: [],
|
|
250
|
-
credentials: {
|
|
251
|
-
loginField: 'email',
|
|
252
|
-
passwordField: 'password',
|
|
253
|
-
},
|
|
254
|
-
isAuthEnabled: true,
|
|
255
|
-
jwtSecret: 'test-secret',
|
|
256
|
-
routesConfig: {
|
|
257
|
-
defaults: [
|
|
258
|
-
'GetMany',
|
|
259
|
-
'GetOne',
|
|
260
|
-
'CreateMany',
|
|
261
|
-
'CreateOne',
|
|
262
|
-
'UpdateMany',
|
|
263
|
-
'UpdateOne',
|
|
264
|
-
'ReplaceOne',
|
|
265
|
-
'DuplicateMany',
|
|
266
|
-
'DuplicateOne',
|
|
267
|
-
'DeleteMany',
|
|
268
|
-
'DeleteOne',
|
|
269
|
-
],
|
|
270
|
-
excluded: [],
|
|
271
|
-
},
|
|
272
|
-
});
|
|
273
|
-
});
|
|
274
|
-
it('should throw an unauthorized exception if access token is expired', async () => {
|
|
275
|
-
await (0, utils_1.wait)(5000);
|
|
276
|
-
const headers = { Authorization: `Bearer ${token}` };
|
|
277
|
-
const { body, status } = await e2e_setup_1.server.get('/auth/account', { headers });
|
|
278
|
-
expect(status).toBe(401);
|
|
279
|
-
expect(body).toEqual({
|
|
280
|
-
message: 'Unauthorized',
|
|
281
|
-
statusCode: 401,
|
|
282
|
-
});
|
|
283
|
-
}, 6000);
|
|
284
|
-
it('should throw an unauthorized exception if secret is invalid', async () => {
|
|
285
|
-
const invalidToken = jwtService.sign({ email: 'u', password: 'p' }, { secret: 'invalid-secret' });
|
|
286
|
-
const headers = { Authorization: `Bearer ${invalidToken}` };
|
|
287
|
-
const { body, status } = await e2e_setup_1.server.get('/auth/account', { headers });
|
|
288
|
-
expect(status).toBe(401);
|
|
289
|
-
expect(body).toEqual({
|
|
290
|
-
message: 'Unauthorized',
|
|
291
|
-
statusCode: 401,
|
|
292
|
-
});
|
|
293
|
-
});
|
|
294
|
-
});
|
|
295
|
-
describe('useAuth with validation options', () => {
|
|
296
|
-
let app;
|
|
297
|
-
let UserEntity = class UserEntity extends src_1.BaseEntity {
|
|
298
|
-
};
|
|
299
|
-
__decorate([
|
|
300
|
-
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
301
|
-
(0, class_validator_1.IsEmail)(),
|
|
302
|
-
__metadata("design:type", String)
|
|
303
|
-
], UserEntity.prototype, "email", void 0);
|
|
304
|
-
__decorate([
|
|
305
|
-
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
306
|
-
(0, class_validator_1.IsStrongPassword)({
|
|
307
|
-
minLength: 6,
|
|
308
|
-
minLowercase: 1,
|
|
309
|
-
minUppercase: 1,
|
|
310
|
-
minNumbers: 1,
|
|
311
|
-
minSymbols: 1,
|
|
312
|
-
}),
|
|
313
|
-
__metadata("design:type", String)
|
|
314
|
-
], UserEntity.prototype, "password", void 0);
|
|
315
|
-
UserEntity = __decorate([
|
|
316
|
-
(0, mongoose_1.Schema)({ collection: 'users' })
|
|
317
|
-
], UserEntity);
|
|
318
|
-
beforeEach(async () => {
|
|
319
|
-
app = await initModule({
|
|
320
|
-
useAuth: {
|
|
321
|
-
userEntity: UserEntity,
|
|
322
|
-
validationPipeOptions: {
|
|
323
|
-
whitelist: true,
|
|
324
|
-
forbidNonWhitelisted: true,
|
|
325
|
-
transform: true,
|
|
326
|
-
},
|
|
327
|
-
},
|
|
201
|
+
describe('GET /auth/account', () => {
|
|
202
|
+
it('should throw an unauthorized exception if access token is missing', async () => {
|
|
203
|
+
const { body, status } = await e2e_setup_1.server.get('/auth/account');
|
|
204
|
+
expect(status).toBe(401);
|
|
205
|
+
expect(body).toEqual({
|
|
206
|
+
message: 'Unauthorized',
|
|
207
|
+
statusCode: 401,
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
it('should return user account', async () => {
|
|
211
|
+
await e2e_setup_1.server.post('/auth/register', { email: 'unit@test.co', password: 'test' });
|
|
212
|
+
const { body: { accessToken } } = await e2e_setup_1.server.post('/auth/login', { email: 'unit@test.co', password: 'test' });
|
|
213
|
+
const headers = { Authorization: `Bearer ${accessToken}` };
|
|
214
|
+
const { body: account, status: accountStatus } = await e2e_setup_1.server.get('/auth/account', { headers });
|
|
215
|
+
expect(accountStatus).toBe(200);
|
|
216
|
+
expect(account).toEqual({ id: expect.any(String), email: 'unit@test.co' });
|
|
217
|
+
});
|
|
328
218
|
});
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
const { body, status } = await e2e_setup_1.server.post('/auth/register', { email: 'unit@test.co', password: 'Test-2', role: 'ADMIN' });
|
|
333
|
-
expect(status).toBe(400);
|
|
219
|
+
it('should throw a Service Unavailable exception when requesting reset password endpoint if reset password options are not configured', async () => {
|
|
220
|
+
const { body, status } = await e2e_setup_1.server.post('/auth/reset-password', { email: 'toto@test.co' });
|
|
221
|
+
expect(status).toBe(503);
|
|
334
222
|
expect(body).toEqual({
|
|
335
|
-
error: '
|
|
336
|
-
message:
|
|
337
|
-
statusCode:
|
|
223
|
+
error: 'Service Unavailable',
|
|
224
|
+
message: 'This feature is not available',
|
|
225
|
+
statusCode: 503,
|
|
338
226
|
});
|
|
339
227
|
});
|
|
340
|
-
it('should throw a
|
|
341
|
-
const { body, status } = await e2e_setup_1.server.
|
|
342
|
-
expect(status).toBe(
|
|
228
|
+
it('should throw a Service Unavailable exception when requesting change password endpoint if reset password options are not configured', async () => {
|
|
229
|
+
const { body, status } = await e2e_setup_1.server.patch('/auth/change-password', { newPassword: 'test' });
|
|
230
|
+
expect(status).toBe(503);
|
|
343
231
|
expect(body).toEqual({
|
|
344
|
-
error: '
|
|
345
|
-
message:
|
|
346
|
-
|
|
347
|
-
'password is not strong enough',
|
|
348
|
-
],
|
|
349
|
-
statusCode: 400,
|
|
232
|
+
error: 'Service Unavailable',
|
|
233
|
+
message: 'This feature is not available',
|
|
234
|
+
statusCode: 503,
|
|
350
235
|
});
|
|
351
236
|
});
|
|
352
|
-
it('should create a new user and return access token if the validation was successful', async () => {
|
|
353
|
-
const { body, status } = await e2e_setup_1.server.post('/auth/register', { email: 'unit@test.co', password: 'Test-2' });
|
|
354
|
-
expect(status).toBe(201);
|
|
355
|
-
expect(body).toEqual({ accessToken: expect.any(String) });
|
|
356
|
-
});
|
|
357
237
|
});
|
|
358
|
-
describe('
|
|
238
|
+
describe('useAuth with jwt options', () => {
|
|
239
|
+
let jwtService;
|
|
240
|
+
let token;
|
|
241
|
+
let app;
|
|
242
|
+
let UserEntity = class UserEntity extends src_1.BaseEntity {
|
|
243
|
+
};
|
|
244
|
+
__decorate([
|
|
245
|
+
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
246
|
+
__metadata("design:type", String)
|
|
247
|
+
], UserEntity.prototype, "email", void 0);
|
|
248
|
+
__decorate([
|
|
249
|
+
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
250
|
+
__metadata("design:type", String)
|
|
251
|
+
], UserEntity.prototype, "password", void 0);
|
|
252
|
+
UserEntity = __decorate([
|
|
253
|
+
(0, mongoose_1.Schema)({ collection: 'users' })
|
|
254
|
+
], UserEntity);
|
|
359
255
|
beforeEach(async () => {
|
|
360
|
-
await
|
|
256
|
+
app = await initModule({
|
|
257
|
+
useAuth: {
|
|
258
|
+
userEntity: UserEntity,
|
|
259
|
+
jwt: {
|
|
260
|
+
secret: 'test-secret',
|
|
261
|
+
expiresIn: '4s',
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
});
|
|
265
|
+
jwtService = app.get(jwt_1.JwtService);
|
|
266
|
+
const { body: { accessToken } } = await e2e_setup_1.server.post('/auth/register', { email: 'unit@test.co', password: 'test' });
|
|
267
|
+
token = accessToken;
|
|
361
268
|
});
|
|
362
|
-
it('should
|
|
363
|
-
|
|
364
|
-
expect(
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
269
|
+
it('should initialize dynamic api module state and authentication API with jwt options', async () => {
|
|
270
|
+
expect(app).toBeDefined();
|
|
271
|
+
expect(src_1.DynamicApiModule.state.get()).toStrictEqual({
|
|
272
|
+
uri,
|
|
273
|
+
initialized: true,
|
|
274
|
+
isGlobalCacheEnabled: true,
|
|
275
|
+
connectionName: 'dynamic-api-connection',
|
|
276
|
+
cacheExcludedPaths: [],
|
|
277
|
+
credentials: {
|
|
278
|
+
loginField: 'email',
|
|
279
|
+
passwordField: 'password',
|
|
280
|
+
},
|
|
281
|
+
isAuthEnabled: true,
|
|
282
|
+
jwtExpirationTime: '4s',
|
|
283
|
+
jwtSecret: 'test-secret',
|
|
284
|
+
routesConfig: {
|
|
285
|
+
defaults: [
|
|
286
|
+
'GetMany',
|
|
287
|
+
'GetOne',
|
|
288
|
+
'CreateMany',
|
|
289
|
+
'CreateOne',
|
|
290
|
+
'UpdateMany',
|
|
291
|
+
'UpdateOne',
|
|
292
|
+
'ReplaceOne',
|
|
293
|
+
'DuplicateMany',
|
|
294
|
+
'DuplicateOne',
|
|
295
|
+
'DeleteMany',
|
|
296
|
+
'DeleteOne',
|
|
297
|
+
],
|
|
298
|
+
excluded: [],
|
|
299
|
+
},
|
|
300
|
+
gatewayOptions: undefined,
|
|
369
301
|
});
|
|
370
302
|
});
|
|
371
|
-
it('should throw an unauthorized exception if
|
|
372
|
-
|
|
303
|
+
it('should throw an unauthorized exception if access token is expired', async () => {
|
|
304
|
+
await (0, utils_1.wait)(5000);
|
|
305
|
+
const headers = { Authorization: `Bearer ${token}` };
|
|
306
|
+
const { body, status } = await e2e_setup_1.server.get('/auth/account', { headers });
|
|
373
307
|
expect(status).toBe(401);
|
|
374
308
|
expect(body).toEqual({
|
|
375
309
|
message: 'Unauthorized',
|
|
376
310
|
statusCode: 401,
|
|
377
311
|
});
|
|
378
|
-
});
|
|
379
|
-
it('should throw an unauthorized exception if
|
|
380
|
-
const
|
|
312
|
+
}, 6000);
|
|
313
|
+
it('should throw an unauthorized exception if secret is invalid', async () => {
|
|
314
|
+
const invalidToken = jwtService.sign({ email: 'u', password: 'p' }, { secret: 'invalid-secret' });
|
|
315
|
+
const headers = { Authorization: `Bearer ${invalidToken}` };
|
|
316
|
+
const { body, status } = await e2e_setup_1.server.get('/auth/account', { headers });
|
|
381
317
|
expect(status).toBe(401);
|
|
382
318
|
expect(body).toEqual({
|
|
383
319
|
message: 'Unauthorized',
|
|
384
320
|
statusCode: 401,
|
|
385
321
|
});
|
|
386
322
|
});
|
|
387
|
-
it('should return access token if the validation was successful', async () => {
|
|
388
|
-
await e2e_setup_1.server.post('/auth/register', { email: 'unit@test.co', password: 'test' });
|
|
389
|
-
const { body, status } = await e2e_setup_1.server.post('/auth/login', { email: 'unit@test.co', password: 'Test-2' });
|
|
390
|
-
expect(status).toBe(200);
|
|
391
|
-
expect(body).toEqual({ accessToken: expect.any(String) });
|
|
392
|
-
});
|
|
393
323
|
});
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
constructor() {
|
|
398
|
-
super(...arguments);
|
|
399
|
-
this.role = 'user';
|
|
400
|
-
}
|
|
401
|
-
};
|
|
402
|
-
__decorate([
|
|
403
|
-
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
404
|
-
__metadata("design:type", String)
|
|
405
|
-
], User.prototype, "email", void 0);
|
|
406
|
-
__decorate([
|
|
407
|
-
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
408
|
-
__metadata("design:type", String)
|
|
409
|
-
], User.prototype, "password", void 0);
|
|
410
|
-
__decorate([
|
|
411
|
-
(0, mongoose_1.Prop)({ type: String, default: 'user' }),
|
|
412
|
-
__metadata("design:type", String)
|
|
413
|
-
], User.prototype, "role", void 0);
|
|
414
|
-
__decorate([
|
|
415
|
-
(0, mongoose_1.Prop)({ type: Boolean, default: false }),
|
|
416
|
-
__metadata("design:type", Boolean)
|
|
417
|
-
], User.prototype, "isVerified", void 0);
|
|
418
|
-
User = __decorate([
|
|
419
|
-
(0, mongoose_1.Schema)({ collection: 'users' })
|
|
420
|
-
], User);
|
|
421
|
-
const admin = { email: 'admin@test.co', password: 'admin', role: 'admin', isVerified: true };
|
|
422
|
-
const user = { email: 'user@test.co', password: 'user' };
|
|
423
|
-
beforeEach(async () => {
|
|
424
|
-
const bcryptService = new src_1.BcryptService();
|
|
425
|
-
const fixtures = async (_) => {
|
|
426
|
-
const model = await (0, utils_1.getModelFromEntity)(User);
|
|
427
|
-
await model.insertMany([
|
|
428
|
-
{ ...admin, password: await bcryptService.hashPassword(admin.password) },
|
|
429
|
-
{ ...user, password: await bcryptService.hashPassword(user.password) },
|
|
430
|
-
]);
|
|
324
|
+
describe('useAuth with validation options', () => {
|
|
325
|
+
let app;
|
|
326
|
+
let UserEntity = class UserEntity extends src_1.BaseEntity {
|
|
431
327
|
};
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
328
|
+
__decorate([
|
|
329
|
+
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
330
|
+
(0, class_validator_1.IsEmail)(),
|
|
331
|
+
__metadata("design:type", String)
|
|
332
|
+
], UserEntity.prototype, "email", void 0);
|
|
333
|
+
__decorate([
|
|
334
|
+
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
335
|
+
(0, class_validator_1.IsStrongPassword)({
|
|
336
|
+
minLength: 6,
|
|
337
|
+
minLowercase: 1,
|
|
338
|
+
minUppercase: 1,
|
|
339
|
+
minNumbers: 1,
|
|
340
|
+
minSymbols: 1,
|
|
341
|
+
}),
|
|
342
|
+
__metadata("design:type", String)
|
|
343
|
+
], UserEntity.prototype, "password", void 0);
|
|
344
|
+
UserEntity = __decorate([
|
|
345
|
+
(0, mongoose_1.Schema)({ collection: 'users' })
|
|
346
|
+
], UserEntity);
|
|
347
|
+
beforeEach(async () => {
|
|
348
|
+
app = await initModule({
|
|
349
|
+
useAuth: {
|
|
350
|
+
userEntity: UserEntity,
|
|
351
|
+
validationPipeOptions: {
|
|
352
|
+
whitelist: true,
|
|
353
|
+
forbidNonWhitelisted: true,
|
|
354
|
+
transform: true,
|
|
444
355
|
},
|
|
445
356
|
},
|
|
446
|
-
login: {
|
|
447
|
-
additionalFields: ['role', 'isVerified'],
|
|
448
|
-
},
|
|
449
|
-
},
|
|
450
|
-
}, fixtures);
|
|
451
|
-
});
|
|
452
|
-
describe('protected', () => {
|
|
453
|
-
it('should throw an unauthorized exception if user is not logged in and protected is true', async () => {
|
|
454
|
-
const { body, status } = await e2e_setup_1.server.post('/auth/register', { email: 'unit@test.co', password: 'test' });
|
|
455
|
-
expect(status).toBe(401);
|
|
456
|
-
expect(body).toEqual({
|
|
457
|
-
message: 'Unauthorized',
|
|
458
|
-
statusCode: 401,
|
|
459
357
|
});
|
|
460
358
|
});
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
359
|
+
describe('POST /auth/register', () => {
|
|
360
|
+
it('should throw a bad request exception if payload contains non whitelisted property', async () => {
|
|
361
|
+
const { body, status } = await e2e_setup_1.server.post('/auth/register', { email: 'unit@test.co', password: 'Test-2', role: 'ADMIN' });
|
|
362
|
+
expect(status).toBe(400);
|
|
363
|
+
expect(body).toEqual({
|
|
364
|
+
error: 'Bad Request',
|
|
365
|
+
message: ['property role should not exist'],
|
|
366
|
+
statusCode: 400,
|
|
367
|
+
});
|
|
368
|
+
});
|
|
369
|
+
it('should throw a bad request exception if validation fails', async () => {
|
|
370
|
+
const { body, status } = await e2e_setup_1.server.post('/auth/register', { email: 'unit.test.co', password: 'test-2' });
|
|
371
|
+
expect(status).toBe(400);
|
|
372
|
+
expect(body).toEqual({
|
|
373
|
+
error: 'Bad Request',
|
|
374
|
+
message: [
|
|
375
|
+
'email must be an email',
|
|
376
|
+
'password is not strong enough',
|
|
377
|
+
],
|
|
378
|
+
statusCode: 400,
|
|
379
|
+
});
|
|
380
|
+
});
|
|
381
|
+
it('should create a new user and return access token if the validation was successful', async () => {
|
|
382
|
+
const { body, status } = await e2e_setup_1.server.post('/auth/register', { email: 'unit@test.co', password: 'Test-2' });
|
|
383
|
+
expect(status).toBe(201);
|
|
384
|
+
expect(body).toEqual({ accessToken: expect.any(String) });
|
|
474
385
|
});
|
|
475
386
|
});
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
387
|
+
describe('POST /auth/login', () => {
|
|
388
|
+
beforeEach(async () => {
|
|
389
|
+
await e2e_setup_1.server.post('/auth/register', { email: 'unit@test.co', password: 'Test-2' });
|
|
390
|
+
});
|
|
391
|
+
it('should throw an unauthorized exception if payload contains non whitelisted property', async () => {
|
|
392
|
+
const { body, status } = await e2e_setup_1.server.post('/auth/login', { email: 'unit@test.co', password: 'Test-2', role: 'ADMIN' });
|
|
393
|
+
expect(status).toBe(400);
|
|
394
|
+
expect(body).toEqual({
|
|
395
|
+
error: 'Bad Request',
|
|
396
|
+
message: ['property role should not exist'],
|
|
397
|
+
statusCode: 400,
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
it('should throw an unauthorized exception if email is missing', async () => {
|
|
401
|
+
const { body, status } = await e2e_setup_1.server.post('/auth/login', { password: 'Test-2' });
|
|
402
|
+
expect(status).toBe(401);
|
|
403
|
+
expect(body).toEqual({
|
|
404
|
+
message: 'Unauthorized',
|
|
405
|
+
statusCode: 401,
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
it('should throw an unauthorized exception if password is missing', async () => {
|
|
409
|
+
const { body, status } = await e2e_setup_1.server.post('/auth/login', { email: 'unit@test.co' });
|
|
410
|
+
expect(status).toBe(401);
|
|
411
|
+
expect(body).toEqual({
|
|
412
|
+
message: 'Unauthorized',
|
|
413
|
+
statusCode: 401,
|
|
414
|
+
});
|
|
415
|
+
});
|
|
416
|
+
it('should return access token if the validation was successful', async () => {
|
|
417
|
+
await e2e_setup_1.server.post('/auth/register', { email: 'unit@test.co', password: 'test' });
|
|
418
|
+
const { body, status } = await e2e_setup_1.server.post('/auth/login', { email: 'unit@test.co', password: 'Test-2' });
|
|
419
|
+
expect(status).toBe(200);
|
|
420
|
+
expect(body).toEqual({ accessToken: expect.any(String) });
|
|
421
|
+
});
|
|
484
422
|
});
|
|
485
423
|
});
|
|
486
|
-
describe('
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
424
|
+
describe('POST /auth/register with register options', () => {
|
|
425
|
+
let User = class User extends src_1.BaseEntity {
|
|
426
|
+
constructor() {
|
|
427
|
+
super(...arguments);
|
|
428
|
+
this.role = 'user';
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
__decorate([
|
|
432
|
+
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
433
|
+
__metadata("design:type", String)
|
|
434
|
+
], User.prototype, "email", void 0);
|
|
435
|
+
__decorate([
|
|
436
|
+
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
437
|
+
__metadata("design:type", String)
|
|
438
|
+
], User.prototype, "password", void 0);
|
|
439
|
+
__decorate([
|
|
440
|
+
(0, mongoose_1.Prop)({ type: String, default: 'user' }),
|
|
441
|
+
__metadata("design:type", String)
|
|
442
|
+
], User.prototype, "role", void 0);
|
|
443
|
+
__decorate([
|
|
444
|
+
(0, mongoose_1.Prop)({ type: Boolean, default: false }),
|
|
445
|
+
__metadata("design:type", Boolean)
|
|
446
|
+
], User.prototype, "isVerified", void 0);
|
|
447
|
+
User = __decorate([
|
|
448
|
+
(0, mongoose_1.Schema)({ collection: 'users' })
|
|
449
|
+
], User);
|
|
450
|
+
const admin = { email: 'admin@test.co', password: 'admin', role: 'admin', isVerified: true };
|
|
451
|
+
const user = { email: 'user@test.co', password: 'user' };
|
|
452
|
+
beforeEach(async () => {
|
|
453
|
+
const bcryptService = new src_1.BcryptService();
|
|
454
|
+
const fixtures = async (_) => {
|
|
455
|
+
const model = await (0, utils_1.getModelFromEntity)(User);
|
|
456
|
+
await model.insertMany([
|
|
457
|
+
{ ...admin, password: await bcryptService.hashPassword(admin.password) },
|
|
458
|
+
{ ...user, password: await bcryptService.hashPassword(user.password) },
|
|
459
|
+
]);
|
|
460
|
+
};
|
|
461
|
+
await initModule({
|
|
462
|
+
useAuth: {
|
|
463
|
+
userEntity: User,
|
|
464
|
+
register: {
|
|
465
|
+
protected: true,
|
|
466
|
+
abilityPredicate: (user) => user.isVerified,
|
|
467
|
+
additionalFields: ['role'],
|
|
468
|
+
callback: async (user, { updateOneDocument }) => {
|
|
469
|
+
if (user.role !== 'admin') {
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
await updateOneDocument(User, { _id: user.id }, { $set: { isVerified: true } });
|
|
473
|
+
},
|
|
474
|
+
},
|
|
475
|
+
login: {
|
|
476
|
+
additionalFields: ['role', 'isVerified'],
|
|
477
|
+
},
|
|
478
|
+
},
|
|
479
|
+
}, fixtures);
|
|
495
480
|
});
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
481
|
+
describe('protected', () => {
|
|
482
|
+
it('should throw an unauthorized exception if user is not logged in and protected is true', async () => {
|
|
483
|
+
const { body, status } = await e2e_setup_1.server.post('/auth/register', { email: 'unit@test.co', password: 'test' });
|
|
484
|
+
expect(status).toBe(401);
|
|
485
|
+
expect(body).toEqual({
|
|
486
|
+
message: 'Unauthorized',
|
|
487
|
+
statusCode: 401,
|
|
488
|
+
});
|
|
489
|
+
});
|
|
490
|
+
});
|
|
491
|
+
describe('abilityPredicate', () => {
|
|
492
|
+
it('should not create a new user if user is not verified', async () => {
|
|
493
|
+
const { email, password } = user;
|
|
494
|
+
const { body: { accessToken } } = await e2e_setup_1.server.post('/auth/login', { email, password });
|
|
495
|
+
const { body, status } = await e2e_setup_1.server.post('/auth/register', { email: 'unit@test.co', password: 'test' }, {
|
|
496
|
+
headers: { Authorization: `Bearer ${accessToken}` },
|
|
497
|
+
});
|
|
498
|
+
expect(status).toBe(403);
|
|
499
|
+
expect(body).toEqual({
|
|
500
|
+
error: 'Forbidden',
|
|
501
|
+
message: 'Access denied',
|
|
502
|
+
statusCode: 403,
|
|
503
|
+
});
|
|
504
|
+
});
|
|
505
|
+
it('should create a new user and return access token if user is verified', async () => {
|
|
506
|
+
const { email, password } = admin;
|
|
507
|
+
const { body: { accessToken } } = await e2e_setup_1.server.post('/auth/login', { email, password });
|
|
508
|
+
const { body, status } = await e2e_setup_1.server.post('/auth/register', { email: 'unit@test.co', password: 'test' }, {
|
|
509
|
+
headers: { Authorization: `Bearer ${accessToken}` },
|
|
510
|
+
});
|
|
511
|
+
expect(status).toBe(201);
|
|
512
|
+
expect(body).toEqual({ accessToken: expect.any(String) });
|
|
513
|
+
});
|
|
507
514
|
});
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
515
|
+
describe('additionalFields', () => {
|
|
516
|
+
it('should allow to register a new user with additional fields', async () => {
|
|
517
|
+
const { email, password } = admin;
|
|
518
|
+
const { body: { accessToken } } = await e2e_setup_1.server.post('/auth/login', { email, password });
|
|
519
|
+
const { body, status } = await e2e_setup_1.server.post('/auth/register', { email: 'client@test.co', password: 'client', role: 'client' }, {
|
|
520
|
+
headers: { Authorization: `Bearer ${accessToken}` },
|
|
521
|
+
});
|
|
522
|
+
expect(status).toBe(201);
|
|
523
|
+
expect(body).toEqual({ accessToken: expect.any(String) });
|
|
524
|
+
});
|
|
525
|
+
});
|
|
526
|
+
describe('callback', () => {
|
|
527
|
+
it('should not set isVerified to true if role is not admin', async () => {
|
|
528
|
+
const { email, password } = admin;
|
|
529
|
+
const { body: loginBody } = await e2e_setup_1.server.post('/auth/login', { email, password });
|
|
530
|
+
const { body: { accessToken } } = await e2e_setup_1.server.post('/auth/register', { email: 'client@test.co', password: 'client', role: 'client' }, {
|
|
531
|
+
headers: { Authorization: `Bearer ${loginBody.accessToken}` },
|
|
532
|
+
});
|
|
533
|
+
const { body, status } = await e2e_setup_1.server.get('/auth/account', { headers: { Authorization: `Bearer ${accessToken}` } });
|
|
534
|
+
expect(status).toBe(200);
|
|
535
|
+
expect(body).toHaveProperty('isVerified', false);
|
|
536
|
+
});
|
|
537
|
+
it('should set isVerified to true if role is admin', async () => {
|
|
538
|
+
const { email, password } = admin;
|
|
539
|
+
const { body: loginBody } = await e2e_setup_1.server.post('/auth/login', { email, password });
|
|
540
|
+
const { body: { accessToken } } = await e2e_setup_1.server.post('/auth/register', { email: 'admin2@test.co', password: 'admin2', role: 'admin' }, {
|
|
541
|
+
headers: { Authorization: `Bearer ${loginBody.accessToken}` },
|
|
542
|
+
});
|
|
543
|
+
const { body, status } = await e2e_setup_1.server.get('/auth/account', { headers: { Authorization: `Bearer ${accessToken}` } });
|
|
544
|
+
expect(status).toBe(200);
|
|
545
|
+
expect(body).toHaveProperty('isVerified', true);
|
|
546
|
+
});
|
|
517
547
|
});
|
|
518
548
|
});
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
}
|
|
526
|
-
};
|
|
527
|
-
__decorate([
|
|
528
|
-
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
529
|
-
__metadata("design:type", String)
|
|
530
|
-
], User.prototype, "username", void 0);
|
|
531
|
-
__decorate([
|
|
532
|
-
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
533
|
-
__metadata("design:type", String)
|
|
534
|
-
], User.prototype, "pass", void 0);
|
|
535
|
-
__decorate([
|
|
536
|
-
(0, mongoose_1.Prop)({ type: String, default: 'user' }),
|
|
537
|
-
__metadata("design:type", String)
|
|
538
|
-
], User.prototype, "role", void 0);
|
|
539
|
-
__decorate([
|
|
540
|
-
(0, mongoose_1.Prop)({ type: Boolean, default: false }),
|
|
541
|
-
__metadata("design:type", Boolean)
|
|
542
|
-
], User.prototype, "isVerified", void 0);
|
|
543
|
-
User = __decorate([
|
|
544
|
-
(0, mongoose_1.Schema)({ collection: 'users' })
|
|
545
|
-
], User);
|
|
546
|
-
const admin = { username: 'admin', pass: 'admin', role: 'admin', isVerified: true };
|
|
547
|
-
const user = { username: 'user', pass: 'user' };
|
|
548
|
-
const client = { username: 'client', pass: 'client', role: 'client', isVerified: true };
|
|
549
|
-
beforeEach(async () => {
|
|
550
|
-
const bcryptService = new src_1.BcryptService();
|
|
551
|
-
const fixtures = async (_) => {
|
|
552
|
-
const model = await (0, utils_1.getModelFromEntity)(User);
|
|
553
|
-
await model.insertMany([
|
|
554
|
-
{ ...admin, pass: await bcryptService.hashPassword(admin.pass) },
|
|
555
|
-
{ ...user, pass: await bcryptService.hashPassword(user.pass) },
|
|
556
|
-
{ ...client, pass: await bcryptService.hashPassword(client.pass) },
|
|
557
|
-
]);
|
|
549
|
+
describe('POST /auth/login with login options', () => {
|
|
550
|
+
let User = class User extends src_1.BaseEntity {
|
|
551
|
+
constructor() {
|
|
552
|
+
super(...arguments);
|
|
553
|
+
this.role = 'user';
|
|
554
|
+
}
|
|
558
555
|
};
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
556
|
+
__decorate([
|
|
557
|
+
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
558
|
+
__metadata("design:type", String)
|
|
559
|
+
], User.prototype, "username", void 0);
|
|
560
|
+
__decorate([
|
|
561
|
+
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
562
|
+
__metadata("design:type", String)
|
|
563
|
+
], User.prototype, "pass", void 0);
|
|
564
|
+
__decorate([
|
|
565
|
+
(0, mongoose_1.Prop)({ type: String, default: 'user' }),
|
|
566
|
+
__metadata("design:type", String)
|
|
567
|
+
], User.prototype, "role", void 0);
|
|
568
|
+
__decorate([
|
|
569
|
+
(0, mongoose_1.Prop)({ type: Boolean, default: false }),
|
|
570
|
+
__metadata("design:type", Boolean)
|
|
571
|
+
], User.prototype, "isVerified", void 0);
|
|
572
|
+
User = __decorate([
|
|
573
|
+
(0, mongoose_1.Schema)({ collection: 'users' })
|
|
574
|
+
], User);
|
|
575
|
+
const admin = { username: 'admin', pass: 'admin', role: 'admin', isVerified: true };
|
|
576
|
+
const user = { username: 'user', pass: 'user' };
|
|
577
|
+
const client = { username: 'client', pass: 'client', role: 'client', isVerified: true };
|
|
578
|
+
beforeEach(async () => {
|
|
579
|
+
const bcryptService = new src_1.BcryptService();
|
|
580
|
+
const fixtures = async (_) => {
|
|
581
|
+
const model = await (0, utils_1.getModelFromEntity)(User);
|
|
582
|
+
await model.insertMany([
|
|
583
|
+
{ ...admin, pass: await bcryptService.hashPassword(admin.pass) },
|
|
584
|
+
{ ...user, pass: await bcryptService.hashPassword(user.pass) },
|
|
585
|
+
{ ...client, pass: await bcryptService.hashPassword(client.pass) },
|
|
586
|
+
]);
|
|
587
|
+
};
|
|
588
|
+
await initModule({
|
|
589
|
+
useAuth: {
|
|
590
|
+
userEntity: User,
|
|
591
|
+
login: {
|
|
592
|
+
loginField: 'username',
|
|
593
|
+
passwordField: 'pass',
|
|
594
|
+
additionalFields: ['role', 'isVerified'],
|
|
595
|
+
abilityPredicate: (user) => user.role === 'admin' || user.role === 'user',
|
|
596
|
+
callback: async (user) => {
|
|
597
|
+
if (user.isVerified) {
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
throw new common_1.UnauthorizedException(`Hello ${user.username}, you must verify your account first!`);
|
|
601
|
+
},
|
|
572
602
|
},
|
|
573
603
|
},
|
|
574
|
-
},
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
604
|
+
}, fixtures);
|
|
605
|
+
});
|
|
606
|
+
describe('loginField', () => {
|
|
607
|
+
it('should throw an unauthorized exception if loginField is missing', async () => {
|
|
608
|
+
const { body, status } = await e2e_setup_1.server.post('/auth/login', { pass: 'test' });
|
|
609
|
+
expect(status).toBe(401);
|
|
610
|
+
expect(body).toEqual({
|
|
611
|
+
message: 'Unauthorized',
|
|
612
|
+
statusCode: 401,
|
|
613
|
+
});
|
|
584
614
|
});
|
|
585
615
|
});
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
616
|
+
describe('passwordField', () => {
|
|
617
|
+
it('should throw an unauthorized exception if passwordField is missing', async () => {
|
|
618
|
+
const { body, status } = await e2e_setup_1.server.post('/auth/login', { username: 'unit' });
|
|
619
|
+
expect(status).toBe(401);
|
|
620
|
+
expect(body).toEqual({
|
|
621
|
+
message: 'Unauthorized',
|
|
622
|
+
statusCode: 401,
|
|
623
|
+
});
|
|
594
624
|
});
|
|
595
625
|
});
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
626
|
+
describe('abilityPredicate', () => {
|
|
627
|
+
it('should throw an forbidden exception if user role is not admin or user', async () => {
|
|
628
|
+
const { username, pass } = client;
|
|
629
|
+
const { body, status } = await e2e_setup_1.server.post('/auth/login', { username, pass });
|
|
630
|
+
expect(status).toBe(403);
|
|
631
|
+
expect(body).toEqual({
|
|
632
|
+
error: 'Forbidden',
|
|
633
|
+
message: 'Access denied',
|
|
634
|
+
statusCode: 403,
|
|
635
|
+
});
|
|
606
636
|
});
|
|
607
637
|
});
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
638
|
+
describe('callback', () => {
|
|
639
|
+
it('should throw an unauthorized exception if user is not verified', async () => {
|
|
640
|
+
const { username, pass } = user;
|
|
641
|
+
const { body, status } = await e2e_setup_1.server.post('/auth/login', { username, pass });
|
|
642
|
+
expect(status).toBe(401);
|
|
643
|
+
expect(body).toEqual({
|
|
644
|
+
error: 'Unauthorized',
|
|
645
|
+
message: `Hello ${username}, you must verify your account first!`,
|
|
646
|
+
statusCode: 401,
|
|
647
|
+
});
|
|
618
648
|
});
|
|
619
649
|
});
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
650
|
+
describe('additionalFields', () => {
|
|
651
|
+
it('should return additional fields', async () => {
|
|
652
|
+
const { username, pass } = admin;
|
|
653
|
+
const { body: { accessToken } } = await e2e_setup_1.server.post('/auth/login', { username, pass });
|
|
654
|
+
const { body, status } = await e2e_setup_1.server.get('/auth/account', { headers: { Authorization: `Bearer ${accessToken}` } });
|
|
655
|
+
expect(status).toBe(200);
|
|
656
|
+
expect(body).toEqual({ id: expect.any(String), username: 'admin', role: 'admin', isVerified: true });
|
|
657
|
+
});
|
|
628
658
|
});
|
|
629
659
|
});
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
let User = class User extends src_1.BaseEntity {
|
|
633
|
-
};
|
|
634
|
-
__decorate([
|
|
635
|
-
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
636
|
-
__metadata("design:type", String)
|
|
637
|
-
], User.prototype, "email", void 0);
|
|
638
|
-
__decorate([
|
|
639
|
-
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
640
|
-
__metadata("design:type", String)
|
|
641
|
-
], User.prototype, "password", void 0);
|
|
642
|
-
__decorate([
|
|
643
|
-
(0, mongoose_1.Prop)({ type: Boolean, default: false }),
|
|
644
|
-
__metadata("design:type", Boolean)
|
|
645
|
-
], User.prototype, "isVerified", void 0);
|
|
646
|
-
__decorate([
|
|
647
|
-
(0, mongoose_1.Prop)({ type: String }),
|
|
648
|
-
__metadata("design:type", String)
|
|
649
|
-
], User.prototype, "resetPasswordToken", void 0);
|
|
650
|
-
User = __decorate([
|
|
651
|
-
(0, mongoose_1.Schema)({ collection: 'users' })
|
|
652
|
-
], User);
|
|
653
|
-
let model;
|
|
654
|
-
let user;
|
|
655
|
-
let client;
|
|
656
|
-
let app;
|
|
657
|
-
beforeEach(async () => {
|
|
658
|
-
user = { email: 'user@test.co', password: 'user', isVerified: true };
|
|
659
|
-
client = { email: 'client@test.co', password: 'client' };
|
|
660
|
-
const bcryptService = new src_1.BcryptService();
|
|
661
|
-
const fixtures = async (_) => {
|
|
662
|
-
model = await (0, utils_1.getModelFromEntity)(User);
|
|
663
|
-
await model.insertMany([
|
|
664
|
-
{ ...user, password: await bcryptService.hashPassword(user.password) },
|
|
665
|
-
{ ...client, password: await bcryptService.hashPassword(client.password) },
|
|
666
|
-
]);
|
|
660
|
+
describe('useAuth with resetPassword options', () => {
|
|
661
|
+
let User = class User extends src_1.BaseEntity {
|
|
667
662
|
};
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
663
|
+
__decorate([
|
|
664
|
+
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
665
|
+
__metadata("design:type", String)
|
|
666
|
+
], User.prototype, "email", void 0);
|
|
667
|
+
__decorate([
|
|
668
|
+
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
669
|
+
__metadata("design:type", String)
|
|
670
|
+
], User.prototype, "password", void 0);
|
|
671
|
+
__decorate([
|
|
672
|
+
(0, mongoose_1.Prop)({ type: Boolean, default: false }),
|
|
673
|
+
__metadata("design:type", Boolean)
|
|
674
|
+
], User.prototype, "isVerified", void 0);
|
|
675
|
+
__decorate([
|
|
676
|
+
(0, mongoose_1.Prop)({ type: String }),
|
|
677
|
+
__metadata("design:type", String)
|
|
678
|
+
], User.prototype, "resetPasswordToken", void 0);
|
|
679
|
+
User = __decorate([
|
|
680
|
+
(0, mongoose_1.Schema)({ collection: 'users' })
|
|
681
|
+
], User);
|
|
682
|
+
let model;
|
|
683
|
+
let user;
|
|
684
|
+
let client;
|
|
685
|
+
let app;
|
|
686
|
+
beforeEach(async () => {
|
|
687
|
+
user = { email: 'user@test.co', password: 'user', isVerified: true };
|
|
688
|
+
client = { email: 'client@test.co', password: 'client' };
|
|
689
|
+
const bcryptService = new src_1.BcryptService();
|
|
690
|
+
const fixtures = async (_) => {
|
|
691
|
+
model = await (0, utils_1.getModelFromEntity)(User);
|
|
692
|
+
await model.insertMany([
|
|
693
|
+
{ ...user, password: await bcryptService.hashPassword(user.password) },
|
|
694
|
+
{ ...client, password: await bcryptService.hashPassword(client.password) },
|
|
695
|
+
]);
|
|
696
|
+
};
|
|
697
|
+
app = await initModule({
|
|
698
|
+
useAuth: {
|
|
699
|
+
userEntity: User,
|
|
700
|
+
resetPassword: {
|
|
701
|
+
emailField: 'email',
|
|
702
|
+
expirationInMinutes: 1,
|
|
703
|
+
resetPasswordCallback: async ({ resetPasswordToken }, { updateUserByEmail }) => {
|
|
704
|
+
await updateUserByEmail({ $set: { resetPasswordToken } });
|
|
705
|
+
},
|
|
706
|
+
changePasswordAbilityPredicate: (user) => user.isVerified && !!user.resetPasswordToken,
|
|
707
|
+
changePasswordCallback: async (user, { updateOneDocument }) => {
|
|
708
|
+
await updateOneDocument(User, { _id: user.id }, { $unset: { resetPasswordToken: 1 } });
|
|
709
|
+
},
|
|
680
710
|
},
|
|
681
711
|
},
|
|
682
|
-
},
|
|
683
|
-
}, fixtures);
|
|
684
|
-
});
|
|
685
|
-
describe('POST /auth/reset-password', () => {
|
|
686
|
-
it('should throw a bad request exception if email is missing', async () => {
|
|
687
|
-
const { body, status } = await e2e_setup_1.server.post('/auth/reset-password', {});
|
|
688
|
-
expect(status).toBe(400);
|
|
689
|
-
expect(body).toEqual({
|
|
690
|
-
error: 'Bad Request',
|
|
691
|
-
message: [
|
|
692
|
-
'email must be an email',
|
|
693
|
-
'email should not be empty',
|
|
694
|
-
'email must be a string',
|
|
695
|
-
],
|
|
696
|
-
statusCode: 400,
|
|
697
|
-
});
|
|
712
|
+
}, fixtures);
|
|
698
713
|
});
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
714
|
+
describe('POST /auth/reset-password', () => {
|
|
715
|
+
it('should throw a bad request exception if email is missing if no validation options are provided', async () => {
|
|
716
|
+
const { body, status } = await e2e_setup_1.server.post('/auth/reset-password', {});
|
|
717
|
+
expect(status).toBe(400);
|
|
718
|
+
expect(body).toEqual({
|
|
719
|
+
error: 'Bad Request',
|
|
720
|
+
message: 'Invalid or missing argument',
|
|
721
|
+
statusCode: 400,
|
|
722
|
+
});
|
|
723
|
+
});
|
|
724
|
+
it('should not throw a bad request exception if email is invalid if no validation options are provided', async () => {
|
|
725
|
+
const { body, status } = await e2e_setup_1.server.post('/auth/reset-password', { email: 'unit.test.co' });
|
|
726
|
+
expect(status).toBe(204);
|
|
727
|
+
expect(body).toEqual({});
|
|
728
|
+
});
|
|
729
|
+
it('should not throw an exception if email is not found', async () => {
|
|
730
|
+
const { body, status } = await e2e_setup_1.server.post('/auth/reset-password', { email: 'invalid@test.co' });
|
|
731
|
+
expect(status).toBe(204);
|
|
732
|
+
expect(body).toEqual({});
|
|
733
|
+
});
|
|
734
|
+
describe('resetPasswordCallback', () => {
|
|
735
|
+
it('should set resetPasswordToken if email is valid', async () => {
|
|
736
|
+
const { email } = user;
|
|
737
|
+
const { resetPasswordToken: resetPasswordTokenBeforeUpdate } = (await model.findOne({ email }).lean().exec());
|
|
738
|
+
const { status } = await e2e_setup_1.server.post('/auth/reset-password', { email });
|
|
739
|
+
const { resetPasswordToken: resetPasswordTokenAfterUpdate } = (await model.findOne({ email }).lean().exec());
|
|
740
|
+
expect(status).toBe(204);
|
|
741
|
+
expect(resetPasswordTokenBeforeUpdate).toStrictEqual(undefined);
|
|
742
|
+
expect(resetPasswordTokenAfterUpdate).toStrictEqual(expect.any(String));
|
|
743
|
+
});
|
|
706
744
|
});
|
|
707
745
|
});
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
746
|
+
describe('PATCH /auth/change-password', () => {
|
|
747
|
+
it('should throw a bad request exception if resetPasswordToken is missing', async () => {
|
|
748
|
+
const { body, status } = await e2e_setup_1.server.patch('/auth/change-password', { newPassword: 'test' });
|
|
749
|
+
expect(status).toBe(400);
|
|
750
|
+
expect(body).toEqual({
|
|
751
|
+
error: 'Bad Request',
|
|
752
|
+
message: 'Invalid or missing argument',
|
|
753
|
+
statusCode: 400,
|
|
754
|
+
});
|
|
755
|
+
});
|
|
756
|
+
it('should throw a bad request exception if newPassword is missing', async () => {
|
|
715
757
|
const { email } = user;
|
|
716
|
-
|
|
717
|
-
const { status } = await e2e_setup_1.server.post('/auth/reset-password', { email });
|
|
758
|
+
await e2e_setup_1.server.post('/auth/reset-password', { email });
|
|
718
759
|
const { resetPasswordToken: resetPasswordTokenAfterUpdate } = (await model.findOne({ email }).lean().exec());
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
expect(
|
|
760
|
+
const resetPasswordToken = resetPasswordTokenAfterUpdate;
|
|
761
|
+
const { body, status } = await e2e_setup_1.server.patch('/auth/change-password', { resetPasswordToken });
|
|
762
|
+
expect(status).toBe(400);
|
|
763
|
+
expect(body).toEqual({
|
|
764
|
+
error: 'Bad Request',
|
|
765
|
+
message: 'Invalid or missing argument',
|
|
766
|
+
statusCode: 400,
|
|
767
|
+
});
|
|
768
|
+
});
|
|
769
|
+
it('should throw an unauthorized exception if resetPasswordToken is invalid', async () => {
|
|
770
|
+
const { body, status } = await e2e_setup_1.server.patch('/auth/change-password', { resetPasswordToken: 'test', newPassword: 'newPassword' });
|
|
771
|
+
expect(status).toBe(400);
|
|
772
|
+
expect(body).toEqual({
|
|
773
|
+
error: 'Bad Request',
|
|
774
|
+
message: 'Invalid reset password token. Please redo the reset password process.',
|
|
775
|
+
statusCode: 400,
|
|
776
|
+
});
|
|
777
|
+
});
|
|
778
|
+
it('should throw an unauthorized exception if resetPasswordToken is expired', async () => {
|
|
779
|
+
const jwtService = app.get(jwt_1.JwtService);
|
|
780
|
+
const expiredResetPasswordToken = jwtService.sign({ email: user.email }, { expiresIn: 1 });
|
|
781
|
+
await (0, utils_1.wait)(500);
|
|
782
|
+
const { body, status } = await e2e_setup_1.server.patch('/auth/change-password', { resetPasswordToken: expiredResetPasswordToken, newPassword: 'newPassword' });
|
|
783
|
+
expect(status).toBe(401);
|
|
784
|
+
expect(body).toEqual({
|
|
785
|
+
error: 'Unauthorized',
|
|
786
|
+
message: 'Time to reset password has expired. Please redo the reset password process.',
|
|
787
|
+
statusCode: 401,
|
|
788
|
+
});
|
|
789
|
+
});
|
|
790
|
+
describe('changePasswordAbilityPredicate', () => {
|
|
791
|
+
let resetPasswordToken;
|
|
792
|
+
beforeEach(async () => {
|
|
793
|
+
await e2e_setup_1.server.post('/auth/reset-password', { email: client.email });
|
|
794
|
+
const { resetPasswordToken: token } = (await model.findOne({ email: client.email }).lean().exec());
|
|
795
|
+
resetPasswordToken = token;
|
|
796
|
+
});
|
|
797
|
+
it('should throw a forbidden exception if user is not allowed to change password', async () => {
|
|
798
|
+
expect(resetPasswordToken).toStrictEqual(expect.any(String));
|
|
799
|
+
const { body, status } = await e2e_setup_1.server.patch('/auth/change-password', { resetPasswordToken, newPassword: 'newPassword' });
|
|
800
|
+
expect(status).toBe(403);
|
|
801
|
+
expect(body).toEqual({
|
|
802
|
+
error: 'Forbidden',
|
|
803
|
+
message: 'You are not allowed to change your password.',
|
|
804
|
+
statusCode: 403,
|
|
805
|
+
});
|
|
806
|
+
});
|
|
807
|
+
});
|
|
808
|
+
describe('changePasswordCallback', () => {
|
|
809
|
+
let resetPasswordToken;
|
|
810
|
+
beforeEach(async () => {
|
|
811
|
+
await e2e_setup_1.server.post('/auth/reset-password', { email: user.email });
|
|
812
|
+
const { resetPasswordToken: token } = (await model.findOne({ email: user.email }).lean().exec());
|
|
813
|
+
resetPasswordToken = token;
|
|
814
|
+
});
|
|
815
|
+
it('should change password and unset resetPasswordToken if resetPasswordToken is valid', async () => {
|
|
816
|
+
expect(resetPasswordToken).toStrictEqual(expect.any(String));
|
|
817
|
+
const newPassword = 'newPassword';
|
|
818
|
+
const bcryptService = app.get(src_1.BcryptService);
|
|
819
|
+
const { password: passwordBeforeUpdate } = (await model.findOne({ email: user.email }).lean().exec());
|
|
820
|
+
const { status } = await e2e_setup_1.server.patch('/auth/change-password', { resetPasswordToken, newPassword });
|
|
821
|
+
const { password: passwordAfterUpdate, resetPasswordToken: tokenAfterUpdate } = (await model.findOne({ email: user.email }).lean().exec());
|
|
822
|
+
const isPreviousPassword = await bcryptService.comparePassword(user.password, passwordBeforeUpdate);
|
|
823
|
+
expect(isPreviousPassword).toBe(true);
|
|
824
|
+
const isNewPassword = await bcryptService.comparePassword(newPassword, passwordAfterUpdate);
|
|
825
|
+
expect(isNewPassword).toBe(true);
|
|
826
|
+
expect(status).toBe(204);
|
|
827
|
+
expect(tokenAfterUpdate).toStrictEqual(undefined);
|
|
828
|
+
});
|
|
722
829
|
});
|
|
723
830
|
});
|
|
724
831
|
});
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
832
|
+
});
|
|
833
|
+
describe('Websockets', () => {
|
|
834
|
+
it('should enable websockets globally', async () => {
|
|
835
|
+
await initModule({
|
|
836
|
+
webSocket: true,
|
|
837
|
+
}, undefined, async (app) => {
|
|
838
|
+
app.useWebSocketAdapter(new socket_adapter_1.SocketAdapter(app));
|
|
839
|
+
}, true);
|
|
840
|
+
expect(src_1.DynamicApiModule.state.get('gatewayOptions')).toStrictEqual({});
|
|
841
|
+
await e2e_setup_1.server.emit('test', { message: 'Hello' });
|
|
842
|
+
expect(e2e_setup_1.handleSocketResponse).toHaveBeenCalledTimes(1);
|
|
843
|
+
expect(e2e_setup_1.handleSocketResponse).toHaveBeenCalledWith({ message: 'Hello' });
|
|
844
|
+
expect(e2e_setup_1.handleSocketException).not.toHaveBeenCalled();
|
|
845
|
+
});
|
|
846
|
+
describe('Authentication EVENTS', () => {
|
|
847
|
+
describe('useAuth when only userEntity is provided', () => {
|
|
848
|
+
let UserEntity = class UserEntity extends src_1.BaseEntity {
|
|
849
|
+
};
|
|
850
|
+
__decorate([
|
|
851
|
+
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
852
|
+
__metadata("design:type", String)
|
|
853
|
+
], UserEntity.prototype, "email", void 0);
|
|
854
|
+
__decorate([
|
|
855
|
+
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
856
|
+
__metadata("design:type", String)
|
|
857
|
+
], UserEntity.prototype, "password", void 0);
|
|
858
|
+
UserEntity = __decorate([
|
|
859
|
+
(0, mongoose_1.Schema)({ collection: 'users' })
|
|
860
|
+
], UserEntity);
|
|
861
|
+
beforeEach(async () => {
|
|
862
|
+
await initModule({
|
|
863
|
+
useAuth: {
|
|
864
|
+
userEntity: UserEntity,
|
|
865
|
+
webSocket: true,
|
|
866
|
+
},
|
|
867
|
+
}, undefined, async (app) => {
|
|
868
|
+
app.useWebSocketAdapter(new socket_adapter_1.SocketAdapter(app));
|
|
869
|
+
});
|
|
736
870
|
});
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
871
|
+
describe('EVENT auth-register', () => {
|
|
872
|
+
it('should throw a ws exception if email is missing', async () => {
|
|
873
|
+
await e2e_setup_1.server.emit('auth-register', { username: 'unit-test', password: 'test-2' });
|
|
874
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledTimes(1);
|
|
875
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledWith({
|
|
876
|
+
message: ['email property is required'],
|
|
877
|
+
});
|
|
878
|
+
expect(e2e_setup_1.handleSocketResponse).not.toHaveBeenCalled();
|
|
879
|
+
});
|
|
880
|
+
it('should throw a ws exception if password is missing', async () => {
|
|
881
|
+
await e2e_setup_1.server.emit('auth-register', { email: 'unit@test.co', pass: 'test-2' });
|
|
882
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledTimes(1);
|
|
883
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledWith({
|
|
884
|
+
message: ['password property is required'],
|
|
885
|
+
});
|
|
886
|
+
expect(e2e_setup_1.handleSocketResponse).not.toHaveBeenCalled();
|
|
887
|
+
});
|
|
888
|
+
it('should create a new user and return access token', async () => {
|
|
889
|
+
await e2e_setup_1.server.emit('auth-register', { email: 'unit@test.co', password: 'test' });
|
|
890
|
+
expect(e2e_setup_1.handleSocketException).not.toHaveBeenCalled();
|
|
891
|
+
expect(e2e_setup_1.handleSocketResponse).toHaveBeenCalledTimes(1);
|
|
892
|
+
expect(e2e_setup_1.handleSocketResponse).toHaveBeenCalledWith({ accessToken: expect.any(String) });
|
|
893
|
+
});
|
|
752
894
|
});
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
895
|
+
describe('EVENT auth-login', () => {
|
|
896
|
+
it('should throw a ws exception if email is missing', async () => {
|
|
897
|
+
await e2e_setup_1.server.emit('auth-login', { password: 'test-2' });
|
|
898
|
+
expect(e2e_setup_1.handleSocketResponse).not.toHaveBeenCalled();
|
|
899
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledTimes(1);
|
|
900
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledWith({
|
|
901
|
+
message: 'Unauthorized',
|
|
902
|
+
});
|
|
903
|
+
});
|
|
904
|
+
it('should throw a ws exception if password is missing', async () => {
|
|
905
|
+
await e2e_setup_1.server.emit('auth-login', { email: 'unit@test.co' });
|
|
906
|
+
expect(e2e_setup_1.handleSocketResponse).not.toHaveBeenCalled();
|
|
907
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledTimes(1);
|
|
908
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledWith({
|
|
909
|
+
message: 'Unauthorized',
|
|
910
|
+
});
|
|
911
|
+
});
|
|
912
|
+
it('should return access token', async () => {
|
|
913
|
+
await e2e_setup_1.server.emit('auth-register', { email: 'unit@test.co', password: 'test' });
|
|
914
|
+
await e2e_setup_1.server.emit('auth-login', { email: 'unit@test.co', password: 'test' });
|
|
915
|
+
expect(e2e_setup_1.handleSocketException).not.toHaveBeenCalled();
|
|
916
|
+
expect(e2e_setup_1.handleSocketResponse).toHaveBeenCalledTimes(2);
|
|
917
|
+
expect(e2e_setup_1.handleSocketResponse).toHaveBeenNthCalledWith(2, { accessToken: expect.any(String) });
|
|
918
|
+
});
|
|
761
919
|
});
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
920
|
+
describe('EVENT auth-get-account', () => {
|
|
921
|
+
it('should throw a ws exception if access token is missing', async () => {
|
|
922
|
+
await e2e_setup_1.server.emit('auth-get-account');
|
|
923
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledTimes(1);
|
|
924
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledWith({
|
|
925
|
+
message: 'Unauthorized',
|
|
926
|
+
});
|
|
927
|
+
expect(e2e_setup_1.handleSocketResponse).not.toHaveBeenCalled();
|
|
928
|
+
});
|
|
929
|
+
it('should return user account', async () => {
|
|
930
|
+
const { accessToken } = await e2e_setup_1.server.emit('auth-register', { email: 'unit@test.co', password: 'test' });
|
|
931
|
+
await e2e_setup_1.server.emit('auth-get-account', undefined, { accessToken });
|
|
932
|
+
expect(e2e_setup_1.handleSocketException).not.toHaveBeenCalled();
|
|
933
|
+
expect(e2e_setup_1.handleSocketResponse).toHaveBeenCalledTimes(2);
|
|
934
|
+
expect(e2e_setup_1.handleSocketResponse).toHaveBeenNthCalledWith(1, { accessToken: expect.any(String) });
|
|
935
|
+
expect(e2e_setup_1.handleSocketResponse).toHaveBeenNthCalledWith(2, { email: 'unit@test.co', id: expect.any(String) });
|
|
936
|
+
});
|
|
937
|
+
});
|
|
938
|
+
it('should throw a ws exception when receiving reset password event if reset password options are not configured', async () => {
|
|
939
|
+
await e2e_setup_1.server.emit('auth-reset-password', { email: 'toto@test.co' });
|
|
940
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledTimes(1);
|
|
941
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledWith({
|
|
942
|
+
message: 'This feature is not available',
|
|
943
|
+
});
|
|
944
|
+
expect(e2e_setup_1.handleSocketResponse).not.toHaveBeenCalled();
|
|
945
|
+
});
|
|
946
|
+
it('should throw a ws exception when receiving change password event if reset password options are not configured', async () => {
|
|
947
|
+
await e2e_setup_1.server.emit('auth-change-password', { newPassword: 'test' });
|
|
948
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledTimes(1);
|
|
949
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledWith({
|
|
950
|
+
message: 'This feature is not available',
|
|
951
|
+
});
|
|
952
|
+
expect(e2e_setup_1.handleSocketResponse).not.toHaveBeenCalled();
|
|
773
953
|
});
|
|
774
954
|
});
|
|
775
|
-
describe('
|
|
776
|
-
let
|
|
955
|
+
describe('useAuth with jwt options', () => {
|
|
956
|
+
let jwtService;
|
|
957
|
+
let accessToken;
|
|
958
|
+
let app;
|
|
959
|
+
let UserEntity = class UserEntity extends src_1.BaseEntity {
|
|
960
|
+
};
|
|
961
|
+
__decorate([
|
|
962
|
+
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
963
|
+
__metadata("design:type", String)
|
|
964
|
+
], UserEntity.prototype, "email", void 0);
|
|
965
|
+
__decorate([
|
|
966
|
+
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
967
|
+
__metadata("design:type", String)
|
|
968
|
+
], UserEntity.prototype, "password", void 0);
|
|
969
|
+
UserEntity = __decorate([
|
|
970
|
+
(0, mongoose_1.Schema)({ collection: 'users' })
|
|
971
|
+
], UserEntity);
|
|
777
972
|
beforeEach(async () => {
|
|
778
|
-
await
|
|
779
|
-
|
|
780
|
-
|
|
973
|
+
app = await initModule({
|
|
974
|
+
useAuth: {
|
|
975
|
+
userEntity: UserEntity,
|
|
976
|
+
webSocket: true,
|
|
977
|
+
jwt: {
|
|
978
|
+
secret: 'test-secret',
|
|
979
|
+
expiresIn: '3s',
|
|
980
|
+
},
|
|
981
|
+
},
|
|
982
|
+
}, undefined, async (_) => {
|
|
983
|
+
_.useWebSocketAdapter(new socket_adapter_1.SocketAdapter(_));
|
|
984
|
+
});
|
|
985
|
+
jwtService = app.get(jwt_1.JwtService);
|
|
986
|
+
const { accessToken: token } = await e2e_setup_1.server.emit('auth-register', { email: 'unit@test.co', password: 'test' });
|
|
987
|
+
accessToken = token;
|
|
781
988
|
});
|
|
782
|
-
it('should
|
|
783
|
-
expect(
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
989
|
+
it('should initialize state and authentication EVENTS with jwt options', async () => {
|
|
990
|
+
expect(app).toBeDefined();
|
|
991
|
+
expect(src_1.DynamicApiModule.state.get()).toStrictEqual({
|
|
992
|
+
uri,
|
|
993
|
+
initialized: true,
|
|
994
|
+
isGlobalCacheEnabled: true,
|
|
995
|
+
connectionName: 'dynamic-api-connection',
|
|
996
|
+
cacheExcludedPaths: [],
|
|
997
|
+
credentials: {
|
|
998
|
+
loginField: 'email',
|
|
999
|
+
passwordField: 'password',
|
|
1000
|
+
},
|
|
1001
|
+
isAuthEnabled: true,
|
|
1002
|
+
jwtExpirationTime: '3s',
|
|
1003
|
+
jwtSecret: 'test-secret',
|
|
1004
|
+
routesConfig: {
|
|
1005
|
+
defaults: [
|
|
1006
|
+
'GetMany',
|
|
1007
|
+
'GetOne',
|
|
1008
|
+
'CreateMany',
|
|
1009
|
+
'CreateOne',
|
|
1010
|
+
'UpdateMany',
|
|
1011
|
+
'UpdateOne',
|
|
1012
|
+
'ReplaceOne',
|
|
1013
|
+
'DuplicateMany',
|
|
1014
|
+
'DuplicateOne',
|
|
1015
|
+
'DeleteMany',
|
|
1016
|
+
'DeleteOne',
|
|
1017
|
+
],
|
|
1018
|
+
excluded: [],
|
|
1019
|
+
},
|
|
1020
|
+
gatewayOptions: undefined,
|
|
1021
|
+
});
|
|
1022
|
+
});
|
|
1023
|
+
it('should throw a ws exception if access token is expired', async () => {
|
|
1024
|
+
e2e_setup_1.handleSocketResponse.mockReset();
|
|
1025
|
+
await (0, utils_1.wait)(4000);
|
|
1026
|
+
await e2e_setup_1.server.emit('auth-get-account', undefined, { accessToken });
|
|
1027
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledTimes(1);
|
|
1028
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledWith({
|
|
1029
|
+
message: 'Unauthorized',
|
|
790
1030
|
});
|
|
1031
|
+
expect(e2e_setup_1.handleSocketResponse).not.toHaveBeenCalled();
|
|
1032
|
+
});
|
|
1033
|
+
it('should throw a ws exception if secret is invalid', async () => {
|
|
1034
|
+
e2e_setup_1.handleSocketResponse.mockReset();
|
|
1035
|
+
const invalidToken = jwtService.sign({ email: 'u', password: 'p' }, { secret: 'invalid-secret' });
|
|
1036
|
+
await e2e_setup_1.server.emit('auth-get-account', undefined, { accessToken: invalidToken });
|
|
1037
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledTimes(1);
|
|
1038
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledWith({
|
|
1039
|
+
message: 'Unauthorized',
|
|
1040
|
+
});
|
|
1041
|
+
expect(e2e_setup_1.handleSocketResponse).not.toHaveBeenCalled();
|
|
791
1042
|
});
|
|
792
1043
|
});
|
|
793
|
-
describe('
|
|
794
|
-
let
|
|
1044
|
+
describe('useAuth with validation options', () => {
|
|
1045
|
+
let UserEntity = class UserEntity extends src_1.BaseEntity {
|
|
1046
|
+
};
|
|
1047
|
+
__decorate([
|
|
1048
|
+
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
1049
|
+
(0, class_validator_1.IsEmail)(),
|
|
1050
|
+
__metadata("design:type", String)
|
|
1051
|
+
], UserEntity.prototype, "email", void 0);
|
|
1052
|
+
__decorate([
|
|
1053
|
+
(0, mongoose_1.Prop)({ type: String, required: true }),
|
|
1054
|
+
(0, class_validator_1.IsStrongPassword)({
|
|
1055
|
+
minLength: 6,
|
|
1056
|
+
minLowercase: 1,
|
|
1057
|
+
minUppercase: 1,
|
|
1058
|
+
minNumbers: 1,
|
|
1059
|
+
minSymbols: 1,
|
|
1060
|
+
}),
|
|
1061
|
+
__metadata("design:type", String)
|
|
1062
|
+
], UserEntity.prototype, "password", void 0);
|
|
1063
|
+
UserEntity = __decorate([
|
|
1064
|
+
(0, mongoose_1.Schema)({ collection: 'users' })
|
|
1065
|
+
], UserEntity);
|
|
795
1066
|
beforeEach(async () => {
|
|
796
|
-
await
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
1067
|
+
await initModule({
|
|
1068
|
+
useAuth: {
|
|
1069
|
+
userEntity: UserEntity,
|
|
1070
|
+
validationPipeOptions: {
|
|
1071
|
+
whitelist: true,
|
|
1072
|
+
forbidNonWhitelisted: true,
|
|
1073
|
+
transform: true,
|
|
1074
|
+
},
|
|
1075
|
+
},
|
|
1076
|
+
webSocket: true,
|
|
1077
|
+
}, undefined, async (_) => {
|
|
1078
|
+
_.useWebSocketAdapter(new socket_adapter_1.SocketAdapter(_));
|
|
1079
|
+
});
|
|
1080
|
+
e2e_setup_1.handleSocketResponse.mockReset();
|
|
1081
|
+
});
|
|
1082
|
+
describe('EVENT auth-register', () => {
|
|
1083
|
+
it('should throw a ws exception if payload contains non whitelisted property', async () => {
|
|
1084
|
+
await e2e_setup_1.server.emit('auth-register', { email: 'unit@test.co', password: 'Test-2', role: 'ADMIN' });
|
|
1085
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledTimes(1);
|
|
1086
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledWith({
|
|
1087
|
+
message: ['property role should not exist'],
|
|
1088
|
+
});
|
|
1089
|
+
expect(e2e_setup_1.handleSocketResponse).not.toHaveBeenCalled();
|
|
1090
|
+
});
|
|
1091
|
+
it('should throw a ws exception if validation fails', async () => {
|
|
1092
|
+
await e2e_setup_1.server.emit('auth-register', { email: 'unit.test.co', password: 'test-2' });
|
|
1093
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledTimes(1);
|
|
1094
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledWith({
|
|
1095
|
+
message: [
|
|
1096
|
+
'email must be an email',
|
|
1097
|
+
'password is not strong enough',
|
|
1098
|
+
],
|
|
1099
|
+
});
|
|
1100
|
+
expect(e2e_setup_1.handleSocketResponse).not.toHaveBeenCalled();
|
|
1101
|
+
});
|
|
1102
|
+
it('should create a new user and emit access token if the validation was successful', async () => {
|
|
1103
|
+
await e2e_setup_1.server.emit('auth-register', { email: 'unit@test.co', password: 'Test-2' });
|
|
1104
|
+
expect(e2e_setup_1.handleSocketException).not.toHaveBeenCalled();
|
|
1105
|
+
expect(e2e_setup_1.handleSocketResponse).toHaveBeenCalledTimes(1);
|
|
1106
|
+
expect(e2e_setup_1.handleSocketResponse).toHaveBeenCalledWith({
|
|
1107
|
+
accessToken: expect.any(String),
|
|
1108
|
+
});
|
|
1109
|
+
});
|
|
1110
|
+
});
|
|
1111
|
+
describe('EVENT auth-login', () => {
|
|
1112
|
+
beforeEach(async () => {
|
|
1113
|
+
await e2e_setup_1.server.emit('auth-register', { email: 'unit@test.co', password: 'Test-2' });
|
|
1114
|
+
e2e_setup_1.handleSocketResponse.mockReset();
|
|
1115
|
+
});
|
|
1116
|
+
it('should throw a ws exception if payload contains non whitelisted property', async () => {
|
|
1117
|
+
await e2e_setup_1.server.emit('auth-login', { email: 'unit@test.co', password: 'Test-2', role: 'ADMIN' });
|
|
1118
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledTimes(1);
|
|
1119
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledWith({
|
|
1120
|
+
message: ['property role should not exist'],
|
|
1121
|
+
});
|
|
1122
|
+
expect(e2e_setup_1.handleSocketResponse).not.toHaveBeenCalled();
|
|
1123
|
+
});
|
|
1124
|
+
it('should throw a ws exception if email is missing', async () => {
|
|
1125
|
+
await e2e_setup_1.server.emit('auth-login', { password: 'Test-2' });
|
|
1126
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledTimes(1);
|
|
1127
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledWith({
|
|
1128
|
+
message: ['email must be an email'],
|
|
1129
|
+
});
|
|
1130
|
+
expect(e2e_setup_1.handleSocketResponse).not.toHaveBeenCalled();
|
|
1131
|
+
});
|
|
1132
|
+
it('should throw a ws exception if password is missing', async () => {
|
|
1133
|
+
await e2e_setup_1.server.emit('auth-login', { email: 'unit@test.co' });
|
|
1134
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledTimes(1);
|
|
1135
|
+
expect(e2e_setup_1.handleSocketException).toHaveBeenCalledWith({
|
|
1136
|
+
message: ['password is not strong enough'],
|
|
1137
|
+
});
|
|
1138
|
+
expect(e2e_setup_1.handleSocketResponse).not.toHaveBeenCalled();
|
|
1139
|
+
});
|
|
1140
|
+
it('should emit access token if the validation was successful', async () => {
|
|
1141
|
+
await e2e_setup_1.server.emit('auth-login', { email: 'unit@test.co', password: 'Test-2' });
|
|
1142
|
+
expect(e2e_setup_1.handleSocketException).not.toHaveBeenCalled();
|
|
1143
|
+
expect(e2e_setup_1.handleSocketResponse).toHaveBeenCalledTimes(1);
|
|
1144
|
+
expect(e2e_setup_1.handleSocketResponse).toHaveBeenCalledWith({
|
|
1145
|
+
accessToken: expect.any(String),
|
|
1146
|
+
});
|
|
1147
|
+
});
|
|
813
1148
|
});
|
|
814
1149
|
});
|
|
815
1150
|
});
|