@tomei/sso 0.38.9 → 0.39.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. package/dist/src/components/api-key/api-key.d.ts +39 -0
  2. package/dist/src/components/api-key/api-key.js +125 -0
  3. package/dist/src/components/api-key/api-key.js.map +1 -0
  4. package/dist/src/components/api-key/api-key.repository.d.ts +6 -0
  5. package/dist/src/components/api-key/api-key.repository.js +26 -0
  6. package/dist/src/components/api-key/api-key.repository.js.map +1 -0
  7. package/dist/src/components/api-key/index.d.ts +3 -0
  8. package/dist/src/components/api-key/index.js +8 -0
  9. package/dist/src/components/api-key/index.js.map +1 -0
  10. package/dist/src/components/login-user/user.js +4 -4
  11. package/dist/src/components/login-user/user.js.map +1 -1
  12. package/dist/src/enum/api-key.enum.d.ts +5 -0
  13. package/dist/src/enum/api-key.enum.js +10 -0
  14. package/dist/src/enum/api-key.enum.js.map +1 -0
  15. package/dist/src/enum/index.d.ts +1 -0
  16. package/dist/src/enum/index.js +1 -0
  17. package/dist/src/enum/index.js.map +1 -1
  18. package/dist/src/interfaces/api-key-attr.interface.d.ts +13 -0
  19. package/dist/src/interfaces/api-key-attr.interface.js +3 -0
  20. package/dist/src/interfaces/api-key-attr.interface.js.map +1 -0
  21. package/dist/src/interfaces/index.d.ts +1 -0
  22. package/dist/src/interfaces/index.js +1 -0
  23. package/dist/src/interfaces/index.js.map +1 -1
  24. package/dist/src/models/api-key-entity.d.ts +17 -0
  25. package/dist/src/models/api-key-entity.js +105 -0
  26. package/dist/src/models/api-key-entity.js.map +1 -0
  27. package/dist/tsconfig.tsbuildinfo +1 -1
  28. package/migrations/20240528063108-create-api-key-table.js +89 -0
  29. package/package.json +1 -1
  30. package/src/components/api-key/api-key.repository.ts +15 -0
  31. package/src/components/api-key/api-key.ts +196 -0
  32. package/src/components/api-key/index.ts +4 -0
  33. package/src/components/login-user/user.ts +4 -4
  34. package/src/enum/api-key.enum.ts +5 -0
  35. package/src/enum/index.ts +1 -0
  36. package/src/interfaces/api-key-attr.interface.ts +14 -0
  37. package/src/interfaces/index.ts +1 -0
  38. package/src/models/api-key-entity.ts +87 -0
