cauthy-auth 0.27.0 → 0.28.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/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { C as Cauthy, a as CauthyEvent, b as CauthyWebhookError, R as Resolved, V as VerifyWebhookOptions, c as createCauthy, v as verifyWebhook } from './cauthy-XkIbG5gE.mjs';
2
2
  export { C as CauthyApiError, a as CauthyConfigError, b as CauthyOptions, c as CauthySystem, J as JsonValue, N as NewMember, O as Organization, d as OrganizationMember, P as PermissionOf, e as Permitted, f as Policy, g as PolicyPermission, h as PolicyRole, i as PublicSession, j as PushPolicyOptions, R as RoleOf, S as Session, k as SessionOrganization, l as SessionStatus, m as SessionUser, n as SystemKey, o as SystemOptions, p as can, q as createSystem, r as definePolicy, s as policySource, t as pullPolicy, u as pushPolicy } from './system-BxMsSIu1.mjs';
3
3
  export { CauthyTheme, ImportedTheme, PushThemeOptions, StackmythThemeOptions, StackmythTokens, ThemeFont, ThemeTexts, pushTheme, themeFromStackmyth, tokensFromStackmyth } from './theme.mjs';
4
- export { A as AuthField, F as FieldProblem, M as MIN_PASSWORD, c as checkCode, a as checkEmail, b as checkName, d as checkNewPassword, e as checkPassword } from './validate-BTRit1O1.mjs';
4
+ export { A as AuthField, D as DEFAULT_PASSWORD_POLICY, F as FieldProblem, M as MIN_PASSWORD, P as PasswordClass, a as PasswordLocale, b as PasswordPolicy, c as PasswordReason, d as checkCode, e as checkEmail, f as checkName, g as checkNewPassword, h as checkPassword, i as describePasswordPolicy, j as explainPasswordProblems, p as passwordPolicyOf, k as passwordProblems } from './validate-sEXG82po.mjs';
5
5
  import { JWTVerifyGetKey } from 'jose';
6
6
 
