@tomei/sso 0.65.0 → 0.65.1
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/.gitlab-ci.yml +40 -0
- package/.husky/commit-msg +0 -0
- package/.husky/pre-commit +0 -0
- package/__tests__/unit/components/login-user/password-expiry.spec.ts +87 -0
- package/dist/__tests__/unit/components/login-user/password-expiry.spec.d.ts +1 -0
- package/dist/__tests__/unit/components/login-user/password-expiry.spec.js +86 -0
- package/dist/__tests__/unit/components/login-user/password-expiry.spec.js.map +1 -0
- package/dist/src/components/login-user/user.d.ts +5 -0
- package/dist/src/components/login-user/user.js +44 -0
- package/dist/src/components/login-user/user.js.map +1 -1
- package/dist/src/components/user-password-history/user-password-history.d.ts +1 -0
- package/dist/src/components/user-password-history/user-password-history.js +41 -2
- package/dist/src/components/user-password-history/user-password-history.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/components/login-user/user.ts +78 -0
- package/src/components/user-password-history/user-password-history.ts +57 -6
package/.gitlab-ci.yml
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
variables:
|
|
2
2
|
SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar" # Defines the location of the analysis task cache
|
|
3
3
|
GIT_DEPTH: "0" # Tells git to fetch all the branches of the project, required by the analysis task
|
|
4
|
+
|
|
5
|
+
stages:
|
|
6
|
+
- build
|
|
7
|
+
- publish
|
|
8
|
+
|
|
4
9
|
sonarcloud-check:
|
|
10
|
+
stage: build
|
|
5
11
|
image:
|
|
6
12
|
name: sonarsource/sonar-scanner-cli:latest
|
|
7
13
|
entrypoint: [""]
|
|
@@ -14,3 +20,37 @@ sonarcloud-check:
|
|
|
14
20
|
only:
|
|
15
21
|
- merge_requests
|
|
16
22
|
- main
|
|
23
|
+
|
|
24
|
+
package-build:
|
|
25
|
+
stage: build
|
|
26
|
+
image: node:20-alpine
|
|
27
|
+
tags:
|
|
28
|
+
- shared
|
|
29
|
+
script:
|
|
30
|
+
- npm ci
|
|
31
|
+
- npm run build
|
|
32
|
+
artifacts:
|
|
33
|
+
paths:
|
|
34
|
+
- dist/
|
|
35
|
+
expire_in: 1 hour
|
|
36
|
+
rules:
|
|
37
|
+
- if: '$CI_COMMIT_TAG =~ /^prod-v[0-9]+\.[0-9]+\.[0-9]+(-retry\.[0-9]+)?$/'
|
|
38
|
+
|
|
39
|
+
package-publish:
|
|
40
|
+
stage: publish
|
|
41
|
+
image: node:20-alpine
|
|
42
|
+
tags:
|
|
43
|
+
- shared
|
|
44
|
+
needs:
|
|
45
|
+
- job: package-build
|
|
46
|
+
artifacts: true
|
|
47
|
+
rules:
|
|
48
|
+
- if: '$CI_COMMIT_TAG =~ /^prod-v[0-9]+\.[0-9]+\.[0-9]+(-retry\.[0-9]+)?$/'
|
|
49
|
+
when: manual
|
|
50
|
+
allow_failure: false
|
|
51
|
+
script:
|
|
52
|
+
- npm ci
|
|
53
|
+
- test -n "$NPM_TOKEN"
|
|
54
|
+
- printf '%s\n' "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > .npmrc
|
|
55
|
+
- npm whoami --registry https://registry.npmjs.org/
|
|
56
|
+
- npm publish --tag latest --access public
|
package/.husky/commit-msg
CHANGED
|
File without changes
|
package/.husky/pre-commit
CHANGED
|
File without changes
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { User } from '../../../../src/components/login-user/user';
|
|
2
|
+
import { UserPasswordHistory } from '../../../../src/components/user-password-history/user-password-history';
|
|
3
|
+
import { YN } from '../../../../src/enum/yn.enum';
|
|
4
|
+
|
|
5
|
+
// User and LoginUser import each other; this test exercises only User's expiry policy.
|
|
6
|
+
jest.mock('../../../../src/components/login-user/login-user', () => ({
|
|
7
|
+
LoginUser: class {},
|
|
8
|
+
}));
|
|
9
|
+
|
|
10
|
+
describe('User.getPasswordExpiryStatus', () => {
|
|
11
|
+
const originalExpiryMonths = process.env.PASSWORD_EXPIRY_MONTHS;
|
|
12
|
+
const originalWarningDays = process.env.PASSWORD_EXPIRY_WARNING_DAYS;
|
|
13
|
+
|
|
14
|
+
const user = (password: string | null) =>
|
|
15
|
+
Object.assign(Object.create(User.prototype), {
|
|
16
|
+
ObjectId: '123',
|
|
17
|
+
_Password: password,
|
|
18
|
+
_NeedToChangePasswordYN: YN.No,
|
|
19
|
+
}) as User;
|
|
20
|
+
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
process.env.PASSWORD_EXPIRY_MONTHS = '1';
|
|
23
|
+
process.env.PASSWORD_EXPIRY_WARNING_DAYS = '14';
|
|
24
|
+
jest.useFakeTimers().setSystemTime(new Date('2026-02-20T12:00:00Z'));
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
jest.restoreAllMocks();
|
|
29
|
+
jest.useRealTimers();
|
|
30
|
+
if (originalExpiryMonths === undefined)
|
|
31
|
+
delete process.env.PASSWORD_EXPIRY_MONTHS;
|
|
32
|
+
else process.env.PASSWORD_EXPIRY_MONTHS = originalExpiryMonths;
|
|
33
|
+
if (originalWarningDays === undefined)
|
|
34
|
+
delete process.env.PASSWORD_EXPIRY_WARNING_DAYS;
|
|
35
|
+
else process.env.PASSWORD_EXPIRY_WARNING_DAYS = originalWarningDays;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('disables expiry when the period is zero', async () => {
|
|
39
|
+
process.env.PASSWORD_EXPIRY_MONTHS = '0';
|
|
40
|
+
const lookup = jest.spyOn(UserPasswordHistory, 'getLatestByUserId');
|
|
41
|
+
|
|
42
|
+
expect(await user('hash').getPasswordExpiryStatus()).toEqual({
|
|
43
|
+
expired: false,
|
|
44
|
+
expiringSoon: false,
|
|
45
|
+
expiresInDays: null,
|
|
46
|
+
});
|
|
47
|
+
expect(lookup).not.toHaveBeenCalled();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('skips an account without a local password', async () => {
|
|
51
|
+
const lookup = jest.spyOn(UserPasswordHistory, 'getLatestByUserId');
|
|
52
|
+
|
|
53
|
+
expect(await user(null).getPasswordExpiryStatus()).toEqual({
|
|
54
|
+
expired: false,
|
|
55
|
+
expiringSoon: false,
|
|
56
|
+
expiresInDays: null,
|
|
57
|
+
});
|
|
58
|
+
expect(lookup).not.toHaveBeenCalled();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('expires an account without password history', async () => {
|
|
62
|
+
jest
|
|
63
|
+
.spyOn(UserPasswordHistory, 'getLatestByUserId')
|
|
64
|
+
.mockResolvedValue(null);
|
|
65
|
+
|
|
66
|
+
expect(await user('hash').getPasswordExpiryStatus()).toEqual({
|
|
67
|
+
expired: true,
|
|
68
|
+
expiringSoon: false,
|
|
69
|
+
expiresInDays: null,
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('warns before expiry and clamps month-end dates', async () => {
|
|
74
|
+
jest.spyOn(UserPasswordHistory, 'getLatestByUserId').mockResolvedValue({
|
|
75
|
+
CreatedAt: new Date('2026-01-31T12:00:00Z'),
|
|
76
|
+
} as UserPasswordHistory);
|
|
77
|
+
|
|
78
|
+
expect(await user('hash').getPasswordExpiryStatus()).toEqual({
|
|
79
|
+
expired: false,
|
|
80
|
+
expiringSoon: true,
|
|
81
|
+
expiresInDays: 8,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
jest.setSystemTime(new Date('2026-02-28T12:00:00Z'));
|
|
85
|
+
expect((await user('hash').getPasswordExpiryStatus()).expired).toBe(true);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const user_1 = require("../../../../src/components/login-user/user");
|
|
13
|
+
const user_password_history_1 = require("../../../../src/components/user-password-history/user-password-history");
|
|
14
|
+
const yn_enum_1 = require("../../../../src/enum/yn.enum");
|
|
15
|
+
jest.mock('../../../../src/components/login-user/login-user', () => ({
|
|
16
|
+
LoginUser: class {
|
|
17
|
+
},
|
|
18
|
+
}));
|
|
19
|
+
describe('User.getPasswordExpiryStatus', () => {
|
|
20
|
+
const originalExpiryMonths = process.env.PASSWORD_EXPIRY_MONTHS;
|
|
21
|
+
const originalWarningDays = process.env.PASSWORD_EXPIRY_WARNING_DAYS;
|
|
22
|
+
const user = (password) => Object.assign(Object.create(user_1.User.prototype), {
|
|
23
|
+
ObjectId: '123',
|
|
24
|
+
_Password: password,
|
|
25
|
+
_NeedToChangePasswordYN: yn_enum_1.YN.No,
|
|
26
|
+
});
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
process.env.PASSWORD_EXPIRY_MONTHS = '1';
|
|
29
|
+
process.env.PASSWORD_EXPIRY_WARNING_DAYS = '14';
|
|
30
|
+
jest.useFakeTimers().setSystemTime(new Date('2026-02-20T12:00:00Z'));
|
|
31
|
+
});
|
|
32
|
+
afterEach(() => {
|
|
33
|
+
jest.restoreAllMocks();
|
|
34
|
+
jest.useRealTimers();
|
|
35
|
+
if (originalExpiryMonths === undefined)
|
|
36
|
+
delete process.env.PASSWORD_EXPIRY_MONTHS;
|
|
37
|
+
else
|
|
38
|
+
process.env.PASSWORD_EXPIRY_MONTHS = originalExpiryMonths;
|
|
39
|
+
if (originalWarningDays === undefined)
|
|
40
|
+
delete process.env.PASSWORD_EXPIRY_WARNING_DAYS;
|
|
41
|
+
else
|
|
42
|
+
process.env.PASSWORD_EXPIRY_WARNING_DAYS = originalWarningDays;
|
|
43
|
+
});
|
|
44
|
+
it('disables expiry when the period is zero', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
45
|
+
process.env.PASSWORD_EXPIRY_MONTHS = '0';
|
|
46
|
+
const lookup = jest.spyOn(user_password_history_1.UserPasswordHistory, 'getLatestByUserId');
|
|
47
|
+
expect(yield user('hash').getPasswordExpiryStatus()).toEqual({
|
|
48
|
+
expired: false,
|
|
49
|
+
expiringSoon: false,
|
|
50
|
+
expiresInDays: null,
|
|
51
|
+
});
|
|
52
|
+
expect(lookup).not.toHaveBeenCalled();
|
|
53
|
+
}));
|
|
54
|
+
it('skips an account without a local password', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
55
|
+
const lookup = jest.spyOn(user_password_history_1.UserPasswordHistory, 'getLatestByUserId');
|
|
56
|
+
expect(yield user(null).getPasswordExpiryStatus()).toEqual({
|
|
57
|
+
expired: false,
|
|
58
|
+
expiringSoon: false,
|
|
59
|
+
expiresInDays: null,
|
|
60
|
+
});
|
|
61
|
+
expect(lookup).not.toHaveBeenCalled();
|
|
62
|
+
}));
|
|
63
|
+
it('expires an account without password history', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
64
|
+
jest
|
|
65
|
+
.spyOn(user_password_history_1.UserPasswordHistory, 'getLatestByUserId')
|
|
66
|
+
.mockResolvedValue(null);
|
|
67
|
+
expect(yield user('hash').getPasswordExpiryStatus()).toEqual({
|
|
68
|
+
expired: true,
|
|
69
|
+
expiringSoon: false,
|
|
70
|
+
expiresInDays: null,
|
|
71
|
+
});
|
|
72
|
+
}));
|
|
73
|
+
it('warns before expiry and clamps month-end dates', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
74
|
+
jest.spyOn(user_password_history_1.UserPasswordHistory, 'getLatestByUserId').mockResolvedValue({
|
|
75
|
+
CreatedAt: new Date('2026-01-31T12:00:00Z'),
|
|
76
|
+
});
|
|
77
|
+
expect(yield user('hash').getPasswordExpiryStatus()).toEqual({
|
|
78
|
+
expired: false,
|
|
79
|
+
expiringSoon: true,
|
|
80
|
+
expiresInDays: 8,
|
|
81
|
+
});
|
|
82
|
+
jest.setSystemTime(new Date('2026-02-28T12:00:00Z'));
|
|
83
|
+
expect((yield user('hash').getPasswordExpiryStatus()).expired).toBe(true);
|
|
84
|
+
}));
|
|
85
|
+
});
|
|
86
|
+
//# sourceMappingURL=password-expiry.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password-expiry.spec.js","sourceRoot":"","sources":["../../../../../__tests__/unit/components/login-user/password-expiry.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -176,6 +176,11 @@ export declare class User extends UserBase {
|
|
|
176
176
|
static findByEmail(AuthContext: AuthContext, dbTransaction: any, Email: string): Promise<User>;
|
|
177
177
|
updatePasscode(loginUser: User, passcode: string, dbTransaction: any): Promise<void>;
|
|
178
178
|
updatePassword(loginUser: User, oldPassword: string, newPassword: string, dbTransaction: any): Promise<void>;
|
|
179
|
+
getPasswordExpiryStatus(dbTransaction?: any): Promise<{
|
|
180
|
+
expired: boolean;
|
|
181
|
+
expiringSoon: boolean;
|
|
182
|
+
expiresInDays: number | null;
|
|
183
|
+
}>;
|
|
179
184
|
verifyPasscode(passcode: string): Promise<void>;
|
|
180
185
|
getReportingUser(dbTransaction: any): Promise<{
|
|
181
186
|
Email: string;
|
|
@@ -2042,6 +2042,7 @@ class User extends general_1.UserBase {
|
|
|
2042
2042
|
};
|
|
2043
2043
|
this.Password = passwordHash;
|
|
2044
2044
|
this.LastPasswordChangedAt = new Date();
|
|
2045
|
+
this.NeedToChangePasswordYN = yn_enum_1.YN.No;
|
|
2045
2046
|
const entityValueAfter = {
|
|
2046
2047
|
UserId: this.UserId,
|
|
2047
2048
|
UserName: this.UserName,
|
|
@@ -2073,6 +2074,7 @@ class User extends general_1.UserBase {
|
|
|
2073
2074
|
yield User._Repository.update({
|
|
2074
2075
|
Password: this.Password,
|
|
2075
2076
|
LastPasswordChangedAt: this.LastPasswordChangedAt,
|
|
2077
|
+
NeedToChangePasswordYN: this.NeedToChangePasswordYN,
|
|
2076
2078
|
}, {
|
|
2077
2079
|
where: {
|
|
2078
2080
|
UserId: this.UserId,
|
|
@@ -2095,6 +2097,48 @@ class User extends general_1.UserBase {
|
|
|
2095
2097
|
}
|
|
2096
2098
|
});
|
|
2097
2099
|
}
|
|
2100
|
+
getPasswordExpiryStatus(dbTransaction) {
|
|
2101
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2102
|
+
try {
|
|
2103
|
+
const expiryMonthsRaw = Number(process.env.PASSWORD_EXPIRY_MONTHS);
|
|
2104
|
+
const expiryMonths = Number.isFinite(expiryMonthsRaw)
|
|
2105
|
+
? Math.max(0, Math.floor(expiryMonthsRaw))
|
|
2106
|
+
: 0;
|
|
2107
|
+
if (expiryMonths === 0) {
|
|
2108
|
+
return { expired: false, expiringSoon: false, expiresInDays: null };
|
|
2109
|
+
}
|
|
2110
|
+
if (!this.Password) {
|
|
2111
|
+
return { expired: false, expiringSoon: false, expiresInDays: null };
|
|
2112
|
+
}
|
|
2113
|
+
if (this.NeedToChangePasswordYN === yn_enum_1.YN.Yes) {
|
|
2114
|
+
return { expired: true, expiringSoon: false, expiresInDays: null };
|
|
2115
|
+
}
|
|
2116
|
+
const warningDaysRaw = Number(process.env.PASSWORD_EXPIRY_WARNING_DAYS);
|
|
2117
|
+
const warningDays = Number.isFinite(warningDaysRaw)
|
|
2118
|
+
? Math.max(0, Math.floor(warningDaysRaw))
|
|
2119
|
+
: 14;
|
|
2120
|
+
const latestHistory = yield user_password_history_1.UserPasswordHistory.getLatestByUserId(dbTransaction, this.UserId);
|
|
2121
|
+
if (!latestHistory) {
|
|
2122
|
+
return { expired: true, expiringSoon: false, expiresInDays: null };
|
|
2123
|
+
}
|
|
2124
|
+
const createdAt = latestHistory.CreatedAt;
|
|
2125
|
+
const expiryMonth = createdAt.getUTCMonth() + expiryMonths;
|
|
2126
|
+
const lastDayOfExpiryMonth = new Date(Date.UTC(createdAt.getUTCFullYear(), expiryMonth + 1, 0)).getUTCDate();
|
|
2127
|
+
const expiryDate = new Date(Date.UTC(createdAt.getUTCFullYear(), expiryMonth, Math.min(createdAt.getUTCDate(), lastDayOfExpiryMonth), createdAt.getUTCHours(), createdAt.getUTCMinutes(), createdAt.getUTCSeconds(), createdAt.getUTCMilliseconds()));
|
|
2128
|
+
const now = new Date();
|
|
2129
|
+
if (now.getTime() >= expiryDate.getTime()) {
|
|
2130
|
+
return { expired: true, expiringSoon: false, expiresInDays: null };
|
|
2131
|
+
}
|
|
2132
|
+
const msPerDay = 24 * 60 * 60 * 1000;
|
|
2133
|
+
const expiringSoon = now.getTime() >= expiryDate.getTime() - warningDays * msPerDay;
|
|
2134
|
+
const expiresInDays = Math.ceil((expiryDate.getTime() - now.getTime()) / msPerDay);
|
|
2135
|
+
return { expired: false, expiringSoon, expiresInDays };
|
|
2136
|
+
}
|
|
2137
|
+
catch (error) {
|
|
2138
|
+
throw error;
|
|
2139
|
+
}
|
|
2140
|
+
});
|
|
2141
|
+
}
|
|
2098
2142
|
verifyPasscode(passcode) {
|
|
2099
2143
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2100
2144
|
try {
|