@@ -0,0 +1,89 @@
1
+ 'use strict';
2
+
3
+ /** @type {import('sequelize-cli').Migration} */
4
+ module.exports = {
5
+ async up(queryInterface, Sequelize) {
6
+ await queryInterface.createTable(
7
+ 'sso_APIKey',
8
+ {
9
+ APIKeyId: {
10
+ primaryKey: true,
11
+ type: Sequelize.INTEGER,
12
+ allowNull: false,
13
+ autoIncrement: true,
14
+ },
15
+ APIKey: {
16
+ type: Sequelize.STRING(128),
17
+ allowNull: false,
18
+ unique: true,
19
+ },
20
+ Name: {
21
+ type: Sequelize.STRING(255),
22
+ allowNull: false,
23
+ },
24
+ Description: {
25
+ type: Sequelize.TEXT,
26
+ allowNull: true,
27
+ },
28
+ Status: {
29
+ type: Sequelize.STRING(50),
30
+ defaultValue: 'Active',
31
+ allowNull: false,
32
+ },
33
+ ExpirationDate: {
34
+ allowNull: false,
35
+ type: Sequelize.DATE,
36
+ },
37
+ CreatedAt: {
38
+ allowNull: false,
39
+ defaultValue: Sequelize.literal('CURRENT_TIMESTAMP(3)'),
40
+ type: Sequelize.DATE,
41
+ },
42
+ CreatedById: {
43
+ type: Sequelize.INTEGER,
44
+ allowNull: true,
45
+ references: {
46
+ model: 'sso_User',
47
+ key: 'UserId',
48
+ },
49
+ onDelete: 'CASCADE',
50
+ onUpdate: 'CASCADE',
51
+ },
52
+ InvokedAt: {
53
+ allowNull: true,
54
+ type: Sequelize.DATE,
55
+ },
56
+ InvokedById: {
57
+ type: Sequelize.INTEGER,
58
+ allowNull: true,
59
+ references: {
60
+ model: 'sso_User',
61
+ key: 'UserId',
62
+ },
63
+ onDelete: 'CASCADE',
64
+ onUpdate: 'CASCADE',
65
+ },
66
+ },
67
+ {
68
+ uniqueKeys: {
69
+ IDX_ApiKey: {
70
+ customIndex: true,
71
+ fields: ['APIKey'],
72
+ },
73
+ IDX_CreatedById: {
74
+ customIndex: true,
75
+ fields: ['CreatedById'],
76
+ },
77
+ IDX_InvokedById: {
78
+ customIndex: true,
79
+ fields: ['InvokedById'],
80
+ },
81
+ },
82
+ },
83
+ );
84
+ },
85
+
86
+ async down(queryInterface, Sequelize) {
87
+ await queryInterface.dropTable('sso_APIKey');
88
+ },
89
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tomei/sso",
3
- "version": "0.38.9",
3
+ "version": "0.39.0",
4
4
  "description": "Tomei SSO Package",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -0,0 +1,15 @@
1
+ import { RepositoryBase, IRepositoryBase } from '@tomei/general';
2
+ import APIKeyModel from 'models/api-key-entity';
3
+
4
+ export class APIKeyRepository
5
+ extends RepositoryBase<APIKeyModel>
6
+ implements IRepositoryBase<APIKeyModel>
7
+ {
8
+ constructor() {
9
+ super(APIKeyModel);
10
+ }
11
+
12
+ async findByPk(id: string, options?: any): Promise<APIKeyModel> {
13
+ return await APIKeyModel.findByPk(parseInt(id), options);
14
+ }
15
+ }
@@ -0,0 +1,196 @@
1
+ import { ClassError, ObjectBase } from '@tomei/general';
2
+ import { APIKeyStatusEnum } from '../../enum/api-key.enum';
3
+ import { APIKeyRepository } from './api-key.repository';
4
+ import { IAPIKeyAttr } from '../../interfaces/api-key-attr.interface';
5
+ import { LoginUser } from '../login-user/login-user';
6
+ import { ApplicationConfig } from '@tomei/config';
7
+ import { randomUUID, randomBytes } from 'crypto';
8
+ import { ActionEnum, Activity } from '@tomei/activity-history';
9
+
10
+ export class APIKey extends ObjectBase {
11
+ ObjectId: string;
12
+ ObjectName: string;
13
+ ObjectType: 'ApiKey';
14
+ TableName: 'sso_APIKey';
15
+
16
+ ApiKey: string;
17
+ Name: string;
18
+ Description: string;
19
+ Status: APIKeyStatusEnum;
20
+ ExperationDate: Date;
21
+ _InvokedById: number;
22
+ _InvokedAt: Date;
23
+ _CreatedAt: Date;
24
+ _CreatedById: number;
25
+
26
+ get APIKeyId(): number {
27
+ return parseInt(this.ObjectId);
28
+ }
29
+
30
+ set APIKeyId(value: number) {
31
+ this.ObjectId = value.toString();
32
+ }
33
+
34
+ get InvokedById(): number {
35
+ return this._InvokedById;
36
+ }
37
+
38
+ get InvokedAt(): Date {
39
+ return this._InvokedAt;
40
+ }
41
+
42
+ get CreatedAt(): Date {
43
+ return this._CreatedAt;
44
+ }
45
+
46
+ get CreatedById(): number {
47
+ return this._CreatedById;
48
+ }
49
+
50
+ protected static _Repo = new APIKeyRepository();
51
+
52
+ protected constructor(apiKeyAttr?: IAPIKeyAttr) {
53
+ super();
54
+ if (apiKeyAttr) {
55
+ this.APIKeyId = apiKeyAttr.APIKeyId;
56
+ this.ApiKey = apiKeyAttr.ApiKey;
57
+ this.Name = apiKeyAttr.Name;
58
+ this.Description = apiKeyAttr.Description;
59
+ this.Status = apiKeyAttr.Status;
60
+ this.ExperationDate = apiKeyAttr.ExperationDate;
61
+ this._InvokedById = apiKeyAttr.InvokedById;
62
+ this._InvokedAt = apiKeyAttr.InvokedAt;
63
+ this._CreatedAt = apiKeyAttr.CreatedAt;
64
+ this._CreatedById = apiKeyAttr.CreatedById;
65
+ }
66
+ }
67
+
68
+ public static async init(ApiKeyId?: number, dbTransaction?: any) {
69
+ try {
70
+ if (ApiKeyId) {
71
+ const apiKeyAttr = await this._Repo.findByPk(
72
+ ApiKeyId.toString(),
73
+ dbTransaction,
74
+ );
75
+ if (apiKeyAttr) {
76
+ return new APIKey(apiKeyAttr);
77
+ } else {
78
+ throw new ClassError(
79
+ 'APIKey',
80
+ 'APIKeyErrMsgO1',
81
+ 'APIKey not found',
82
+ 'init',
83
+ );
84
+ }
85
+ }
86
+ return new APIKey();
87
+ } catch (error) {
88
+ throw error;
89
+ }
90
+ }
91
+
92
+ async generate(loginUser: LoginUser, dbTransaction?: any) {
93
+ //This method generates a new API key and saves it into the database.
94
+ try {
95
+ // Part 2: Privilege Checking
96
+ // Call loginUser.checkPrivileges() method by passing:
97
+ // SystemCode: <get_from_app_config>
98
+ // PrivilegeCode: "API_KEY_CREATE"
99
+ const systemCode =
100
+ ApplicationConfig.getComponentConfigValue('system-code');
101
+ const isPrivileged = await loginUser.checkPrivileges(
102
+ systemCode,
103
+ 'API_KEY_CREATE',
104
+ );
105
+
106
+ if (!isPrivileged) {
107
+ throw new ClassError(
108
+ 'APIKey',
109
+ 'APIKeyErrMsgO2',
110
+ 'User does not have privilege to generate API key.',
111
+ 'generate',
112
+ );
113
+ }
114
+
115
+ // Part 3: Generate API Key
116
+ // Populate the following attributes:
117
+ // CreatedById: Set to loginUser.UserId.
118
+ this._CreatedById = loginUser.UserId;
119
+ // CreatedAt: Set to current date time.
120
+ this._CreatedAt = new Date();
121
+ // Generate a unique API key string:
122
+ // Use a secure random function or crypto module to generate a 64-character hexadecimal string.
123
+ // Assign the generated string to this.ApiKey.
124
+ this.ApiKey = randomBytes(64).toString('hex');
125
+
126
+ // Part 4: Save API Key to Database
127
+ // Call APIKey._Repo.create() by passing:
128
+ // loginUser
129
+ // dbTransaction
130
+ // This APIKey instance.
131
+ const EntityValueAfter: any = {
132
+ ApiKey: this.ApiKey,
133
+ Name: this.Name,
134
+ Status: this.Status,
135
+ ExpirationDate: this.ExperationDate,
136
+ CreatedAt: this.CreatedAt,
137
+ CreatedById: this.CreatedById,
138
+ InvokedAt: this.InvokedAt,
139
+ InvokedById: this.InvokedById,
140
+ };
141
+
142
+ const data = await APIKey._Repo.create(EntityValueAfter, {
143
+ transaction: dbTransaction,
144
+ });
145
+
146
+ EntityValueAfter.ApiKeyId = data.APIKeyId;
147
+
148
+ // Part 5: Record Generate API Key Activity
149
+ // Initialise EntityValueBefore variable and set to empty object.
150
+ const EntityValueBefore = {};
151
+ // Initialise EntityValueAfter variable and set to this APIKey instance.
152
+ // Instantiate new activity from Activity class, call createId() method, then set:
153
+ const activity = new Activity();
154
+ activity.ActivityId = activity.createId();
155
+ // Action: ActionEnum.Create
156
+ // Description: "Generate API key."
157
+ // EntityType: "APIKey"
158
+ // EntityId: <this.APIKeyId>
159
+ // EntityValueBefore: EntityValueBefore
160
+ // EntityValueAfter: EntityValueAfter
161
+ activity.Action = ActionEnum.CREATE;
162
+ activity.Description = 'Generate API key.';
163
+ activity.EntityType = 'APIKey';
164
+ activity.EntityId = this.ObjectId;
165
+ activity.EntityValueBefore = JSON.stringify(EntityValueBefore);
166
+ activity.EntityValueAfter = JSON.stringify(EntityValueAfter);
167
+ // Call new activity create method by passing:
168
+ // dbTransaction
169
+ // userId: loginUser.ObjectId
170
+ await activity.create(loginUser.ObjectId, dbTransaction);
171
+
172
+ // Part 6: Returns
173
+ // Translate the created APIKey entity into an object and return the following fields:
174
+ // ApiKey
175
+ // Name
176
+ // Status
177
+ // ExpirationDate
178
+ // CreatedAt
179
+ // CreatedById
180
+ // InvokedAt
181
+ // InvokedById
182
+ return {
183
+ ApiKey: this.ApiKey,
184
+ Name: this.Name,
185
+ Status: this.Status,
186
+ ExpirationDate: this.ExperationDate,
187
+ CreatedAt: this.CreatedAt,
188
+ CreatedById: this.CreatedById,
189
+ InvokedAt: this.InvokedAt,
190
+ InvokedById: this.InvokedById,
191
+ };
192
+ } catch (error) {
193
+ throw error;
194
+ }
195
+ }
196
+ }
@@ -0,0 +1,4 @@
1
+ import { APIKeyRepository } from './api-key.repository';
2
+ import { APIKey } from './api-key';
3
+
4
+ export { APIKeyRepository, APIKey };
@@ -32,6 +32,7 @@ import { LoginStatusEnum } from '../../enum/login-status.enum';
32
32
  import { RedisService } from '../../redis-client/redis.service';
33
33
  import { LoginUser } from './login-user';
34
34
  import { SessionService } from '../../session/session.service';
35
+ import { randomUUID } from 'crypto';
35
36
 
36
37
  export class User extends UserBase {
37
38
  ObjectId: string;
@@ -565,16 +566,15 @@ export class User extends UserBase {
565
566
  const userSession = await this._SessionService.retrieveUserSession(
566
567
  this.ObjectId,
567
568
  );
568
- let systemLogin = userSession.systemLogins.find(
569
+ const systemLogin = userSession.systemLogins.find(
569
570
  (system) => system.code === systemCode,
570
571
  );
571
572
 
572
573
  // generate new session id
573
- const { randomUUID } = require('crypto');
574
- const sessionId = randomUUID();
574
+ const sessionId: string = randomUUID();
575
575
 
576
576
  if (systemLogin) {
577
- systemLogin = systemLogin.sessionId = sessionId;
577
+ systemLogin.sessionId = sessionId;
578
578
  userSession.systemLogins.map((system) =>
579
579
  system.code === systemCode ? systemLogin : system,
580
580
  );
@@ -0,0 +1,5 @@
1
+ export enum APIKeyStatusEnum {
2
+ ACTIVE = 'Active',
3
+ INACTIVE = 'Inactive',
4
+ EXPIRED = 'Expired',
5
+ }
package/src/enum/index.ts CHANGED
@@ -3,3 +3,4 @@ export * from './user-status.enum';
3
3
  export * from './group-type.enum';
4
4
  export * from './object-status.enum';
5
5
  export * from './login-status.enum';
6
+ export * from './api-key.enum';
@@ -0,0 +1,14 @@
1
+ import { APIKeyStatusEnum } from '../enum/api-key.enum';
2
+
3
+ export interface IAPIKeyAttr {
4
+ APIKeyId: number;
5
+ ApiKey: string;
6
+ Name: string;
7
+ Description: string;
8
+ Status: APIKeyStatusEnum;
9
+ ExperationDate: Date;
10
+ CreatedById: number;
11
+ InvokedById: number;
12
+ CreatedAt: Date;
13
+ InvokedAt: Date;
14
+ }
@@ -10,3 +10,4 @@ export * from './group-object-privilege.interface';
10
10
  export * from './group-privilege.interface';
11
11
  export * from './system-search-attr.interface';
12
12
  export * from './group-search-attr.interface';
13
+ export * from './api-key-attr.interface';
@@ -0,0 +1,87 @@
1
+ import {
2
+ BelongsTo,
3
+ Column,
4
+ CreatedAt,
5
+ DataType,
6
+ ForeignKey,
7
+ Index,
8
+ Model,
9
+ Table,
10
+ } from 'sequelize-typescript';
11
+ import User from './user.entity';
12
+ import { APIKeyStatusEnum } from '../enum/api-key.enum';
13
+
14
+ @Table({
15
+ tableName: 'sso_ApiKey',
16
+ timestamps: true,
17
+ createdAt: 'CreatedAt',
18
+ updatedAt: false,
19
+ })
20
+ export default class APIKeyModel extends Model {
21
+ @Column({
22
+ primaryKey: true,
23
+ type: DataType.INTEGER,
24
+ allowNull: false,
25
+ autoIncrement: true,
26
+ })
27
+ APIKeyId: number;
28
+
29
+ @Column({
30
+ type: DataType.STRING(128),
31
+ })
32
+ @Index('IDX_ApiKey')
33
+ ApiKey: string;
34
+
35
+ @Column({
36
+ type: DataType.STRING(255),
37
+ allowNull: false,
38
+ })
39
+ Name: string;
40
+
41
+ @Column({
42
+ type: DataType.TEXT,
43
+ allowNull: true,
44
+ })
45
+ Description: string;
46
+
47
+ @Column({
48
+ type: DataType.STRING(50),
49
+ allowNull: false,
50
+ })
51
+ Status: APIKeyStatusEnum;
52
+
53
+ @Column({
54
+ type: DataType.DATE,
55
+ allowNull: true,
56
+ })
57
+ ExperationDate: Date;
58
+
59
+ @ForeignKey(() => User)
60
+ @Column({
61
+ type: DataType.INTEGER,
62
+ })
63
+ @Index('IDX_CreatedById')
64
+ CreatedById: number;
65
+
66
+ @ForeignKey(() => User)
67
+ @Column({
68
+ type: DataType.INTEGER,
69
+ })
70
+ @Index('IDX_InvokedById')
71
+ InvokedById: number;
72
+
73
+ @CreatedAt
74
+ CreatedAt: Date;
75
+
76
+ @Column({
77
+ type: DataType.DATE,
78
+ allowNull: true,
79
+ })
80
+ InvokedAt: Date;
81
+
82
+ @BelongsTo(() => User, 'CreatedById')
83
+ CreatedByUser: User;
84
+
85
+ @BelongsTo(() => User, 'RevokedById')
86
+ UpdatedByUser: User;
87
+ }