@open-mercato/shared 0.4.11-develop.1561.c31ede76ba → 0.4.11-develop.1570.dcc5b7c59a
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/dist/lib/version.js
CHANGED
package/dist/lib/version.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/version.ts"],
|
|
4
|
-
"sourcesContent": ["// Build-time generated version\nexport const APP_VERSION = '0.4.11-develop.
|
|
4
|
+
"sourcesContent": ["// Build-time generated version\nexport const APP_VERSION = '0.4.11-develop.1570.dcc5b7c59a'\nexport const appVersion = APP_VERSION\n"],
|
|
5
5
|
"mappings": "AACO,MAAM,cAAc;AACpB,MAAM,aAAa;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildPasswordSchema,
|
|
3
|
+
formatPasswordRequirements,
|
|
4
|
+
getPasswordPolicy,
|
|
5
|
+
getPasswordRequirements,
|
|
6
|
+
validatePassword,
|
|
7
|
+
} from '../passwordPolicy'
|
|
8
|
+
|
|
9
|
+
describe('passwordPolicy', () => {
|
|
10
|
+
it('returns the default policy when no env overrides are present', () => {
|
|
11
|
+
expect(getPasswordPolicy({} as NodeJS.ProcessEnv)).toEqual({
|
|
12
|
+
minLength: 6,
|
|
13
|
+
requireDigit: true,
|
|
14
|
+
requireUppercase: true,
|
|
15
|
+
requireSpecial: true,
|
|
16
|
+
})
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('prefers server env values, falls back to NEXT_PUBLIC values, and clamps min length', () => {
|
|
20
|
+
const env = {
|
|
21
|
+
OM_PASSWORD_MIN_LENGTH: '0',
|
|
22
|
+
OM_PASSWORD_REQUIRE_DIGIT: 'disabled',
|
|
23
|
+
OM_PASSWORD_REQUIRE_SPECIAL: ' ',
|
|
24
|
+
NEXT_PUBLIC_OM_PASSWORD_MIN_LENGTH: '12',
|
|
25
|
+
NEXT_PUBLIC_OM_PASSWORD_REQUIRE_DIGIT: 'enabled',
|
|
26
|
+
NEXT_PUBLIC_OM_PASSWORD_REQUIRE_UPPERCASE: 'false',
|
|
27
|
+
NEXT_PUBLIC_OM_PASSWORD_REQUIRE_SPECIAL: 'off',
|
|
28
|
+
} as NodeJS.ProcessEnv
|
|
29
|
+
|
|
30
|
+
expect(getPasswordPolicy(env)).toEqual({
|
|
31
|
+
minLength: 1,
|
|
32
|
+
requireDigit: false,
|
|
33
|
+
requireUppercase: false,
|
|
34
|
+
requireSpecial: false,
|
|
35
|
+
})
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('falls back to defaults when env overrides are invalid', () => {
|
|
39
|
+
const env = {
|
|
40
|
+
OM_PASSWORD_MIN_LENGTH: 'not-a-number',
|
|
41
|
+
OM_PASSWORD_REQUIRE_DIGIT: 'maybe',
|
|
42
|
+
OM_PASSWORD_REQUIRE_UPPERCASE: 'sometimes',
|
|
43
|
+
OM_PASSWORD_REQUIRE_SPECIAL: 'unknown',
|
|
44
|
+
} as NodeJS.ProcessEnv
|
|
45
|
+
|
|
46
|
+
expect(getPasswordPolicy(env)).toEqual({
|
|
47
|
+
minLength: 6,
|
|
48
|
+
requireDigit: true,
|
|
49
|
+
requireUppercase: true,
|
|
50
|
+
requireSpecial: true,
|
|
51
|
+
})
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('returns enabled requirements in policy order', () => {
|
|
55
|
+
expect(
|
|
56
|
+
getPasswordRequirements({
|
|
57
|
+
minLength: 10,
|
|
58
|
+
requireDigit: false,
|
|
59
|
+
requireUppercase: true,
|
|
60
|
+
requireSpecial: true,
|
|
61
|
+
}),
|
|
62
|
+
).toEqual([
|
|
63
|
+
{ id: 'minLength', value: 10 },
|
|
64
|
+
{ id: 'uppercase' },
|
|
65
|
+
{ id: 'special' },
|
|
66
|
+
])
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it('formats requirement text with translation keys, params, and custom separators', () => {
|
|
70
|
+
const translate = jest.fn(
|
|
71
|
+
(key: string, fallback: string, params?: Record<string, string | number>) => {
|
|
72
|
+
switch (key) {
|
|
73
|
+
case 'custom.password.minLength':
|
|
74
|
+
return `min:${String(params?.min)}`
|
|
75
|
+
case 'custom.password.uppercase':
|
|
76
|
+
return 'uppercase'
|
|
77
|
+
case 'custom.password.special':
|
|
78
|
+
return ' '
|
|
79
|
+
case 'custom.password.separator':
|
|
80
|
+
return ' | '
|
|
81
|
+
default:
|
|
82
|
+
return fallback
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
expect(
|
|
88
|
+
formatPasswordRequirements(
|
|
89
|
+
{
|
|
90
|
+
minLength: 12,
|
|
91
|
+
requireDigit: false,
|
|
92
|
+
requireUppercase: true,
|
|
93
|
+
requireSpecial: true,
|
|
94
|
+
},
|
|
95
|
+
translate,
|
|
96
|
+
'custom.password',
|
|
97
|
+
),
|
|
98
|
+
).toBe('min:12 | uppercase')
|
|
99
|
+
|
|
100
|
+
expect(translate).toHaveBeenCalledWith(
|
|
101
|
+
'custom.password.minLength',
|
|
102
|
+
'At least {min} characters',
|
|
103
|
+
{ min: 12 },
|
|
104
|
+
)
|
|
105
|
+
expect(translate).toHaveBeenCalledWith('custom.password.separator', ', ')
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('returns ordered violations for passwords that fail enabled checks', () => {
|
|
109
|
+
expect(
|
|
110
|
+
validatePassword('abc', {
|
|
111
|
+
minLength: 6,
|
|
112
|
+
requireDigit: true,
|
|
113
|
+
requireUppercase: true,
|
|
114
|
+
requireSpecial: true,
|
|
115
|
+
}),
|
|
116
|
+
).toEqual({
|
|
117
|
+
ok: false,
|
|
118
|
+
violations: ['minLength', 'digit', 'uppercase', 'special'],
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
expect(
|
|
122
|
+
validatePassword('Password1', {
|
|
123
|
+
minLength: 8,
|
|
124
|
+
requireDigit: true,
|
|
125
|
+
requireUppercase: true,
|
|
126
|
+
requireSpecial: false,
|
|
127
|
+
}),
|
|
128
|
+
).toEqual({
|
|
129
|
+
ok: true,
|
|
130
|
+
violations: [],
|
|
131
|
+
})
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
it('builds a zod schema that enforces both policy and max length', () => {
|
|
135
|
+
const schema = buildPasswordSchema({
|
|
136
|
+
policy: {
|
|
137
|
+
minLength: 8,
|
|
138
|
+
requireDigit: true,
|
|
139
|
+
requireUppercase: true,
|
|
140
|
+
requireSpecial: false,
|
|
141
|
+
},
|
|
142
|
+
maxLength: 10,
|
|
143
|
+
message: 'Weak password',
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
expect(schema.safeParse('Password1').success).toBe(true)
|
|
147
|
+
|
|
148
|
+
const weakResult = schema.safeParse('password1')
|
|
149
|
+
expect(weakResult.success).toBe(false)
|
|
150
|
+
if (weakResult.success) throw new Error('Expected lowercase password to fail schema validation')
|
|
151
|
+
expect(weakResult.error.issues).toEqual(
|
|
152
|
+
expect.arrayContaining([expect.objectContaining({ message: 'Weak password' })]),
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
const tooLongResult = schema.safeParse('Password1234')
|
|
156
|
+
expect(tooLongResult.success).toBe(false)
|
|
157
|
+
if (tooLongResult.success) throw new Error('Expected overlong password to fail schema validation')
|
|
158
|
+
expect(tooLongResult.error.issues).toEqual(
|
|
159
|
+
expect.arrayContaining([expect.objectContaining({ message: 'Weak password' })]),
|
|
160
|
+
)
|
|
161
|
+
})
|
|
162
|
+
})
|