@descope/web-components-ui 3.25.0 → 3.26.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.
@@ -13,6 +13,7 @@ const overrideAttrs = [
13
13
  'data-password-policy-actual-passwordstrength',
14
14
  'data-password-policy-value-disallowedchars',
15
15
  'data-password-policy-value-email',
16
+ 'data-password-policy-value-reuse',
16
17
  ];
17
18
  const dataAttrs = ['data', 'active-policies', 'overrides', ...overrideAttrs];
18
19
  const policyAttrs = ['label', 'value', ...dataAttrs];
@@ -109,6 +110,13 @@ class RawPolicyValidation extends createBaseClass({ componentName, baseSelector:
109
110
  }
110
111
  }
111
112
 
113
+ if (attrName === 'data-password-policy-value-reuse') {
114
+ const ln = Number(newValue);
115
+ if (!Number.isNaN(ln) && ln > 0) {
116
+ this.#overrides = { ...this.#overrides, reuse: { value: `${ln}` } };
117
+ }
118
+ }
119
+
112
120
  if (attrName === 'data-password-policy-value-passwordstrength') {
113
121
  const passwordStrength = parseInt(newValue);
114
122
  if (!Number.isNaN(passwordStrength) && passwordStrength >= 0) {
@@ -227,17 +235,17 @@ class RawPolicyValidation extends createBaseClass({ componentName, baseSelector:
227
235
  });
228
236
  }
229
237
 
230
- return this.#activePolicies.reduce((results, id) => {
238
+ const items = this.#activePolicies.reduce((results, id) => {
231
239
  const policy = policies.find((p) => p.id === id);
232
240
 
233
241
  if (!policy) {
234
242
  return results;
235
243
  }
236
244
 
237
- const { pattern, message, data, compare } = policy;
245
+ const { pattern, message, data, compare, info } = policy;
238
246
  const normalizedCompare = typeof compare === 'string' ? compare.toUpperCase() : compare;
239
247
 
240
- if ((!pattern && !compare) || !message) {
248
+ if ((!pattern && !compare && !info) || !message) {
241
249
  return results;
242
250
  }
243
251
 
@@ -246,7 +254,11 @@ class RawPolicyValidation extends createBaseClass({ componentName, baseSelector:
246
254
  id,
247
255
  };
248
256
 
249
- if (pattern) {
257
+ if (info) {
258
+ // informational rule the client can't check (e.g. password reuse):
259
+ // `valid` stays undefined, so it renders neutral and never blocks `isValid`
260
+ validationResult.info = true;
261
+ } else if (pattern) {
250
262
  const exp = new RegExp(interpolateString(pattern, data));
251
263
  validationResult.valid = exp.test(this.value);
252
264
  } else if (normalizedCompare === 'STR_NEQ_CI') {
@@ -275,14 +287,17 @@ class RawPolicyValidation extends createBaseClass({ componentName, baseSelector:
275
287
 
276
288
  return results;
277
289
  }, []);
290
+
291
+ // informational rules always render last
292
+ return items.sort((a, b) => Number(!!a.info) - Number(!!b.info));
278
293
  }
279
294
 
280
295
  get isValid() {
281
296
  return !this.validate().some(({ valid }) => valid === false);
282
297
  }
283
298
 
284
- buildValidationItem({ valid, message }) {
285
- const status = !this.value ? 'none' : valid;
299
+ buildValidationItem({ valid, message, info }) {
300
+ const status = !this.value || info ? 'none' : valid;
286
301
  const li = document.createElement('li');
287
302
  li.className = 'item';
288
303
  li.dataset.valid = status;
@@ -47,6 +47,12 @@ const availablePolicies = [
47
47
  compare: 'STR_NEQ_CI',
48
48
  data: { expected: 'user@example.com' },
49
49
  },
50
+ {
51
+ id: 'reuse',
52
+ message: 'Cannot be one of your last {{value}} passwords',
53
+ info: true,
54
+ data: { value: 3 },
55
+ },
50
56
  ];
51
57
 
52
58
  // HTML-attribute-escape any user-supplied string so the template still parses
@@ -72,10 +78,21 @@ const Template = ({
72
78
  useMinLength,
73
79
  useDisallowedChars,
74
80
  useDisallowEmail,
81
+ useReuse,
75
82
  minLengthValue,
76
83
  disallowedCharsValue,
77
84
  emailValue,
85
+ useCustomReuseMessage,
78
86
  }) => {
87
+ // custom reuse message, as a Descoper would set it on the screen
88
+ const policiesData = useCustomReuseMessage
89
+ ? data.map((p) =>
90
+ p.id === 'reuse'
91
+ ? { ...p, message: 'Must differ from your previous {{value}} passwords' }
92
+ : p
93
+ )
94
+ : data;
95
+
79
96
  const policies = [
80
97
  useMinLength ? 'minlength' : null,
81
98
  useLowercase ? 'lowercase' : null,
@@ -85,13 +102,14 @@ const Template = ({
85
102
  useSymbol ? 'nonalphanumeric' : null,
86
103
  useDisallowedChars ? 'disallowedchars' : null,
87
104
  useDisallowEmail ? 'disallowemail' : null,
105
+ useReuse ? 'reuse' : null,
88
106
  ].filter(Boolean);
89
107
 
90
108
  return `
91
109
  <descope-policy-validation
92
110
  label="${escapeAttr(label)}"
93
111
  value="${escapeAttr(value)}"
94
- data="${escapeAttr(JSON.stringify(data) || '')}"
112
+ data="${escapeAttr(JSON.stringify(policiesData) || '')}"
95
113
  active-policies="${policies || ''}"
96
114
  data-password-policy-value-minlength="${escapeAttr(minLengthValue)}"
97
115
  data-password-policy-value-disallowedchars="${escapeAttr(disallowedCharsValue)}"
@@ -128,7 +146,9 @@ Default.args = {
128
146
  useMinLength: false,
129
147
  useDisallowedChars: false,
130
148
  useDisallowEmail: false,
149
+ useReuse: false,
131
150
  minLengthValue: undefined,
132
151
  disallowedCharsValue: `'"`,
133
152
  emailValue: 'user@example.com',
153
+ useCustomReuseMessage: false,
134
154
  };