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