@tomei/sso 0.65.0 → 0.66.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.
Files changed (66) hide show
  1. package/.commitlintrc.json +22 -22
  2. package/.gitlab-ci.yml +16 -16
  3. package/.husky/commit-msg +15 -15
  4. package/.husky/pre-commit +7 -7
  5. package/.prettierrc +4 -4
  6. package/Jenkinsfile +57 -57
  7. package/README.md +23 -23
  8. package/__tests__/unit/components/group/group.spec.ts +79 -79
  9. package/__tests__/unit/components/group-object-privilege/group-object-privilege.spec.ts +88 -88
  10. package/__tests__/unit/components/group-privilege/group-privilege.spec.ts +68 -68
  11. package/__tests__/unit/components/group-reporting-user/group-reporting-user.spec.ts +66 -66
  12. package/__tests__/unit/components/group-system-access/group-system-access.spec.ts +83 -83
  13. package/__tests__/unit/components/login-user/l.spec.ts +746 -746
  14. package/__tests__/unit/components/login-user/login.spec.ts +1164 -1164
  15. package/__tests__/unit/components/password-hash/password-hash.service.spec.ts +31 -31
  16. package/__tests__/unit/components/system/system.spec.ts +254 -254
  17. package/__tests__/unit/components/system-privilege/system-privilege.spec.ts +83 -83
  18. package/__tests__/unit/components/user-group/user-group.spec.ts +86 -86
  19. package/__tests__/unit/components/user-object-privilege/user-object-privilege.spec.ts +78 -78
  20. package/__tests__/unit/components/user-privilege/user-privilege.spec.ts +72 -72
  21. package/__tests__/unit/components/user-system-access/user-system-access.spec.ts +89 -89
  22. package/__tests__/unit/redis-client/redis.service.spec.ts +23 -23
  23. package/__tests__/unit/session/session.service.spec.ts +47 -47
  24. package/__tests__/unit/system-privilege/system-privilage.spec.ts +91 -91
  25. package/create-sso-user.sql +39 -39
  26. package/dist/__tests__/unit/components/group-privilege/group-privilege.test.d.ts +1 -0
  27. package/dist/__tests__/unit/components/group-privilege/group-privilege.test.js +71 -0
  28. package/dist/__tests__/unit/components/group-privilege/group-privilege.test.js.map +1 -0
  29. package/dist/__tests__/unit/components/login-user/login-user.spec.d.ts +0 -0
  30. package/dist/__tests__/unit/components/login-user/login-user.spec.js +6 -0
  31. package/dist/__tests__/unit/components/login-user/login-user.spec.js.map +1 -0
  32. package/dist/src/components/login-user/login-user.js +63 -64
  33. package/dist/src/components/login-user/login-user.js.map +1 -1
  34. package/dist/src/index.d.ts +1 -0
  35. package/dist/src/index.js +1 -0
  36. package/dist/src/index.js.map +1 -1
  37. package/dist/tsconfig.tsbuildinfo +1 -1
  38. package/eslint.config.mjs +58 -58
  39. package/jest.config.js +14 -14
  40. package/migrations/20240314080602-create-user-table.js +124 -124
  41. package/migrations/20240314080603-create-user-group-table.js +85 -85
  42. package/migrations/20240314080604-create-user-user-group-table.js +55 -55
  43. package/migrations/20240314080605-create-login-history-table.js +53 -53
  44. package/migrations/20240527064925-create-system-table.js +78 -78
  45. package/migrations/20240527064926-create-system-privilege-table.js +71 -71
  46. package/migrations/20240527065342-create-group-table.js +93 -93
  47. package/migrations/20240527065633-create-group-reporting-user-table.js +76 -76
  48. package/migrations/20240528011551-create-group-system-access-table.js +72 -72
  49. package/migrations/20240528023018-user-system-access-table.js +75 -75
  50. package/migrations/20240528032229-user-privilege-table.js +76 -76
  51. package/migrations/20240528063003-create-group-privilege-table.js +76 -76
  52. package/migrations/20240528063051-create-group-object-privilege-table.js +84 -84
  53. package/migrations/20240528063107-create-user-object-privilege-table.js +84 -84
  54. package/migrations/20240528063108-create-api-key-table.js +85 -85
  55. package/migrations/20241104104802-create-building-table.js +95 -95
  56. package/migrations/20250108091132-add-area-manager-user-id-to-building-table.js +14 -14
  57. package/migrations/20250108091133-add-passcode-to-user-table.js +36 -36
  58. package/migrations/20250210115636-create-user-reporting-hierarchy.js +76 -76
  59. package/migrations/20250326043818-crate-user-password-history.js +42 -42
  60. package/migrations/20250610070720-added-MFBypassYN-to-sso-user.js +30 -30
  61. package/package.json +90 -87
  62. package/sampledotenv +7 -7
  63. package/src/components/login-user/login-user.ts +90 -89
  64. package/src/index.ts +1 -0
  65. package/tsconfig.build.json +5 -5
  66. package/tsconfig.json +23 -23
