cauthy-auth 0.9.0 → 0.11.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 +61 -5
- package/dist/client.d.ts +61 -5
- package/dist/client.js +118 -12
- package/dist/client.js.map +1 -1
- package/dist/client.mjs +117 -12
- package/dist/client.mjs.map +1 -1
- package/dist/index.js +121 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +121 -6
- package/dist/index.mjs.map +1 -1
- package/dist/react.d.mts +68 -5
- package/dist/react.d.ts +68 -5
- package/dist/react.js +203 -18
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +202 -18
- package/dist/react.mjs.map +1 -1
- package/dist/svelte.d.mts +1 -1
- package/dist/svelte.d.ts +1 -1
- package/dist/svelte.js +116 -12
- package/dist/svelte.js.map +1 -1
- package/dist/svelte.mjs +116 -12
- package/dist/svelte.mjs.map +1 -1
- package/dist/vue.d.mts +1 -1
- package/dist/vue.d.ts +1 -1
- package/dist/vue.js +116 -12
- package/dist/vue.js.map +1 -1
- package/dist/vue.mjs +116 -12
- package/dist/vue.mjs.map +1 -1
- package/package.json +1 -1
package/dist/vue.js
CHANGED
|
@@ -29,6 +29,73 @@ __export(vue_exports, {
|
|
|
29
29
|
module.exports = __toCommonJS(vue_exports);
|
|
30
30
|
var import_vue = require("vue");
|
|
31
31
|
|
|
32
|
+
// src/passkey.ts
|
|
33
|
+
function canUsePasskeys() {
|
|
34
|
+
return typeof window !== "undefined" && typeof window.PublicKeyCredential === "function" && typeof navigator !== "undefined" && typeof navigator.credentials?.get === "function";
|
|
35
|
+
}
|
|
36
|
+
function bytes(text2) {
|
|
37
|
+
const b64 = text2.replace(/-/g, "+").replace(/_/g, "/").padEnd(Math.ceil(text2.length / 4) * 4, "=");
|
|
38
|
+
const bin = atob(b64);
|
|
39
|
+
const out = new Uint8Array(bin.length);
|
|
40
|
+
for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
|
|
41
|
+
return out.buffer;
|
|
42
|
+
}
|
|
43
|
+
function text(buf) {
|
|
44
|
+
if (!buf) return null;
|
|
45
|
+
const view = new Uint8Array(buf);
|
|
46
|
+
let bin = "";
|
|
47
|
+
for (let i = 0; i < view.byteLength; i++) bin += String.fromCharCode(view[i]);
|
|
48
|
+
return btoa(bin).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
49
|
+
}
|
|
50
|
+
var withId = (list) => (list ?? []).map((c) => ({ ...c, id: bytes(c.id) }));
|
|
51
|
+
async function getPasskey(options) {
|
|
52
|
+
const publicKey = { ...options, challenge: bytes(options.challenge), allowCredentials: withId(options.allowCredentials) };
|
|
53
|
+
const cred = await navigator.credentials.get({ publicKey });
|
|
54
|
+
if (cred === null) throw new DOMException("No passkey was chosen.", "NotAllowedError");
|
|
55
|
+
const r = cred.response;
|
|
56
|
+
return {
|
|
57
|
+
id: cred.id,
|
|
58
|
+
rawId: text(cred.rawId),
|
|
59
|
+
type: cred.type,
|
|
60
|
+
response: {
|
|
61
|
+
authenticatorData: text(r.authenticatorData),
|
|
62
|
+
clientDataJSON: text(r.clientDataJSON),
|
|
63
|
+
signature: text(r.signature),
|
|
64
|
+
userHandle: text(r.userHandle)
|
|
65
|
+
},
|
|
66
|
+
clientExtensionResults: cred.getClientExtensionResults?.() ?? {}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
async function makePasskey(options) {
|
|
70
|
+
const publicKey = {
|
|
71
|
+
...options,
|
|
72
|
+
challenge: bytes(options.challenge),
|
|
73
|
+
user: { ...options.user, id: bytes(options.user.id) },
|
|
74
|
+
excludeCredentials: withId(options.excludeCredentials)
|
|
75
|
+
};
|
|
76
|
+
const cred = await navigator.credentials.create({ publicKey });
|
|
77
|
+
if (cred === null) throw new DOMException("No passkey was made.", "NotAllowedError");
|
|
78
|
+
const r = cred.response;
|
|
79
|
+
return {
|
|
80
|
+
id: cred.id,
|
|
81
|
+
rawId: text(cred.rawId),
|
|
82
|
+
type: cred.type,
|
|
83
|
+
response: {
|
|
84
|
+
clientDataJSON: text(r.clientDataJSON),
|
|
85
|
+
attestationObject: text(r.attestationObject),
|
|
86
|
+
transports: typeof r.getTransports === "function" ? r.getTransports() : []
|
|
87
|
+
},
|
|
88
|
+
clientExtensionResults: cred.getClientExtensionResults?.() ?? {}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function ceremonyError(e) {
|
|
92
|
+
const name = e instanceof Error || e instanceof DOMException ? e.name : "";
|
|
93
|
+
if (name === "NotAllowedError" || name === "AbortError") return { code: "cancelled", message: "The passkey was not used. Try again when you are ready." };
|
|
94
|
+
if (name === "InvalidStateError") return { code: "passkey_exists", message: "This device already has a passkey for this account." };
|
|
95
|
+
if (name === "SecurityError") return { code: "passkey_unavailable", message: "Passkeys cannot be used on this page." };
|
|
96
|
+
return { code: "passkey_failed", message: "The passkey could not be used. Try again, or sign in another way." };
|
|
97
|
+
}
|
|
98
|
+
|
|
32
99
|
// src/theme.ts
|
|
33
100
|
function fromWire(wire) {
|
|
34
101
|
const names = {
|
|
@@ -107,13 +174,17 @@ var UNAVAILABLE = { code: "unavailable", message: "Sign-in is unavailable right
|
|
|
107
174
|
function createAuthClient(options = {}) {
|
|
108
175
|
const base = (options.basePath ?? "/api/auth").replace(/\/+$/, "");
|
|
109
176
|
const doFetch = (...args) => (options.fetch ?? fetch)(...args);
|
|
177
|
+
const locale = () => {
|
|
178
|
+
const said = typeof options.locale === "function" ? options.locale() : options.locale;
|
|
179
|
+
return (said ?? (typeof document === "undefined" ? "" : document.documentElement?.lang) ?? "").trim();
|
|
180
|
+
};
|
|
110
181
|
async function post(path, form, bad) {
|
|
111
182
|
if (bad) return { ok: false, error: { code: bad.code, message: bad.message, field: bad.field } };
|
|
112
183
|
try {
|
|
113
184
|
const res = await doFetch(`${base}${path}`, {
|
|
114
185
|
method: "POST",
|
|
115
186
|
credentials: "same-origin",
|
|
116
|
-
headers: { "content-type": "application/json", accept: "application/json" },
|
|
187
|
+
headers: { "content-type": "application/json", accept: "application/json", ...locale() ? { "x-cauthy-locale": locale() } : {} },
|
|
117
188
|
body: JSON.stringify(form)
|
|
118
189
|
});
|
|
119
190
|
const body = await res.json().catch(() => null);
|
|
@@ -141,6 +212,28 @@ function createAuthClient(options = {}) {
|
|
|
141
212
|
if (o.locale) q.set("locale", o.locale);
|
|
142
213
|
return `${base}/login?${q}`;
|
|
143
214
|
};
|
|
215
|
+
async function methods() {
|
|
216
|
+
try {
|
|
217
|
+
const res = await doFetch(`${base}/methods`, { credentials: "same-origin", headers: { accept: "application/json" } });
|
|
218
|
+
if (res.ok) {
|
|
219
|
+
const m = await res.json();
|
|
220
|
+
return { providers: [], signUp: true, magicLink: false, passkey: false, ...m, passkeyHere: m.passkeyHere === true, passkeyOnCauthy: m.passkeyOnCauthy ?? m.passkey === true };
|
|
221
|
+
}
|
|
222
|
+
} catch {
|
|
223
|
+
}
|
|
224
|
+
return { providers: [], signUp: true, magicLink: false, passkey: false, passkeyHere: false, passkeyOnCauthy: false };
|
|
225
|
+
}
|
|
226
|
+
async function ceremony(begin, finish, form, run, more = {}) {
|
|
227
|
+
const begun = await post(begin, form, null);
|
|
228
|
+
if (!begun.ok) return begun;
|
|
229
|
+
let credential;
|
|
230
|
+
try {
|
|
231
|
+
credential = await run(begun.options);
|
|
232
|
+
} catch (e) {
|
|
233
|
+
return { ok: false, error: ceremonyError(e) };
|
|
234
|
+
}
|
|
235
|
+
return post(finish, { credential, ...more }, null);
|
|
236
|
+
}
|
|
144
237
|
return {
|
|
145
238
|
signIn: {
|
|
146
239
|
email: (f) => post("/sign-in/email", { email: f.email, password: f.password }, firstProblem(checkEmail(f.email), checkPassword(f.password))),
|
|
@@ -149,8 +242,16 @@ function createAuthClient(options = {}) {
|
|
|
149
242
|
magicLinkVerify: (f) => post("/sign-in/magic-link/verify", { token: f.token }, null),
|
|
150
243
|
emailCode: (f) => post("/sign-in/email-code", { code: f.code }, checkCode(f.code)),
|
|
151
244
|
passkeyUrl,
|
|
152
|
-
passkey(o) {
|
|
245
|
+
async passkey(o) {
|
|
246
|
+
const m = await methods();
|
|
247
|
+
if (m.passkeyHere && canUsePasskeys()) {
|
|
248
|
+
const r = await ceremony("/sign-in/passkey/begin", "/sign-in/passkey/finish", {}, getPasskey);
|
|
249
|
+
if (r.ok || r.error.code !== "passkey_unavailable" || !m.passkeyOnCauthy) return r;
|
|
250
|
+
} else if (!m.passkeyOnCauthy) {
|
|
251
|
+
return { ok: false, error: { code: "passkey_unavailable", message: "Passkeys cannot be used here." } };
|
|
252
|
+
}
|
|
153
253
|
window.location.assign(passkeyUrl(o));
|
|
254
|
+
return { ok: true, status: "redirected" };
|
|
154
255
|
},
|
|
155
256
|
socialUrl,
|
|
156
257
|
social(provider, o) {
|
|
@@ -194,7 +295,16 @@ function createAuthClient(options = {}) {
|
|
|
194
295
|
const body = await read("/me/sessions");
|
|
195
296
|
return body && Array.isArray(body.sessions) ? body.sessions : [];
|
|
196
297
|
},
|
|
197
|
-
signOutEverywhere: () => post("/me/sessions/end", {}, null)
|
|
298
|
+
signOutEverywhere: () => post("/me/sessions/end", {}, null),
|
|
299
|
+
async passkeys() {
|
|
300
|
+
const body = await read("/me/passkeys");
|
|
301
|
+
return body && Array.isArray(body.passkeys) ? body.passkeys : [];
|
|
302
|
+
},
|
|
303
|
+
addPasskey(f = {}) {
|
|
304
|
+
if (!canUsePasskeys()) return Promise.resolve({ ok: false, error: { code: "passkey_unavailable", message: "This browser cannot make passkeys." } });
|
|
305
|
+
return ceremony("/me/passkeys/add/begin", "/me/passkeys/add/finish", { password: f.password ?? "" }, makePasskey, { name: f.name ?? "" });
|
|
306
|
+
},
|
|
307
|
+
removePasskey: (id) => post("/me/passkeys/remove", { id }, null)
|
|
198
308
|
},
|
|
199
309
|
async getSession() {
|
|
200
310
|
try {
|
|
@@ -209,14 +319,7 @@ function createAuthClient(options = {}) {
|
|
|
209
319
|
looked ??= read("/look").then((wire) => wire && typeof wire === "object" ? fromWire(wire) : null);
|
|
210
320
|
return looked;
|
|
211
321
|
},
|
|
212
|
-
|
|
213
|
-
try {
|
|
214
|
-
const res = await doFetch(`${base}/methods`, { credentials: "same-origin", headers: { accept: "application/json" } });
|
|
215
|
-
if (res.ok) return await res.json();
|
|
216
|
-
} catch {
|
|
217
|
-
}
|
|
218
|
-
return { providers: [], signUp: true, magicLink: false, passkey: false };
|
|
219
|
-
}
|
|
322
|
+
methods
|
|
220
323
|
};
|
|
221
324
|
}
|
|
222
325
|
|
|
@@ -312,7 +415,8 @@ function createSessionStore(options = {}) {
|
|
|
312
415
|
email: (f) => then(client.signIn.email(f)),
|
|
313
416
|
mfa: (f) => then(client.signIn.mfa(f)),
|
|
314
417
|
magicLinkVerify: (f) => then(client.signIn.magicLinkVerify(f)),
|
|
315
|
-
emailCode: (f) => then(client.signIn.emailCode(f))
|
|
418
|
+
emailCode: (f) => then(client.signIn.emailCode(f)),
|
|
419
|
+
passkey: (o) => then(client.signIn.passkey(o))
|
|
316
420
|
},
|
|
317
421
|
signUp: { email: (f) => then(client.signUp.email(f)) },
|
|
318
422
|
signOut: () => then(client.signOut()),
|