7
7
  interface ConnectOptions {
@@ -33,10 +33,16 @@ interface Connected {
33
33
  /** Shown this once: Cauthy keeps only its hash. */
34
34
  clientSecret: string;
35
35
  redirectUris: string[];
36
+ /**
37
+ * The subscription to events, when `eventsUrl` was given. Its `secret` signs
38
+ * the HMAC header (X-Cauthy-Signature) and is shown this once; `auth.webhook`
39
+ * does not need it, as it verifies by Cauthy's published keys.
40
+ */
36
41
  webhook: {
37
42
  id: string;
38
43
  url: string;
39
44
  events: string[];
45
+ secret: string;
40
46
  } | null;
41
47
  /**
42
48
  * Everything the application sets: what Cauthy answered, plus CAUTHY_SECRET,
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { C as Cauthy, a as CauthyEvent, b as CauthyWebhookError, R as Resolved, V as VerifyWebhookOptions, c as createCauthy, v as verifyWebhook } from './cauthy-DGAy45G2.js';
2
2
  export { C as CauthyApiError, a as CauthyConfigError, b as CauthyOptions, c as CauthySystem, J as JsonValue, N as NewMember, O as Organization, d as OrganizationMember, P as PermissionOf, e as Permitted, f as Policy, g as PolicyPermission, h as PolicyRole, i as PublicSession, j as PushPolicyOptions, R as RoleOf, S as Session, k as SessionOrganization, l as SessionStatus, m as SessionUser, n as SystemKey, o as SystemOptions, p as can, q as createSystem, r as definePolicy, s as policySource, t as pullPolicy, u as pushPolicy } from './system-DTIeDXDP.js';
3
3
  export { CauthyTheme, ImportedTheme, PushThemeOptions, StackmythThemeOptions, StackmythTokens, ThemeFont, ThemeTexts, pushTheme, themeFromStackmyth, tokensFromStackmyth } from './theme.js';
4
- export { A as AuthField, F as FieldProblem, M as MIN_PASSWORD, c as checkCode, a as checkEmail, b as checkName, d as checkNewPassword, e as checkPassword } from './validate-BTRit1O1.js';
4
+ export { A as AuthField, D as DEFAULT_PASSWORD_POLICY, F as FieldProblem, M as MIN_PASSWORD, P as PasswordClass, a as PasswordLocale, b as PasswordPolicy, c as PasswordReason, d as checkCode, e as checkEmail, f as checkName, g as checkNewPassword, h as checkPassword, i as describePasswordPolicy, j as explainPasswordProblems, p as passwordPolicyOf, k as passwordProblems } from './validate-sEXG82po.js';
5
5
  import { JWTVerifyGetKey } from 'jose';
6
6
 
7
7
  interface ConnectOptions {
@@ -33,10 +33,16 @@ interface Connected {
33
33
  /** Shown this once: Cauthy keeps only its hash. */
34
34
  clientSecret: string;
35
35
  redirectUris: string[];
36
+ /**
37
+ * The subscription to events, when `eventsUrl` was given. Its `secret` signs
38
+ * the HMAC header (X-Cauthy-Signature) and is shown this once; `auth.webhook`
39
+ * does not need it, as it verifies by Cauthy's published keys.
40
+ */
36
41
  webhook: {
37
42
  id: string;
38
43
  url: string;
39
44
  events: string[];
45
+ secret: string;
40
46
  } | null;
41
47
  /**
42
48
  * Everything the application sets: what Cauthy answered, plus CAUTHY_SECRET,
package/dist/index.js CHANGED
@@ -24,6 +24,7 @@ __export(src_exports, {
24
24
  CauthyConfigError: () => CauthyConfigError,
25
25
  CauthyTokenError: () => CauthyTokenError,
26
26
  CauthyWebhookError: () => CauthyWebhookError,
27
+ DEFAULT_PASSWORD_POLICY: () => DEFAULT_PASSWORD_POLICY,
27
28
  MIN_PASSWORD: () => MIN_PASSWORD,
28
29
  can: () => can,
29
30
  checkCode: () => checkCode,
@@ -35,6 +36,10 @@ __export(src_exports, {
35
36
  createCauthy: () => createCauthy,
36
37
  createSystem: () => createSystem,
37
38
  definePolicy: () => definePolicy,
39
+ describePasswordPolicy: () => describePasswordPolicy,
40
+ explainPasswordProblems: () => explainPasswordProblems,
41
+ passwordPolicyOf: () => passwordPolicyOf,
42
+ passwordProblems: () => passwordProblems,
38
43
  policySource: () => policySource,
39
44
  pullPolicy: () => pullPolicy,
40
45
  pushPolicy: () => pushPolicy,
@@ -543,7 +548,9 @@ function createSystem(given = {}) {
543
548
  async function fail(res, what) {
544
549
  const body = await res.json().catch(() => null);
545
550
  const first = body?.errors?.[0];
546
- throw new CauthyApiError(res.status, first?.code ?? "error", `Cauthy refused ${what} (${res.status}): ${first?.message ?? res.statusText}`);
551
+ const code = typeof body?.error === "string" ? body.error : first?.code;
552
+ const message = typeof body?.error === "string" ? body.error_description : first?.message;
553
+ throw new CauthyApiError(res.status, code ?? "error", `Cauthy refused ${what} (${res.status}): ${message ?? res.statusText}`);
547
554
  }
548
555
  let held;
549
556
  let asking;
@@ -653,9 +660,113 @@ function createSystem(given = {}) {
653
660
  }
654
661
 
655
662
  // src/validate.ts
656
- var MIN_PASSWORD = 8;
657
- var MAX_PASSWORD = 256;
663
+ var MIN_PASSWORD = 12;
664
+ var MAX_PASSWORD = 128;
665
+ var FLOOR_PASSWORD = 8;
658
666
  var MAX_NAME = 120;
667
+ var CLASSES = ["lowercase", "uppercase", "digit", "symbol"];
668
+ var DEFAULT_PASSWORD_POLICY = Object.freeze({ min: MIN_PASSWORD, max: MAX_PASSWORD, requires: [], min_classes: 0, reject_breached: false });
669
+ var int = (v, fallback) => typeof v === "number" && Number.isFinite(v) ? Math.trunc(v) : fallback;
670
+ function passwordPolicyOf(raw) {
671
+ const r = raw && typeof raw === "object" ? raw : {};
672
+ const min = Math.min(Math.max(int(r.min ?? r.min_length, MIN_PASSWORD) || MIN_PASSWORD, FLOOR_PASSWORD), MAX_PASSWORD);
673
+ const max = Math.max(Math.min(int(r.max ?? r.max_length, MAX_PASSWORD) || MAX_PASSWORD, MAX_PASSWORD), min);
674
+ const asked = Array.isArray(r.requires) ? r.requires : [];
675
+ return {
676
+ min,
677
+ max,
678
+ requires: CLASSES.filter((c) => asked.includes(c)),
679
+ min_classes: Math.min(Math.max(int(r.min_classes ?? r.minClasses, 0), 0), CLASSES.length),
680
+ reject_breached: (r.reject_breached ?? r.rejectBreached) === true
681
+ };
682
+ }
683
+ function utf8Length(v) {
684
+ let n = 0;
685
+ for (const ch of v) {
686
+ const c = ch.codePointAt(0);
687
+ n += c < 128 ? 1 : c < 2048 ? 2 : c < 65536 ? 3 : 4;
688
+ }
689
+ return n;
690
+ }
691
+ function classesOf(v) {
692
+ const has = /* @__PURE__ */ new Set();
693
+ for (const ch of v) {
694
+ if (/\p{Ll}/u.test(ch)) has.add("lowercase");
695
+ else if (/\p{Lu}/u.test(ch)) has.add("uppercase");
696
+ else if (/\p{Nd}/u.test(ch)) has.add("digit");
697
+ else if (!/\p{L}/u.test(ch)) has.add("symbol");
698
+ }
699
+ return has;
700
+ }
701
+ function passwordProblems(value, policy = DEFAULT_PASSWORD_POLICY) {
702
+ const p = passwordPolicyOf(policy);
703
+ const out2 = [];
704
+ const length = utf8Length(value);
705
+ if (length < p.min) out2.push("too_short");
706
+ if (length > p.max) out2.push("too_long");
707
+ const has = classesOf(value);
708
+ for (const c of p.requires) if (!has.has(c)) out2.push(`needs_${c}`);
709
+ if (p.min_classes > 0 && CLASSES.filter((c) => has.has(c)).length < p.min_classes) out2.push("needs_classes");
710
+ return out2;
711
+ }
712
+ var RULES = {
713
+ en: {
714
+ between: "Between {min} and {max} characters.",
715
+ requires: "Include {kinds}.",
716
+ and: "and",
717
+ classes: "Use at least {n} of these: lowercase letters, uppercase letters, digits, symbols.",
718
+ breached: "Passwords found in known data breaches are not accepted.",
719
+ kinds: { lowercase: "a lowercase letter", uppercase: "an uppercase letter", digit: "a digit", symbol: "a symbol" },
720
+ reasons: {
721
+ too_short: "Use at least {min} characters.",
722
+ too_long: "Use at most {max} characters.",
723
+ needs_lowercase: "Include a lowercase letter.",
724
+ needs_uppercase: "Include an uppercase letter.",
725
+ needs_digit: "Include a digit.",
726
+ needs_symbol: "Include a symbol.",
727
+ needs_classes: "Use at least {n} of these: lowercase letters, uppercase letters, digits, symbols.",
728
+ breached: "This password appears in a known data breach. Choose a different one."
729
+ }
730
+ },
731
+ es: {
732
+ between: "Entre {min} y {max} caracteres.",
733
+ requires: "Incluye {kinds}.",
734
+ and: "y",
735
+ classes: "Usa al menos {n} de estos tipos: min\xFAsculas, may\xFAsculas, n\xFAmeros, s\xEDmbolos.",
736
+ breached: "No se aceptan contrase\xF1as que aparecen en filtraciones de datos conocidas.",
737
+ kinds: { lowercase: "una min\xFAscula", uppercase: "una may\xFAscula", digit: "un n\xFAmero", symbol: "un s\xEDmbolo" },
738
+ reasons: {
739
+ too_short: "Usa al menos {min} caracteres.",
740
+ too_long: "Usa como m\xE1ximo {max} caracteres.",
741
+ needs_lowercase: "Incluye una min\xFAscula.",
742
+ needs_uppercase: "Incluye una may\xFAscula.",
743
+ needs_digit: "Incluye un n\xFAmero.",
744
+ needs_symbol: "Incluye un s\xEDmbolo.",
745
+ needs_classes: "Usa al menos {n} de estos tipos: min\xFAsculas, may\xFAsculas, n\xFAmeros, s\xEDmbolos.",
746
+ breached: "Esta contrase\xF1a aparece en una filtraci\xF3n de datos conocida. Elige otra."
747
+ }
748
+ }
749
+ };
750
+ var fill = (s, p) => s.replace("{min}", String(p.min)).replace("{max}", String(p.max)).replace("{n}", String(p.min_classes));
751
+ function describePasswordPolicy(policy = DEFAULT_PASSWORD_POLICY, locale = "en") {
752
+ const p = passwordPolicyOf(policy);
753
+ const t = RULES[locale] ?? RULES.en;
754
+ const parts = [fill(t.between, p)];
755
+ if (p.requires.length > 0) {
756
+ const kinds = p.requires.map((c) => t.kinds[c]);
757
+ const listed = kinds.length === 1 ? kinds[0] : `${kinds.slice(0, -1).join(", ")} ${t.and} ${kinds[kinds.length - 1]}`;
758
+ parts.push(t.requires.replace("{kinds}", listed));
759
+ }
760
+ if (p.min_classes > 0) parts.push(fill(t.classes, p));
761
+ if (p.reject_breached) parts.push(t.breached);
762
+ return parts.join(" ");
763
+ }
764
+ function explainPasswordProblems(reasons, policy = DEFAULT_PASSWORD_POLICY, locale = "en") {
765
+ const p = passwordPolicyOf(policy);
766
+ const t = RULES[locale] ?? RULES.en;
767
+ const said = reasons.filter((r) => r in t.reasons).map((r) => fill(t.reasons[r], p));
768
+ return said.length > 0 ? said.join(" ") : describePasswordPolicy(p, locale);
769
+ }
659
770
  var EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
660
771
  function checkEmail(value) {
661
772
  const v = typeof value === "string" ? value.trim() : "";
@@ -668,13 +779,12 @@ function checkPassword(value) {
668
779
  if (value.length > MAX_PASSWORD) return { field: "password", code: "too_long", message: "That password is too long." };
669
780
  return null;
670
781
  }
671
- function checkNewPassword(value) {
672
- const basic = checkPassword(value);
673
- if (basic) return basic;
674
- if (value.length < MIN_PASSWORD) {
675
- return { field: "password", code: "too_short", message: `Use at least ${MIN_PASSWORD} characters.` };
676
- }
677
- return null;
782
+ function checkNewPassword(value, policy) {
783
+ if (typeof value !== "string" || value === "") return { field: "password", code: "required", message: "Enter your password." };
784
+ const p = policy ? passwordPolicyOf(policy) : DEFAULT_PASSWORD_POLICY;
785
+ const reasons = passwordProblems(value, p);
786
+ if (reasons.length === 0) return null;
787
+ return { field: "password", code: reasons[0], message: explainPasswordProblems(reasons, p) };
678
788
  }
679
789
  function checkName(value) {
680
790
  if (value === void 0 || value === null || value === "") return null;
@@ -1133,7 +1243,7 @@ function createCauthy(given = {}) {
1133
1243
  connectedAt: String(d?.created_at ?? ""),
1134
1244
  lastUsedAt: String(d?.last_used_at ?? "")
1135
1245
  });
1136
- const problem = (status2, code, message, field, headers) => json({ error: { code, message, ...field ? { field } : {} } }, status2, headers);
1246
+ const problem = (status2, code, message, field, headers, reasons) => json({ error: { code, message, ...field ? { field } : {}, ...reasons && reasons.length > 0 ? { reasons } : {} } }, status2, headers);
1137
1247
  const invalid = (p) => problem(400, p.code, p.message, p.field);
1138
1248
  function ownRequest(request) {
1139
1249
  const origin = request.headers.get("origin");
@@ -1191,7 +1301,8 @@ function createCauthy(given = {}) {
1191
1301
  const b = res.status === 204 || res.status === 202 ? null : await res.json().catch(() => null);
1192
1302
  if (res.ok) return { status: res.status, data: b?.data ?? b };
1193
1303
  const first = b?.errors?.[0];
1194
- return { status: res.status, data: null, error: { code: String(first?.code ?? "error"), message: String(first?.message ?? "The request could not be completed.") } };
1304
+ const reasons = Array.isArray(first?.meta?.reasons) ? first.meta.reasons.map(String) : void 0;
1305
+ return { status: res.status, data: null, error: { code: String(first?.code ?? "error"), message: String(first?.message ?? "The request could not be completed."), ...reasons ? { reasons } : {} } };
1195
1306
  } catch {
1196
1307
  return { status: 503, data: null, error: { code: "unavailable", message: "Sign-in is unavailable right now. Try again in a moment." } };
1197
1308
  }
@@ -1219,6 +1330,19 @@ function createCauthy(given = {}) {
1219
1330
  return json({ status: "signed_in", session: await toPublic(toSession(s)), ...more }, 200, h);
1220
1331
  }
1221
1332
  let lookCache = null;
1333
+ let policyCache = null;
1334
+ const keepPolicy = (settings) => {
1335
+ policyCache = { until: Date.now() + LOOK_TTL_MS, policy: settings.error || !settings.data?.password_policy ? null : passwordPolicyOf(settings.data.password_policy) };
1336
+ return policyCache.policy;
1337
+ };
1338
+ async function workspacePolicy(request) {
1339
+ if (policyCache !== null && policyCache.until >= Date.now()) return policyCache.policy;
1340
+ return keepPolicy(await ask(request, "GET", "/v1/auth/settings"));
1341
+ }
1342
+ async function newPasswordProblem(request, value) {
1343
+ const policy = await workspacePolicy(request);
1344
+ return checkNewPassword(value, policy ?? { min: 8, max: 128, requires: [], min_classes: 0, reject_breached: false });
1345
+ }
1222
1346
  async function ownRoute(request, url, route) {
1223
1347
  const post = request.method === "POST";
1224
1348
  const own = [
@@ -1296,6 +1420,7 @@ function createCauthy(given = {}) {
1296
1420
  ask(request, "GET", "/v1/auth/sso/connections")
1297
1421
  ]);
1298
1422
  const list = Array.isArray(providers.data) ? providers.data : [];
1423
+ const password = keepPolicy(settings);
1299
1424
  const here = place.data?.here === true;
1300
1425
  return json({
1301
1426
  providers: list.map((p) => ({ id: String(p.provider ?? p.id ?? ""), name: String(p.label ?? p.name ?? p.provider ?? "") })).filter((p) => p.id !== ""),
@@ -1311,7 +1436,9 @@ function createCauthy(given = {}) {
1311
1436
  sso: Array.isArray(sso.data) && sso.data.some((c) => c?.discoverable === true),
1312
1437
  // The terms a sign-up accepts and the consents it answers, when the workspace asks any.
1313
1438
  ...settings.data?.legal ? { legal: legalOf(settings.data.legal) } : {},
1314
- ...settings.data?.captcha_enabled === true && settings.data?.captcha_site_key ? { captchaSiteKey: String(settings.data.captcha_site_key) } : {}
1439
+ ...settings.data?.captcha_enabled === true && settings.data?.captcha_site_key ? { captchaSiteKey: String(settings.data.captcha_site_key) } : {},
1440
+ // What a new password must be: for the form to say it and check it.
1441
+ ...password ? { password } : {}
1315
1442
  });
1316
1443
  }
1317
1444
  if (route === "/sign-in/sso" && !post) {
@@ -1601,13 +1728,13 @@ function createCauthy(given = {}) {
1601
1728
  return json({ status: "sent", sentTo: String(res.data?.sent_to ?? ""), channel: String(res.data?.channel ?? "sms") });
1602
1729
  }
1603
1730
  if (route === "/sign-up/email") {
1604
- const bad = firstProblem(checkName(b.name), checkEmail(b.email), checkNewPassword(b.password), checkOrganization(b.organization));
1731
+ const bad = firstProblem(checkName(b.name), checkEmail(b.email), await newPasswordProblem(request, b.password), checkOrganization(b.organization));
1605
1732
  if (bad) return invalid(bad);
1606
1733
  const email = String(b.email).trim();
1607
1734
  const organization = typeof b.organization === "string" && b.organization.trim() !== "" ? { organization: { name: b.organization.trim() } } : {};
1608
1735
  const legal = { ...b.acceptLegal === true ? { accept_legal: true } : {}, ...b.consents && typeof b.consents === "object" ? { consents: b.consents } : {} };
1609
1736
  const made = await ask(request, "POST", "/v1/auth/register", { email, password: b.password, display_name: typeof b.name === "string" ? b.name.trim() : "", ...organization, ...legal }, pages.verifyEmail);
1610
- if (made.error) return problem(made.status, made.error.code, made.error.message);
1737
+ if (made.error) return problem(made.status, made.error.code, made.error.message, made.error.code === "weak_password" ? "password" : void 0, void 0, made.error.reasons);
1611
1738
  if (made.data?.verification_required === true) return json({ status: "verification_required", email });
1612
1739
  const res = await ask(request, "POST", "/v1/auth/login", { email, password: b.password });
1613
1740
  if (res.error || res.data?.mfa_required === true) return json({ status: "verification_required", email });
@@ -1623,7 +1750,7 @@ function createCauthy(given = {}) {
1623
1750
  const mine = await signedInAs(request);
1624
1751
  if ("response" in mine) return mine.response;
1625
1752
  const as = (path, payload, method = "POST") => ask(request, method, path, payload, void 0, mine.token);
1626
- const refused = (res, field) => problem(res.status, res.error.code, res.error.message, field, mine.headers);
1753
+ const refused = (res, field) => problem(res.status, res.error.code, res.error.message, field, mine.headers, res.error.reasons);
1627
1754
  const password = typeof b.password === "string" ? b.password : "";
1628
1755
  if (route === "/me") {
1629
1756
  const bad = checkName(b.name);
@@ -1644,7 +1771,7 @@ function createCauthy(given = {}) {
1644
1771
  return json({ status: "accepted" }, 200, mine.headers);
1645
1772
  }
1646
1773
  if (route === "/me/password") {
1647
- const bad = checkNewPassword(b.newPassword);
1774
+ const bad = await newPasswordProblem(request, b.newPassword);
1648
1775
  if (bad) return problem(400, bad.code, bad.message, "newPassword");
1649
1776
  const res = await as("/v1/auth/me/password", { current_password: password, new_password: b.newPassword });
1650
1777
  if (res.error) return refused(res, res.error.code === "wrong_password" ? "password" : res.error.code === "weak_password" ? "newPassword" : void 0);
@@ -1737,7 +1864,7 @@ function createCauthy(given = {}) {
1737
1864
  return json({ status: "removed", id }, 200, mine.headers);
1738
1865
  }
1739
1866
  if (route === "/me/upgrade") {
1740
- const bad = firstProblem(checkName(b.name), checkEmail(b.email), checkNewPassword(b.password));
1867
+ const bad = firstProblem(checkName(b.name), checkEmail(b.email), await newPasswordProblem(request, b.password));
1741
1868
  if (bad) return invalid(bad);
1742
1869
  const res = await as("/v1/auth/anonymous/upgrade", { email: String(b.email).trim(), password: b.password, display_name: typeof b.name === "string" ? b.name.trim() : "" });
1743
1870
  if (res.error) return refused(res, res.error.code === "weak_password" ? "password" : "email");
@@ -1804,10 +1931,10 @@ function createCauthy(given = {}) {
1804
1931
  const badLink = () => problem(422, "invalid_token", "This link is not valid, or it has expired.");
1805
1932
  if (route === "/reset-password") {
1806
1933
  if (!isToken(b.token)) return badLink();
1807
- const bad = checkNewPassword(b.password);
1934
+ const bad = await newPasswordProblem(request, b.password);
1808
1935
  if (bad) return invalid(bad);
1809
1936
  const res = await ask(request, "POST", "/v1/auth/password/change", { token: String(b.token), new_password: b.password });
1810
- if (res.error) return problem(res.status, res.error.code, res.error.message, res.error.code === "weak_password" ? "password" : void 0);
1937
+ if (res.error) return problem(res.status, res.error.code, res.error.message, res.error.code === "weak_password" ? "password" : void 0, void 0, res.error.reasons);
1811
1938
  return json({ status: "changed" });
1812
1939
  }
1813
1940
  if (route === "/verify-email") {
@@ -2181,6 +2308,7 @@ async function verifyToken(from, options = {}) {
2181
2308
  CauthyConfigError,
2182
2309
  CauthyTokenError,
2183
2310
  CauthyWebhookError,
2311
+ DEFAULT_PASSWORD_POLICY,
2184
2312
  MIN_PASSWORD,
2185
2313
  can,
2186
2314
  checkCode,
@@ -2192,6 +2320,10 @@ async function verifyToken(from, options = {}) {
2192
2320
  createCauthy,
2193
2321
  createSystem,
2194
2322
  definePolicy,
2323
+ describePasswordPolicy,
2324
+ explainPasswordProblems,
2325
+ passwordPolicyOf,
2326
+ passwordProblems,
2195
2327
  policySource,
2196
2328
  pullPolicy,
2197
2329
  pushPolicy,