cauthy-auth 0.27.1 → 0.28.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/README.md +1 -1
- package/dist/{cauthy-DGAy45G2.d.ts → cauthy-BAwAJChs.d.ts} +1 -1
- package/dist/{cauthy-XkIbG5gE.d.mts → cauthy-CTVg4kvo.d.mts} +1 -1
- package/dist/client.d.mts +13 -4
- package/dist/client.d.ts +13 -4
- package/dist/client.js +130 -15
- package/dist/client.js.map +1 -1
- package/dist/client.mjs +124 -14
- package/dist/client.mjs.map +1 -1
- package/dist/express.d.mts +2 -2
- package/dist/express.d.ts +2 -2
- package/dist/fastify.d.mts +2 -2
- package/dist/fastify.d.ts +2 -2
- package/dist/hono.d.mts +2 -2
- package/dist/hono.d.ts +2 -2
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +174 -19
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +169 -19
- package/dist/index.mjs.map +1 -1
- package/dist/next.d.mts +2 -2
- package/dist/next.d.ts +2 -2
- package/dist/react.d.mts +27 -1
- package/dist/react.d.ts +27 -1
- package/dist/react.js +146 -19
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +146 -19
- package/dist/react.mjs.map +1 -1
- package/dist/styles.css +6 -0
- package/dist/svelte.d.mts +3 -3
- package/dist/svelte.d.ts +3 -3
- package/dist/svelte.js +118 -13
- package/dist/svelte.js.map +1 -1
- package/dist/svelte.mjs +118 -13
- package/dist/svelte.mjs.map +1 -1
- package/dist/{system-DTIeDXDP.d.ts → system-Bn8uckvQ.d.ts} +5 -3
- package/dist/{system-BxMsSIu1.d.mts → system-CVBW_AV8.d.mts} +5 -3
- package/dist/validate-sEXG82po.d.mts +66 -0
- package/dist/validate-sEXG82po.d.ts +66 -0
- package/dist/vue.d.mts +3 -3
- package/dist/vue.d.ts +3 -3
- package/dist/vue.js +118 -13
- package/dist/vue.js.map +1 -1
- package/dist/vue.mjs +118 -13
- package/dist/vue.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/validate-YbEfIzfl.d.mts +0 -19
- package/dist/validate-YbEfIzfl.d.ts +0 -19
package/dist/index.mjs
CHANGED
|
@@ -609,7 +609,111 @@ function createSystem(given = {}) {
|
|
|
609
609
|
// src/validate.ts
|
|
610
610
|
var MIN_PASSWORD = 12;
|
|
611
611
|
var MAX_PASSWORD = 128;
|
|
612
|
+
var FLOOR_PASSWORD = 8;
|
|
612
613
|
var MAX_NAME = 120;
|
|
614
|
+
var CLASSES = ["lowercase", "uppercase", "digit", "symbol"];
|
|
615
|
+
var DEFAULT_PASSWORD_POLICY = Object.freeze({ min: MIN_PASSWORD, max: MAX_PASSWORD, requires: [], min_classes: 0, reject_breached: false });
|
|
616
|
+
var int = (v, fallback) => typeof v === "number" && Number.isFinite(v) ? Math.trunc(v) : fallback;
|
|
617
|
+
function passwordPolicyOf(raw) {
|
|
618
|
+
const r = raw && typeof raw === "object" ? raw : {};
|
|
619
|
+
const min = Math.min(Math.max(int(r.min ?? r.min_length, MIN_PASSWORD) || MIN_PASSWORD, FLOOR_PASSWORD), MAX_PASSWORD);
|
|
620
|
+
const max = Math.max(Math.min(int(r.max ?? r.max_length, MAX_PASSWORD) || MAX_PASSWORD, MAX_PASSWORD), min);
|
|
621
|
+
const asked = Array.isArray(r.requires) ? r.requires : [];
|
|
622
|
+
return {
|
|
623
|
+
min,
|
|
624
|
+
max,
|
|
625
|
+
requires: CLASSES.filter((c) => asked.includes(c)),
|
|
626
|
+
min_classes: Math.min(Math.max(int(r.min_classes ?? r.minClasses, 0), 0), CLASSES.length),
|
|
627
|
+
reject_breached: (r.reject_breached ?? r.rejectBreached) === true
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
function utf8Length(v) {
|
|
631
|
+
let n = 0;
|
|
632
|
+
for (const ch of v) {
|
|
633
|
+
const c = ch.codePointAt(0);
|
|
634
|
+
n += c < 128 ? 1 : c < 2048 ? 2 : c < 65536 ? 3 : 4;
|
|
635
|
+
}
|
|
636
|
+
return n;
|
|
637
|
+
}
|
|
638
|
+
function classesOf(v) {
|
|
639
|
+
const has = /* @__PURE__ */ new Set();
|
|
640
|
+
for (const ch of v) {
|
|
641
|
+
if (/\p{Ll}/u.test(ch)) has.add("lowercase");
|
|
642
|
+
else if (/\p{Lu}/u.test(ch)) has.add("uppercase");
|
|
643
|
+
else if (/\p{Nd}/u.test(ch)) has.add("digit");
|
|
644
|
+
else if (!/\p{L}/u.test(ch)) has.add("symbol");
|
|
645
|
+
}
|
|
646
|
+
return has;
|
|
647
|
+
}
|
|
648
|
+
function passwordProblems(value, policy = DEFAULT_PASSWORD_POLICY) {
|
|
649
|
+
const p = passwordPolicyOf(policy);
|
|
650
|
+
const out2 = [];
|
|
651
|
+
const length = utf8Length(value);
|
|
652
|
+
if (length < p.min) out2.push("too_short");
|
|
653
|
+
if (length > p.max) out2.push("too_long");
|
|
654
|
+
const has = classesOf(value);
|
|
655
|
+
for (const c of p.requires) if (!has.has(c)) out2.push(`needs_${c}`);
|
|
656
|
+
if (p.min_classes > 0 && CLASSES.filter((c) => has.has(c)).length < p.min_classes) out2.push("needs_classes");
|
|
657
|
+
return out2;
|
|
658
|
+
}
|
|
659
|
+
var RULES = {
|
|
660
|
+
en: {
|
|
661
|
+
between: "Between {min} and {max} characters.",
|
|
662
|
+
requires: "Include {kinds}.",
|
|
663
|
+
and: "and",
|
|
664
|
+
classes: "Use at least {n} of these: lowercase letters, uppercase letters, digits, symbols.",
|
|
665
|
+
breached: "Passwords found in known data breaches are not accepted.",
|
|
666
|
+
kinds: { lowercase: "a lowercase letter", uppercase: "an uppercase letter", digit: "a digit", symbol: "a symbol" },
|
|
667
|
+
reasons: {
|
|
668
|
+
too_short: "Use at least {min} characters.",
|
|
669
|
+
too_long: "Use at most {max} characters.",
|
|
670
|
+
needs_lowercase: "Include a lowercase letter.",
|
|
671
|
+
needs_uppercase: "Include an uppercase letter.",
|
|
672
|
+
needs_digit: "Include a digit.",
|
|
673
|
+
needs_symbol: "Include a symbol.",
|
|
674
|
+
needs_classes: "Use at least {n} of these: lowercase letters, uppercase letters, digits, symbols.",
|
|
675
|
+
breached: "This password appears in a known data breach. Choose a different one."
|
|
676
|
+
}
|
|
677
|
+
},
|
|
678
|
+
es: {
|
|
679
|
+
between: "Entre {min} y {max} caracteres.",
|
|
680
|
+
requires: "Incluye {kinds}.",
|
|
681
|
+
and: "y",
|
|
682
|
+
classes: "Usa al menos {n} de estos tipos: min\xFAsculas, may\xFAsculas, n\xFAmeros, s\xEDmbolos.",
|
|
683
|
+
breached: "No se aceptan contrase\xF1as que aparecen en filtraciones de datos conocidas.",
|
|
684
|
+
kinds: { lowercase: "una min\xFAscula", uppercase: "una may\xFAscula", digit: "un n\xFAmero", symbol: "un s\xEDmbolo" },
|
|
685
|
+
reasons: {
|
|
686
|
+
too_short: "Usa al menos {min} caracteres.",
|
|
687
|
+
too_long: "Usa como m\xE1ximo {max} caracteres.",
|
|
688
|
+
needs_lowercase: "Incluye una min\xFAscula.",
|
|
689
|
+
needs_uppercase: "Incluye una may\xFAscula.",
|
|
690
|
+
needs_digit: "Incluye un n\xFAmero.",
|
|
691
|
+
needs_symbol: "Incluye un s\xEDmbolo.",
|
|
692
|
+
needs_classes: "Usa al menos {n} de estos tipos: min\xFAsculas, may\xFAsculas, n\xFAmeros, s\xEDmbolos.",
|
|
693
|
+
breached: "Esta contrase\xF1a aparece en una filtraci\xF3n de datos conocida. Elige otra."
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
};
|
|
697
|
+
var fill = (s, p) => s.replace("{min}", String(p.min)).replace("{max}", String(p.max)).replace("{n}", String(p.min_classes));
|
|
698
|
+
function describePasswordPolicy(policy = DEFAULT_PASSWORD_POLICY, locale = "en") {
|
|
699
|
+
const p = passwordPolicyOf(policy);
|
|
700
|
+
const t = RULES[locale] ?? RULES.en;
|
|
701
|
+
const parts = [fill(t.between, p)];
|
|
702
|
+
if (p.requires.length > 0) {
|
|
703
|
+
const kinds = p.requires.map((c) => t.kinds[c]);
|
|
704
|
+
const listed = kinds.length === 1 ? kinds[0] : `${kinds.slice(0, -1).join(", ")} ${t.and} ${kinds[kinds.length - 1]}`;
|
|
705
|
+
parts.push(t.requires.replace("{kinds}", listed));
|
|
706
|
+
}
|
|
707
|
+
if (p.min_classes > 0) parts.push(fill(t.classes, p));
|
|
708
|
+
if (p.reject_breached) parts.push(t.breached);
|
|
709
|
+
return parts.join(" ");
|
|
710
|
+
}
|
|
711
|
+
function explainPasswordProblems(reasons, policy = DEFAULT_PASSWORD_POLICY, locale = "en") {
|
|
712
|
+
const p = passwordPolicyOf(policy);
|
|
713
|
+
const t = RULES[locale] ?? RULES.en;
|
|
714
|
+
const said = reasons.filter((r) => r in t.reasons).map((r) => fill(t.reasons[r], p));
|
|
715
|
+
return said.length > 0 ? said.join(" ") : describePasswordPolicy(p, locale);
|
|
716
|
+
}
|
|
613
717
|
var EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
614
718
|
function checkEmail(value) {
|
|
615
719
|
const v = typeof value === "string" ? value.trim() : "";
|
|
@@ -622,13 +726,12 @@ function checkPassword(value) {
|
|
|
622
726
|
if (value.length > MAX_PASSWORD) return { field: "password", code: "too_long", message: "That password is too long." };
|
|
623
727
|
return null;
|
|
624
728
|
}
|
|
625
|
-
function checkNewPassword(value) {
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
}
|
|
631
|
-
return null;
|
|
729
|
+
function checkNewPassword(value, policy) {
|
|
730
|
+
if (typeof value !== "string" || value === "") return { field: "password", code: "required", message: "Enter your password." };
|
|
731
|
+
const p = policy ? passwordPolicyOf(policy) : DEFAULT_PASSWORD_POLICY;
|
|
732
|
+
const reasons = passwordProblems(value, p);
|
|
733
|
+
if (reasons.length === 0) return null;
|
|
734
|
+
return { field: "password", code: reasons[0], message: explainPasswordProblems(reasons, p) };
|
|
632
735
|
}
|
|
633
736
|
function checkName(value) {
|
|
634
737
|
if (value === void 0 || value === null || value === "") return null;
|
|
@@ -743,6 +846,13 @@ function providerIn(segment) {
|
|
|
743
846
|
function env2(name) {
|
|
744
847
|
return typeof process !== "undefined" ? process.env?.[name] : void 0;
|
|
745
848
|
}
|
|
849
|
+
function hostOf(origin) {
|
|
850
|
+
try {
|
|
851
|
+
return new URL(origin).hostname;
|
|
852
|
+
} catch {
|
|
853
|
+
return void 0;
|
|
854
|
+
}
|
|
855
|
+
}
|
|
746
856
|
function b64url(bytes) {
|
|
747
857
|
let s = "";
|
|
748
858
|
for (const b of bytes) s += String.fromCharCode(b);
|
|
@@ -776,6 +886,10 @@ function createCauthy(given = {}) {
|
|
|
776
886
|
if (!/^https?:\/\//.test(issuer)) throw new CauthyConfigError("issuer (CAUTHY_ISSUER) must be Cauthy's address, e.g. https://id.example.com");
|
|
777
887
|
if (clientId === "") throw new CauthyConfigError("clientId (CAUTHY_CLIENT_ID) is required");
|
|
778
888
|
if (secret.length < 32) throw new CauthyConfigError("secret (CAUTHY_SECRET) must be at least 32 characters: it encrypts the session cookie");
|
|
889
|
+
const baseURL = given.baseURL ?? env2("CAUTHY_BASE_URL");
|
|
890
|
+
if (baseURL !== void 0 && baseURL !== "" && !/^https?:\/\/[^/]+\/*$/.test(baseURL)) {
|
|
891
|
+
throw new CauthyConfigError("baseURL (CAUTHY_BASE_URL) must be the application's public origin, e.g. https://app.example.com");
|
|
892
|
+
}
|
|
779
893
|
const basePath = "/" + (given.basePath ?? "/api/auth").replace(/^\/+|\/+$/g, "");
|
|
780
894
|
const afterSignIn = localPath(given.afterSignIn, "/");
|
|
781
895
|
const afterSignOut = localPath(given.afterSignOut, "/");
|
|
@@ -791,7 +905,12 @@ function createCauthy(given = {}) {
|
|
|
791
905
|
verifyEmail: given.pages?.verifyEmail ? localPath(given.pages.verifyEmail, "/") : void 0
|
|
792
906
|
};
|
|
793
907
|
const ownSystem = createSystem({ issuer, clientId, clientSecret, key: given.systemKey, fetch: given.fetch });
|
|
794
|
-
const originOf = (request) =>
|
|
908
|
+
const originOf = (request) => {
|
|
909
|
+
if (baseURL) return withoutTrailingSlashes(baseURL);
|
|
910
|
+
const url = new URL(request.url);
|
|
911
|
+
const proto = request.headers.get("x-forwarded-proto")?.split(",")[0]?.trim().toLowerCase();
|
|
912
|
+
return proto === "https" || proto === "http" ? `${proto}://${url.host}` : url.origin;
|
|
913
|
+
};
|
|
795
914
|
const attrs = (request, maxAge) => ({ secure: originOf(request).startsWith("https://"), maxAge });
|
|
796
915
|
async function token(form) {
|
|
797
916
|
const body2 = new URLSearchParams({ client_id: clientId, ...form });
|
|
@@ -1087,11 +1206,20 @@ function createCauthy(given = {}) {
|
|
|
1087
1206
|
connectedAt: String(d?.created_at ?? ""),
|
|
1088
1207
|
lastUsedAt: String(d?.last_used_at ?? "")
|
|
1089
1208
|
});
|
|
1090
|
-
const problem = (status2, code, message, field, headers) => json({ error: { code, message, ...field ? { field } : {} } }, status2, headers);
|
|
1209
|
+
const problem = (status2, code, message, field, headers, reasons) => json({ error: { code, message, ...field ? { field } : {}, ...reasons && reasons.length > 0 ? { reasons } : {} } }, status2, headers);
|
|
1091
1210
|
const invalid = (p) => problem(400, p.code, p.message, p.field);
|
|
1211
|
+
let explained = false;
|
|
1092
1212
|
function ownRequest(request) {
|
|
1093
1213
|
const origin = request.headers.get("origin");
|
|
1094
|
-
if (origin !== null)
|
|
1214
|
+
if (origin !== null) {
|
|
1215
|
+
const own = originOf(request);
|
|
1216
|
+
if (origin === own || origin === new URL(request.url).origin) return true;
|
|
1217
|
+
if (!explained && hostOf(origin) === new URL(own).hostname) {
|
|
1218
|
+
explained = true;
|
|
1219
|
+
console.warn(`cauthy-auth: refused a request from ${origin} as cross_site: this application sees itself as ${own}. Behind a proxy? Set CAUTHY_BASE_URL (or baseURL) to the public origin.`);
|
|
1220
|
+
}
|
|
1221
|
+
return false;
|
|
1222
|
+
}
|
|
1095
1223
|
return (request.headers.get("sec-fetch-site") ?? "same-origin") === "same-origin";
|
|
1096
1224
|
}
|
|
1097
1225
|
async function body(request) {
|
|
@@ -1145,7 +1273,8 @@ function createCauthy(given = {}) {
|
|
|
1145
1273
|
const b = res.status === 204 || res.status === 202 ? null : await res.json().catch(() => null);
|
|
1146
1274
|
if (res.ok) return { status: res.status, data: b?.data ?? b };
|
|
1147
1275
|
const first = b?.errors?.[0];
|
|
1148
|
-
|
|
1276
|
+
const reasons = Array.isArray(first?.meta?.reasons) ? first.meta.reasons.map(String) : void 0;
|
|
1277
|
+
return { status: res.status, data: null, error: { code: String(first?.code ?? "error"), message: String(first?.message ?? "The request could not be completed."), ...reasons ? { reasons } : {} } };
|
|
1149
1278
|
} catch {
|
|
1150
1279
|
return { status: 503, data: null, error: { code: "unavailable", message: "Sign-in is unavailable right now. Try again in a moment." } };
|
|
1151
1280
|
}
|
|
@@ -1173,6 +1302,19 @@ function createCauthy(given = {}) {
|
|
|
1173
1302
|
return json({ status: "signed_in", session: await toPublic(toSession(s)), ...more }, 200, h);
|
|
1174
1303
|
}
|
|
1175
1304
|
let lookCache = null;
|
|
1305
|
+
let policyCache = null;
|
|
1306
|
+
const keepPolicy = (settings) => {
|
|
1307
|
+
policyCache = { until: Date.now() + LOOK_TTL_MS, policy: settings.error || !settings.data?.password_policy ? null : passwordPolicyOf(settings.data.password_policy) };
|
|
1308
|
+
return policyCache.policy;
|
|
1309
|
+
};
|
|
1310
|
+
async function workspacePolicy(request) {
|
|
1311
|
+
if (policyCache !== null && policyCache.until >= Date.now()) return policyCache.policy;
|
|
1312
|
+
return keepPolicy(await ask(request, "GET", "/v1/auth/settings"));
|
|
1313
|
+
}
|
|
1314
|
+
async function newPasswordProblem(request, value) {
|
|
1315
|
+
const policy = await workspacePolicy(request);
|
|
1316
|
+
return checkNewPassword(value, policy ?? { min: 8, max: 128, requires: [], min_classes: 0, reject_breached: false });
|
|
1317
|
+
}
|
|
1176
1318
|
async function ownRoute(request, url, route) {
|
|
1177
1319
|
const post = request.method === "POST";
|
|
1178
1320
|
const own = [
|
|
@@ -1250,6 +1392,7 @@ function createCauthy(given = {}) {
|
|
|
1250
1392
|
ask(request, "GET", "/v1/auth/sso/connections")
|
|
1251
1393
|
]);
|
|
1252
1394
|
const list = Array.isArray(providers.data) ? providers.data : [];
|
|
1395
|
+
const password = keepPolicy(settings);
|
|
1253
1396
|
const here = place.data?.here === true;
|
|
1254
1397
|
return json({
|
|
1255
1398
|
providers: list.map((p) => ({ id: String(p.provider ?? p.id ?? ""), name: String(p.label ?? p.name ?? p.provider ?? "") })).filter((p) => p.id !== ""),
|
|
@@ -1265,7 +1408,9 @@ function createCauthy(given = {}) {
|
|
|
1265
1408
|
sso: Array.isArray(sso.data) && sso.data.some((c) => c?.discoverable === true),
|
|
1266
1409
|
// The terms a sign-up accepts and the consents it answers, when the workspace asks any.
|
|
1267
1410
|
...settings.data?.legal ? { legal: legalOf(settings.data.legal) } : {},
|
|
1268
|
-
...settings.data?.captcha_enabled === true && settings.data?.captcha_site_key ? { captchaSiteKey: String(settings.data.captcha_site_key) } : {}
|
|
1411
|
+
...settings.data?.captcha_enabled === true && settings.data?.captcha_site_key ? { captchaSiteKey: String(settings.data.captcha_site_key) } : {},
|
|
1412
|
+
// What a new password must be: for the form to say it and check it.
|
|
1413
|
+
...password ? { password } : {}
|
|
1269
1414
|
});
|
|
1270
1415
|
}
|
|
1271
1416
|
if (route === "/sign-in/sso" && !post) {
|
|
@@ -1555,13 +1700,13 @@ function createCauthy(given = {}) {
|
|
|
1555
1700
|
return json({ status: "sent", sentTo: String(res.data?.sent_to ?? ""), channel: String(res.data?.channel ?? "sms") });
|
|
1556
1701
|
}
|
|
1557
1702
|
if (route === "/sign-up/email") {
|
|
1558
|
-
const bad = firstProblem(checkName(b.name), checkEmail(b.email),
|
|
1703
|
+
const bad = firstProblem(checkName(b.name), checkEmail(b.email), await newPasswordProblem(request, b.password), checkOrganization(b.organization));
|
|
1559
1704
|
if (bad) return invalid(bad);
|
|
1560
1705
|
const email = String(b.email).trim();
|
|
1561
1706
|
const organization = typeof b.organization === "string" && b.organization.trim() !== "" ? { organization: { name: b.organization.trim() } } : {};
|
|
1562
1707
|
const legal = { ...b.acceptLegal === true ? { accept_legal: true } : {}, ...b.consents && typeof b.consents === "object" ? { consents: b.consents } : {} };
|
|
1563
1708
|
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);
|
|
1564
|
-
if (made.error) return problem(made.status, made.error.code, made.error.message);
|
|
1709
|
+
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);
|
|
1565
1710
|
if (made.data?.verification_required === true) return json({ status: "verification_required", email });
|
|
1566
1711
|
const res = await ask(request, "POST", "/v1/auth/login", { email, password: b.password });
|
|
1567
1712
|
if (res.error || res.data?.mfa_required === true) return json({ status: "verification_required", email });
|
|
@@ -1577,7 +1722,7 @@ function createCauthy(given = {}) {
|
|
|
1577
1722
|
const mine = await signedInAs(request);
|
|
1578
1723
|
if ("response" in mine) return mine.response;
|
|
1579
1724
|
const as = (path, payload, method = "POST") => ask(request, method, path, payload, void 0, mine.token);
|
|
1580
|
-
const refused = (res, field) => problem(res.status, res.error.code, res.error.message, field, mine.headers);
|
|
1725
|
+
const refused = (res, field) => problem(res.status, res.error.code, res.error.message, field, mine.headers, res.error.reasons);
|
|
1581
1726
|
const password = typeof b.password === "string" ? b.password : "";
|
|
1582
1727
|
if (route === "/me") {
|
|
1583
1728
|
const bad = checkName(b.name);
|
|
@@ -1598,7 +1743,7 @@ function createCauthy(given = {}) {
|
|
|
1598
1743
|
return json({ status: "accepted" }, 200, mine.headers);
|
|
1599
1744
|
}
|
|
1600
1745
|
if (route === "/me/password") {
|
|
1601
|
-
const bad =
|
|
1746
|
+
const bad = await newPasswordProblem(request, b.newPassword);
|
|
1602
1747
|
if (bad) return problem(400, bad.code, bad.message, "newPassword");
|
|
1603
1748
|
const res = await as("/v1/auth/me/password", { current_password: password, new_password: b.newPassword });
|
|
1604
1749
|
if (res.error) return refused(res, res.error.code === "wrong_password" ? "password" : res.error.code === "weak_password" ? "newPassword" : void 0);
|
|
@@ -1691,7 +1836,7 @@ function createCauthy(given = {}) {
|
|
|
1691
1836
|
return json({ status: "removed", id }, 200, mine.headers);
|
|
1692
1837
|
}
|
|
1693
1838
|
if (route === "/me/upgrade") {
|
|
1694
|
-
const bad = firstProblem(checkName(b.name), checkEmail(b.email),
|
|
1839
|
+
const bad = firstProblem(checkName(b.name), checkEmail(b.email), await newPasswordProblem(request, b.password));
|
|
1695
1840
|
if (bad) return invalid(bad);
|
|
1696
1841
|
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() : "" });
|
|
1697
1842
|
if (res.error) return refused(res, res.error.code === "weak_password" ? "password" : "email");
|
|
@@ -1758,10 +1903,10 @@ function createCauthy(given = {}) {
|
|
|
1758
1903
|
const badLink = () => problem(422, "invalid_token", "This link is not valid, or it has expired.");
|
|
1759
1904
|
if (route === "/reset-password") {
|
|
1760
1905
|
if (!isToken(b.token)) return badLink();
|
|
1761
|
-
const bad =
|
|
1906
|
+
const bad = await newPasswordProblem(request, b.password);
|
|
1762
1907
|
if (bad) return invalid(bad);
|
|
1763
1908
|
const res = await ask(request, "POST", "/v1/auth/password/change", { token: String(b.token), new_password: b.password });
|
|
1764
|
-
if (res.error) return problem(res.status, res.error.code, res.error.message, res.error.code === "weak_password" ? "password" : void 0);
|
|
1909
|
+
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);
|
|
1765
1910
|
return json({ status: "changed" });
|
|
1766
1911
|
}
|
|
1767
1912
|
if (route === "/verify-email") {
|
|
@@ -2134,6 +2279,7 @@ export {
|
|
|
2134
2279
|
CauthyConfigError,
|
|
2135
2280
|
CauthyTokenError,
|
|
2136
2281
|
CauthyWebhookError,
|
|
2282
|
+
DEFAULT_PASSWORD_POLICY,
|
|
2137
2283
|
MIN_PASSWORD,
|
|
2138
2284
|
can,
|
|
2139
2285
|
checkCode,
|
|
@@ -2145,6 +2291,10 @@ export {
|
|
|
2145
2291
|
createCauthy,
|
|
2146
2292
|
createSystem,
|
|
2147
2293
|
definePolicy,
|
|
2294
|
+
describePasswordPolicy,
|
|
2295
|
+
explainPasswordProblems,
|
|
2296
|
+
passwordPolicyOf,
|
|
2297
|
+
passwordProblems,
|
|
2148
2298
|
policySource,
|
|
2149
2299
|
pullPolicy,
|
|
2150
2300
|
pushPolicy,
|