@tomei/sso
Version:
Tomei SSO Package
1,085 lines • 117 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.User = void 0;
const general_1 = require("@tomei/general");
const user_repository_1 = require("./user.repository");
const system_repository_1 = require("../system/system.repository");
const login_history_repository_1 = require("../login-history/login-history.repository");
const password_hash_service_1 = require("../password-hash/password-hash.service");
const user_group_repository_1 = require("../user-group/user-group.repository");
const staff_entity_1 = require("../../models/staff.entity");
const system_privilege_entity_1 = require("../../models/system-privilege.entity");
const yn_enum_1 = require("../../enum/yn.enum");
const enum_1 = require("../../enum");
const config_1 = require("@tomei/config");
const sequelize_1 = require("sequelize");
const activity_history_1 = require("@tomei/activity-history");
const group_entity_1 = require("../../models/group.entity");
const group_system_access_repository_1 = require("../group-system-access/group-system-access.repository");
const group_repository_1 = require("../group/group.repository");
const system_entity_1 = require("../../models/system.entity");
const user_system_access_repository_1 = require("../user-system-access/user-system-access.repository");
const group_system_access_entity_1 = require("../../models/group-system-access.entity");
const user_privilege_repository_1 = require("../user-privilege/user-privilege.repository");
const user_object_privilege_repository_1 = require("../user-object-privilege/user-object-privilege.repository");
const group_privilege_entity_1 = require("../../models/group-privilege.entity");
const group_object_privilege_repository_1 = require("../group-object-privilege/group-object-privilege.repository");
const speakeasy = require("speakeasy");
const login_status_enum_1 = require("../../enum/login-status.enum");
const redis_service_1 = require("../../redis-client/redis.service");
const login_user_1 = require("./login-user");
const session_service_1 = require("../../session/session.service");
const crypto_1 = require("crypto");
const user_entity_1 = require("../../models/user.entity");
const user_reporting_hierarchy_repository_1 = require("../user-reporting-hierarchy/user-reporting-hierarchy.repository");
const user_password_history_1 = require("../user-password-history/user-password-history");
class User extends general_1.UserBase {
get SessionService() {
return this._SessionService;
}
get UserId() {
return parseInt(this.ObjectId);
}
set UserId(value) {
this.ObjectId = value.toString();
}
get Password() {
return this._Password;
}
set Password(value) {
this._Password = value;
}
get Status() {
return this._Status;
}
set Status(value) {
this._Status = value;
}
get UserName() {
return this._UserName;
}
set UserName(value) {
this._UserName = value;
}
get DefaultPasswordChangedYN() {
return this._DefaultPasswordChangedYN;
}
set DefaultPasswordChangedYN(value) {
this._DefaultPasswordChangedYN = value;
}
get FirstLoginAt() {
return this._FirstLoginAt;
}
set FirstLoginAt(value) {
this._FirstLoginAt = value;
}
get LastLoginAt() {
return this._LastLoginAt;
}
set LastLoginAt(value) {
this._LastLoginAt = value;
}
get MFAEnabled() {
return this._MFAEnabled;
}
set MFAEnabled(value) {
this._MFAEnabled = value;
}
get MFAConfig() {
return this._MFAConfig;
}
set MFAConfig(value) {
this._MFAConfig = value;
}
get MFABypassYN() {
return this._MFABypassYN;
}
set MFABypassYN(value) {
this._MFABypassYN = value;
}
get RecoveryEmail() {
return this._RecoveryEmail;
}
set RecoveryEmail(value) {
this._RecoveryEmail = value;
}
get FailedLoginAttemptCount() {
return this._FailedLoginAttemptCount;
}
set FailedLoginAttemptCount(value) {
this._FailedLoginAttemptCount = value;
}
get LastFailedLoginAt() {
return this._LastFailedLoginAt;
}
set LastFailedLoginAt(value) {
this._LastFailedLoginAt = value;
}
get LastPasswordChangedAt() {
return this._LastPasswordChangedAt;
}
set LastPasswordChangedAt(value) {
this._LastPasswordChangedAt = value;
}
get NeedToChangePasswordYN() {
return this._NeedToChangePasswordYN;
}
set NeedToChangePasswordYN(value) {
this._NeedToChangePasswordYN = value;
}
get CreatedById() {
return this._CreatedById;
}
set CreatedById(value) {
this._CreatedById = value;
}
get CreatedAt() {
return this._CreatedAt;
}
set CreatedAt(value) {
this._CreatedAt = value;
}
get UpdatedById() {
return this._UpdatedById;
}
set UpdatedById(value) {
this._UpdatedById = value;
}
get UpdatedAt() {
return this._UpdatedAt;
}
set UpdatedAt(value) {
this._UpdatedAt = value;
}
get PasscodeHash() {
return this._PasscodeHash;
}
set PasscodeHash(value) {
this._PasscodeHash = value;
}
get PasscodeUpdatedAt() {
return this._PasscodeUpdatedAt;
}
set PasscodeUpdatedAt(value) {
this._PasscodeUpdatedAt = value;
}
getDetails() {
return __awaiter(this, void 0, void 0, function* () {
return {
FullName: this.FullName,
UserName: this.UserName,
IDNo: this.IDNo,
IDType: this.IDType,
Email: this.Email,
ContactNo: this.ContactNo,
};
});
}
constructor(sessionService, dbTransaction, userInfo) {
super();
this.ObjectName = 'User';
this.TableName = 'sso_Users';
this.ObjectType = 'User';
this._SessionService = sessionService;
if (dbTransaction) {
this._dbTransaction = dbTransaction;
}
if (userInfo) {
this.UserId = userInfo.UserId;
this.UserName = userInfo.UserName;
this.FullName = userInfo.FullName;
this.IDNo = userInfo.IDNo;
this.IDType = userInfo.IDType;
this.Email = userInfo.Email;
this.ContactNo = userInfo.ContactNo;
this.Password = userInfo.Password;
this.staffs = userInfo.staffs;
this.Status = userInfo.Status;
this.DefaultPasswordChangedYN = userInfo.DefaultPasswordChangedYN;
this.FirstLoginAt = userInfo.FirstLoginAt;
this.LastLoginAt = userInfo.LastLoginAt;
this.MFAEnabled = userInfo.MFAEnabled;
this.MFAConfig = userInfo.MFAConfig;
this.MFABypassYN = userInfo.MFABypassYN;
this.RecoveryEmail = userInfo.RecoveryEmail;
this.FailedLoginAttemptCount = userInfo.FailedLoginAttemptCount;
this.LastFailedLoginAt = userInfo.LastFailedLoginAt;
this.LastPasswordChangedAt = userInfo.LastPasswordChangedAt;
this.NeedToChangePasswordYN = userInfo.NeedToChangePasswordYN;
this.PasscodeHash = userInfo.PasscodeHash;
this.PasscodeUpdatedAt = userInfo.PasscodeUpdatedAt;
this.CreatedById = userInfo.CreatedById;
this.CreatedAt = userInfo.CreatedAt;
this.UpdatedById = userInfo.UpdatedById;
this.UpdatedAt = userInfo.UpdatedAt;
}
}
static init(sessionService_1, userId_1) {
return __awaiter(this, arguments, void 0, function* (sessionService, userId, dbTransaction = null) {
User._RedisService = yield redis_service_1.RedisService.init();
if (userId) {
if (dbTransaction) {
User._Repository = new user_repository_1.UserRepository();
}
const user = yield User._Repository.findOne({
where: {
UserId: userId,
},
include: [
{
model: staff_entity_1.default,
},
],
transaction: dbTransaction,
});
if (!user) {
throw new Error('Invalid credentials.');
}
if (user) {
const userAttr = {
UserId: user.UserId,
UserName: user.UserName,
FullName: (user === null || user === void 0 ? void 0 : user.FullName) || null,
IDNo: (user === null || user === void 0 ? void 0 : user.IdNo) || null,
IDType: (user === null || user === void 0 ? void 0 : user.IdType) || null,
ContactNo: (user === null || user === void 0 ? void 0 : user.ContactNo) || null,
Email: user.Email,
Password: user.Password,
Status: user.Status,
DefaultPasswordChangedYN: user.DefaultPasswordChangedYN,
FirstLoginAt: user.FirstLoginAt,
LastLoginAt: user.LastLoginAt,
MFAEnabled: user.MFAEnabled,
MFAConfig: user.MFAConfig,
MFABypassYN: user.MFABypassYN,
RecoveryEmail: user.RecoveryEmail,
FailedLoginAttemptCount: user.FailedLoginAttemptCount,
LastFailedLoginAt: user.LastFailedLoginAt,
LastPasswordChangedAt: user.LastPasswordChangedAt,
NeedToChangePasswordYN: user.NeedToChangePasswordYN,
PasscodeHash: user.PasscodeHash,
PasscodeUpdatedAt: user.PasscodeUpdatedAt,
CreatedById: user.CreatedById,
CreatedAt: user.CreatedAt,
UpdatedById: user.UpdatedById,
UpdatedAt: user.UpdatedAt,
staffs: user === null || user === void 0 ? void 0 : user.Staff,
};
return new User(sessionService, dbTransaction, userAttr);
}
else {
throw new Error('User not found');
}
}
return new User(sessionService, dbTransaction);
});
}
static initUsingEmail(sessionService_1, email_1) {
return __awaiter(this, arguments, void 0, function* (sessionService, email, dbTransaction = null) {
User._RedisService = yield redis_service_1.RedisService.init();
if (email) {
if (dbTransaction) {
User._Repository = new user_repository_1.UserRepository();
}
const user = yield User._Repository.findOne({
where: {
Email: email,
},
include: [
{
model: staff_entity_1.default,
},
],
transaction: dbTransaction,
});
if (!user) {
throw new Error('Invalid email.');
}
if (user) {
const userAttr = {
UserId: user.UserId,
UserName: user.UserName,
FullName: (user === null || user === void 0 ? void 0 : user.FullName) || null,
IDNo: (user === null || user === void 0 ? void 0 : user.IdNo) || null,
IDType: (user === null || user === void 0 ? void 0 : user.IdType) || null,
ContactNo: (user === null || user === void 0 ? void 0 : user.ContactNo) || null,
Email: user.Email,
Password: user.Password,
Status: user.Status,
DefaultPasswordChangedYN: user.DefaultPasswordChangedYN,
FirstLoginAt: user.FirstLoginAt,
LastLoginAt: user.LastLoginAt,
MFAEnabled: user.MFAEnabled,
MFAConfig: user.MFAConfig,
MFABypassYN: user.MFABypassYN,
RecoveryEmail: user.RecoveryEmail,
FailedLoginAttemptCount: user.FailedLoginAttemptCount,
LastFailedLoginAt: user.LastFailedLoginAt,
LastPasswordChangedAt: user.LastPasswordChangedAt,
NeedToChangePasswordYN: user.NeedToChangePasswordYN,
PasscodeHash: user.PasscodeHash,
PasscodeUpdatedAt: user.PasscodeUpdatedAt,
CreatedById: user.CreatedById,
CreatedAt: user.CreatedAt,
UpdatedById: user.UpdatedById,
UpdatedAt: user.UpdatedAt,
staffs: user === null || user === void 0 ? void 0 : user.Staff,
};
return new User(sessionService, dbTransaction, userAttr);
}
else {
throw new Error('User not found');
}
}
});
}
setEmail(email, dbTransaction) {
return __awaiter(this, void 0, void 0, function* () {
try {
if (this.Email === email) {
return;
}
const user = yield User._Repository.findOne({
where: {
Email: email,
},
transaction: dbTransaction,
});
if (user) {
throw new general_1.ClassError('LoginUser', 'LoginUserErrMsg0X', 'Email already exists');
}
this.Email = email;
}
catch (error) {
throw error;
}
});
}
login(systemCode, email, password, ipAddress, dbTransaction) {
return __awaiter(this, void 0, void 0, function* () {
try {
if (!this.ObjectId) {
const user = yield User._Repository.findOne({
transaction: dbTransaction,
where: {
Email: email,
Status: {
[sequelize_1.Op.or]: [enum_1.UserStatus.ACTIVE, enum_1.UserStatus.LOCKED],
},
},
include: [
{
model: staff_entity_1.default,
},
],
});
if (user) {
const userAttr = {
UserId: user.UserId,
UserName: user.UserName,
FullName: (user === null || user === void 0 ? void 0 : user.FullName) || null,
IDNo: (user === null || user === void 0 ? void 0 : user.IdNo) || null,
IDType: (user === null || user === void 0 ? void 0 : user.IdType) || null,
ContactNo: (user === null || user === void 0 ? void 0 : user.ContactNo) || null,
Email: user.Email,
Password: user.Password,
Status: user.Status,
DefaultPasswordChangedYN: user.DefaultPasswordChangedYN,
FirstLoginAt: user.FirstLoginAt,
LastLoginAt: user.LastLoginAt,
MFAEnabled: user.MFAEnabled,
MFAConfig: user.MFAConfig,
MFABypassYN: user.MFABypassYN,
RecoveryEmail: user.RecoveryEmail,
FailedLoginAttemptCount: user.FailedLoginAttemptCount,
LastFailedLoginAt: user.LastFailedLoginAt,
LastPasswordChangedAt: user.LastPasswordChangedAt,
NeedToChangePasswordYN: user.NeedToChangePasswordYN,
PasscodeHash: user.PasscodeHash,
PasscodeUpdatedAt: user.PasscodeUpdatedAt,
CreatedById: user.CreatedById,
CreatedAt: user.CreatedAt,
UpdatedById: user.UpdatedById,
UpdatedAt: user.UpdatedAt,
staffs: (user === null || user === void 0 ? void 0 : user.Staff) || null,
};
this.UserId = userAttr.UserId;
this.FullName = userAttr.FullName;
this.IDNo = userAttr.IDNo;
this.Email = userAttr.Email;
this.ContactNo = userAttr.ContactNo;
this.Password = userAttr.Password;
this.Status = userAttr.Status;
this.DefaultPasswordChangedYN = userAttr.DefaultPasswordChangedYN;
this.FirstLoginAt = userAttr.FirstLoginAt;
this.LastLoginAt = userAttr.LastLoginAt;
this.MFAEnabled = userAttr.MFAEnabled;
this.MFAConfig = userAttr.MFAConfig;
this.RecoveryEmail = userAttr.RecoveryEmail;
this.FailedLoginAttemptCount = userAttr.FailedLoginAttemptCount;
this.LastFailedLoginAt = userAttr.LastFailedLoginAt;
this.LastPasswordChangedAt = userAttr.LastPasswordChangedAt;
this.NeedToChangePasswordYN = userAttr.NeedToChangePasswordYN;
this.CreatedById = userAttr.CreatedById;
this.CreatedAt = userAttr.CreatedAt;
this.UpdatedById = userAttr.UpdatedById;
this.UpdatedAt = userAttr.UpdatedAt;
this.staffs = userAttr.staffs;
}
else {
console.error('User not found for email:', email);
throw new general_1.ClassError('User', 'UserErrMsg0X', 'Invalid Credentials');
}
}
if (this.ObjectId && this.Email !== email) {
console.error('Email mismatch:', this.Email, email);
throw new Error('Invalid credentials.');
}
const check2FA = yield User.check2FA(this, dbTransaction);
try {
const system = yield User._SystemRepository.findOne({
where: {
SystemCode: systemCode,
Status: 'Active',
},
});
if (!system) {
throw new Error('Access denied: invalid or unauthorized system.');
}
const passwordHashService = new password_hash_service_1.PasswordHashService();
const isPasswordValid = yield passwordHashService.verify(password, this.Password);
if (!isPasswordValid) {
console.error('Invalid password for user:', this.UserId);
throw new Error('Invalid credentials.');
}
yield this.checkSystemAccess(this.UserId, system.SystemCode, dbTransaction);
if (this.Status === enum_1.UserStatus.LOCKED) {
const isReleaseLock = User.shouldReleaseLock(this.LastFailedLoginAt);
if (isReleaseLock) {
yield User.releaseLock(this.UserId, dbTransaction);
this.Status = enum_1.UserStatus.ACTIVE;
}
else {
throw new Error('Your account has been locked. Please contact the administrator for assistance.');
}
}
}
catch (error) {
yield this.incrementFailedLoginAttemptCount(dbTransaction);
throw error;
}
const system = yield User._SystemRepository.findOne({
where: {
SystemCode: systemCode,
},
});
yield this.alertNewLogin(this.ObjectId, system.SystemCode, ipAddress);
this.FailedLoginAttemptCount = 0;
this.LastLoginAt = new Date();
if (!this.FirstLoginAt) {
this.FirstLoginAt = new Date();
}
yield User._Repository.update({
FullName: this.FullName,
UserName: this.UserName,
IDNo: this.IDNo,
Email: this.Email,
ContactNo: this.ContactNo,
Password: this.Password,
Status: this.Status,
DefaultPasswordChangedYN: this.DefaultPasswordChangedYN,
FirstLoginAt: this.FirstLoginAt,
LastLoginAt: this.LastLoginAt,
MFAEnabled: this.MFAEnabled,
MFAConfig: this.MFAConfig,
RecoveryEmail: this.RecoveryEmail,
FailedLoginAttemptCount: this.FailedLoginAttemptCount,
LastFailedLoginAt: this.LastFailedLoginAt,
LastPasswordChangedAt: this.LastPasswordChangedAt,
NeedToChangePasswordYN: this.NeedToChangePasswordYN,
}, {
where: {
UserId: this.UserId,
},
transaction: dbTransaction,
});
const sessionName = config_1.ApplicationConfig.getComponentConfigValue('sessionName');
if (!sessionName) {
console.error('Session name is not set in the configuration');
throw new Error('Session name is not set in the configuration');
}
const userSession = yield this._SessionService.retrieveUserSession(this.ObjectId, sessionName);
const systemLogin = userSession.systemLogins.find((system) => system.code === systemCode);
const sessionId = (0, crypto_1.randomUUID)();
if (systemLogin) {
const privileges = yield this.getPrivileges(system.SystemCode, dbTransaction);
systemLogin.sessionId = sessionId;
systemLogin.privileges = privileges;
userSession.systemLogins.map((system) => system.code === systemCode ? systemLogin : system);
}
else {
const newLogin = {
id: system.SystemCode,
code: system.SystemCode,
sessionId: sessionId,
privileges: yield this.getPrivileges(system.SystemCode, dbTransaction),
};
userSession.systemLogins.push(newLogin);
}
this._SessionService.setUserSession(this.ObjectId, userSession, sessionName);
yield User._LoginHistoryRepository.create({
UserId: this.UserId,
SystemCode: system.SystemCode,
OriginIp: ipAddress,
CreatedAt: new Date(),
LoginStatus: login_status_enum_1.LoginStatusEnum.SUCCESS,
}, {
transaction: dbTransaction,
});
const is2FAEnabledYN = config_1.ComponentConfig.getComponentConfigValue('@tomei/sso', 'is2FAEnabledYN');
const loginUser = yield login_user_1.LoginUser.init(this.SessionService, this.UserId, dbTransaction);
if (is2FAEnabledYN === 'Y') {
loginUser.session.Id = `${this.UserId}:`;
}
else {
loginUser.session.Id = `${this.UserId}:${sessionId}`;
}
return loginUser;
}
catch (error) {
if (this.ObjectId) {
yield User._LoginHistoryRepository.create({
UserId: this.UserId,
SystemCode: systemCode,
OriginIp: ipAddress,
LoginStatus: login_status_enum_1.LoginStatusEnum.FAILURE,
CreatedAt: new Date(),
}, {
transaction: dbTransaction,
});
}
console.error('Login failed:', error);
throw error;
}
});
}
checkSystemAccess(userId, systemCode, dbTransaction) {
return __awaiter(this, void 0, void 0, function* () {
try {
let isUserHaveAccess = false;
const systemAccess = yield User._UserSystemAccessRepo.findOne({
where: {
UserId: userId,
SystemCode: systemCode,
Status: 'Active',
},
dbTransaction,
});
if (systemAccess) {
isUserHaveAccess = true;
}
else {
const userGroups = yield User._UserGroupRepo.findAll({
where: {
UserId: userId,
InheritGroupSystemAccessYN: 'Y',
Status: 'Active',
},
include: [
{
model: group_entity_1.default,
},
],
dbTransaction,
});
outer: for (const usergroup of userGroups) {
const group = usergroup.Group;
const groupSystemAccess = yield User.getInheritedSystemAccess(dbTransaction, group);
for (const system of groupSystemAccess) {
if (system.SystemCode === systemCode) {
isUserHaveAccess = true;
break outer;
}
}
}
}
if (!isUserHaveAccess) {
throw new Error("User don't have access to the system.");
}
}
catch (error) {
console.error('Error checking system access:', error);
throw error;
}
});
}
checkPrivileges(systemCode, privilegeName) {
return __awaiter(this, void 0, void 0, function* () {
try {
if (!this.ObjectId) {
throw new Error('ObjectId(UserId) is not set');
}
const sessionName = config_1.ApplicationConfig.getComponentConfigValue('sessionName');
if (!sessionName) {
throw new Error('Session name is not set in the configuration');
}
const userSession = yield this._SessionService.retrieveUserSession(this.ObjectId, sessionName);
const systemLogin = userSession.systemLogins.find((system) => system.code === systemCode);
if (!systemLogin) {
return false;
}
const privileges = systemLogin.privileges;
const hasPrivilege = privileges.includes(privilegeName);
return hasPrivilege;
}
catch (error) {
throw error;
}
});
}
alertNewLogin(userId, systemCode, ipAddress) {
return __awaiter(this, void 0, void 0, function* () {
try {
const userLogins = yield User._LoginHistoryRepository.findAll({
where: {
UserId: userId,
SystemCode: systemCode,
},
});
const gotPreviousLogins = (userLogins === null || userLogins === void 0 ? void 0 : userLogins.length) !== 0;
let ipFound = undefined;
if (gotPreviousLogins) {
ipFound = userLogins.find((item) => item.OriginIp === ipAddress);
}
}
catch (error) {
throw error;
}
});
}
getPrivileges(systemCode, dbTransaction) {
return __awaiter(this, void 0, void 0, function* () {
try {
const system = yield User._SystemRepository.findOne({
where: {
SystemCode: systemCode,
},
transaction: dbTransaction,
});
if (!system) {
throw new Error('Invalid system code.');
}
const userPrivileges = yield this.getUserPersonalPrivileges(systemCode, dbTransaction);
const objectPrivileges = yield this.getObjectPrivileges(systemCode, dbTransaction);
const userGroupOwnByUser = yield User._UserGroupRepo.findAll({
where: {
UserId: this.UserId,
InheritGroupSystemAccessYN: 'Y',
InheritGroupPrivilegeYN: 'Y',
Status: 'Active',
},
include: [
{
model: group_entity_1.default,
where: {
Status: 'Active',
},
include: [
{
model: group_system_access_entity_1.default,
where: {
SystemCode: systemCode,
},
},
],
},
],
transaction: dbTransaction,
});
let groupsPrivileges = [];
for (const userGroup of userGroupOwnByUser) {
const gp = yield this.getInheritedPrivileges(userGroup.GroupCode, systemCode, dbTransaction);
groupsPrivileges = [...groupsPrivileges, ...gp];
}
const privileges = [
...userPrivileges,
...objectPrivileges,
...groupsPrivileges,
];
return privileges;
}
catch (error) {
throw error;
}
});
}
getInheritedPrivileges(groupCode, systemCode, dbTransaction) {
return __awaiter(this, void 0, void 0, function* () {
try {
const group = yield User._GroupRepo.findOne({
where: {
GroupCode: groupCode,
Status: 'Active',
},
include: [
{
model: group_privilege_entity_1.default,
where: {
Status: 'Active',
},
include: [
{
model: system_privilege_entity_1.default,
where: {
SystemCode: systemCode,
Status: 'Active',
},
},
],
},
],
transaction: dbTransaction,
});
const objectPrivileges = yield User._GroupObjectPrivilegeRepo.findAll({
where: {
GroupCode: groupCode,
},
include: {
model: system_privilege_entity_1.default,
where: {
SystemCode: systemCode,
Status: 'Active',
},
},
transaction: dbTransaction,
});
const gp = (group === null || group === void 0 ? void 0 : group.GroupPrivileges) || [];
const op = objectPrivileges || [];
let privileges = [];
const groupPrivileges = [];
for (const groupPrivilege of gp) {
groupPrivileges.push(groupPrivilege.Privilege.PrivilegeCode);
}
const ops = [];
for (const objectPrivilege of op) {
ops.push(objectPrivilege.Privilege.PrivilegeCode);
}
privileges = [...privileges, ...groupPrivileges, ...ops];
if ((group === null || group === void 0 ? void 0 : group.ParentGroupCode) && (group === null || group === void 0 ? void 0 : group.InheritParentPrivilegeYN) === 'Y') {
const parentGroupPrivileges = yield this.getInheritedPrivileges(group.ParentGroupCode, systemCode, dbTransaction);
privileges = [...privileges, ...parentGroupPrivileges];
}
return privileges;
}
catch (error) {
throw error;
}
});
}
getUserPersonalPrivileges(systemCode, dbTransaction) {
return __awaiter(this, void 0, void 0, function* () {
try {
const userPrivileges = (yield User._UserPrivilegeRepo.findAll({
where: {
UserId: this.UserId,
Status: 'Active',
},
include: {
model: system_privilege_entity_1.default,
where: {
SystemCode: systemCode,
Status: 'Active',
},
},
transaction: dbTransaction,
})) || [];
const privileges = userPrivileges.map((u) => u.Privilege.PrivilegeCode);
return privileges;
}
catch (error) {
throw error;
}
});
}
getObjectPrivileges(systemCode, dbTransaction) {
return __awaiter(this, void 0, void 0, function* () {
try {
const userObjectPrivileges = (yield User._UserObjectPrivilegeRepo.findAll({
where: {
UserId: this.UserId,
},
include: {
model: system_privilege_entity_1.default,
where: {
SystemCode: systemCode,
Status: 'Active',
},
},
transaction: dbTransaction,
})) || [];
const privilegesCodes = userObjectPrivileges.map((u) => u.Privilege.PrivilegeCode);
return privilegesCodes;
}
catch (error) {
throw error;
}
});
}
static checkUserInfoDuplicated(dbTransaction, query) {
return __awaiter(this, void 0, void 0, function* () {
try {
const { Email, UserName, IdType, IdNo, ContactNo } = query;
const where = {
[sequelize_1.Op.or]: {},
};
if (Email) {
where[sequelize_1.Op.or]['Email'] = Email;
}
if (UserName) {
where[sequelize_1.Op.or]['UserName'] = UserName;
}
if (IdType && IdNo) {
where[sequelize_1.Op.and] = [{ IdType: IdType }, { IdNo: IdNo }];
}
if (ContactNo) {
where[sequelize_1.Op.or]['ContactNo'] = ContactNo;
}
const user = yield User._Repository.findAll({
where,
transaction: dbTransaction,
});
if (user && user.length > 0) {
throw new general_1.ClassError('LoginUser', 'LoginUserErrMsg0X', 'User info already exists');
}
}
catch (error) {
throw error;
}
});
}
static generateDefaultPassword() {
try {
const passwordPolicy = config_1.ComponentConfig.getComponentConfigValue('@tomei/sso', 'passwordPolicy');
if (!passwordPolicy ||
!passwordPolicy.maxLen ||
!passwordPolicy.minLen ||
!passwordPolicy.nonAcceptableChar ||
!passwordPolicy.numOfCapitalLetters ||
!passwordPolicy.numOfNumbers ||
!passwordPolicy.numOfSpecialChars) {
throw new general_1.ClassError('LoginUser', 'LoginUserErrMsg0X', 'Missing password policy. Please set in config file.');
}
if (passwordPolicy.numOfCapitalLetters +
passwordPolicy.numOfNumbers +
passwordPolicy.numOfSpecialChars >
passwordPolicy.maxLen) {
throw new general_1.ClassError('LoginUser', 'LoginUserErrMsg0X', 'Password policy is invalid. Please set in config file.');
}
const { maxLen, minLen, nonAcceptableChar, numOfCapitalLetters, numOfNumbers, numOfSpecialChars, } = passwordPolicy;
const passwordLength = Math.floor(Math.random() * (maxLen - minLen + 1)) + minLen;
const words = 'abcdefghijklmnopqrstuvwxyz';
const capitalLetters = words.toUpperCase();
const numbers = '0123456789';
const specialChars = '!@#$%^&*()_+-={}[]|:;"<>,.?/~`';
const nonAcceptableChars = nonAcceptableChar.split(',');
const filteredWords = words
.split('')
.filter((word) => !nonAcceptableChars.includes(word));
const filteredCapitalLetters = capitalLetters
.split('')
.filter((word) => !nonAcceptableChars.includes(word));
const filteredNumbers = numbers
.split('')
.filter((word) => !nonAcceptableChars.includes(word));
const filteredSpecialChars = specialChars
.split('')
.filter((word) => !nonAcceptableChars.includes(word));
const generatedCapitalLetters = [];
const generatedNumbers = [];
const generatedSpecialChars = [];
const generatedWords = [];
for (let i = 0; i < numOfCapitalLetters; i++) {
const randomIndex = Math.floor(Math.random() * filteredCapitalLetters.length);
generatedCapitalLetters.push(filteredCapitalLetters[randomIndex]);
}
for (let i = 0; i < numOfNumbers; i++) {
const randomIndex = Math.floor(Math.random() * filteredNumbers.length);
generatedNumbers.push(filteredNumbers[randomIndex]);
}
for (let i = 0; i < numOfSpecialChars; i++) {
const randomIndex = Math.floor(Math.random() * filteredSpecialChars.length);
generatedSpecialChars.push(filteredSpecialChars[randomIndex]);
}
for (let i = 0; i <
passwordLength -
(numOfCapitalLetters + numOfNumbers + numOfSpecialChars); i++) {
const randomIndex = Math.floor(Math.random() * filteredWords.length);
generatedWords.push(filteredWords[randomIndex]);
}
let generatedPassword = '';
const allGeneratedChars = generatedCapitalLetters.concat(generatedNumbers, generatedSpecialChars, generatedWords);
allGeneratedChars.sort(() => Math.random() - 0.5);
generatedPassword = allGeneratedChars.join('');
return generatedPassword;
}
catch (error) {
throw error;
}
}
static setPassword(dbTransaction, user, password) {
return __awaiter(this, void 0, void 0, function* () {
try {
const passwordPolicy = config_1.ComponentConfig.getComponentConfigValue('@tomei/sso', 'passwordPolicy');
if (!passwordPolicy ||
!passwordPolicy.maxLen ||
!passwordPolicy.minLen ||
!passwordPolicy.nonAcceptableChar ||
!passwordPolicy.numOfCapitalLetters ||
!passwordPolicy.numOfNumbers ||
!passwordPolicy.numOfSpecialChars) {
throw new general_1.ClassError('LoginUser', 'LoginUserErrMsg0X', 'Missing password policy. Please set in config file.');
}
try {
if (password.length < passwordPolicy.minLen) {
throw Error('Password is too short');
}
if (password.length > passwordPolicy.maxLen) {
throw Error('Password is too long');
}
const nonAcceptableChars = passwordPolicy.nonAcceptableChar.split(',');
const nonAcceptableCharsFound = nonAcceptableChars.some((char) => password.includes(char));
if (nonAcceptableCharsFound) {
throw Error('Password contains unacceptable characters');
}
const capitalLetters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const numOfCapitalLetters = passwordPolicy.numOfCapitalLetters;
const capitalLettersFound = capitalLetters
.split('')
.filter((char) => password.includes(char)).length;
if (capitalLettersFound < numOfCapitalLetters) {
throw Error('Password does not contain enough capital letters');
}
const numbers = '0123456789';
const numOfNumbers = passwordPolicy.numOfNumbers;
const numbersFound = numbers
.split('')
.filter((char) => password.includes(char)).length;
if (numbersFound < numOfNumbers) {
throw Error('Password does not contain enough numbers');
}
const specialChars = '!@#$%^&*()_+-={}[]|:;"<>,.?/~`';
const numOfSpecialChars = passwordPolicy.numOfSpecialChars;
const specialCharsFound = specialChars
.split('')
.filter((char) => password.includes(char)).length;
if (specialCharsFound < numOfSpecialChars) {
throw Error('Password does not contain enough special characters');
}
}
catch (error) {
throw new general_1.ClassError('LoginUser', 'LoginUserErrMsg0X', "Your password doesn't meet security requirements. Try using a mix of uppercase and lowercase letters, numbers, and symbols.");
}
const passwordHashService = new password_hash_service_1.PasswordHashService();
const hashedPassword = yield passwordHashService.hashPassword(password);
user._Password = hashedPassword;
return user;
}
catch (error) {
throw error;
}
});
}
generateAuthorizationToken() {
return __awaiter(this, void 0, void 0, function* () {
const plaintextToken = (0, crypto_1.randomBytes)(32).toString('hex');
const hashedToken = (0, crypto_1.createHash)('sha256')
.update(plaintextToken)
.digest('hex');
this._SessionService.setAuthorizationCode(hashedToken, this.ObjectId, 60 * 60 * 24);
return { plaintextToken, hashedToken };
});
}
validateAuthorizationToken(autorizationToken) {
return __awaiter(this, void 0, void 0, function* () {
try {
const hashedSubmittedToken = (0, crypto_1.createHash)('sha256')
.update(autorizationToken)
.digest('hex');
const userId = yield this._SessionService.retrieveAuthorizationCode(hashedSubmittedToken);
if (!userId) {
return null;
}
yield this._SessionService.deleteAuthorizationCode(hashedSubmittedToken);
return userId;
}
catch (error) {
throw error;
}
});
}
static resetPassword(sessionService, autorizationToken, password, dbTransaction) {
return __awaiter(this, void 0, void 0, function* () {
try {
const hashedSubmittedToken = (0, crypto_1.createHash)('sha256')
.update(autorizationToken)
.digest('hex');
const userId = yield sessionService.retrieveAuthorizationCode(hashedSubmittedToken);
if (!userId) {
throw new general_1.ClassError('LoginUser', 'LoginUserErrMsg0X', 'Invalid token', 'setupFirstPassword', 401);
}
yield sessionService.deleteAuthorizationCode(hashedSubmittedToken);
console.log(`Token verified for user: ${userId}`);
const passwordHashService = new password_hash_service_1.PasswordHashService();
yield user_password_history_1.UserPasswordHistory.validate(dbTransaction, parseInt(userId), password, passwordHashService);
const user = yield User.init(sessionService, parseInt(userId), dbTransaction);
yield User.setPassword(dbTransaction, user, password);
let userData = yield User._Repository.update({
Password: user._Password,
DefaultPasswordChangedYN: yn_enum_1.YN.Yes,
NeedToChangePasswordYN: yn_enum_1.YN.No,
}, {
where: {
UserId: user.UserId,
},
transaction: dbTransaction,
});
yield user_password_history_1.UserPasswordHistory.create(dbTransaction, parseInt(userId), user._Password);
}
catch (error) {
throw error;
}
});
}
static create(loginUser, dbTransaction, user) {
return __awaiter(this, void 0, void 0, function* () {
try {
const systemCode = config_1.ApplicationConfig.getComponentConfigValue('system-code');
const isPrivileged = yield loginUser.checkPrivileges(systemCode, 'User - Create');
if (!isPrivileged) {
throw new general_1.ClassError('LoginUser', 'LoginUserErrMsg0X', 'You do not have the privilege to create user');
}
if (!user.Email && !user.UserName) {
throw new general_1.ClassError('LoginUser', 'LoginUserErrMsg0X', 'Email and Username is required');
}
yield User.checkUserInfoDuplicated(dbTransaction, {
Email: user.Email,
UserName: user.UserName,
IdType: user.IDType,
IdNo: user.IDNo,
ContactNo: user.ContactNo,
});
const defaultPassword = User.generateDefaultPassword();
user = yield User.setPassword(dbTransaction, user, defaultPassword);
const userInfo = {
UserName: user.UserName,
FullName: user.FullName,
IDNo: user