@smartsoft001/auth-domain 2.75.0 → 2.80.0

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/index.js ADDED
@@ -0,0 +1,282 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result)
9
+ __defProp(target, key, result);
10
+ return result;
11
+ };
12
+ var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
13
+
14
+ // packages/auth/domain/src/lib/entities/user.entity.ts
15
+ import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
16
+ var User = class {
17
+ };
18
+ __decorateClass([
19
+ PrimaryGeneratedColumn()
20
+ ], User.prototype, "id", 2);
21
+ __decorateClass([
22
+ Column("permissions")
23
+ ], User.prototype, "permissions", 2);
24
+ __decorateClass([
25
+ Column("username")
26
+ ], User.prototype, "username", 2);
27
+ __decorateClass([
28
+ Column("password")
29
+ ], User.prototype, "password", 2);
30
+ __decorateClass([
31
+ Column("disabled")
32
+ ], User.prototype, "disabled", 2);
33
+ __decorateClass([
34
+ Column("lastLoginDate")
35
+ ], User.prototype, "lastLoginDate", 2);
36
+ __decorateClass([
37
+ Column("authRefreshToken")
38
+ ], User.prototype, "authRefreshToken", 2);
39
+ __decorateClass([
40
+ Column("facebookUserId")
41
+ ], User.prototype, "facebookUserId", 2);
42
+ __decorateClass([
43
+ Column("googleUserId")
44
+ ], User.prototype, "googleUserId", 2);
45
+ User = __decorateClass([
46
+ Entity("users")
47
+ ], User);
48
+
49
+ // packages/auth/domain/src/lib/feature-create-token/token.factory.ts
50
+ import { Injectable } from "@nestjs/common";
51
+ import { InjectRepository } from "@nestjs/typeorm";
52
+ import { Guid as Guid2 } from "guid-typescript";
53
+
54
+ // packages/shared/models/src/lib/symbols.ts
55
+ var SYMBOL_MODEL = Symbol.for("smartsoft:model");
56
+ var SYMBOL_FIELD = Symbol.for("smartsoft:field");
57
+
58
+ // packages/shared/models/src/lib/decorators/model/model.decorator.ts
59
+ import "reflect-metadata";
60
+
61
+ // packages/shared/models/src/lib/decorators/field/field.decorator.ts
62
+ import "reflect-metadata";
63
+
64
+ // packages/shared/utils/src/lib/services/password/password.service.ts
65
+ import * as md5_ from "md5";
66
+ var md5 = md5_;
67
+ var PasswordService = class _PasswordService {
68
+ /**
69
+ * Hash password text
70
+ * @param p {string} - text
71
+ * @return - hashed text
72
+ */
73
+ static hash(p) {
74
+ return Promise.resolve(md5(p));
75
+ }
76
+ /**
77
+ * Compare password text with hashed text
78
+ * @param p {string} - password text
79
+ * @param h {string} - hashed text
80
+ */
81
+ static async compare(p, h) {
82
+ const hp = await _PasswordService.hash(p);
83
+ return hp === h;
84
+ }
85
+ };
86
+
87
+ // packages/shared/utils/src/lib/services/object/object.service.ts
88
+ import { stringify } from "flatted";
89
+
90
+ // packages/shared/utils/src/lib/services/guid/guid.service.ts
91
+ import { Guid } from "guid-typescript";
92
+
93
+ // packages/shared/utils/src/lib/services/array/array.service.ts
94
+ import * as _ from "lodash";
95
+
96
+ // packages/shared/domain-core/src/lib/errors.ts
97
+ var DomainValidationError = class _DomainValidationError extends Error {
98
+ constructor(msg) {
99
+ super(msg);
100
+ this.type = _DomainValidationError;
101
+ }
102
+ };
103
+
104
+ // packages/auth/domain/src/lib/feature-create-token/token.factory.ts
105
+ var TokenFactory = class {
106
+ constructor(config, repository, jwtService, fbService, googleService) {
107
+ this.config = config;
108
+ this.repository = repository;
109
+ this.jwtService = jwtService;
110
+ this.fbService = fbService;
111
+ this.googleService = googleService;
112
+ this._invalidUsernameOrPasswordMessage = "Invalid username or password";
113
+ }
114
+ static getQuery(config, customProvider = false) {
115
+ switch (config.grant_type) {
116
+ case "fb":
117
+ return { facebookUserId: config.fb_user_id };
118
+ case "google":
119
+ return { googleUserId: config.google_user_id };
120
+ case "password":
121
+ return { username: config.username };
122
+ case "refresh_token":
123
+ return { authRefreshToken: config.refresh_token };
124
+ default:
125
+ if (!customProvider) {
126
+ throw new DomainValidationError("Invalid grand type");
127
+ }
128
+ return null;
129
+ }
130
+ }
131
+ static checkDisabled(user) {
132
+ if (user.disabled)
133
+ throw new DomainValidationError("user disabled");
134
+ }
135
+ async create(options) {
136
+ if (options.request.grant_type === "fb") {
137
+ options.request.fb_user_id = await this.fbService.getUserId(
138
+ options.request.fb_token
139
+ );
140
+ }
141
+ if (options.request.grant_type === "google") {
142
+ options.request.google_user_id = await this.googleService.getUserId(
143
+ options.request.google_token
144
+ );
145
+ }
146
+ this.valid(options.request);
147
+ const query = TokenFactory.getQuery(
148
+ options.request,
149
+ !!options.userProvider
150
+ );
151
+ const user = options.userProvider ? await options.userProvider.get(query, options.request, options.httpReq) : await this.repository.findOne(query);
152
+ if (!options.validationProvider || !options.validationProvider.replace) {
153
+ this.checkUser(options.request, user);
154
+ TokenFactory.checkDisabled(user);
155
+ await this.checkPassword(options.request, user);
156
+ }
157
+ if (options.validationProvider) {
158
+ await options.validationProvider.check({
159
+ request: options.request,
160
+ user
161
+ });
162
+ }
163
+ const refreshToken = Guid2.raw();
164
+ await this.repository.update(
165
+ {
166
+ ...query,
167
+ disabled: { $ne: true }
168
+ },
169
+ {
170
+ lastLoginDate: /* @__PURE__ */ new Date(),
171
+ authRefreshToken: refreshToken
172
+ }
173
+ );
174
+ const payload = {
175
+ permissions: user.permissions,
176
+ scope: options.request.scope
177
+ };
178
+ if (options.payloadProvider) {
179
+ await options.payloadProvider.change(payload, {
180
+ user,
181
+ request: options.request,
182
+ httpReq: options.httpReq
183
+ });
184
+ }
185
+ return {
186
+ expired_in: this.config.expiredIn,
187
+ token_type: "bearer",
188
+ access_token: this.jwtService.sign(payload, {
189
+ expiresIn: this.config.expiredIn,
190
+ subject: user.username
191
+ }),
192
+ refresh_token: refreshToken,
193
+ username: user.username
194
+ };
195
+ }
196
+ checkUser(config, user) {
197
+ if (!user)
198
+ throw new DomainValidationError(
199
+ config.grant_type === "password" ? this._invalidUsernameOrPasswordMessage : "Invalid token"
200
+ );
201
+ }
202
+ async checkPassword(config, user) {
203
+ if (config.grant_type === "password" && !await PasswordService.compare(config.password, user.password))
204
+ throw new DomainValidationError(this._invalidUsernameOrPasswordMessage);
205
+ }
206
+ valid(req) {
207
+ if (!req)
208
+ throw new DomainValidationError("config is empty");
209
+ if (!req.grant_type)
210
+ throw new DomainValidationError("grant_type is empty");
211
+ if (req.grant_type === "password") {
212
+ if (!req.username)
213
+ throw new DomainValidationError("username is empty");
214
+ if (!req.password)
215
+ throw new DomainValidationError("password is empty");
216
+ if (!req.client_id)
217
+ throw new DomainValidationError("client_id is empty");
218
+ if (!this.config.clients.some((c) => c === req.client_id))
219
+ throw new DomainValidationError("client_id is incorrect");
220
+ } else if (req.grant_type === "refresh_token") {
221
+ if (!req.refresh_token)
222
+ throw new DomainValidationError("refresh_token is empty");
223
+ } else if (req.grant_type === "fb") {
224
+ if (!req.fb_token)
225
+ throw new DomainValidationError("fb_token is empty");
226
+ if (!req.fb_user_id)
227
+ throw new DomainValidationError("fb_user_id is empty");
228
+ } else if (req.grant_type === "google") {
229
+ if (!req.google_token)
230
+ throw new DomainValidationError("google_token is empty");
231
+ if (!req.google_user_id)
232
+ throw new DomainValidationError("google_user_id is empty");
233
+ }
234
+ }
235
+ };
236
+ TokenFactory = __decorateClass([
237
+ Injectable(),
238
+ __decorateParam(1, InjectRepository(User))
239
+ ], TokenFactory);
240
+
241
+ // packages/auth/domain/src/lib/feature-create-token/token.config.ts
242
+ import { Injectable as Injectable2 } from "@nestjs/common";
243
+ var TokenConfig = class {
244
+ constructor() {
245
+ this.clients = [];
246
+ }
247
+ };
248
+ TokenConfig = __decorateClass([
249
+ Injectable2()
250
+ ], TokenConfig);
251
+
252
+ // packages/auth/domain/src/lib/feature-create-token/token-payload.provider.ts
253
+ var AUTH_TOKEN_PAYLOAD_PROVIDER = "AUTH_TOKEN_PAYLOAD_PROVIDER";
254
+ var ITokenPayloadProvider = class {
255
+ };
256
+
257
+ // packages/auth/domain/src/lib/feature-create-token/token-validation.provider.ts
258
+ var AUTH_TOKEN_VALIDATION_PROVIDER = "AUTH_TOKEN_VALIDATION_PROVIDER";
259
+ var ITokenValidationProvider = class {
260
+ };
261
+
262
+ // packages/auth/domain/src/lib/feature-create-token/token-user.provider.ts
263
+ var AUTH_TOKEN_USER_PROVIDER = "AUTH_TOKEN_USER_PROVIDER";
264
+ var ITokenUserProvider = class {
265
+ };
266
+
267
+ // packages/auth/domain/src/index.ts
268
+ var DOMAIN_SERVICES = [TokenFactory];
269
+ var ENTITIES = [User];
270
+ export {
271
+ AUTH_TOKEN_PAYLOAD_PROVIDER,
272
+ AUTH_TOKEN_USER_PROVIDER,
273
+ AUTH_TOKEN_VALIDATION_PROVIDER,
274
+ DOMAIN_SERVICES,
275
+ ENTITIES,
276
+ ITokenPayloadProvider,
277
+ ITokenUserProvider,
278
+ ITokenValidationProvider,
279
+ TokenConfig,
280
+ TokenFactory,
281
+ User
282
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smartsoft001/auth-domain",
3
- "version": "2.75.0",
3
+ "version": "2.80.0",
4
4
  "description": "Utils for authorization",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,9 +1,6 @@
1
1
  import { User } from './lib/entities/user.entity';
2
2
  import { TokenFactory } from './lib/feature-create-token/token.factory';
3
-
4
3
  export * from './lib/entities';
5
4
  export * from './lib/feature-create-token';
6
-
7
- export const DOMAIN_SERVICES = [TokenFactory];
8
-
9
- export const ENTITIES = [User];
5
+ export declare const DOMAIN_SERVICES: (typeof TokenFactory)[];
6
+ export declare const ENTITIES: (typeof User)[];
@@ -0,0 +1,13 @@
1
+ import { IEntity } from '@smartsoft001/domain-core';
2
+ import { IUser, IUserCredentials } from '@smartsoft001/users';
3
+ export declare class User implements IEntity<string>, IUser, IUserCredentials {
4
+ id: string;
5
+ permissions: Array<string>;
6
+ username: string;
7
+ password: string;
8
+ disabled: boolean;
9
+ lastLoginDate: Date;
10
+ authRefreshToken: string;
11
+ facebookUserId?: string;
12
+ googleUserId?: string;
13
+ }
@@ -0,0 +1,39 @@
1
+ import { IUserCredentials } from '@smartsoft001/users';
2
+ export type IAuthTokenRequest = IAuthTokenRequestPassword | IAuthTokenRequestRefreshToken | IAuthTokenRequestCustom | IAuthTokenRequestFb | IAuthTokenRequestGoogle;
3
+ export interface IAuthTokenRequestFb extends IUserCredentials {
4
+ grant_type: 'fb';
5
+ fb_token: string;
6
+ fb_user_id?: string;
7
+ scope?: string;
8
+ client_id: string;
9
+ }
10
+ export interface IAuthTokenRequestGoogle extends IUserCredentials {
11
+ grant_type: 'google';
12
+ google_token: string;
13
+ google_user_id?: string;
14
+ scope?: string;
15
+ client_id: string;
16
+ }
17
+ export interface IAuthTokenRequestPassword extends IUserCredentials {
18
+ grant_type: 'password';
19
+ username: string;
20
+ password: string;
21
+ scope?: string;
22
+ client_id: string;
23
+ }
24
+ export interface IAuthTokenRequestRefreshToken {
25
+ grant_type: 'refresh_token';
26
+ refresh_token: string;
27
+ scope?: string;
28
+ }
29
+ export interface IAuthToken {
30
+ access_token: string;
31
+ refresh_token: string;
32
+ expired_in: number;
33
+ token_type: 'bearer';
34
+ username?: string;
35
+ }
36
+ export interface IAuthTokenRequestCustom {
37
+ grant_type: string;
38
+ [key: string]: string;
39
+ }
@@ -0,0 +1,11 @@
1
+ import { Request } from 'express';
2
+ import { IAuthTokenRequest } from './interfaces';
3
+ import { User } from '../entities/user.entity';
4
+ export declare const AUTH_TOKEN_PAYLOAD_PROVIDER = "AUTH_TOKEN_PAYLOAD_PROVIDER";
5
+ export declare abstract class ITokenPayloadProvider {
6
+ abstract change(basePayload: any, data: {
7
+ request?: IAuthTokenRequest;
8
+ user?: User;
9
+ httpReq?: Request;
10
+ }): Promise<void>;
11
+ }
@@ -0,0 +1,7 @@
1
+ import { Request } from 'express';
2
+ import { IAuthTokenRequest } from './interfaces';
3
+ import { User } from '../entities/user.entity';
4
+ export declare const AUTH_TOKEN_USER_PROVIDER = "AUTH_TOKEN_USER_PROVIDER";
5
+ export declare abstract class ITokenUserProvider {
6
+ abstract get(baseQuery: Partial<User>, request: IAuthTokenRequest, httpReq?: Request): Promise<User>;
7
+ }
@@ -0,0 +1,10 @@
1
+ import { IAuthTokenRequest } from './interfaces';
2
+ import { User } from '../entities';
3
+ export declare const AUTH_TOKEN_VALIDATION_PROVIDER = "AUTH_TOKEN_VALIDATION_PROVIDER";
4
+ export declare abstract class ITokenValidationProvider {
5
+ abstract replace?: boolean;
6
+ abstract check(data: {
7
+ request?: IAuthTokenRequest;
8
+ user?: User;
9
+ }): Promise<void>;
10
+ }
@@ -0,0 +1,5 @@
1
+ export declare class TokenConfig {
2
+ expiredIn: number;
3
+ clients: Array<string>;
4
+ secretOrPrivateKey: string;
5
+ }
@@ -0,0 +1,39 @@
1
+ import { JwtService } from '@nestjs/jwt';
2
+ import { Request } from 'express';
3
+ import { Repository } from 'typeorm';
4
+ import { IFactory } from '@smartsoft001/domain-core';
5
+ import { FbService } from '@smartsoft001/fb';
6
+ import { GoogleService } from '@smartsoft001/google';
7
+ import { User } from '../entities';
8
+ import { IAuthToken, IAuthTokenRequest } from './interfaces';
9
+ import { ITokenPayloadProvider } from './token-payload.provider';
10
+ import { ITokenUserProvider } from './token-user.provider';
11
+ import { ITokenValidationProvider } from './token-validation.provider';
12
+ import { TokenConfig } from './token.config';
13
+ export declare class TokenFactory implements IFactory<IAuthToken, {
14
+ httpReq?: Request;
15
+ request: IAuthTokenRequest;
16
+ payloadProvider?: ITokenPayloadProvider;
17
+ validationProvider?: ITokenValidationProvider;
18
+ userProvider?: ITokenUserProvider;
19
+ }> {
20
+ private config;
21
+ private repository;
22
+ private jwtService;
23
+ private fbService;
24
+ private googleService;
25
+ private _invalidUsernameOrPasswordMessage;
26
+ constructor(config: TokenConfig, repository: Repository<User>, jwtService: JwtService, fbService: FbService, googleService: GoogleService);
27
+ static getQuery(config: IAuthTokenRequest, customProvider?: boolean): Partial<User>;
28
+ static checkDisabled(user: User): void;
29
+ create(options: {
30
+ httpReq?: Request;
31
+ request: IAuthTokenRequest;
32
+ payloadProvider?: ITokenPayloadProvider;
33
+ validationProvider?: ITokenValidationProvider;
34
+ userProvider?: ITokenUserProvider;
35
+ }): Promise<IAuthToken>;
36
+ private checkUser;
37
+ private checkPassword;
38
+ private valid;
39
+ }
package/.eslintrc.json DELETED
@@ -1,26 +0,0 @@
1
- {
2
- "extends": ["../../../.eslintrc.json"],
3
- "ignorePatterns": ["!**/*"],
4
- "rules": {
5
- "import/order": "off"
6
- },
7
- "overrides": [
8
- {
9
- "files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
10
- "rules": {}
11
- },
12
- {
13
- "files": ["*.ts", "*.tsx"],
14
- "rules": {}
15
- },
16
- {
17
- "files": ["*.js", "*.jsx"],
18
- "rules": {}
19
- },
20
- {
21
- "files": "package.json",
22
- "parser": "jsonc-eslint-parser",
23
- "rules": {}
24
- }
25
- ]
26
- }
package/jest.config.ts DELETED
@@ -1,26 +0,0 @@
1
- /* eslint-disable */
2
- export default {
3
- displayName: 'auth-domain',
4
- preset: '../../../jest.preset.js',
5
- testEnvironment: 'node',
6
- transform: {
7
- '^.+\\.[tj]sx?$': [
8
- 'ts-jest',
9
- {
10
- tsConfig: '<rootDir>/tsconfig.spec.json',
11
- },
12
- ],
13
- },
14
- moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
15
- coverageDirectory: '../../../coverage/packages/auth/domain',
16
- /* TODO: Update to latest Jest snapshotFormat
17
- * By default Nx has kept the older style of Jest Snapshot formats
18
- * to prevent breaking of any existing tests with snapshots.
19
- * It's recommend you update to the latest format.
20
- * You can do this by removing snapshotFormat property
21
- * and running tests with --update-snapshot flag.
22
- * Example: From within the project directory, run "nx test --update-snapshot"
23
- * More info: https://jestjs.io/docs/upgrading-to-jest29#snapshot-format
24
- */
25
- snapshotFormat: { escapeString: true, printBasicPrototype: true },
26
- };
package/project.json DELETED
@@ -1,44 +0,0 @@
1
- {
2
- "name": "auth-domain",
3
- "$schema": "../../../node_modules/nx/schemas/project-schema.json",
4
- "sourceRoot": "packages/auth/domain/src",
5
- "projectType": "library",
6
- "targets": {
7
- "lint": {
8
- "executor": "@nx/eslint:lint",
9
- "outputs": ["{options.outputFile}"],
10
- "options": {
11
- "lintFilePatterns": [
12
- "packages/auth/domain/**/*.{ts,tsx,js,jsx}",
13
- "packages/auth/domain/package.json"
14
- ]
15
- }
16
- },
17
- "test": {
18
- "executor": "@nx/jest:jest",
19
- "outputs": ["{workspaceRoot}/coverage/packages/auth/domain"],
20
- "options": {
21
- "jestConfig": "packages/auth/domain/jest.config.ts"
22
- }
23
- },
24
- "build": {
25
- "executor": "@nx/esbuild:esbuild",
26
- "outputs": ["{options.outputPath}"],
27
- "options": {
28
- "outputPath": "dist/packages/auth/domain",
29
- "tsConfig": "packages/auth/domain/tsconfig.lib.json",
30
- "packageJson": "packages/auth/domain/package.json",
31
- "main": "packages/auth/domain/src/index.ts",
32
- "assets": ["packages/auth/domain/*.md"]
33
- }
34
- },
35
- "deploy": {
36
- "executor": "ngx-deploy-npm:deploy",
37
- "options": {
38
- "access": "public",
39
- "distFolderPath": "dist/packages/auth/domain"
40
- },
41
- "dependsOn": ["build"]
42
- }
43
- }
44
- }
@@ -1,34 +0,0 @@
1
- import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
2
-
3
- import { IEntity } from '@smartsoft001/domain-core';
4
- import { IUser, IUserCredentials } from '@smartsoft001/users';
5
-
6
- @Entity('users')
7
- export class User implements IEntity<string>, IUser, IUserCredentials {
8
- @PrimaryGeneratedColumn()
9
- id: string;
10
-
11
- @Column('permissions')
12
- permissions: Array<string>;
13
-
14
- @Column('username')
15
- username: string;
16
-
17
- @Column('password')
18
- password: string;
19
-
20
- @Column('disabled')
21
- disabled: boolean;
22
-
23
- @Column('lastLoginDate')
24
- lastLoginDate: Date;
25
-
26
- @Column('authRefreshToken')
27
- authRefreshToken: string;
28
-
29
- @Column('facebookUserId')
30
- facebookUserId?: string;
31
-
32
- @Column('googleUserId')
33
- googleUserId?: string;
34
- }
@@ -1,51 +0,0 @@
1
- import { IUserCredentials } from '@smartsoft001/users';
2
-
3
- export type IAuthTokenRequest =
4
- | IAuthTokenRequestPassword
5
- | IAuthTokenRequestRefreshToken
6
- | IAuthTokenRequestCustom
7
- | IAuthTokenRequestFb
8
- | IAuthTokenRequestGoogle;
9
-
10
- export interface IAuthTokenRequestFb extends IUserCredentials {
11
- grant_type: 'fb';
12
- fb_token: string;
13
- fb_user_id?: string;
14
- scope?: string;
15
- client_id: string;
16
- }
17
-
18
- export interface IAuthTokenRequestGoogle extends IUserCredentials {
19
- grant_type: 'google';
20
- google_token: string;
21
- google_user_id?: string;
22
- scope?: string;
23
- client_id: string;
24
- }
25
-
26
- export interface IAuthTokenRequestPassword extends IUserCredentials {
27
- grant_type: 'password';
28
- username: string;
29
- password: string;
30
- scope?: string;
31
- client_id: string;
32
- }
33
-
34
- export interface IAuthTokenRequestRefreshToken {
35
- grant_type: 'refresh_token';
36
- refresh_token: string;
37
- scope?: string;
38
- }
39
-
40
- export interface IAuthToken {
41
- access_token: string;
42
- refresh_token: string;
43
- expired_in: number;
44
- token_type: 'bearer';
45
- username?: string;
46
- }
47
-
48
- export interface IAuthTokenRequestCustom {
49
- grant_type: string;
50
- [key: string]: string;
51
- }
@@ -1,17 +0,0 @@
1
- import { Request } from 'express';
2
-
3
- import { IAuthTokenRequest } from './interfaces';
4
- import { User } from '../entities/user.entity';
5
-
6
- export const AUTH_TOKEN_PAYLOAD_PROVIDER = 'AUTH_TOKEN_PAYLOAD_PROVIDER';
7
-
8
- export abstract class ITokenPayloadProvider {
9
- abstract change(
10
- basePayload,
11
- data: {
12
- request?: IAuthTokenRequest;
13
- user?: User;
14
- httpReq?: Request;
15
- },
16
- ): Promise<void>;
17
- }
@@ -1,14 +0,0 @@
1
- import { Request } from 'express';
2
-
3
- import { IAuthTokenRequest } from './interfaces';
4
- import { User } from '../entities/user.entity';
5
-
6
- export const AUTH_TOKEN_USER_PROVIDER = 'AUTH_TOKEN_USER_PROVIDER';
7
-
8
- export abstract class ITokenUserProvider {
9
- abstract get(
10
- baseQuery: Partial<User>,
11
- request: IAuthTokenRequest,
12
- httpReq?: Request,
13
- ): Promise<User>;
14
- }
@@ -1,13 +0,0 @@
1
- import { IAuthTokenRequest } from './interfaces';
2
- import { User } from '../entities';
3
-
4
- export const AUTH_TOKEN_VALIDATION_PROVIDER = 'AUTH_TOKEN_VALIDATION_PROVIDER';
5
-
6
- export abstract class ITokenValidationProvider {
7
- abstract replace?: boolean;
8
-
9
- abstract check(data: {
10
- request?: IAuthTokenRequest;
11
- user?: User;
12
- }): Promise<void>;
13
- }
@@ -1,8 +0,0 @@
1
- import { Injectable } from '@nestjs/common';
2
-
3
- @Injectable()
4
- export class TokenConfig {
5
- expiredIn: number;
6
- clients: Array<string> = [];
7
- secretOrPrivateKey: string;
8
- }
@@ -1,194 +0,0 @@
1
- import { JwtService } from '@nestjs/jwt';
2
- import { Test } from '@nestjs/testing';
3
- import { getRepositoryToken } from '@nestjs/typeorm';
4
- import { Repository } from 'typeorm';
5
-
6
- import { DomainValidationError } from '@smartsoft001/domain-core';
7
- import { FbService } from '@smartsoft001/fb';
8
- import { GoogleService } from '@smartsoft001/google';
9
- import { PasswordService } from '@smartsoft001/utils';
10
-
11
- import { User } from '../entities';
12
- import { TokenConfig } from './token.config';
13
- import { TokenFactory } from './token.factory';
14
-
15
- describe('auth-domain: TokenFactory', () => {
16
- let tokenFactory: TokenFactory;
17
- let repository: Repository<User>;
18
- let jwtService: JwtService;
19
- let fbService: FbService;
20
- let googleService: GoogleService;
21
-
22
- beforeEach(async () => {
23
- const module = await Test.createTestingModule({
24
- providers: [
25
- TokenFactory,
26
- {
27
- provide: TokenConfig,
28
- useValue: {
29
- expiredIn: 3600,
30
- clients: ['test-client'],
31
- },
32
- },
33
- {
34
- provide: getRepositoryToken(User),
35
- useValue: {
36
- findOne: jest.fn(),
37
- update: jest.fn(),
38
- },
39
- },
40
- {
41
- provide: JwtService,
42
- useValue: {
43
- sign: jest.fn(),
44
- },
45
- },
46
- {
47
- provide: FbService,
48
- useValue: {
49
- getUserId: jest.fn(),
50
- },
51
- },
52
- {
53
- provide: GoogleService,
54
- useValue: {
55
- getUserId: jest.fn(),
56
- },
57
- },
58
- ],
59
- }).compile();
60
-
61
- tokenFactory = module.get<TokenFactory>(TokenFactory);
62
- repository = module.get<Repository<User>>(getRepositoryToken(User));
63
- jwtService = module.get<JwtService>(JwtService);
64
- fbService = module.get<FbService>(FbService);
65
- googleService = module.get<GoogleService>(GoogleService);
66
- });
67
-
68
- describe('getQuery', () => {
69
- it('should return query for password grant type', () => {
70
- const query = TokenFactory.getQuery({
71
- grant_type: 'password',
72
- username: 'test',
73
- });
74
- expect(query).toEqual({ username: 'test' });
75
- });
76
-
77
- it('should return query for refresh_token grant type', () => {
78
- const query = TokenFactory.getQuery({
79
- grant_type: 'refresh_token',
80
- refresh_token: 'token',
81
- });
82
- expect(query).toEqual({ authRefreshToken: 'token' });
83
- });
84
-
85
- it('should return query for fb grant type', () => {
86
- const query = TokenFactory.getQuery({
87
- grant_type: 'fb',
88
- fb_user_id: 'fb123',
89
- });
90
- expect(query).toEqual({ facebookUserId: 'fb123' });
91
- });
92
-
93
- it('should return query for google grant type', () => {
94
- const query = TokenFactory.getQuery({
95
- grant_type: 'google',
96
- google_user_id: 'g123',
97
- });
98
- expect(query).toEqual({ googleUserId: 'g123' });
99
- });
100
-
101
- it('should throw error for invalid grant type', () => {
102
- expect(() => TokenFactory.getQuery({ grant_type: 'invalid' })).toThrow(
103
- DomainValidationError,
104
- );
105
- });
106
- });
107
-
108
- describe('checkDisabled', () => {
109
- it('should throw error when user is disabled', () => {
110
- const user = { disabled: true } as User;
111
- expect(() => TokenFactory.checkDisabled(user)).toThrow(
112
- DomainValidationError,
113
- );
114
- });
115
- });
116
-
117
- describe('create', () => {
118
- beforeEach(() => {
119
- jest.spyOn(PasswordService, 'compare').mockResolvedValue(true);
120
- });
121
-
122
- it('should create token for valid password credentials', async () => {
123
- const user = { username: 'test', permissions: ['read'] };
124
- (repository.findOne as jest.Mock).mockResolvedValue(user);
125
- (jwtService.sign as jest.Mock).mockReturnValue('signed-token');
126
-
127
- const result = await tokenFactory.create({
128
- request: {
129
- grant_type: 'password',
130
- username: 'test',
131
- password: 'test',
132
- client_id: 'test-client',
133
- },
134
- });
135
-
136
- expect(result.token_type).toBe('bearer');
137
- });
138
-
139
- it('should create token for valid fb credentials', async () => {
140
- const user = { username: 'fb-user', permissions: ['read'] };
141
- (fbService.getUserId as jest.Mock).mockResolvedValue('fb123');
142
- (repository.findOne as jest.Mock).mockResolvedValue(user);
143
- (jwtService.sign as jest.Mock).mockReturnValue('signed-token');
144
-
145
- const result = await tokenFactory.create({
146
- request: {
147
- grant_type: 'fb',
148
- fb_token: 'token',
149
- },
150
- });
151
-
152
- expect(result.token_type).toBe('bearer');
153
- });
154
-
155
- it('should create token for valid google credentials', async () => {
156
- const user = { username: 'google-user', permissions: ['read'] };
157
- (googleService.getUserId as jest.Mock).mockResolvedValue('g123');
158
- (repository.findOne as jest.Mock).mockResolvedValue(user);
159
- (jwtService.sign as jest.Mock).mockReturnValue('signed-token');
160
-
161
- const result = await tokenFactory.create({
162
- request: {
163
- grant_type: 'google',
164
- google_token: 'token',
165
- },
166
- });
167
-
168
- expect(result.token_type).toBe('bearer');
169
- });
170
-
171
- it('should throw error for invalid request', async () => {
172
- await expect(
173
- tokenFactory.create({
174
- request: {} as any,
175
- }),
176
- ).rejects.toThrow(DomainValidationError);
177
- });
178
-
179
- it('should throw error when user is not found', async () => {
180
- (repository.findOne as jest.Mock).mockResolvedValue(null);
181
-
182
- await expect(
183
- tokenFactory.create({
184
- request: {
185
- grant_type: 'password',
186
- username: 'test',
187
- password: 'test',
188
- client_id: 'test-client',
189
- },
190
- }),
191
- ).rejects.toThrow(DomainValidationError);
192
- });
193
- });
194
- });
@@ -1,200 +0,0 @@
1
- import { Injectable } from '@nestjs/common';
2
- import { JwtService } from '@nestjs/jwt';
3
- import { InjectRepository } from '@nestjs/typeorm';
4
- import { Request } from 'express';
5
- import { Guid } from 'guid-typescript';
6
- import { Repository } from 'typeorm';
7
-
8
- import { DomainValidationError, IFactory } from '@smartsoft001/domain-core';
9
- import { FbService } from '@smartsoft001/fb';
10
- import { GoogleService } from '@smartsoft001/google';
11
- import { PasswordService } from '@smartsoft001/utils';
12
-
13
- import { User } from '../entities';
14
- import { IAuthToken, IAuthTokenRequest } from './interfaces';
15
- import { ITokenPayloadProvider } from './token-payload.provider';
16
- import { ITokenUserProvider } from './token-user.provider';
17
- import { ITokenValidationProvider } from './token-validation.provider';
18
- import { TokenConfig } from './token.config';
19
-
20
- @Injectable()
21
- export class TokenFactory
22
- implements
23
- IFactory<
24
- IAuthToken,
25
- {
26
- httpReq?: Request;
27
- request: IAuthTokenRequest;
28
- payloadProvider?: ITokenPayloadProvider;
29
- validationProvider?: ITokenValidationProvider;
30
- userProvider?: ITokenUserProvider;
31
- }
32
- >
33
- {
34
- private _invalidUsernameOrPasswordMessage = 'Invalid username or password';
35
-
36
- constructor(
37
- private config: TokenConfig,
38
- @InjectRepository(User) private repository: Repository<User>,
39
- private jwtService: JwtService,
40
- private fbService: FbService,
41
- private googleService: GoogleService,
42
- ) {}
43
-
44
- static getQuery(
45
- config: IAuthTokenRequest,
46
- customProvider = false,
47
- ): Partial<User> {
48
- switch (config.grant_type) {
49
- case 'fb':
50
- return { facebookUserId: config.fb_user_id };
51
- case 'google':
52
- return { googleUserId: config.google_user_id };
53
- case 'password':
54
- return { username: config.username };
55
- case 'refresh_token':
56
- return { authRefreshToken: config.refresh_token };
57
- default:
58
- if (!customProvider) {
59
- throw new DomainValidationError('Invalid grand type');
60
- }
61
- return null;
62
- }
63
- }
64
-
65
- static checkDisabled(user: User) {
66
- if (user.disabled) throw new DomainValidationError('user disabled');
67
- }
68
-
69
- async create(options: {
70
- httpReq?: Request;
71
- request: IAuthTokenRequest;
72
- payloadProvider?: ITokenPayloadProvider;
73
- validationProvider?: ITokenValidationProvider;
74
- userProvider?: ITokenUserProvider;
75
- }): Promise<IAuthToken> {
76
- if (options.request.grant_type === 'fb') {
77
- options.request.fb_user_id = await this.fbService.getUserId(
78
- options.request.fb_token,
79
- );
80
- }
81
-
82
- if (options.request.grant_type === 'google') {
83
- options.request.google_user_id = await this.googleService.getUserId(
84
- options.request.google_token,
85
- );
86
- }
87
-
88
- this.valid(options.request);
89
-
90
- const query = TokenFactory.getQuery(
91
- options.request,
92
- !!options.userProvider,
93
- );
94
-
95
- const user = options.userProvider
96
- ? await options.userProvider.get(query, options.request, options.httpReq)
97
- : await this.repository.findOne(query as any);
98
-
99
- if (!options.validationProvider || !options.validationProvider.replace) {
100
- this.checkUser(options.request, user);
101
- TokenFactory.checkDisabled(user);
102
- await this.checkPassword(options.request, user);
103
- }
104
-
105
- if (options.validationProvider) {
106
- await options.validationProvider.check({
107
- request: options.request,
108
- user,
109
- });
110
- }
111
-
112
- const refreshToken = Guid.raw();
113
- await this.repository.update(
114
- {
115
- ...query,
116
- disabled: { $ne: true },
117
- } as any,
118
- {
119
- lastLoginDate: new Date(),
120
- authRefreshToken: refreshToken,
121
- },
122
- );
123
-
124
- const payload = {
125
- permissions: user.permissions,
126
- scope: options.request.scope,
127
- };
128
-
129
- if (options.payloadProvider) {
130
- await options.payloadProvider.change(payload, {
131
- user,
132
- request: options.request,
133
- httpReq: options.httpReq,
134
- });
135
- }
136
-
137
- return {
138
- expired_in: this.config.expiredIn,
139
- token_type: 'bearer',
140
- access_token: this.jwtService.sign(payload, {
141
- expiresIn: this.config.expiredIn,
142
- subject: user.username,
143
- }),
144
- refresh_token: refreshToken,
145
- username: user.username,
146
- };
147
- }
148
-
149
- private checkUser(config: IAuthTokenRequest, user: User): void {
150
- if (!user)
151
- throw new DomainValidationError(
152
- config.grant_type === 'password'
153
- ? this._invalidUsernameOrPasswordMessage
154
- : 'Invalid token',
155
- );
156
- }
157
-
158
- private async checkPassword(
159
- config: IAuthTokenRequest,
160
- user: User,
161
- ): Promise<void> {
162
- if (
163
- config.grant_type === 'password' &&
164
- !(await PasswordService.compare(config.password, user.password))
165
- )
166
- throw new DomainValidationError(this._invalidUsernameOrPasswordMessage);
167
- }
168
-
169
- private valid(req: NonNullable<IAuthTokenRequest>): void {
170
- if (!req) throw new DomainValidationError('config is empty');
171
- if (!req.grant_type) throw new DomainValidationError('grant_type is empty');
172
-
173
- // password
174
- if (req.grant_type === 'password') {
175
- if (!req.username) throw new DomainValidationError('username is empty');
176
- if (!req.password) throw new DomainValidationError('password is empty');
177
- if (!req.client_id) throw new DomainValidationError('client_id is empty');
178
- if (!this.config.clients.some((c) => c === req.client_id))
179
- throw new DomainValidationError('client_id is incorrect');
180
-
181
- // refres token
182
- } else if (req.grant_type === 'refresh_token') {
183
- if (!req.refresh_token)
184
- throw new DomainValidationError('refresh_token is empty');
185
-
186
- // fb token
187
- } else if (req.grant_type === 'fb') {
188
- if (!req.fb_token) throw new DomainValidationError('fb_token is empty');
189
-
190
- if (!req.fb_user_id)
191
- throw new DomainValidationError('fb_user_id is empty');
192
- } else if (req.grant_type === 'google') {
193
- if (!req.google_token)
194
- throw new DomainValidationError('google_token is empty');
195
-
196
- if (!req.google_user_id)
197
- throw new DomainValidationError('google_user_id is empty');
198
- }
199
- }
200
- }
package/tsconfig.json DELETED
@@ -1,13 +0,0 @@
1
- {
2
- "extends": "../../../tsconfig.base.json",
3
- "files": [],
4
- "include": [],
5
- "references": [
6
- {
7
- "path": "./tsconfig.lib.json"
8
- },
9
- {
10
- "path": "./tsconfig.spec.json"
11
- }
12
- ]
13
- }
package/tsconfig.lib.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "extends": "./tsconfig.json",
3
- "compilerOptions": {
4
- "outDir": "../../../dist/out-tsc",
5
- "declaration": true,
6
- "types": ["node"]
7
- },
8
- "exclude": ["**/*.spec.ts", "**/*.test.ts", "jest.config.ts"],
9
- "include": ["**/*.ts"]
10
- }
@@ -1,20 +0,0 @@
1
- {
2
- "extends": "./tsconfig.json",
3
- "compilerOptions": {
4
- "outDir": "../../../dist/out-tsc",
5
- "module": "commonjs",
6
- "types": ["jest", "node"]
7
- },
8
- "include": [
9
- "**/*.spec.ts",
10
- "**/*.test.ts",
11
- "**/*.spec.tsx",
12
- "**/*.test.tsx",
13
- "**/*.spec.js",
14
- "**/*.test.js",
15
- "**/*.spec.jsx",
16
- "**/*.test.jsx",
17
- "**/*.d.ts",
18
- "jest.config.ts"
19
- ]
20
- }
File without changes
File without changes