package/package.json CHANGED
@@ -1,87 +1,90 @@
1
- {
2
- "name": "@tomei/sso",
3
- "version": "0.65.0",
4
- "description": "Tomei SSO Package",
5
- "main": "dist/index.js",
6
- "scripts": {
7
- "start:dev": "tsc -w",
8
- "build": "tsc",
9
- "prepare": "husky",
10
- "format": "prettier --write \"src/**/*.ts\"",
11
- "lint": "npx eslint . --fix",
12
- "test": "jest --forceExit --detectOpenHandles --coverage"
13
- },
14
- "repository": {
15
- "type": "git",
16
- "url": "git+ssh://git@gitlab.com/tomei-package/sso.git"
17
- },
18
- "keywords": [
19
- "tomei",
20
- "sso"
21
- ],
22
- "author": "Tomei",
23
- "license": "ISC",
24
- "bugs": {
25
- "url": "https://gitlab.com/tomei-package/sso/issues"
26
- },
27
- "homepage": "https://gitlab.com/tomei-package/sso#readme",
28
- "devDependencies": {
29
- "@commitlint/cli": "^19.8.1",
30
- "@commitlint/config-conventional": "^19.8.1",
31
- "@eslint/js": "^9.35.0",
32
- "@tsconfig/node18": "^18.2.4",
33
- "@types/bcrypt": "^6.0.0",
34
- "@types/jest": "^30.0.0",
35
- "@types/node": "^24.5.2",
36
- "@types/validator": "^13.15.3",
37
- "@typescript-eslint/eslint-plugin": "^8.44.0",
38
- "@typescript-eslint/parser": "^8.44.0",
39
- "cls-hooked": "^4.2.2",
40
- "dotenv": "^17.2.2",
41
- "eslint": "^9.35.0",
42
- "eslint-config-prettier": "^10.1.8",
43
- "eslint-plugin-import": "^2.32.0",
44
- "eslint-plugin-prettier": "^5.5.4",
45
- "globals": "^16.4.0",
46
- "husky": "^9.1.7",
47
- "jest": "^30.1.3",
48
- "jest-mock-extended": "^4.0.0",
49
- "jest-sonar-reporter": "^2.0.0",
50
- "lint-staged": "^16.1.6",
51
- "prettier": "^3.6.2",
52
- "redis-mock": "^0.56.3",
53
- "ts-jest": "^29.4.3",
54
- "ts-node": "^10.9.2",
55
- "tsc-watch": "^7.1.1",
56
- "tsconfig-paths": "^4.2.0",
57
- "typescript": "^5.9.2"
58
- },
59
- "publishConfig": {
60
- "access": "public"
61
- },
62
- "peerDependencies": {
63
- "@tomei/activity-history": "^0.4.4",
64
- "@tomei/config": "^0.3.22",
65
- "@tomei/general": "^0.21.10",
66
- "@tomei/mailer": "^0.6.2",
67
- "argon2": "^0.44.0",
68
- "redis": "^5.8.2",
69
- "reflect-metadata": "^0.2.2",
70
- "sequelize": "^6.37.7",
71
- "sequelize-cli": "^6.6.3",
72
- "sequelize-typescript": "^2.1.6",
73
- "speakeasy": "^2.0.0",
74
- "uuid": "^11.1.0"
75
- },
76
- "lint-staged": {
77
- "*/**/*.{js,ts,tsx}": [
78
- "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
79
- "eslint \"{src,apps,libs,test}/**/*.ts\" --fix"
80
- ]
81
- },
82
- "jestSonar": {
83
- "reportPath": "coverage",
84
- "reportFile": "test-report.xml",
85
- "indent": 2
86
- }
87
- }
1
+ {
2
+ "name": "@tomei/sso",
3
+ "version": "0.66.0",
4
+ "description": "Tomei SSO Package",
5
+ "main": "dist/index.js",
6
+ "scripts": {
7
+ "start:dev": "tsc -w",
8
+ "build": "tsc",
9
+ "prepare": "husky",
10
+ "format": "prettier --write \"src/**/*.ts\"",
11
+ "lint": "npx eslint . --fix",
12
+ "test": "jest --forceExit --detectOpenHandles --coverage"
13
+ },
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+ssh://git@gitlab.com/tomei-package/sso.git"
17
+ },
18
+ "keywords": [
19
+ "tomei",
20
+ "sso"
21
+ ],
22
+ "author": "Tomei",
23
+ "license": "ISC",
24
+ "bugs": {
25
+ "url": "https://gitlab.com/tomei-package/sso/issues"
26
+ },
27
+ "homepage": "https://gitlab.com/tomei-package/sso#readme",
28
+ "devDependencies": {
29
+ "@commitlint/cli": "^19.8.1",
30
+ "@commitlint/config-conventional": "^19.8.1",
31
+ "@eslint/js": "^9.35.0",
32
+ "@tsconfig/node18": "^18.2.4",
33
+ "@types/bcrypt": "^6.0.0",
34
+ "@types/jest": "^30.0.0",
35
+ "@types/node": "^24.5.2",
36
+ "@types/validator": "^13.15.3",
37
+ "@typescript-eslint/eslint-plugin": "^8.44.0",
38
+ "@typescript-eslint/parser": "^8.44.0",
39
+ "cls-hooked": "^4.2.2",
40
+ "dotenv": "^17.2.2",
41
+ "eslint": "^9.35.0",
42
+ "eslint-config-prettier": "^10.1.8",
43
+ "eslint-plugin-import": "^2.32.0",
44
+ "eslint-plugin-prettier": "^5.5.4",
45
+ "globals": "^16.4.0",
46
+ "husky": "^9.1.7",
47
+ "jest": "^30.1.3",
48
+ "jest-mock-extended": "^4.0.0",
49
+ "jest-sonar-reporter": "^2.0.0",
50
+ "lint-staged": "^16.1.6",
51
+ "prettier": "^3.6.2",
52
+ "redis-mock": "^0.56.3",
53
+ "ts-jest": "^29.4.3",
54
+ "ts-node": "^10.9.2",
55
+ "tsc-watch": "^7.1.1",
56
+ "tsconfig-paths": "^4.2.0",
57
+ "typescript": "^5.9.2"
58
+ },
59
+ "publishConfig": {
60
+ "access": "public"
61
+ },
62
+ "peerDependencies": {
63
+ "@tomei/activity-history": "^0.4.4",
64
+ "@tomei/config": "^0.3.22",
65
+ "@tomei/general": "^0.21.10",
66
+ "@tomei/mailer": "^0.6.2",
67
+ "argon2": "^0.44.0",
68
+ "redis": "^5.8.2",
69
+ "reflect-metadata": "^0.2.2",
70
+ "sequelize": "^6.37.7",
71
+ "sequelize-cli": "^6.6.3",
72
+ "sequelize-typescript": "^2.1.6",
73
+ "speakeasy": "^2.0.0",
74
+ "uuid": "^11.1.0"
75
+ },
76
+ "lint-staged": {
77
+ "*/**/*.{js,ts,tsx}": [
78
+ "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
79
+ "eslint \"{src,apps,libs,test}/**/*.ts\" --fix"
80
+ ]
81
+ },
82
+ "jestSonar": {
83
+ "reportPath": "coverage",
84
+ "reportFile": "test-report.xml",
85
+ "indent": 2
86
+ },
87
+ "dependencies": {
88
+ "axios": "^1.13.2"
89
+ }
90
+ }
package/sampledotenv CHANGED
@@ -1,8 +1,8 @@
1
- DATABASE_URL=
2
- SHADOW_DATABASE_URL=
3
- REDIS_URL=
4
- REDIS_PASSWORD=
5
- SMTP_HOST=
6
- SMTP_PORT=
7
- EMAIL_SENDER=
1
+ DATABASE_URL=
2
+ SHADOW_DATABASE_URL=
3
+ REDIS_URL=
4
+ REDIS_PASSWORD=
5
+ SMTP_HOST=
6
+ SMTP_PORT=
7
+ EMAIL_SENDER=
8
8
  EMAIL_PASSWORD=
