@mrgnw/anahtar 0.0.12 → 0.0.14
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/components/AuthFlow.svelte +35 -1
- package/dist/components/OtpInput.svelte +15 -1
- package/dist/components/PasskeyPrompt.svelte +21 -3
- package/dist/i18n/af.d.ts +3 -0
- package/dist/i18n/af.js +28 -0
- package/dist/i18n/ak.d.ts +3 -0
- package/dist/i18n/ak.js +28 -0
- package/dist/i18n/am.d.ts +3 -0
- package/dist/i18n/am.js +28 -0
- package/dist/i18n/ar.js +1 -1
- package/dist/i18n/as.d.ts +3 -0
- package/dist/i18n/as.js +28 -0
- package/dist/i18n/az.d.ts +3 -0
- package/dist/i18n/az.js +28 -0
- package/dist/i18n/be.d.ts +3 -0
- package/dist/i18n/be.js +28 -0
- package/dist/i18n/bg.d.ts +3 -0
- package/dist/i18n/bg.js +28 -0
- package/dist/i18n/bn.d.ts +3 -0
- package/dist/i18n/bn.js +28 -0
- package/dist/i18n/ca.d.ts +3 -0
- package/dist/i18n/ca.js +28 -0
- package/dist/i18n/cs.d.ts +3 -0
- package/dist/i18n/cs.js +28 -0
- package/dist/i18n/da.d.ts +3 -0
- package/dist/i18n/da.js +28 -0
- package/dist/i18n/el.d.ts +3 -0
- package/dist/i18n/el.js +28 -0
- package/dist/i18n/es.js +1 -1
- package/dist/i18n/fa.d.ts +3 -0
- package/dist/i18n/fa.js +28 -0
- package/dist/i18n/ff.d.ts +3 -0
- package/dist/i18n/ff.js +28 -0
- package/dist/i18n/fi.d.ts +3 -0
- package/dist/i18n/fi.js +28 -0
- package/dist/i18n/fil.d.ts +3 -0
- package/dist/i18n/fil.js +28 -0
- package/dist/i18n/fr.js +1 -1
- package/dist/i18n/gu.d.ts +3 -0
- package/dist/i18n/gu.js +28 -0
- package/dist/i18n/ha.d.ts +3 -0
- package/dist/i18n/ha.js +28 -0
- package/dist/i18n/he.d.ts +3 -0
- package/dist/i18n/he.js +28 -0
- package/dist/i18n/hi.d.ts +3 -0
- package/dist/i18n/hi.js +28 -0
- package/dist/i18n/hr.d.ts +3 -0
- package/dist/i18n/hr.js +28 -0
- package/dist/i18n/ht.d.ts +3 -0
- package/dist/i18n/ht.js +28 -0
- package/dist/i18n/hu.d.ts +3 -0
- package/dist/i18n/hu.js +28 -0
- package/dist/i18n/hy.d.ts +3 -0
- package/dist/i18n/hy.js +28 -0
- package/dist/i18n/id.d.ts +3 -0
- package/dist/i18n/id.js +28 -0
- package/dist/i18n/ig.d.ts +3 -0
- package/dist/i18n/ig.js +28 -0
- package/dist/i18n/index.js +157 -1
- package/dist/i18n/it.d.ts +3 -0
- package/dist/i18n/it.js +28 -0
- package/dist/i18n/ja.js +1 -1
- package/dist/i18n/jv.d.ts +3 -0
- package/dist/i18n/jv.js +28 -0
- package/dist/i18n/kk.d.ts +3 -0
- package/dist/i18n/kk.js +28 -0
- package/dist/i18n/km.d.ts +3 -0
- package/dist/i18n/km.js +28 -0
- package/dist/i18n/kn.d.ts +3 -0
- package/dist/i18n/kn.js +28 -0
- package/dist/i18n/ko.js +1 -1
- package/dist/i18n/ku.d.ts +3 -0
- package/dist/i18n/ku.js +28 -0
- package/dist/i18n/ln.d.ts +3 -0
- package/dist/i18n/ln.js +28 -0
- package/dist/i18n/lo.d.ts +3 -0
- package/dist/i18n/lo.js +28 -0
- package/dist/i18n/mg.d.ts +3 -0
- package/dist/i18n/mg.js +28 -0
- package/dist/i18n/ml.d.ts +3 -0
- package/dist/i18n/ml.js +28 -0
- package/dist/i18n/mn.d.ts +3 -0
- package/dist/i18n/mn.js +28 -0
- package/dist/i18n/mr.d.ts +3 -0
- package/dist/i18n/mr.js +28 -0
- package/dist/i18n/ms.d.ts +3 -0
- package/dist/i18n/ms.js +28 -0
- package/dist/i18n/my.d.ts +3 -0
- package/dist/i18n/my.js +28 -0
- package/dist/i18n/ne.d.ts +3 -0
- package/dist/i18n/ne.js +28 -0
- package/dist/i18n/nl.d.ts +3 -0
- package/dist/i18n/nl.js +28 -0
- package/dist/i18n/no.d.ts +3 -0
- package/dist/i18n/no.js +28 -0
- package/dist/i18n/ny.d.ts +3 -0
- package/dist/i18n/ny.js +28 -0
- package/dist/i18n/om.d.ts +3 -0
- package/dist/i18n/om.js +28 -0
- package/dist/i18n/or.d.ts +3 -0
- package/dist/i18n/or.js +28 -0
- package/dist/i18n/pa.d.ts +3 -0
- package/dist/i18n/pa.js +28 -0
- package/dist/i18n/pl.d.ts +3 -0
- package/dist/i18n/pl.js +28 -0
- package/dist/i18n/ps.d.ts +3 -0
- package/dist/i18n/ps.js +28 -0
- package/dist/i18n/pt.js +1 -1
- package/dist/i18n/rn.d.ts +3 -0
- package/dist/i18n/rn.js +28 -0
- package/dist/i18n/ro.d.ts +3 -0
- package/dist/i18n/ro.js +28 -0
- package/dist/i18n/ru.d.ts +3 -0
- package/dist/i18n/ru.js +28 -0
- package/dist/i18n/rw.d.ts +3 -0
- package/dist/i18n/rw.js +28 -0
- package/dist/i18n/sd.d.ts +3 -0
- package/dist/i18n/sd.js +28 -0
- package/dist/i18n/si.d.ts +3 -0
- package/dist/i18n/si.js +28 -0
- package/dist/i18n/sk.d.ts +3 -0
- package/dist/i18n/sk.js +28 -0
- package/dist/i18n/so.d.ts +3 -0
- package/dist/i18n/so.js +28 -0
- package/dist/i18n/sq.d.ts +3 -0
- package/dist/i18n/sq.js +28 -0
- package/dist/i18n/sr.d.ts +3 -0
- package/dist/i18n/sr.js +28 -0
- package/dist/i18n/st.d.ts +3 -0
- package/dist/i18n/st.js +28 -0
- package/dist/i18n/su.d.ts +3 -0
- package/dist/i18n/su.js +28 -0
- package/dist/i18n/sv.d.ts +3 -0
- package/dist/i18n/sv.js +28 -0
- package/dist/i18n/sw.d.ts +3 -0
- package/dist/i18n/sw.js +28 -0
- package/dist/i18n/ta.d.ts +3 -0
- package/dist/i18n/ta.js +28 -0
- package/dist/i18n/te.d.ts +3 -0
- package/dist/i18n/te.js +28 -0
- package/dist/i18n/tg.d.ts +3 -0
- package/dist/i18n/tg.js +28 -0
- package/dist/i18n/th.d.ts +3 -0
- package/dist/i18n/th.js +28 -0
- package/dist/i18n/ti.d.ts +3 -0
- package/dist/i18n/ti.js +28 -0
- package/dist/i18n/tk.d.ts +3 -0
- package/dist/i18n/tk.js +28 -0
- package/dist/i18n/tr.js +1 -1
- package/dist/i18n/ts.d.ts +3 -0
- package/dist/i18n/ts.js +28 -0
- package/dist/i18n/tt.d.ts +3 -0
- package/dist/i18n/tt.js +28 -0
- package/dist/i18n/ug.d.ts +3 -0
- package/dist/i18n/ug.js +28 -0
- package/dist/i18n/uk.d.ts +3 -0
- package/dist/i18n/uk.js +28 -0
- package/dist/i18n/ur.d.ts +3 -0
- package/dist/i18n/ur.js +28 -0
- package/dist/i18n/uz.d.ts +3 -0
- package/dist/i18n/uz.js +28 -0
- package/dist/i18n/vi.d.ts +3 -0
- package/dist/i18n/vi.js +28 -0
- package/dist/i18n/yo.d.ts +3 -0
- package/dist/i18n/yo.js +28 -0
- package/dist/i18n/zh.js +1 -1
- package/dist/i18n/zu.d.ts +3 -0
- package/dist/i18n/zu.js +28 -0
- package/dist/kit/handlers.d.ts +2 -2
- package/dist/kit/handlers.js +61 -46
- package/dist/passkey.d.ts +1 -0
- package/dist/passkey.js +22 -0
- package/package.json +1 -1
package/dist/kit/handlers.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { json } from
|
|
2
|
-
import { generateOTP, verifyOTP } from
|
|
3
|
-
import { generateAuthenticationChallenge, generateRegistrationChallenge, removePasskey, verifyAuthenticationResponse, verifyRegistrationResponse } from
|
|
4
|
-
import { createSession, invalidateSession, validateSession } from
|
|
5
|
-
import { resolveMessages, detectLocaleServer } from
|
|
1
|
+
import { json } from "@sveltejs/kit";
|
|
2
|
+
import { generateOTP, verifyOTP } from "../otp.js";
|
|
3
|
+
import { generateAuthenticationChallenge, generateAuthenticationChallengeForUser, generateRegistrationChallenge, removePasskey, verifyAuthenticationResponse, verifyRegistrationResponse, } from "../passkey.js";
|
|
4
|
+
import { createSession, invalidateSession, validateSession, } from "../session.js";
|
|
5
|
+
import { resolveMessages, detectLocaleServer, } from "../i18n/index.js";
|
|
6
6
|
const SESSION_MAX_AGE_SECONDS = 30 * 24 * 60 * 60;
|
|
7
7
|
function getMessages(event, config) {
|
|
8
8
|
const locale = config.locale ?? detectLocaleServer(event.request);
|
|
@@ -19,32 +19,36 @@ export function createHandlers(config) {
|
|
|
19
19
|
function cookieOpts(event) {
|
|
20
20
|
return {
|
|
21
21
|
httpOnly: true,
|
|
22
|
-
secure: event.url.protocol ===
|
|
23
|
-
sameSite:
|
|
24
|
-
path:
|
|
25
|
-
maxAge
|
|
22
|
+
secure: event.url.protocol === "https:",
|
|
23
|
+
sameSite: "lax",
|
|
24
|
+
path: "/",
|
|
25
|
+
maxAge,
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
const routes = {
|
|
29
29
|
start: {
|
|
30
|
-
method:
|
|
30
|
+
method: "POST",
|
|
31
31
|
handler: async (event) => {
|
|
32
32
|
const m = getMessages(event, config);
|
|
33
33
|
const body = await event.request.json().catch(() => null);
|
|
34
|
-
if (!body ||
|
|
34
|
+
if (!body ||
|
|
35
|
+
typeof body.email !== "string" ||
|
|
36
|
+
!body.email.includes("@")) {
|
|
35
37
|
return json({ error: m.errorInvalidEmail }, { status: 400 });
|
|
36
38
|
}
|
|
37
39
|
const { code } = await generateOTP(config.db, body.email, config);
|
|
38
40
|
await config.onSendOTP(body.email, code);
|
|
39
41
|
return json({ success: true });
|
|
40
|
-
}
|
|
42
|
+
},
|
|
41
43
|
},
|
|
42
44
|
verify: {
|
|
43
|
-
method:
|
|
45
|
+
method: "POST",
|
|
44
46
|
handler: async (event) => {
|
|
45
47
|
const m = getMessages(event, config);
|
|
46
48
|
const body = await event.request.json().catch(() => null);
|
|
47
|
-
if (!body ||
|
|
49
|
+
if (!body ||
|
|
50
|
+
typeof body.email !== "string" ||
|
|
51
|
+
typeof body.code !== "string") {
|
|
48
52
|
return json({ error: m.errorInvalidInput }, { status: 400 });
|
|
49
53
|
}
|
|
50
54
|
const otp = await verifyOTP(config.db, body.email, body.code, config);
|
|
@@ -54,7 +58,7 @@ export function createHandlers(config) {
|
|
|
54
58
|
expired: m.errorCodeExpired,
|
|
55
59
|
rate_limited: m.errorTooManyAttempts,
|
|
56
60
|
};
|
|
57
|
-
return json({ error: messages[otp.error] }, { status: otp.error ===
|
|
61
|
+
return json({ error: messages[otp.error] }, { status: otp.error === "rate_limited" ? 429 : 400 });
|
|
58
62
|
}
|
|
59
63
|
let user = await config.db.getUserByEmail(body.email);
|
|
60
64
|
if (!user) {
|
|
@@ -66,12 +70,12 @@ export function createHandlers(config) {
|
|
|
66
70
|
return json({
|
|
67
71
|
user: { id: user.id, email: user.email },
|
|
68
72
|
hasPasskey: passkeys.length > 0,
|
|
69
|
-
skipPasskeyPrompt: user.skipPasskeyPrompt
|
|
73
|
+
skipPasskeyPrompt: user.skipPasskeyPrompt,
|
|
70
74
|
});
|
|
71
|
-
}
|
|
75
|
+
},
|
|
72
76
|
},
|
|
73
77
|
logout: {
|
|
74
|
-
method:
|
|
78
|
+
method: "POST",
|
|
75
79
|
handler: async (event) => {
|
|
76
80
|
const token = event.cookies.get(config.cookie);
|
|
77
81
|
if (token) {
|
|
@@ -79,20 +83,31 @@ export function createHandlers(config) {
|
|
|
79
83
|
if (result) {
|
|
80
84
|
await invalidateSession(config.db, result.session.id);
|
|
81
85
|
}
|
|
82
|
-
event.cookies.delete(config.cookie, { path:
|
|
86
|
+
event.cookies.delete(config.cookie, { path: "/" });
|
|
83
87
|
}
|
|
84
88
|
return json({ ok: true });
|
|
85
|
-
}
|
|
89
|
+
},
|
|
86
90
|
},
|
|
87
|
-
|
|
88
|
-
method:
|
|
91
|
+
"passkey/login-start": {
|
|
92
|
+
method: "GET",
|
|
89
93
|
handler: async (event) => {
|
|
90
94
|
const options = await generateAuthenticationChallenge(config.db, event.url);
|
|
91
95
|
return json(options);
|
|
92
|
-
}
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
"passkey/check-email": {
|
|
99
|
+
method: "POST",
|
|
100
|
+
handler: async (event) => {
|
|
101
|
+
const body = await event.request.json().catch(() => null);
|
|
102
|
+
const email = body?.email;
|
|
103
|
+
if (!email || typeof email !== "string")
|
|
104
|
+
return json({ allowCredentials: [] });
|
|
105
|
+
const options = await generateAuthenticationChallengeForUser(config.db, email, event.url);
|
|
106
|
+
return json(options);
|
|
107
|
+
},
|
|
93
108
|
},
|
|
94
|
-
|
|
95
|
-
method:
|
|
109
|
+
"passkey/login-finish": {
|
|
110
|
+
method: "POST",
|
|
96
111
|
handler: async (event) => {
|
|
97
112
|
const m = getMessages(event, config);
|
|
98
113
|
const body = await event.request.json().catch(() => null);
|
|
@@ -104,10 +119,10 @@ export function createHandlers(config) {
|
|
|
104
119
|
const session = await createSession(config.db, result.user.id, config);
|
|
105
120
|
event.cookies.set(config.cookie, session.sessionToken, cookieOpts(event));
|
|
106
121
|
return json({ user: result.user });
|
|
107
|
-
}
|
|
122
|
+
},
|
|
108
123
|
},
|
|
109
|
-
|
|
110
|
-
method:
|
|
124
|
+
"passkey/register-start": {
|
|
125
|
+
method: "POST",
|
|
111
126
|
handler: async (event) => {
|
|
112
127
|
const m = getMessages(event, config);
|
|
113
128
|
const user = requireAuth(event, m);
|
|
@@ -115,10 +130,10 @@ export function createHandlers(config) {
|
|
|
115
130
|
return user;
|
|
116
131
|
const options = await generateRegistrationChallenge(config.db, user, event.url, config);
|
|
117
132
|
return json(options);
|
|
118
|
-
}
|
|
133
|
+
},
|
|
119
134
|
},
|
|
120
|
-
|
|
121
|
-
method:
|
|
135
|
+
"passkey/register-finish": {
|
|
136
|
+
method: "POST",
|
|
122
137
|
handler: async (event) => {
|
|
123
138
|
const m = getMessages(event, config);
|
|
124
139
|
const user = requireAuth(event, m);
|
|
@@ -128,34 +143,34 @@ export function createHandlers(config) {
|
|
|
128
143
|
if (!body)
|
|
129
144
|
return json({ error: m.errorInvalidInput }, { status: 400 });
|
|
130
145
|
const { name, ...response } = body;
|
|
131
|
-
const passkeyName = typeof name ===
|
|
146
|
+
const passkeyName = typeof name === "string" && name.trim() ? name.trim() : null;
|
|
132
147
|
const result = await verifyRegistrationResponse(config.db, user.id, response, event.url, passkeyName);
|
|
133
148
|
if (!result.ok) {
|
|
134
|
-
console.error(
|
|
149
|
+
console.error("register-finish failed:", result.reason);
|
|
135
150
|
return json({ error: m.errorPasskeyRegFailed, reason: result.reason }, { status: 400 });
|
|
136
151
|
}
|
|
137
152
|
return json({ success: true });
|
|
138
|
-
}
|
|
153
|
+
},
|
|
139
154
|
},
|
|
140
|
-
|
|
141
|
-
method:
|
|
155
|
+
"passkey/remove": {
|
|
156
|
+
method: "POST",
|
|
142
157
|
handler: async (event) => {
|
|
143
158
|
const m = getMessages(event, config);
|
|
144
159
|
const user = requireAuth(event, m);
|
|
145
160
|
if (user instanceof Response)
|
|
146
161
|
return user;
|
|
147
162
|
const body = await event.request.json().catch(() => null);
|
|
148
|
-
if (!body || typeof body.passkeyId !==
|
|
163
|
+
if (!body || typeof body.passkeyId !== "string") {
|
|
149
164
|
return json({ error: m.errorInvalidInput }, { status: 400 });
|
|
150
165
|
}
|
|
151
166
|
const success = await removePasskey(config.db, body.passkeyId, user.id);
|
|
152
167
|
if (!success)
|
|
153
168
|
return json({ error: m.errorPasskeyNotFound }, { status: 404 });
|
|
154
169
|
return json({ success: true });
|
|
155
|
-
}
|
|
170
|
+
},
|
|
156
171
|
},
|
|
157
|
-
|
|
158
|
-
method:
|
|
172
|
+
"skip-passkey": {
|
|
173
|
+
method: "POST",
|
|
159
174
|
handler: async (event) => {
|
|
160
175
|
const m = getMessages(event, config);
|
|
161
176
|
const user = requireAuth(event, m);
|
|
@@ -163,12 +178,12 @@ export function createHandlers(config) {
|
|
|
163
178
|
return user;
|
|
164
179
|
await config.db.setSkipPasskeyPrompt(user.id, true);
|
|
165
180
|
return json({ success: true });
|
|
166
|
-
}
|
|
167
|
-
}
|
|
181
|
+
},
|
|
182
|
+
},
|
|
168
183
|
};
|
|
169
184
|
function getRoute(event) {
|
|
170
185
|
const path = event.params.path;
|
|
171
|
-
if (typeof path ===
|
|
186
|
+
if (typeof path === "string")
|
|
172
187
|
return path;
|
|
173
188
|
return null;
|
|
174
189
|
}
|
|
@@ -179,7 +194,7 @@ export function createHandlers(config) {
|
|
|
179
194
|
if (!path)
|
|
180
195
|
return json({ error: m.errorNotFound }, { status: 404 });
|
|
181
196
|
const route = routes[path];
|
|
182
|
-
if (!route || route.method !==
|
|
197
|
+
if (!route || route.method !== "GET") {
|
|
183
198
|
return json({ error: m.errorNotFound }, { status: 404 });
|
|
184
199
|
}
|
|
185
200
|
return route.handler(event);
|
|
@@ -190,10 +205,10 @@ export function createHandlers(config) {
|
|
|
190
205
|
if (!path)
|
|
191
206
|
return json({ error: m.errorNotFound }, { status: 404 });
|
|
192
207
|
const route = routes[path];
|
|
193
|
-
if (!route || route.method !==
|
|
208
|
+
if (!route || route.method !== "POST") {
|
|
194
209
|
return json({ error: m.errorNotFound }, { status: 404 });
|
|
195
210
|
}
|
|
196
211
|
return route.handler(event);
|
|
197
|
-
}
|
|
212
|
+
},
|
|
198
213
|
};
|
|
199
214
|
}
|
package/dist/passkey.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export declare function verifyRegistrationResponse(db: AuthDB, userId: string, r
|
|
|
14
14
|
ok: false;
|
|
15
15
|
reason: string;
|
|
16
16
|
}>;
|
|
17
|
+
export declare function generateAuthenticationChallengeForUser(db: AuthDB, email: string, requestUrl: URL): Promise<import("@simplewebauthn/server").PublicKeyCredentialRequestOptionsJSON>;
|
|
17
18
|
export declare function generateAuthenticationChallenge(db: AuthDB, requestUrl: URL): Promise<import("@simplewebauthn/server").PublicKeyCredentialRequestOptionsJSON>;
|
|
18
19
|
export declare function verifyAuthenticationResponse(db: AuthDB, response: AuthenticationResponseJSON, requestUrl: URL): Promise<{
|
|
19
20
|
user: {
|
package/dist/passkey.js
CHANGED
|
@@ -81,6 +81,28 @@ export async function verifyRegistrationResponse(db, userId, response, requestUr
|
|
|
81
81
|
return { ok: false, reason: `verification threw: ${e}` };
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
|
+
export async function generateAuthenticationChallengeForUser(db, email, requestUrl) {
|
|
85
|
+
const { rpID } = getWebAuthnConfig(requestUrl);
|
|
86
|
+
const user = await db.getUserByEmail(email);
|
|
87
|
+
if (!user)
|
|
88
|
+
return generateAuthenticationChallenge(db, requestUrl);
|
|
89
|
+
const passkeys = await db.getUserPasskeys(user.id);
|
|
90
|
+
if (passkeys.length === 0)
|
|
91
|
+
return generateAuthenticationChallenge(db, requestUrl);
|
|
92
|
+
const allowCredentials = passkeys.map((pk) => ({
|
|
93
|
+
id: pk.credentialId,
|
|
94
|
+
transports: pk.transports
|
|
95
|
+
? JSON.parse(pk.transports)
|
|
96
|
+
: undefined,
|
|
97
|
+
}));
|
|
98
|
+
const options = await generateAuthenticationOptions({
|
|
99
|
+
rpID,
|
|
100
|
+
allowCredentials,
|
|
101
|
+
userVerification: "preferred",
|
|
102
|
+
});
|
|
103
|
+
await db.storeChallenge(options.challenge, user.id, Date.now() + CHALLENGE_EXPIRY_MS);
|
|
104
|
+
return options;
|
|
105
|
+
}
|
|
84
106
|
export async function generateAuthenticationChallenge(db, requestUrl) {
|
|
85
107
|
const { rpID } = getWebAuthnConfig(requestUrl);
|
|
86
108
|
const options = await generateAuthenticationOptions({
|