@tomei/sso 0.4.0 → 0.8.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/__tests__/unit/components/login-user/login-user.spec.ts +107 -19
- package/__tests__/unit/session/session.service.spec.ts +20 -0
- package/dist/__tests__/unit/components/login-user/login-user.spec.js +89 -18
- package/dist/__tests__/unit/components/login-user/login-user.spec.js.map +1 -1
- package/dist/__tests__/unit/session/session.service.spec.js +19 -0
- package/dist/__tests__/unit/session/session.service.spec.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/src/components/login-user/login-user.d.ts +3 -1
- package/dist/src/components/login-user/login-user.js +82 -19
- package/dist/src/components/login-user/login-user.js.map +1 -1
- package/dist/src/index.d.ts +0 -1
- package/dist/src/index.js +0 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/session/interfaces/session-service.interface.d.ts +1 -0
- package/dist/src/session/session.service.d.ts +1 -0
- package/dist/src/session/session.service.js +12 -0
- package/dist/src/session/session.service.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/index.ts +1 -1
- package/package.json +4 -1
- package/src/components/login-user/login-user.ts +107 -21
- package/src/index.ts +0 -1
- package/src/session/interfaces/session-service.interface.ts +1 -0
- package/src/session/session.service.ts +10 -0
- package/src/mail/index.ts +0 -2
- package/src/mail/interfaces/index.ts +0 -2
- package/src/mail/interfaces/send-mail.interface.ts +0 -8
- package/src/mail/interfaces/send-new-login-alert.interface.ts +0 -6
- package/src/mail/mail.service.ts +0 -33
- package/src/mail/mail.ts +0 -40
package/index.ts
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export * from
|
1
|
+
export * from './src';
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@tomei/sso",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.8.0",
|
4
4
|
"description": "Tomei SSO Package",
|
5
5
|
"main": "dist/index.js",
|
6
6
|
"scripts": {
|
@@ -70,5 +70,8 @@
|
|
70
70
|
"prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
71
71
|
"eslint \"{src,apps,libs,test}/**/*.ts\" --fix"
|
72
72
|
]
|
73
|
+
},
|
74
|
+
"dependencies": {
|
75
|
+
"@tomei/mailer": "^0.1.3"
|
73
76
|
}
|
74
77
|
}
|
@@ -6,12 +6,13 @@ import { UserRepository } from './user.repository';
|
|
6
6
|
import { SystemRepository } from '../system/system.repository';
|
7
7
|
import { SystemAccessRepository } from '../system-access/system-access.repository';
|
8
8
|
import { LoginHistoryRepository } from '../login-history/login-history.repository';
|
9
|
-
import { MailService } from '../../mail/mail.service';
|
10
9
|
import { UserUserGroupRepository } from '../user-user-group/user-user-group.repository';
|
11
10
|
import { PasswordHashService } from '../password-hash/password-hash.service';
|
12
11
|
import { SessionService } from '../../session/session.service';
|
13
12
|
import { UserGroupRepository } from '../user-group/user-group.repository';
|
14
|
-
|
13
|
+
import * as nodemailer from 'nodemailer';
|
14
|
+
import { Mailer } from '@tomei/mailer';
|
15
|
+
import { ISystemLogin } from '../../../src/interfaces/system-login.interface';
|
15
16
|
export class LoginUser extends ObjectBase implements IPerson {
|
16
17
|
FullName: string;
|
17
18
|
IDNo: string;
|
@@ -28,7 +29,6 @@ export class LoginUser extends ObjectBase implements IPerson {
|
|
28
29
|
private _OriginIP: string;
|
29
30
|
private _SessionService: ISessionService;
|
30
31
|
private _PasswordHashService = new PasswordHashService();
|
31
|
-
private _MailService = new MailService();
|
32
32
|
private static _Repository = new UserRepository();
|
33
33
|
private static _SystemRepository = new SystemRepository();
|
34
34
|
private static _SystemAccessRepository = new SystemAccessRepository();
|
@@ -233,26 +233,53 @@ export class LoginUser extends ObjectBase implements IPerson {
|
|
233
233
|
systemId: string,
|
234
234
|
ipAddress: string,
|
235
235
|
) {
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
236
|
+
try {
|
237
|
+
const userLogins = await LoginUser._LoginHistoryRepository.findAll({
|
238
|
+
where: {
|
239
|
+
userId: userId,
|
240
|
+
systemId: systemId,
|
241
|
+
},
|
242
|
+
});
|
242
243
|
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
244
|
+
const gotPreviousLogins = userLogins?.length !== 0;
|
245
|
+
let ipFound = null;
|
246
|
+
if (gotPreviousLogins) {
|
247
|
+
ipFound = userLogins.find((item) => item.ipAddress === ipAddress);
|
248
|
+
}
|
248
249
|
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
250
|
+
if (gotPreviousLogins && !ipFound) {
|
251
|
+
const SMTP_HOST = process.env.SMTP_HOST || '';
|
252
|
+
const SMTP_PORT = process.env.SMTP_PORT || '';
|
253
|
+
const EMAIL_SENDER = process.env.EMAIL_SENDER || '';
|
254
|
+
const EMAIL_PASSWORD = process.env.EMAIL_PASSWORD || '';
|
255
|
+
|
256
|
+
const mailer = new Mailer(nodemailer, {
|
257
|
+
host: SMTP_HOST,
|
258
|
+
port: Number(SMTP_PORT),
|
259
|
+
secure: Number(SMTP_PORT) === 465,
|
260
|
+
auth: {
|
261
|
+
user: EMAIL_SENDER,
|
262
|
+
pass: EMAIL_PASSWORD,
|
263
|
+
},
|
264
|
+
});
|
265
|
+
|
266
|
+
await mailer.sendMail({
|
267
|
+
from: process.env.EMAIL_SENDER,
|
268
|
+
to: this.Email,
|
269
|
+
subject: 'New Login Alert',
|
270
|
+
html: `<p>Dear ${this.FullName},</p>
|
271
|
+
<p>There was a new login to your account from ${ipAddress} on ${new Date().toLocaleString()}.</p>
|
272
|
+
<p>If this was you, you can safely ignore this email.</p>
|
273
|
+
<p>If you suspect that someone else is trying to access your account, please contact us immediately at itd-support@tomei.com.my.</p>
|
274
|
+
<p>Thank you!,</p>
|
275
|
+
<p>
|
276
|
+
Best Regards,
|
277
|
+
IT Department
|
278
|
+
</p>`,
|
279
|
+
});
|
280
|
+
}
|
281
|
+
} catch (error) {
|
282
|
+
throw error;
|
256
283
|
}
|
257
284
|
}
|
258
285
|
|
@@ -431,4 +458,63 @@ export class LoginUser extends ObjectBase implements IPerson {
|
|
431
458
|
throw error;
|
432
459
|
}
|
433
460
|
}
|
461
|
+
|
462
|
+
async checkPrivileges(
|
463
|
+
systemCode: string,
|
464
|
+
privilegeName: string,
|
465
|
+
): Promise<boolean> {
|
466
|
+
if (!this.ObjectId) {
|
467
|
+
throw new Error('ObjectId(UserId) is not set');
|
468
|
+
}
|
469
|
+
|
470
|
+
const userSession = await this._SessionService.retrieveUserSession(
|
471
|
+
this.ObjectId,
|
472
|
+
);
|
473
|
+
|
474
|
+
const systemLogin = userSession.systemLogins.find(
|
475
|
+
(system) => system.code === systemCode,
|
476
|
+
);
|
477
|
+
|
478
|
+
if (!systemLogin) {
|
479
|
+
return false;
|
480
|
+
}
|
481
|
+
|
482
|
+
const privileges = systemLogin.privileges;
|
483
|
+
const hasPrivilege = privileges.includes(privilegeName);
|
484
|
+
return hasPrivilege;
|
485
|
+
}
|
486
|
+
|
487
|
+
async checkSession(
|
488
|
+
systemCode: string,
|
489
|
+
sessionId: string,
|
490
|
+
userId: string,
|
491
|
+
): Promise<ISystemLogin> {
|
492
|
+
try {
|
493
|
+
const userSession = await this._SessionService.retrieveUserSession(
|
494
|
+
userId,
|
495
|
+
);
|
496
|
+
|
497
|
+
if (userSession.systemLogins.length === 0) {
|
498
|
+
throw new Error('Session expired.');
|
499
|
+
}
|
500
|
+
|
501
|
+
const systemLogin = userSession.systemLogins.find(
|
502
|
+
(sl) => sl.code === systemCode,
|
503
|
+
);
|
504
|
+
|
505
|
+
if (!systemLogin) {
|
506
|
+
throw new Error('Session expired.');
|
507
|
+
}
|
508
|
+
|
509
|
+
if (systemLogin.sessionId !== sessionId) {
|
510
|
+
throw new Error('Session expired.');
|
511
|
+
}
|
512
|
+
|
513
|
+
await this._SessionService.refreshDuration(userId);
|
514
|
+
|
515
|
+
return systemLogin;
|
516
|
+
} catch (error) {
|
517
|
+
throw error;
|
518
|
+
}
|
519
|
+
}
|
434
520
|
}
|
package/src/index.ts
CHANGED
@@ -3,4 +3,5 @@ import { IUserSession } from '../../interfaces/user-session.interface';
|
|
3
3
|
export interface ISessionService {
|
4
4
|
retrieveUserSession(userId: string): Promise<IUserSession>;
|
5
5
|
setUserSession(userId: string, sessionData: IUserSession): Promise<void>;
|
6
|
+
refreshDuration(userId: string): Promise<void>;
|
6
7
|
}
|
@@ -42,4 +42,14 @@ export class SessionService implements ISessionService {
|
|
42
42
|
throw error;
|
43
43
|
}
|
44
44
|
}
|
45
|
+
|
46
|
+
async refreshDuration(userid: string): Promise<void> {
|
47
|
+
try {
|
48
|
+
const key = `tomei-sid:${userid}`;
|
49
|
+
const userSession = await this.retrieveUserSession(userid);
|
50
|
+
await this.setUserSession(key, userSession);
|
51
|
+
} catch (error) {
|
52
|
+
throw error;
|
53
|
+
}
|
54
|
+
}
|
45
55
|
}
|
package/src/mail/index.ts
DELETED
package/src/mail/mail.service.ts
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
import { ISendNewLoginAlertOptions } from './interfaces/send-new-login-alert.interface';
|
2
|
-
import Mail from './mail';
|
3
|
-
|
4
|
-
export class MailService {
|
5
|
-
MailClient: Mail;
|
6
|
-
constructor() {
|
7
|
-
this.MailClient = Mail.init();
|
8
|
-
}
|
9
|
-
|
10
|
-
public async sendNewLoginAlertEmail(
|
11
|
-
options: ISendNewLoginAlertOptions,
|
12
|
-
): Promise<void> {
|
13
|
-
try {
|
14
|
-
await this.MailClient.sendMail({
|
15
|
-
to: options.Email,
|
16
|
-
subject: 'New Login Alert',
|
17
|
-
html: `<p>Dear ${options.Name},</p>
|
18
|
-
<p>There was a new login to your account from ${
|
19
|
-
options.IpAddress
|
20
|
-
} on ${options.LoginDate.toLocaleString()}.</p>
|
21
|
-
<p>If this was you, you can safely ignore this email.</p>
|
22
|
-
<p>If you suspect that someone else is trying to access your account, please contact us immediately at itd-support@tomei.com.my.</p>
|
23
|
-
<p>Thank you!,</p>
|
24
|
-
<p>
|
25
|
-
Best Regards,
|
26
|
-
IT Department
|
27
|
-
</p>`,
|
28
|
-
});
|
29
|
-
} catch (error) {
|
30
|
-
throw error;
|
31
|
-
}
|
32
|
-
}
|
33
|
-
}
|
package/src/mail/mail.ts
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
import * as nodemailer from 'nodemailer';
|
2
|
-
import { ISendMailOptionsInterface } from './interfaces/send-mail.interface';
|
3
|
-
|
4
|
-
export default class Mail {
|
5
|
-
private static transporter: nodemailer.Transporter;
|
6
|
-
|
7
|
-
constructor() {}
|
8
|
-
|
9
|
-
static init() {
|
10
|
-
if (!Mail.transporter) {
|
11
|
-
Mail.transporter = nodemailer.createTransport({
|
12
|
-
host: process.env.SMTP_HOST,
|
13
|
-
port: Number(process.env.SMTP_PORT),
|
14
|
-
secure: Number(process.env.SMTP_PORT) === 465,
|
15
|
-
auth: {
|
16
|
-
user: process.env.EMAIL_SENDER,
|
17
|
-
pass: process.env.EMAIL_PASSWORD,
|
18
|
-
},
|
19
|
-
});
|
20
|
-
}
|
21
|
-
return new Mail();
|
22
|
-
}
|
23
|
-
|
24
|
-
//SEND MAIL
|
25
|
-
async sendMail(options: ISendMailOptionsInterface): Promise<void> {
|
26
|
-
try {
|
27
|
-
await Mail.transporter.sendMail({
|
28
|
-
from: process.env.EMAIL_SENDER,
|
29
|
-
to: options.to,
|
30
|
-
cc: options.cc,
|
31
|
-
bcc: options.bcc,
|
32
|
-
subject: options.subject,
|
33
|
-
text: options.text,
|
34
|
-
html: options.html,
|
35
|
-
});
|
36
|
-
} catch (error) {
|
37
|
-
throw error;
|
38
|
-
}
|
39
|
-
}
|
40
|
-
}
|