@@ -12,7 +12,8 @@ import { createHash, randomBytes, randomUUID } from 'crypto';
12
12
  import { UserGroupRepository } from '../user-group/user-group.repository';
13
13
  import GroupSystemAccessModel from '../../models/group-system-access.entity';
14
14
  import SystemModel from '../../models/system.entity';
15
- import { ApplicationConfig } from '@tomei/config';
15
+ import { ApplicationConfig, ComponentConfig } from '@tomei/config';
16
+ import axios from 'axios';
16
17
 
17
18
  export class LoginUser extends User implements ILoginUser {
18
19
  session = {
@@ -26,20 +27,24 @@ export class LoginUser extends User implements ILoginUser {
26
27
  ): Promise<LoginUser> {
27
28
  User._RedisService = await RedisService.init();
28
29
  if (userId) {
29
- if (dbTransaction) {
30
- User._Repository = new UserRepository();
31
- }
32
- const user = await User._Repository.findOne({
33
- where: {
34
- UserId: userId,
35
- },
36
- include: [
37
- {
38
- model: Staff,
30
+ const loginApiEndpoint = ComponentConfig.getComponentConfigValue(
31
+ '@tomei/sso',
32
+ 'loginApiEndpoint',
33
+ );
34
+
35
+ let payload = { UserId: userId };
36
+
37
+ const { data } = await axios.post(
38
+ `${loginApiEndpoint.baseUrl}${loginApiEndpoint.getProfile}`,
39
+ payload,
40
+ {
41
+ headers: {
42
+ 'Content-Type': 'application/json',
43
+ 'x-api-key': loginApiEndpoint.apiKey,
39
44
  },
40
- ],
41
- transaction: dbTransaction,
42
- });
45
+ },
46
+ );
47
+ const user = data.loginUser;
43
48
 
44
49
  if (!user) {
45
50
  throw new Error('Invalid credentials.');
@@ -54,21 +59,21 @@ export class LoginUser extends User implements ILoginUser {
54
59
  IDType: user?.IdType || null,
55
60
  ContactNo: user?.ContactNo || null,
56
61
  Email: user.Email,
57
- Password: user.Password,
62
+ Password: null,
58
63
  Status: user.Status,
59
- DefaultPasswordChangedYN: user.DefaultPasswordChangedYN,
60
- FirstLoginAt: user.FirstLoginAt,
61
- LastLoginAt: user.LastLoginAt,
62
- MFAEnabled: user.MFAEnabled,
63
- MFAConfig: user.MFAConfig,
64
- MFABypassYN: user.MFABypassYN,
65
- RecoveryEmail: user.RecoveryEmail,
66
- FailedLoginAttemptCount: user.FailedLoginAttemptCount,
67
- LastFailedLoginAt: user.LastFailedLoginAt,
68
- LastPasswordChangedAt: user.LastPasswordChangedAt,
69
- NeedToChangePasswordYN: user.NeedToChangePasswordYN,
70
- PasscodeHash: user.PasscodeHash,
71
- PasscodeUpdatedAt: user.PasscodeUpdatedAt,
64
+ DefaultPasswordChangedYN: null,
65
+ FirstLoginAt: null,
66
+ LastLoginAt: null,
67
+ MFAEnabled: null,
68
+ MFAConfig: null,
69
+ MFABypassYN: null,
70
+ RecoveryEmail: null,
71
+ FailedLoginAttemptCount: null,
72
+ LastFailedLoginAt: null,
73
+ LastPasswordChangedAt: null,
74
+ NeedToChangePasswordYN: null,
75
+ PasscodeHash: null,
76
+ PasscodeUpdatedAt: null,
72
77
  CreatedById: user.CreatedById,
73
78
  CreatedAt: user.CreatedAt,
74
79
  UpdatedById: user.UpdatedById,
@@ -99,21 +104,28 @@ export class LoginUser extends User implements ILoginUser {
99
104
  throw new Error('Session name is not set');
100
105
  }
101
106
 
102
- const userSession = await this._SessionService.retrieveUserSession(
103
- this.ObjectId,
104
- sessionName,
107
+ const loginApiEndpoint = ComponentConfig.getComponentConfigValue(
108
+ '@tomei/sso',
109
+ 'loginApiEndpoint',
105
110
  );
106
-
107
- const systemLogin = userSession.systemLogins.find(
108
- (system) => system.code === systemCode,
111
+ let payload = {
112
+ SystemCode: systemCode,
113
+ SessionName: sessionName,
114
+ PrivilegeName: privilegeName,
115
+ UserId: this.ObjectId,
116
+ };
117
+ const { data } = await axios.post(
118
+ `${loginApiEndpoint.baseUrl}${loginApiEndpoint.checkPrivileges}`,
119
+ payload,
120
+ {
121
+ headers: {
122
+ 'Content-Type': 'application/json',
123
+ 'x-api-key': loginApiEndpoint.apiKey,
124
+ },
125
+ },
109
126
  );
127
+ const hasPrivilege = data.hasPrivilege;
110
128
 
111
- if (!systemLogin) {
112
- return false;
113
- }
114
-
115
- const privileges = systemLogin.privileges;
116
- const hasPrivilege = privileges.includes(privilegeName);
117
129
  return hasPrivilege;
118
130
  } catch (error) {
119
131
  throw error;
@@ -131,28 +143,27 @@ export class LoginUser extends User implements ILoginUser {
131
143
  if (!sessionName) {
132
144
  throw new Error('Session name is not set');
133
145
  }
134
- const userSession = await this._SessionService.retrieveUserSession(
135
- userId,
136
- sessionName,
146
+ const loginApiEndpoint = ComponentConfig.getComponentConfigValue(
147
+ '@tomei/sso',
148
+ 'loginApiEndpoint',
137
149
  );
138
-
139
- if (userSession.systemLogins.length === 0) {
140
- throw new Error('Session expired.');
141
- }
142
-
143
- const systemLogin = userSession.systemLogins.find(
144
- (sl) => sl.code === systemCode,
150
+ let payload = {
151
+ SystemCode: systemCode,
152
+ SessionName: sessionName,
153
+ SessionId: sessionId,
154
+ UserId: userId,
155
+ };
156
+ const { data } = await axios.post(
157
+ `${loginApiEndpoint.baseUrl}${loginApiEndpoint.checkSession}`,
158
+ payload,
159
+ {
160
+ headers: {
161
+ 'Content-Type': 'application/json',
162
+ 'x-api-key': loginApiEndpoint.apiKey,
163
+ },
164
+ },
145
165
  );
146
-
147
- if (!systemLogin) {
148
- throw new Error('Session expired.');
149
- }
150
-
151
- if (systemLogin.sessionId !== sessionId) {
152
- throw new Error('Session expired.');
153
- }
154
-
155
- await this._SessionService.refreshDuration(userId, sessionName);
166
+ const systemLogin = data.systemLogin;
156
167
 
157
168
  return systemLogin;
158
169
  } catch (error) {
@@ -328,36 +339,26 @@ export class LoginUser extends User implements ILoginUser {
328
339
  throw new Error('Session name is not set in the configuration');
329
340
  }
330
341
 
331
- const userSession = await this._SessionService.retrieveUserSession(
332
- this.ObjectId,
333
- sessionName,
342
+ const loginApiEndpoint = ComponentConfig.getComponentConfigValue(
343
+ '@tomei/sso',
344
+ 'loginApiEndpoint',
334
345
  );
335
- const systemLogin = userSession.systemLogins.find(
336
- (system) => system.code === systemCode,
337
- );
338
-
339
- if (systemLogin) {
340
- const privileges = await this.getPrivileges(systemCode, dbTransaction);
341
- systemLogin.sessionId = sessionId;
342
- systemLogin.privileges = privileges;
343
- userSession.systemLogins.map((system) =>
344
- system.code === systemCode ? systemLogin : system,
345
- );
346
- } else {
347
- // if not, add new system login into the userSession
348
- const newLogin = {
349
- id: systemCode,
350
- code: systemCode,
351
- sessionId: sessionId,
352
- privileges: await this.getPrivileges(systemCode, dbTransaction),
353
- };
354
- userSession.systemLogins.push(newLogin);
355
- }
356
- // then update userSession inside the redis storage with 1 day duration of time-to-live
357
- this._SessionService.setUserSession(
358
- this.ObjectId,
359
- userSession,
360
- sessionName,
346
+ let payload = {
347
+ SystemCode: systemCode,
348
+ SessionName: sessionName,
349
+ SessionId: sessionId,
350
+ UserId: this.ObjectId,
351
+ };
352
+
353
+ await axios.post(
354
+ `${loginApiEndpoint.baseUrl}${loginApiEndpoint.setSession}`,
355
+ payload,
356
+ {
357
+ headers: {
358
+ 'Content-Type': 'application/json',
359
+ 'x-api-key': loginApiEndpoint.apiKey,
360
+ },
361
+ },
361
362
  );
362
363
  }
363
364
  }
package/src/index.ts CHANGED
@@ -6,3 +6,4 @@ export * from './session';
6
6
  export * from './enum';
7
7
  export * as ssoDb from './database';
8
8
  export * from './types';
9
+ export * from './models/user.entity';
@@ -1,6 +1,6 @@
1
- {
2
- "extends": "./tsconfig.json",
3
- "include": ["**/*.ts"],
4
- "exclude": ["node_modules", "__tests__", "dist", "**/*spec.ts"]
5
- }
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "include": ["**/*.ts"],
4
+ "exclude": ["node_modules", "__tests__", "dist", "**/*spec.ts"]
5
+ }
6
6
 
package/tsconfig.json CHANGED
@@ -1,24 +1,24 @@
1
- {
2
- "compilerOptions": {
3
- "module": "commonjs",
4
- "declaration": true,
5
- "removeComments": true,
6
- "emitDecoratorMetadata": true,
7
- "experimentalDecorators": true,
8
- "allowSyntheticDefaultImports": true,
9
- "moduleResolution": "node",
10
- "target": "es6",
11
- "sourceMap": true,
12
- "outDir": "./dist",
13
- "baseUrl": "./src",
14
- "rootDir": "./",
15
- "incremental": true,
16
- "skipLibCheck": true,
17
- "noImplicitAny": false,
18
- "strictBindCallApply": false,
19
- "forceConsistentCasingInFileNames": false,
20
- "noFallthroughCasesInSwitch": false,
21
- "strictNullChecks": false,
22
- },
23
- "exclude": ["node_modules", "dist"]
1
+ {
2
+ "compilerOptions": {
3
+ "module": "commonjs",
4
+ "declaration": true,
5
+ "removeComments": true,
6
+ "emitDecoratorMetadata": true,
7
+ "experimentalDecorators": true,
8
+ "allowSyntheticDefaultImports": true,
9
+ "moduleResolution": "node",
10
+ "target": "es6",
11
+ "sourceMap": true,
12
+ "outDir": "./dist",
13
+ "baseUrl": "./src",
14
+ "rootDir": "./",
15
+ "incremental": true,
16
+ "skipLibCheck": true,
17
+ "noImplicitAny": false,
18
+ "strictBindCallApply": false,
19
+ "forceConsistentCasingInFileNames": false,
20
+ "noFallthroughCasesInSwitch": false,
21
+ "strictNullChecks": false,
22
+ },
23
+ "exclude": ["node_modules", "dist"]
24
24
  }