cauthy-auth 0.27.1 → 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/client.d.mts +12 -3
- package/dist/client.d.ts +12 -3
- 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/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +147 -17
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +142 -17
- package/dist/index.mjs.map +1 -1
- 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 +1 -1
- package/dist/svelte.d.ts +1 -1
- 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/validate-sEXG82po.d.mts +66 -0
- package/dist/validate-sEXG82po.d.ts +66 -0
- package/dist/vue.d.mts +1 -1
- package/dist/vue.d.ts +1 -1
- 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/styles.css
CHANGED
|
@@ -122,6 +122,12 @@
|
|
|
122
122
|
color: var(--cauthy-error);
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
/* What a new password must be, under its field. */
|
|
126
|
+
:where([data-cauthy] .cauthy-hint) {
|
|
127
|
+
font-size: 12px;
|
|
128
|
+
color: var(--cauthy-text-muted);
|
|
129
|
+
}
|
|
130
|
+
|
|
125
131
|
/* ── Buttons ─────────────────────────────────────────────────────────────── */
|
|
126
132
|
|
|
127
133
|
:where([data-cauthy] .cauthy-button),
|
package/dist/svelte.d.mts
CHANGED
|
@@ -3,7 +3,7 @@ export { Account, AccountSession, AuthClient, AuthError, AuthMethods, AuthResult
|
|
|
3
3
|
import { i as PublicSession } from './system-BxMsSIu1.mjs';
|
|
4
4
|
export { P as PermissionOf, f as Policy, R as RoleOf, k as SessionOrganization, m as SessionUser, p as can, r as definePolicy } from './system-BxMsSIu1.mjs';
|
|
5
5
|
import './theme.mjs';
|
|
6
|
-
import './validate-
|
|
6
|
+
import './validate-sEXG82po.mjs';
|
|
7
7
|
import 'jose';
|
|
8
8
|
|
|
9
9
|
/** A value Svelte can read with `$`: its store contract. */
|
package/dist/svelte.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export { Account, AccountSession, AuthClient, AuthError, AuthMethods, AuthResult
|
|
|
3
3
|
import { i as PublicSession } from './system-DTIeDXDP.js';
|
|
4
4
|
export { P as PermissionOf, f as Policy, R as RoleOf, k as SessionOrganization, m as SessionUser, p as can, r as definePolicy } from './system-DTIeDXDP.js';
|
|
5
5
|
import './theme.js';
|
|
6
|
-
import './validate-
|
|
6
|
+
import './validate-sEXG82po.js';
|
|
7
7
|
import 'jose';
|
|
8
8
|
|
|
9
9
|
/** A value Svelte can read with `$`: its store contract. */
|
package/dist/svelte.js
CHANGED
|
@@ -146,7 +146,111 @@ function fromWire(wire) {
|
|
|
146
146
|
// src/validate.ts
|
|
147
147
|
var MIN_PASSWORD = 12;
|
|
148
148
|
var MAX_PASSWORD = 128;
|
|
149
|
+
var FLOOR_PASSWORD = 8;
|
|
149
150
|
var MAX_NAME = 120;
|
|
151
|
+
var CLASSES = ["lowercase", "uppercase", "digit", "symbol"];
|
|
152
|
+
var DEFAULT_PASSWORD_POLICY = Object.freeze({ min: MIN_PASSWORD, max: MAX_PASSWORD, requires: [], min_classes: 0, reject_breached: false });
|
|
153
|
+
var int = (v, fallback) => typeof v === "number" && Number.isFinite(v) ? Math.trunc(v) : fallback;
|
|
154
|
+
function passwordPolicyOf(raw) {
|
|
155
|
+
const r = raw && typeof raw === "object" ? raw : {};
|
|
156
|
+
const min = Math.min(Math.max(int(r.min ?? r.min_length, MIN_PASSWORD) || MIN_PASSWORD, FLOOR_PASSWORD), MAX_PASSWORD);
|
|
157
|
+
const max = Math.max(Math.min(int(r.max ?? r.max_length, MAX_PASSWORD) || MAX_PASSWORD, MAX_PASSWORD), min);
|
|
158
|
+
const asked = Array.isArray(r.requires) ? r.requires : [];
|
|
159
|
+
return {
|
|
160
|
+
min,
|
|
161
|
+
max,
|
|
162
|
+
requires: CLASSES.filter((c) => asked.includes(c)),
|
|
163
|
+
min_classes: Math.min(Math.max(int(r.min_classes ?? r.minClasses, 0), 0), CLASSES.length),
|
|
164
|
+
reject_breached: (r.reject_breached ?? r.rejectBreached) === true
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
function utf8Length(v) {
|
|
168
|
+
let n = 0;
|
|
169
|
+
for (const ch of v) {
|
|
170
|
+
const c = ch.codePointAt(0);
|
|
171
|
+
n += c < 128 ? 1 : c < 2048 ? 2 : c < 65536 ? 3 : 4;
|
|
172
|
+
}
|
|
173
|
+
return n;
|
|
174
|
+
}
|
|
175
|
+
function classesOf(v) {
|
|
176
|
+
const has = /* @__PURE__ */ new Set();
|
|
177
|
+
for (const ch of v) {
|
|
178
|
+
if (/\p{Ll}/u.test(ch)) has.add("lowercase");
|
|
179
|
+
else if (/\p{Lu}/u.test(ch)) has.add("uppercase");
|
|
180
|
+
else if (/\p{Nd}/u.test(ch)) has.add("digit");
|
|
181
|
+
else if (!/\p{L}/u.test(ch)) has.add("symbol");
|
|
182
|
+
}
|
|
183
|
+
return has;
|
|
184
|
+
}
|
|
185
|
+
function passwordProblems(value, policy = DEFAULT_PASSWORD_POLICY) {
|
|
186
|
+
const p = passwordPolicyOf(policy);
|
|
187
|
+
const out = [];
|
|
188
|
+
const length = utf8Length(value);
|
|
189
|
+
if (length < p.min) out.push("too_short");
|
|
190
|
+
if (length > p.max) out.push("too_long");
|
|
191
|
+
const has = classesOf(value);
|
|
192
|
+
for (const c of p.requires) if (!has.has(c)) out.push(`needs_${c}`);
|
|
193
|
+
if (p.min_classes > 0 && CLASSES.filter((c) => has.has(c)).length < p.min_classes) out.push("needs_classes");
|
|
194
|
+
return out;
|
|
195
|
+
}
|
|
196
|
+
var RULES = {
|
|
197
|
+
en: {
|
|
198
|
+
between: "Between {min} and {max} characters.",
|
|
199
|
+
requires: "Include {kinds}.",
|
|
200
|
+
and: "and",
|
|
201
|
+
classes: "Use at least {n} of these: lowercase letters, uppercase letters, digits, symbols.",
|
|
202
|
+
breached: "Passwords found in known data breaches are not accepted.",
|
|
203
|
+
kinds: { lowercase: "a lowercase letter", uppercase: "an uppercase letter", digit: "a digit", symbol: "a symbol" },
|
|
204
|
+
reasons: {
|
|
205
|
+
too_short: "Use at least {min} characters.",
|
|
206
|
+
too_long: "Use at most {max} characters.",
|
|
207
|
+
needs_lowercase: "Include a lowercase letter.",
|
|
208
|
+
needs_uppercase: "Include an uppercase letter.",
|
|
209
|
+
needs_digit: "Include a digit.",
|
|
210
|
+
needs_symbol: "Include a symbol.",
|
|
211
|
+
needs_classes: "Use at least {n} of these: lowercase letters, uppercase letters, digits, symbols.",
|
|
212
|
+
breached: "This password appears in a known data breach. Choose a different one."
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
es: {
|
|
216
|
+
between: "Entre {min} y {max} caracteres.",
|
|
217
|
+
requires: "Incluye {kinds}.",
|
|
218
|
+
and: "y",
|
|
219
|
+
classes: "Usa al menos {n} de estos tipos: min\xFAsculas, may\xFAsculas, n\xFAmeros, s\xEDmbolos.",
|
|
220
|
+
breached: "No se aceptan contrase\xF1as que aparecen en filtraciones de datos conocidas.",
|
|
221
|
+
kinds: { lowercase: "una min\xFAscula", uppercase: "una may\xFAscula", digit: "un n\xFAmero", symbol: "un s\xEDmbolo" },
|
|
222
|
+
reasons: {
|
|
223
|
+
too_short: "Usa al menos {min} caracteres.",
|
|
224
|
+
too_long: "Usa como m\xE1ximo {max} caracteres.",
|
|
225
|
+
needs_lowercase: "Incluye una min\xFAscula.",
|
|
226
|
+
needs_uppercase: "Incluye una may\xFAscula.",
|
|
227
|
+
needs_digit: "Incluye un n\xFAmero.",
|
|
228
|
+
needs_symbol: "Incluye un s\xEDmbolo.",
|
|
229
|
+
needs_classes: "Usa al menos {n} de estos tipos: min\xFAsculas, may\xFAsculas, n\xFAmeros, s\xEDmbolos.",
|
|
230
|
+
breached: "Esta contrase\xF1a aparece en una filtraci\xF3n de datos conocida. Elige otra."
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
var fill = (s, p) => s.replace("{min}", String(p.min)).replace("{max}", String(p.max)).replace("{n}", String(p.min_classes));
|
|
235
|
+
function describePasswordPolicy(policy = DEFAULT_PASSWORD_POLICY, locale = "en") {
|
|
236
|
+
const p = passwordPolicyOf(policy);
|
|
237
|
+
const t = RULES[locale] ?? RULES.en;
|
|
238
|
+
const parts = [fill(t.between, p)];
|
|
239
|
+
if (p.requires.length > 0) {
|
|
240
|
+
const kinds = p.requires.map((c) => t.kinds[c]);
|
|
241
|
+
const listed = kinds.length === 1 ? kinds[0] : `${kinds.slice(0, -1).join(", ")} ${t.and} ${kinds[kinds.length - 1]}`;
|
|
242
|
+
parts.push(t.requires.replace("{kinds}", listed));
|
|
243
|
+
}
|
|
244
|
+
if (p.min_classes > 0) parts.push(fill(t.classes, p));
|
|
245
|
+
if (p.reject_breached) parts.push(t.breached);
|
|
246
|
+
return parts.join(" ");
|
|
247
|
+
}
|
|
248
|
+
function explainPasswordProblems(reasons, policy = DEFAULT_PASSWORD_POLICY, locale = "en") {
|
|
249
|
+
const p = passwordPolicyOf(policy);
|
|
250
|
+
const t = RULES[locale] ?? RULES.en;
|
|
251
|
+
const said = reasons.filter((r) => r in t.reasons).map((r) => fill(t.reasons[r], p));
|
|
252
|
+
return said.length > 0 ? said.join(" ") : describePasswordPolicy(p, locale);
|
|
253
|
+
}
|
|
150
254
|
var EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
151
255
|
function checkEmail(value) {
|
|
152
256
|
const v = typeof value === "string" ? value.trim() : "";
|
|
@@ -159,13 +263,12 @@ function checkPassword(value) {
|
|
|
159
263
|
if (value.length > MAX_PASSWORD) return { field: "password", code: "too_long", message: "That password is too long." };
|
|
160
264
|
return null;
|
|
161
265
|
}
|
|
162
|
-
function checkNewPassword(value) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
168
|
-
return null;
|
|
266
|
+
function checkNewPassword(value, policy) {
|
|
267
|
+
if (typeof value !== "string" || value === "") return { field: "password", code: "required", message: "Enter your password." };
|
|
268
|
+
const p = policy ? passwordPolicyOf(policy) : DEFAULT_PASSWORD_POLICY;
|
|
269
|
+
const reasons = passwordProblems(value, p);
|
|
270
|
+
if (reasons.length === 0) return null;
|
|
271
|
+
return { field: "password", code: reasons[0], message: explainPasswordProblems(reasons, p) };
|
|
169
272
|
}
|
|
170
273
|
function checkName(value) {
|
|
171
274
|
if (value === void 0 || value === null || value === "") return null;
|
|
@@ -228,7 +331,7 @@ function createAuthClient(options = {}) {
|
|
|
228
331
|
const body = await res.json().catch(() => null);
|
|
229
332
|
if (res.ok && body && typeof body.status === "string") return { ok: true, ...body };
|
|
230
333
|
const e = body?.error;
|
|
231
|
-
return { ok: false, error: e && typeof e.code === "string" ? { code: e.code, message: String(e.message ?? ""), ...e.field ? { field: e.field } : {} } : UNAVAILABLE };
|
|
334
|
+
return { ok: false, error: e && typeof e.code === "string" ? { code: e.code, message: String(e.message ?? ""), ...e.field ? { field: e.field } : {}, ...Array.isArray(e.reasons) ? { reasons: e.reasons.map(String) } : {} } : UNAVAILABLE };
|
|
232
335
|
} catch {
|
|
233
336
|
return { ok: false, error: UNAVAILABLE };
|
|
234
337
|
}
|
|
@@ -256,12 +359,14 @@ function createAuthClient(options = {}) {
|
|
|
256
359
|
if (o.locale) q.set("locale", o.locale);
|
|
257
360
|
return `${base}/login?${q}`;
|
|
258
361
|
};
|
|
362
|
+
let policy;
|
|
259
363
|
async function methods() {
|
|
260
364
|
try {
|
|
261
365
|
const res = await doFetch(`${base}/methods`, { credentials: "same-origin", headers: { accept: "application/json" } });
|
|
262
366
|
if (res.ok) {
|
|
263
367
|
const m = await res.json();
|
|
264
|
-
|
|
368
|
+
if (m.password) policy = passwordPolicyOf(m.password);
|
|
369
|
+
return { providers: [], signUp: true, magicLink: false, passkey: false, ...m, ...policy ? { password: policy } : {}, passkeyHere: m.passkeyHere === true, passkeyOnCauthy: m.passkeyOnCauthy ?? m.passkey === true, sso: m.sso === true };
|
|
265
370
|
}
|
|
266
371
|
} catch {
|
|
267
372
|
}
|
|
@@ -405,12 +510,12 @@ function createAuthClient(options = {}) {
|
|
|
405
510
|
email: (f) => post(
|
|
406
511
|
"/sign-up/email",
|
|
407
512
|
{ email: f.email, password: f.password, name: f.name, organization: f.organization, acceptLegal: f.acceptLegal, consents: f.consents },
|
|
408
|
-
firstProblem(checkName(f.name), checkEmail(f.email), checkNewPassword(f.password), checkOrganization(f.organization)),
|
|
513
|
+
firstProblem(checkName(f.name), checkEmail(f.email), checkNewPassword(f.password, policy), checkOrganization(f.organization)),
|
|
409
514
|
f.captchaToken
|
|
410
515
|
)
|
|
411
516
|
},
|
|
412
517
|
forgotPassword: (f) => post("/forgot-password", { email: f.email }, checkEmail(f.email), f.captchaToken),
|
|
413
|
-
resetPassword: (f) => post("/reset-password", { token: f.token, password: f.password }, checkNewPassword(f.password)),
|
|
518
|
+
resetPassword: (f) => post("/reset-password", { token: f.token, password: f.password }, checkNewPassword(f.password, policy)),
|
|
414
519
|
verifyEmail: (f) => post("/verify-email", { token: f.token }, null),
|
|
415
520
|
signOut: () => post("/sign-out", {}, null),
|
|
416
521
|
organizations: {
|
|
@@ -444,7 +549,7 @@ function createAuthClient(options = {}) {
|
|
|
444
549
|
},
|
|
445
550
|
acceptLegal: (f = {}) => post("/me/legal/accept", { kinds: f.kinds ?? [] }, null),
|
|
446
551
|
changePassword: (f) => {
|
|
447
|
-
const bad = checkNewPassword(f.newPassword);
|
|
552
|
+
const bad = checkNewPassword(f.newPassword, policy);
|
|
448
553
|
return post("/me/password", { password: f.password, newPassword: f.newPassword }, bad ? { ...bad, field: "newPassword" } : null);
|
|
449
554
|
},
|
|
450
555
|
mfa: {
|
|
@@ -475,7 +580,7 @@ function createAuthClient(options = {}) {
|
|
|
475
580
|
return body && Array.isArray(body.sessions) ? body.sessions : [];
|
|
476
581
|
},
|
|
477
582
|
signOutEverywhere: () => post("/me/sessions/end", {}, null),
|
|
478
|
-
upgrade: (f) => post("/me/upgrade", { email: f.email, password: f.password, name: f.name ?? "" }, firstProblem(checkName(f.name), checkEmail(f.email), checkNewPassword(f.password))),
|
|
583
|
+
upgrade: (f) => post("/me/upgrade", { email: f.email, password: f.password, name: f.name ?? "" }, firstProblem(checkName(f.name), checkEmail(f.email), checkNewPassword(f.password, policy))),
|
|
479
584
|
upgradeUrl,
|
|
480
585
|
upgradeWith(provider, o) {
|
|
481
586
|
window.location.assign(upgradeUrl(provider, o));
|