cauthy-auth 0.11.0 → 0.13.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/README.md +3 -2
- package/dist/cli.js +299 -20
- package/dist/client.d.mts +94 -1
- package/dist/client.d.ts +94 -1
- package/dist/client.js +107 -9
- package/dist/client.js.map +1 -1
- package/dist/client.mjs +106 -9
- package/dist/client.mjs.map +1 -1
- package/dist/index.js +67 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +67 -1
- package/dist/index.mjs.map +1 -1
- package/dist/react.d.mts +123 -1
- package/dist/react.d.ts +123 -1
- package/dist/react.js +358 -17
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +356 -17
- package/dist/react.mjs.map +1 -1
- package/dist/styles.css +5 -0
- package/dist/svelte.js +105 -9
- package/dist/svelte.js.map +1 -1
- package/dist/svelte.mjs +105 -9
- package/dist/svelte.mjs.map +1 -1
- package/dist/vue.js +105 -9
- package/dist/vue.js.map +1 -1
- package/dist/vue.mjs +105 -9
- package/dist/vue.mjs.map +1 -1
- package/package.json +1 -1
package/dist/styles.css
CHANGED
package/dist/svelte.js
CHANGED
|
@@ -30,6 +30,15 @@ module.exports = __toCommonJS(svelte_exports);
|
|
|
30
30
|
function canUsePasskeys() {
|
|
31
31
|
return typeof window !== "undefined" && typeof window.PublicKeyCredential === "function" && typeof navigator !== "undefined" && typeof navigator.credentials?.get === "function";
|
|
32
32
|
}
|
|
33
|
+
async function canAutofillPasskeys() {
|
|
34
|
+
if (!canUsePasskeys()) return false;
|
|
35
|
+
const pkc = window.PublicKeyCredential;
|
|
36
|
+
try {
|
|
37
|
+
return typeof pkc.isConditionalMediationAvailable === "function" && await pkc.isConditionalMediationAvailable() === true;
|
|
38
|
+
} catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
33
42
|
function bytes(text2) {
|
|
34
43
|
const b64 = text2.replace(/-/g, "+").replace(/_/g, "/").padEnd(Math.ceil(text2.length / 4) * 4, "=");
|
|
35
44
|
const bin = atob(b64);
|
|
@@ -45,9 +54,9 @@ function text(buf) {
|
|
|
45
54
|
return btoa(bin).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
46
55
|
}
|
|
47
56
|
var withId = (list) => (list ?? []).map((c) => ({ ...c, id: bytes(c.id) }));
|
|
48
|
-
async function getPasskey(options) {
|
|
57
|
+
async function getPasskey(options, how = {}) {
|
|
49
58
|
const publicKey = { ...options, challenge: bytes(options.challenge), allowCredentials: withId(options.allowCredentials) };
|
|
50
|
-
const cred = await navigator.credentials.get({ publicKey });
|
|
59
|
+
const cred = await navigator.credentials.get({ publicKey, ...how });
|
|
51
60
|
if (cred === null) throw new DOMException("No passkey was chosen.", "NotAllowedError");
|
|
52
61
|
const r = cred.response;
|
|
53
62
|
return {
|
|
@@ -167,6 +176,24 @@ function firstProblem(...checks) {
|
|
|
167
176
|
}
|
|
168
177
|
|
|
169
178
|
// src/client.ts
|
|
179
|
+
var googleScript = null;
|
|
180
|
+
function loadGoogleIdentity() {
|
|
181
|
+
const ready = () => window.google?.accounts?.id;
|
|
182
|
+
if (ready()) return Promise.resolve(ready());
|
|
183
|
+
googleScript ??= new Promise((resolve, reject) => {
|
|
184
|
+
const script = document.createElement("script");
|
|
185
|
+
script.src = "https://accounts.google.com/gsi/client";
|
|
186
|
+
script.async = true;
|
|
187
|
+
script.onload = () => ready() ? resolve(ready()) : reject(new Error("google identity services did not load"));
|
|
188
|
+
script.onerror = () => {
|
|
189
|
+
googleScript = null;
|
|
190
|
+
reject(new Error("google identity services did not load"));
|
|
191
|
+
};
|
|
192
|
+
document.head.appendChild(script);
|
|
193
|
+
});
|
|
194
|
+
return googleScript;
|
|
195
|
+
}
|
|
196
|
+
var PASSKEY_SECONDS = 300;
|
|
170
197
|
var UNAVAILABLE = { code: "unavailable", message: "Sign-in is unavailable right now. Try again in a moment." };
|
|
171
198
|
function createAuthClient(options = {}) {
|
|
172
199
|
const base = (options.basePath ?? "/api/auth").replace(/\/+$/, "");
|
|
@@ -175,13 +202,13 @@ function createAuthClient(options = {}) {
|
|
|
175
202
|
const said = typeof options.locale === "function" ? options.locale() : options.locale;
|
|
176
203
|
return (said ?? (typeof document === "undefined" ? "" : document.documentElement?.lang) ?? "").trim();
|
|
177
204
|
};
|
|
178
|
-
async function post(path, form, bad) {
|
|
205
|
+
async function post(path, form, bad, captchaToken) {
|
|
179
206
|
if (bad) return { ok: false, error: { code: bad.code, message: bad.message, field: bad.field } };
|
|
180
207
|
try {
|
|
181
208
|
const res = await doFetch(`${base}${path}`, {
|
|
182
209
|
method: "POST",
|
|
183
210
|
credentials: "same-origin",
|
|
184
|
-
headers: { "content-type": "application/json", accept: "application/json", ...locale() ? { "x-cauthy-locale": locale() } : {} },
|
|
211
|
+
headers: { "content-type": "application/json", accept: "application/json", ...locale() ? { "x-cauthy-locale": locale() } : {}, ...captchaToken ? { "x-cauthy-captcha": captchaToken } : {} },
|
|
185
212
|
body: JSON.stringify(form)
|
|
186
213
|
});
|
|
187
214
|
const body = await res.json().catch(() => null);
|
|
@@ -233,9 +260,11 @@ function createAuthClient(options = {}) {
|
|
|
233
260
|
}
|
|
234
261
|
return {
|
|
235
262
|
signIn: {
|
|
236
|
-
email: (f) => post("/sign-in/email", { email: f.email, password: f.password }, firstProblem(checkEmail(f.email), checkPassword(f.password))),
|
|
263
|
+
email: (f) => post("/sign-in/email", { email: f.email, password: f.password }, firstProblem(checkEmail(f.email), checkPassword(f.password)), f.captchaToken),
|
|
237
264
|
mfa: (f) => post("/sign-in/mfa", { code: f.code }, checkCode(f.code)),
|
|
238
|
-
|
|
265
|
+
mfaMethods: () => post("/sign-in/mfa/methods", {}, null),
|
|
266
|
+
mfaSendCode: () => post("/sign-in/mfa/send", {}, null),
|
|
267
|
+
magicLink: (f) => post("/sign-in/magic-link", { email: f.email }, checkEmail(f.email), f.captchaToken),
|
|
239
268
|
magicLinkVerify: (f) => post("/sign-in/magic-link/verify", { token: f.token }, null),
|
|
240
269
|
emailCode: (f) => post("/sign-in/email-code", { code: f.code }, checkCode(f.code)),
|
|
241
270
|
passkeyUrl,
|
|
@@ -250,15 +279,75 @@ function createAuthClient(options = {}) {
|
|
|
250
279
|
window.location.assign(passkeyUrl(o));
|
|
251
280
|
return { ok: true, status: "redirected" };
|
|
252
281
|
},
|
|
282
|
+
async passkeyAutofill(o = {}) {
|
|
283
|
+
const cancelled = { ok: false, error: { code: "cancelled", message: "No passkey was chosen." } };
|
|
284
|
+
const m = await methods();
|
|
285
|
+
if (!m.passkeyHere || !await canAutofillPasskeys()) return cancelled;
|
|
286
|
+
for (; ; ) {
|
|
287
|
+
if (o.signal?.aborted) return cancelled;
|
|
288
|
+
const begun = await post("/sign-in/passkey/begin", {}, null);
|
|
289
|
+
if (!begun.ok) return begun;
|
|
290
|
+
const renew = new AbortController();
|
|
291
|
+
const stop = () => renew.abort();
|
|
292
|
+
o.signal?.addEventListener("abort", stop, { once: true });
|
|
293
|
+
const timer = setTimeout(stop, (PASSKEY_SECONDS - 30) * 1e3);
|
|
294
|
+
let credential;
|
|
295
|
+
try {
|
|
296
|
+
credential = await getPasskey(begun.options, { mediation: "conditional", signal: renew.signal });
|
|
297
|
+
} catch (e) {
|
|
298
|
+
if (o.signal?.aborted) return cancelled;
|
|
299
|
+
if (renew.signal.aborted) continue;
|
|
300
|
+
return { ok: false, error: ceremonyError(e) };
|
|
301
|
+
} finally {
|
|
302
|
+
clearTimeout(timer);
|
|
303
|
+
o.signal?.removeEventListener("abort", stop);
|
|
304
|
+
}
|
|
305
|
+
return post("/sign-in/passkey/finish", { credential }, null);
|
|
306
|
+
}
|
|
307
|
+
},
|
|
308
|
+
async googleOneTap(o = {}) {
|
|
309
|
+
const cancelled = { ok: false, error: { code: "cancelled", message: "No Google account was chosen." } };
|
|
310
|
+
if (typeof window === "undefined" || o.signal?.aborted) return cancelled;
|
|
311
|
+
const begun = await post("/sign-in/google-one-tap/begin", {}, null);
|
|
312
|
+
if (!begun.ok) return begun;
|
|
313
|
+
let gis;
|
|
314
|
+
try {
|
|
315
|
+
gis = await loadGoogleIdentity();
|
|
316
|
+
} catch {
|
|
317
|
+
return { ok: false, error: { code: "unavailable", message: "Google could not be reached. Try again, or sign in another way." } };
|
|
318
|
+
}
|
|
319
|
+
const credential = await new Promise((done) => {
|
|
320
|
+
o.signal?.addEventListener("abort", () => {
|
|
321
|
+
gis.cancel();
|
|
322
|
+
done(null);
|
|
323
|
+
}, { once: true });
|
|
324
|
+
gis.initialize({
|
|
325
|
+
client_id: begun.clientId,
|
|
326
|
+
nonce: begun.nonce,
|
|
327
|
+
context: o.context ?? "signin",
|
|
328
|
+
callback: (r) => done(r.credential ?? null),
|
|
329
|
+
auto_select: false,
|
|
330
|
+
cancel_on_tap_outside: true,
|
|
331
|
+
itp_support: true,
|
|
332
|
+
use_fedcm_for_prompt: true
|
|
333
|
+
});
|
|
334
|
+
gis.prompt((moment) => {
|
|
335
|
+
if (moment.isNotDisplayed?.() || moment.isSkippedMoment?.()) done(null);
|
|
336
|
+
else if (moment.isDismissedMoment?.() && moment.getDismissedReason?.() !== "credential_returned") done(null);
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
if (credential === null) return cancelled;
|
|
340
|
+
return post("/sign-in/google-one-tap", { credential }, null);
|
|
341
|
+
},
|
|
253
342
|
socialUrl,
|
|
254
343
|
social(provider, o) {
|
|
255
344
|
window.location.assign(socialUrl(provider, o));
|
|
256
345
|
}
|
|
257
346
|
},
|
|
258
347
|
signUp: {
|
|
259
|
-
email: (f) => post("/sign-up/email", { email: f.email, password: f.password, name: f.name }, firstProblem(checkName(f.name), checkEmail(f.email), checkNewPassword(f.password)))
|
|
348
|
+
email: (f) => post("/sign-up/email", { email: f.email, password: f.password, name: f.name }, firstProblem(checkName(f.name), checkEmail(f.email), checkNewPassword(f.password)), f.captchaToken)
|
|
260
349
|
},
|
|
261
|
-
forgotPassword: (f) => post("/forgot-password", { email: f.email }, checkEmail(f.email)),
|
|
350
|
+
forgotPassword: (f) => post("/forgot-password", { email: f.email }, checkEmail(f.email), f.captchaToken),
|
|
262
351
|
resetPassword: (f) => post("/reset-password", { token: f.token, password: f.password }, checkNewPassword(f.password)),
|
|
263
352
|
verifyEmail: (f) => post("/verify-email", { token: f.token }, null),
|
|
264
353
|
signOut: () => post("/sign-out", {}, null),
|
|
@@ -276,7 +365,14 @@ function createAuthClient(options = {}) {
|
|
|
276
365
|
setup: (f) => post("/me/mfa/setup", { password: f.password }, null),
|
|
277
366
|
verify: (f) => post("/me/mfa/verify", { code: f.code }, checkCode(f.code)),
|
|
278
367
|
disable: (f) => post("/me/mfa/disable", { password: f.password }, null),
|
|
279
|
-
recoveryCodes: (f) => post("/me/mfa/recovery-codes", { password: f.password }, null)
|
|
368
|
+
recoveryCodes: (f) => post("/me/mfa/recovery-codes", { password: f.password }, null),
|
|
369
|
+
async factors() {
|
|
370
|
+
const body = await read("/me/mfa/factors");
|
|
371
|
+
return body && typeof body.totp === "boolean" ? body : null;
|
|
372
|
+
},
|
|
373
|
+
addPhone: (f) => post("/me/mfa/phone", { phone: f.phone, channel: f.channel, password: f.password }, null),
|
|
374
|
+
verifyPhone: (f) => post("/me/mfa/phone/verify", { code: f.code }, checkCode(f.code)),
|
|
375
|
+
removePhone: (f) => post("/me/mfa/phone/remove", { password: f.password }, null)
|
|
280
376
|
},
|
|
281
377
|
changeEmail: (f) => post("/me/email", { email: f.email, password: f.password }, checkEmail(f.email)),
|
|
282
378
|
async identities() {
|