@descope/web-components-ui 3.9.1 → 3.10.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/dist/cjs/index.cjs.js +74 -8
- package/dist/cjs/index.cjs.js.map +1 -1
- package/dist/index.esm.js +76 -8
- package/dist/index.esm.js.map +1 -1
- package/dist/umd/DescopeDev.js +1 -1
- package/dist/umd/DescopeDev.js.map +1 -1
- package/dist/umd/descope-new-password-descope-new-password-internal-index-js.js +1 -1
- package/dist/umd/descope-new-password-descope-new-password-internal-index-js.js.map +1 -1
- package/dist/umd/descope-new-password-index-js.js +1 -1
- package/dist/umd/descope-new-password-index-js.js.map +1 -1
- package/dist/umd/descope-policy-validation-index-js.js +1 -1
- package/dist/umd/descope-policy-validation-index-js.js.map +1 -1
- package/dist/umd/index.js +1 -1
- package/package.json +35 -35
- package/src/components/descope-new-password/NewPasswordClass.js +2 -0
- package/src/components/descope-new-password/descope-new-password-internal/NewPasswordInternal.js +2 -0
- package/src/components/descope-policy-validation/PolicyValidationClass.js +72 -8
- package/stories/descope-new-password.stories.js +25 -1
- package/stories/descope-policy-validation.stories.js +39 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@descope/web-components-ui",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.10.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/cjs/index.cjs.js",
|
|
6
6
|
"module": "dist/index.esm.js",
|
|
@@ -52,10 +52,10 @@
|
|
|
52
52
|
"webpack-cli": "^7.0.0",
|
|
53
53
|
"webpack-dev-server": "^5.0.0",
|
|
54
54
|
"webpack-subresource-integrity": "5.2.0-rc.1",
|
|
55
|
-
"rollup-replace-plugin": "3.
|
|
56
|
-
"test-drivers": "3.
|
|
57
|
-
"webpack-extract-font-loader": "3.
|
|
58
|
-
"webpack-replace-plugin": "3.
|
|
55
|
+
"rollup-replace-plugin": "3.10.0",
|
|
56
|
+
"test-drivers": "3.10.0",
|
|
57
|
+
"webpack-extract-font-loader": "3.10.0",
|
|
58
|
+
"webpack-replace-plugin": "3.10.0"
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
61
|
"@vaadin/checkbox": "24.3.4",
|
|
@@ -79,36 +79,36 @@
|
|
|
79
79
|
"libphonenumber-js": "^1.11.12",
|
|
80
80
|
"lodash.debounce": "4.0.8",
|
|
81
81
|
"lodash.merge": "4.6.2",
|
|
82
|
-
"@descope-ui/
|
|
83
|
-
"@descope-ui/descope-address-field": "3.
|
|
84
|
-
"@descope-ui/
|
|
85
|
-
"@descope-ui/descope-
|
|
86
|
-
"@descope-ui/descope-
|
|
87
|
-
"@descope-ui/descope-avatar": "3.
|
|
88
|
-
"@descope-ui/descope-badge": "3.
|
|
89
|
-
"@descope-ui/descope-button": "3.
|
|
90
|
-
"@descope-ui/descope-collapsible-container": "3.
|
|
91
|
-
"@descope-ui/descope-combo-box": "3.
|
|
92
|
-
"@descope-ui/descope-enriched-text": "3.
|
|
93
|
-
"@descope-ui/descope-icon": "3.
|
|
94
|
-
"@descope-ui/descope-image": "3.
|
|
95
|
-
"@descope-ui/descope-link": "3.
|
|
96
|
-
"@descope-ui/descope-list": "3.
|
|
97
|
-
"@descope-ui/descope-
|
|
98
|
-
"@descope-ui/descope-
|
|
99
|
-
"@descope-ui/descope-
|
|
100
|
-
"@descope-ui/descope-outbound-
|
|
101
|
-
"@descope-ui/descope-
|
|
102
|
-
"@descope-ui/descope-password-strength": "3.
|
|
103
|
-
"@descope-ui/descope-ponyhot": "3.
|
|
104
|
-
"@descope-ui/descope-recovery-codes": "3.
|
|
105
|
-
"@descope-ui/descope-text": "3.
|
|
106
|
-
"@descope-ui/descope-timer": "3.
|
|
107
|
-
"@descope-ui/descope-
|
|
108
|
-
"@descope-ui/descope-
|
|
109
|
-
"@descope-ui/descope-trusted-devices": "3.
|
|
110
|
-
"@descope-ui/descope-attachment": "3.
|
|
111
|
-
"@descope-ui/descope-anchored": "3.
|
|
82
|
+
"@descope-ui/descope-country-subdivision-city-field": "3.10.0",
|
|
83
|
+
"@descope-ui/descope-address-field": "3.10.0",
|
|
84
|
+
"@descope-ui/common": "3.10.0",
|
|
85
|
+
"@descope-ui/descope-autocomplete-field": "3.10.0",
|
|
86
|
+
"@descope-ui/descope-apps-list": "3.10.0",
|
|
87
|
+
"@descope-ui/descope-avatar": "3.10.0",
|
|
88
|
+
"@descope-ui/descope-badge": "3.10.0",
|
|
89
|
+
"@descope-ui/descope-button": "3.10.0",
|
|
90
|
+
"@descope-ui/descope-collapsible-container": "3.10.0",
|
|
91
|
+
"@descope-ui/descope-combo-box": "3.10.0",
|
|
92
|
+
"@descope-ui/descope-enriched-text": "3.10.0",
|
|
93
|
+
"@descope-ui/descope-icon": "3.10.0",
|
|
94
|
+
"@descope-ui/descope-image": "3.10.0",
|
|
95
|
+
"@descope-ui/descope-link": "3.10.0",
|
|
96
|
+
"@descope-ui/descope-list": "3.10.0",
|
|
97
|
+
"@descope-ui/descope-multi-line-mappings": "3.10.0",
|
|
98
|
+
"@descope-ui/descope-list-item": "3.10.0",
|
|
99
|
+
"@descope-ui/descope-outbound-app-button": "3.10.0",
|
|
100
|
+
"@descope-ui/descope-outbound-apps": "3.10.0",
|
|
101
|
+
"@descope-ui/descope-multi-select-combo-box": "3.10.0",
|
|
102
|
+
"@descope-ui/descope-password-strength": "3.10.0",
|
|
103
|
+
"@descope-ui/descope-ponyhot": "3.10.0",
|
|
104
|
+
"@descope-ui/descope-recovery-codes": "3.10.0",
|
|
105
|
+
"@descope-ui/descope-text": "3.10.0",
|
|
106
|
+
"@descope-ui/descope-timer": "3.10.0",
|
|
107
|
+
"@descope-ui/descope-tooltip": "3.10.0",
|
|
108
|
+
"@descope-ui/descope-timer-button": "3.10.0",
|
|
109
|
+
"@descope-ui/descope-trusted-devices": "3.10.0",
|
|
110
|
+
"@descope-ui/descope-attachment": "3.10.0",
|
|
111
|
+
"@descope-ui/descope-anchored": "3.10.0"
|
|
112
112
|
},
|
|
113
113
|
"overrides": {
|
|
114
114
|
"@vaadin/avatar": "24.3.4",
|
|
@@ -58,6 +58,8 @@ const customMixin = (superclass) =>
|
|
|
58
58
|
'available-policies',
|
|
59
59
|
'data-password-policy-value-minlength',
|
|
60
60
|
'data-password-policy-value-passwordstrength',
|
|
61
|
+
'data-password-policy-value-disallowedchars',
|
|
62
|
+
'data-password-policy-value-email',
|
|
61
63
|
'label-type',
|
|
62
64
|
'manual-visibility-toggle',
|
|
63
65
|
],
|
package/src/components/descope-new-password/descope-new-password-internal/NewPasswordInternal.js
CHANGED
|
@@ -18,6 +18,8 @@ const policyPanelAttrs = [
|
|
|
18
18
|
'active-policies',
|
|
19
19
|
'data-password-policy-value-minlength',
|
|
20
20
|
'data-password-policy-value-passwordstrength',
|
|
21
|
+
'data-password-policy-value-disallowedchars',
|
|
22
|
+
'data-password-policy-value-email',
|
|
21
23
|
'manual-visibility-toggle',
|
|
22
24
|
];
|
|
23
25
|
const commonAttrs = [
|
|
@@ -11,6 +11,8 @@ const overrideAttrs = [
|
|
|
11
11
|
'data-password-policy-value-minlength',
|
|
12
12
|
'data-password-policy-value-passwordstrength',
|
|
13
13
|
'data-password-policy-actual-passwordstrength',
|
|
14
|
+
'data-password-policy-value-disallowedchars',
|
|
15
|
+
'data-password-policy-value-email',
|
|
14
16
|
];
|
|
15
17
|
const dataAttrs = ['data', 'active-policies', 'overrides', ...overrideAttrs];
|
|
16
18
|
const policyAttrs = ['label', 'value', ...dataAttrs];
|
|
@@ -129,6 +131,46 @@ class RawPolicyValidation extends createBaseClass({ componentName, baseSelector:
|
|
|
129
131
|
};
|
|
130
132
|
}
|
|
131
133
|
}
|
|
134
|
+
|
|
135
|
+
// disallowedchars: this stores the configured char list in
|
|
136
|
+
// overrides.disallowedchars.value so the message can interpolate
|
|
137
|
+
// `{{value}}`. The regex pattern itself is built upstream (orchestrator
|
|
138
|
+
// or caller) and shipped on the policy entry — it is not derived from
|
|
139
|
+
// this override. When the attribute is cleared, drop the override so
|
|
140
|
+
// the panel doesn't keep stale data.
|
|
141
|
+
if (attrName === 'data-password-policy-value-disallowedchars') {
|
|
142
|
+
if (newValue) {
|
|
143
|
+
this.#overrides = {
|
|
144
|
+
...this.#overrides,
|
|
145
|
+
disallowedchars: {
|
|
146
|
+
...this.#overrides?.disallowedchars,
|
|
147
|
+
value: newValue,
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
} else if (this.#overrides?.disallowedchars) {
|
|
151
|
+
const { disallowedchars: _drop, ...rest } = this.#overrides;
|
|
152
|
+
this.#overrides = rest;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// disallowemail: stash the user's email so the STR_NEQ_CI comparator
|
|
157
|
+
// has an `expected` to compare against the live password value. Clear
|
|
158
|
+
// the override when the attribute is removed/empty so we don't keep
|
|
159
|
+
// blocking against a previous user's email.
|
|
160
|
+
if (attrName === 'data-password-policy-value-email') {
|
|
161
|
+
if (newValue) {
|
|
162
|
+
this.#overrides = {
|
|
163
|
+
...this.#overrides,
|
|
164
|
+
disallowemail: {
|
|
165
|
+
...this.#overrides?.disallowemail,
|
|
166
|
+
expected: newValue,
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
} else if (this.#overrides?.disallowemail) {
|
|
170
|
+
const { disallowemail: _drop, ...rest } = this.#overrides;
|
|
171
|
+
this.#overrides = rest;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
132
174
|
}
|
|
133
175
|
|
|
134
176
|
this.renderItems(this.#availablePolicies, this.#activePolicies, this.#overrides);
|
|
@@ -193,6 +235,7 @@ class RawPolicyValidation extends createBaseClass({ componentName, baseSelector:
|
|
|
193
235
|
}
|
|
194
236
|
|
|
195
237
|
const { pattern, message, data, compare } = policy;
|
|
238
|
+
const normalizedCompare = typeof compare === 'string' ? compare.toUpperCase() : compare;
|
|
196
239
|
|
|
197
240
|
if ((!pattern && !compare) || !message) {
|
|
198
241
|
return results;
|
|
@@ -206,9 +249,23 @@ class RawPolicyValidation extends createBaseClass({ componentName, baseSelector:
|
|
|
206
249
|
if (pattern) {
|
|
207
250
|
const exp = new RegExp(interpolateString(pattern, data));
|
|
208
251
|
validationResult.valid = exp.test(this.value);
|
|
252
|
+
} else if (normalizedCompare === 'STR_NEQ_CI') {
|
|
253
|
+
// Compare the live password against the configured string AND its
|
|
254
|
+
// local-part (before '@'), case-insensitively. Used by the
|
|
255
|
+
// disallowemail policy.
|
|
256
|
+
const expected = (data?.expected ?? '').toLowerCase();
|
|
257
|
+
const actual = (this.value ?? '').toLowerCase();
|
|
258
|
+
if (!expected || !actual) {
|
|
259
|
+
// nothing to compare → mark valid so we don't block the flow
|
|
260
|
+
validationResult.valid = true;
|
|
261
|
+
} else {
|
|
262
|
+
const at = expected.indexOf('@');
|
|
263
|
+
const localPart = at > 0 ? expected.slice(0, at) : expected;
|
|
264
|
+
validationResult.valid = actual !== expected && actual !== localPart;
|
|
265
|
+
}
|
|
209
266
|
} else if (compare) {
|
|
210
267
|
validationResult.valid = this.compareValues(
|
|
211
|
-
|
|
268
|
+
normalizedCompare,
|
|
212
269
|
data?.expected ?? -1,
|
|
213
270
|
data?.actual ?? -1
|
|
214
271
|
);
|
|
@@ -224,13 +281,18 @@ class RawPolicyValidation extends createBaseClass({ componentName, baseSelector:
|
|
|
224
281
|
return !this.validate().some(({ valid }) => valid === false);
|
|
225
282
|
}
|
|
226
283
|
|
|
227
|
-
|
|
284
|
+
buildValidationItem({ valid, message }) {
|
|
228
285
|
const status = !this.value ? 'none' : valid;
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
286
|
+
const li = document.createElement('li');
|
|
287
|
+
li.className = 'item';
|
|
288
|
+
li.dataset.valid = status;
|
|
289
|
+
const span = document.createElement('span');
|
|
290
|
+
span.className = 'message';
|
|
291
|
+
// `textContent` handles any tenant-configured string in `message` safely
|
|
292
|
+
// (e.g. the disallowedchars list) without needing to escape HTML.
|
|
293
|
+
span.textContent = message ?? '';
|
|
294
|
+
li.appendChild(span);
|
|
295
|
+
return li;
|
|
234
296
|
}
|
|
235
297
|
|
|
236
298
|
renderItems(availablePolicies, activePolicies) {
|
|
@@ -238,7 +300,9 @@ class RawPolicyValidation extends createBaseClass({ componentName, baseSelector:
|
|
|
238
300
|
return;
|
|
239
301
|
}
|
|
240
302
|
|
|
241
|
-
this.list.
|
|
303
|
+
this.list.replaceChildren(
|
|
304
|
+
...this.validate().map(this.buildValidationItem.bind(this)),
|
|
305
|
+
);
|
|
242
306
|
}
|
|
243
307
|
|
|
244
308
|
updateLabel(val) {
|
|
@@ -18,6 +18,16 @@ import {
|
|
|
18
18
|
defaultValueMissingControl,
|
|
19
19
|
} from './commonControls';
|
|
20
20
|
|
|
21
|
+
// HTML-attribute-escape user-supplied values (and JSON blobs) so quotes in
|
|
22
|
+
// e.g. the disallowedchars pattern don't break out of attribute quoting.
|
|
23
|
+
const escapeAttr = (v) =>
|
|
24
|
+
String(v ?? '')
|
|
25
|
+
.replace(/&/g, '&')
|
|
26
|
+
.replace(/"/g, '"')
|
|
27
|
+
.replace(/'/g, ''')
|
|
28
|
+
.replace(/</g, '<')
|
|
29
|
+
.replace(/>/g, '>');
|
|
30
|
+
|
|
21
31
|
const policyData = [
|
|
22
32
|
{
|
|
23
33
|
id: 'minlength',
|
|
@@ -60,6 +70,18 @@ const policyData = [
|
|
|
60
70
|
message: '1 symbol',
|
|
61
71
|
pattern: '[^a-zA-Z0-9]',
|
|
62
72
|
},
|
|
73
|
+
{
|
|
74
|
+
id: 'disallowedchars',
|
|
75
|
+
message: 'Does not contain: {{value}}',
|
|
76
|
+
pattern: `^[^'"]*$`,
|
|
77
|
+
data: { value: `'"` },
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
id: 'disallowemail',
|
|
81
|
+
message: 'Does not match your email',
|
|
82
|
+
compare: 'STR_NEQ_CI',
|
|
83
|
+
data: { expected: 'user@example.com' },
|
|
84
|
+
},
|
|
63
85
|
];
|
|
64
86
|
|
|
65
87
|
const Template = ({
|
|
@@ -113,7 +135,7 @@ const Template = ({
|
|
|
113
135
|
data-password-policy-value-minlength="${minLengthDataAttr}"
|
|
114
136
|
data-password-policy-value-passwordstrength="${passwordStrengthDataAttr}"
|
|
115
137
|
st-host-direction="${direction ?? ''}"
|
|
116
|
-
available-policies=
|
|
138
|
+
available-policies="${escapeAttr(JSON.stringify(availablePolicies) || '')}"
|
|
117
139
|
active-policies="${activePolicies || ''}"
|
|
118
140
|
policy-label="${policyLabel || ''}"
|
|
119
141
|
st-policy-preview-background-color="${stPolicyPreviewBgColor || ''}"
|
|
@@ -202,6 +224,8 @@ Default.args = {
|
|
|
202
224
|
'number',
|
|
203
225
|
'nonalphanumeric',
|
|
204
226
|
'passwordstrength',
|
|
227
|
+
'disallowedchars',
|
|
228
|
+
'disallowemail',
|
|
205
229
|
],
|
|
206
230
|
'data-password-policy-value-minlength': '8',
|
|
207
231
|
'data-password-policy-value-passwordstrength': '2',
|
|
@@ -35,8 +35,30 @@ const availablePolicies = [
|
|
|
35
35
|
message: '1 symbol',
|
|
36
36
|
pattern: '[^a-zA-Z0-9]',
|
|
37
37
|
},
|
|
38
|
+
{
|
|
39
|
+
id: 'disallowedchars',
|
|
40
|
+
message: 'Does not contain: {{value}}',
|
|
41
|
+
pattern: `^[^'"]*$`,
|
|
42
|
+
data: { value: `'"` },
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: 'disallowemail',
|
|
46
|
+
message: 'Does not match your email',
|
|
47
|
+
compare: 'STR_NEQ_CI',
|
|
48
|
+
data: { expected: 'user@example.com' },
|
|
49
|
+
},
|
|
38
50
|
];
|
|
39
51
|
|
|
52
|
+
// HTML-attribute-escape any user-supplied string so the template still parses
|
|
53
|
+
// when the value itself contains quotes (eg. the default disallowed-chars `'"`).
|
|
54
|
+
const escapeAttr = (v) =>
|
|
55
|
+
String(v ?? '')
|
|
56
|
+
.replace(/&/g, '&')
|
|
57
|
+
.replace(/"/g, '"')
|
|
58
|
+
.replace(/'/g, ''')
|
|
59
|
+
.replace(/</g, '<')
|
|
60
|
+
.replace(/>/g, '>');
|
|
61
|
+
|
|
40
62
|
const Template = ({
|
|
41
63
|
value,
|
|
42
64
|
label,
|
|
@@ -48,7 +70,11 @@ const Template = ({
|
|
|
48
70
|
useAnyLetter,
|
|
49
71
|
useSymbol,
|
|
50
72
|
useMinLength,
|
|
73
|
+
useDisallowedChars,
|
|
74
|
+
useDisallowEmail,
|
|
51
75
|
minLengthValue,
|
|
76
|
+
disallowedCharsValue,
|
|
77
|
+
emailValue,
|
|
52
78
|
}) => {
|
|
53
79
|
const policies = [
|
|
54
80
|
useMinLength ? 'minlength' : null,
|
|
@@ -57,16 +83,20 @@ const Template = ({
|
|
|
57
83
|
useAnyLetter ? 'anyletter' : null,
|
|
58
84
|
useNumber ? 'number' : null,
|
|
59
85
|
useSymbol ? 'nonalphanumeric' : null,
|
|
86
|
+
useDisallowedChars ? 'disallowedchars' : null,
|
|
87
|
+
useDisallowEmail ? 'disallowemail' : null,
|
|
60
88
|
].filter(Boolean);
|
|
61
89
|
|
|
62
90
|
return `
|
|
63
91
|
<descope-policy-validation
|
|
64
|
-
label="${label}"
|
|
65
|
-
value="${value}"
|
|
66
|
-
data=
|
|
92
|
+
label="${escapeAttr(label)}"
|
|
93
|
+
value="${escapeAttr(value)}"
|
|
94
|
+
data="${escapeAttr(JSON.stringify(data) || '')}"
|
|
67
95
|
active-policies="${policies || ''}"
|
|
68
|
-
data-password-policy-value-minlength="${minLengthValue
|
|
69
|
-
|
|
96
|
+
data-password-policy-value-minlength="${escapeAttr(minLengthValue)}"
|
|
97
|
+
data-password-policy-value-disallowedchars="${escapeAttr(disallowedCharsValue)}"
|
|
98
|
+
data-password-policy-value-email="${escapeAttr(emailValue)}"
|
|
99
|
+
st-host-direction="${escapeAttr(direction)}"
|
|
70
100
|
></descope-policy-validation>
|
|
71
101
|
`;
|
|
72
102
|
};
|
|
@@ -96,5 +126,9 @@ Default.args = {
|
|
|
96
126
|
useAnyLetter: false,
|
|
97
127
|
useSymbol: false,
|
|
98
128
|
useMinLength: false,
|
|
129
|
+
useDisallowedChars: false,
|
|
130
|
+
useDisallowEmail: false,
|
|
99
131
|
minLengthValue: undefined,
|
|
132
|
+
disallowedCharsValue: `'"`,
|
|
133
|
+
emailValue: 'user@example.com',
|
|
100
134
|
};
|