@vilio/auth-passkey-module 0.0.2

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.
Files changed (48) hide show
  1. package/dist/actions/settings.d.ts +10 -0
  2. package/dist/actions/settings.d.ts.map +1 -0
  3. package/dist/actions/settings.js +17 -0
  4. package/dist/actions/settings.js.map +1 -0
  5. package/dist/client.d.ts +1 -0
  6. package/dist/client.d.ts.map +1 -0
  7. package/dist/client.js +3 -0
  8. package/dist/client.js.map +1 -0
  9. package/dist/index.d.ts +4 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +118 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/routes.d.ts +5 -0
  14. package/dist/routes.d.ts.map +1 -0
  15. package/dist/routes.js +195 -0
  16. package/dist/routes.js.map +1 -0
  17. package/dist/schema.d.ts +415 -0
  18. package/dist/schema.d.ts.map +1 -0
  19. package/dist/schema.js +28 -0
  20. package/dist/schema.js.map +1 -0
  21. package/dist/server/passkey.d.ts +8 -0
  22. package/dist/server/passkey.d.ts.map +1 -0
  23. package/dist/server/passkey.js +126 -0
  24. package/dist/server/passkey.js.map +1 -0
  25. package/dist/ui/passkey-button.d.ts +2 -0
  26. package/dist/ui/passkey-button.d.ts.map +1 -0
  27. package/dist/ui/passkey-button.js +56 -0
  28. package/dist/ui/passkey-button.js.map +1 -0
  29. package/dist/ui/session-badge.d.ts +5 -0
  30. package/dist/ui/session-badge.d.ts.map +1 -0
  31. package/dist/ui/session-badge.js +16 -0
  32. package/dist/ui/session-badge.js.map +1 -0
  33. package/dist/ui/settings-auth-passkey.d.ts +2 -0
  34. package/dist/ui/settings-auth-passkey.d.ts.map +1 -0
  35. package/dist/ui/settings-auth-passkey.js +32 -0
  36. package/dist/ui/settings-auth-passkey.js.map +1 -0
  37. package/dist/ui/settings-passkey.d.ts +2 -0
  38. package/dist/ui/settings-passkey.d.ts.map +1 -0
  39. package/dist/ui/settings-passkey.js +110 -0
  40. package/dist/ui/settings-passkey.js.map +1 -0
  41. package/dist/ui/verify-page.d.ts +2 -0
  42. package/dist/ui/verify-page.d.ts.map +1 -0
  43. package/dist/ui/verify-page.js +45 -0
  44. package/dist/ui/verify-page.js.map +1 -0
  45. package/locales/en/global.json +52 -0
  46. package/locales/pl/global.json +52 -0
  47. package/manifest.json +11 -0
  48. package/package.json +45 -0
@@ -0,0 +1,415 @@
1
+ export declare const authenticatorTable: import("drizzle-orm/pg-core").PgTableWithColumns<{
2
+ name: "authenticators";
3
+ schema: undefined;
4
+ columns: {
5
+ id: import("drizzle-orm/pg-core").PgColumn<{
6
+ name: string;
7
+ tableName: "authenticators";
8
+ dataType: "string";
9
+ data: string;
10
+ driverParam: string;
11
+ notNull: true;
12
+ hasDefault: false;
13
+ isPrimaryKey: true;
14
+ isAutoincrement: false;
15
+ hasRuntimeDefault: false;
16
+ enumValues: [string, ...string[]];
17
+ baseColumn: never;
18
+ identity: undefined;
19
+ generated: undefined;
20
+ }, {}>;
21
+ name: import("drizzle-orm/pg-core").PgColumn<{
22
+ name: string;
23
+ tableName: "authenticators";
24
+ dataType: "string";
25
+ data: string;
26
+ driverParam: string;
27
+ notNull: false;
28
+ hasDefault: false;
29
+ isPrimaryKey: false;
30
+ isAutoincrement: false;
31
+ hasRuntimeDefault: false;
32
+ enumValues: [string, ...string[]];
33
+ baseColumn: never;
34
+ identity: undefined;
35
+ generated: undefined;
36
+ }, {}>;
37
+ credentialPublicKey: import("drizzle-orm/pg-core").PgColumn<{
38
+ name: string;
39
+ tableName: "authenticators";
40
+ dataType: "object buffer";
41
+ data: Buffer<ArrayBufferLike>;
42
+ driverParam: Buffer<ArrayBufferLike>;
43
+ notNull: true;
44
+ hasDefault: false;
45
+ isPrimaryKey: false;
46
+ isAutoincrement: false;
47
+ hasRuntimeDefault: false;
48
+ enumValues: undefined;
49
+ baseColumn: never;
50
+ identity: undefined;
51
+ generated: undefined;
52
+ }, {}>;
53
+ counter: import("drizzle-orm/pg-core").PgColumn<{
54
+ name: string;
55
+ tableName: "authenticators";
56
+ dataType: "number int32";
57
+ data: number;
58
+ driverParam: string | number;
59
+ notNull: true;
60
+ hasDefault: false;
61
+ isPrimaryKey: false;
62
+ isAutoincrement: false;
63
+ hasRuntimeDefault: false;
64
+ enumValues: undefined;
65
+ baseColumn: never;
66
+ identity: undefined;
67
+ generated: undefined;
68
+ }, {}>;
69
+ credentialDeviceType: import("drizzle-orm/pg-core").PgColumn<{
70
+ name: string;
71
+ tableName: "authenticators";
72
+ dataType: "string";
73
+ data: string;
74
+ driverParam: string;
75
+ notNull: true;
76
+ hasDefault: false;
77
+ isPrimaryKey: false;
78
+ isAutoincrement: false;
79
+ hasRuntimeDefault: false;
80
+ enumValues: [string, ...string[]];
81
+ baseColumn: never;
82
+ identity: undefined;
83
+ generated: undefined;
84
+ }, {}>;
85
+ credentialBackedUp: import("drizzle-orm/pg-core").PgColumn<{
86
+ name: string;
87
+ tableName: "authenticators";
88
+ dataType: "boolean";
89
+ data: boolean;
90
+ driverParam: boolean;
91
+ notNull: true;
92
+ hasDefault: false;
93
+ isPrimaryKey: false;
94
+ isAutoincrement: false;
95
+ hasRuntimeDefault: false;
96
+ enumValues: undefined;
97
+ baseColumn: never;
98
+ identity: undefined;
99
+ generated: undefined;
100
+ }, {}>;
101
+ transports: import("drizzle-orm/pg-core").PgColumn<{
102
+ name: string;
103
+ tableName: "authenticators";
104
+ dataType: "string";
105
+ data: string;
106
+ driverParam: string;
107
+ notNull: false;
108
+ hasDefault: false;
109
+ isPrimaryKey: false;
110
+ isAutoincrement: false;
111
+ hasRuntimeDefault: false;
112
+ enumValues: [string, ...string[]];
113
+ baseColumn: never;
114
+ identity: undefined;
115
+ generated: undefined;
116
+ }, {}>;
117
+ userId: import("drizzle-orm/pg-core").PgColumn<{
118
+ name: string;
119
+ tableName: "authenticators";
120
+ dataType: "string";
121
+ data: string;
122
+ driverParam: string;
123
+ notNull: true;
124
+ hasDefault: false;
125
+ isPrimaryKey: false;
126
+ isAutoincrement: false;
127
+ hasRuntimeDefault: false;
128
+ enumValues: [string, ...string[]];
129
+ baseColumn: never;
130
+ identity: undefined;
131
+ generated: undefined;
132
+ }, {}>;
133
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
134
+ name: string;
135
+ tableName: "authenticators";
136
+ dataType: "object date";
137
+ data: Date;
138
+ driverParam: string;
139
+ notNull: true;
140
+ hasDefault: true;
141
+ isPrimaryKey: false;
142
+ isAutoincrement: false;
143
+ hasRuntimeDefault: false;
144
+ enumValues: undefined;
145
+ baseColumn: never;
146
+ identity: undefined;
147
+ generated: undefined;
148
+ }, {}>;
149
+ };
150
+ dialect: "pg";
151
+ }>;
152
+ export declare const passkeySettingsTable: import("drizzle-orm/pg-core").PgTableWithColumns<{
153
+ name: "passkey_settings";
154
+ schema: undefined;
155
+ columns: {
156
+ userId: import("drizzle-orm/pg-core").PgColumn<{
157
+ name: string;
158
+ tableName: "passkey_settings";
159
+ dataType: "string";
160
+ data: string;
161
+ driverParam: string;
162
+ notNull: true;
163
+ hasDefault: false;
164
+ isPrimaryKey: true;
165
+ isAutoincrement: false;
166
+ hasRuntimeDefault: false;
167
+ enumValues: [string, ...string[]];
168
+ baseColumn: never;
169
+ identity: undefined;
170
+ generated: undefined;
171
+ }, {}>;
172
+ twoFactorEnabled: import("drizzle-orm/pg-core").PgColumn<{
173
+ name: string;
174
+ tableName: "passkey_settings";
175
+ dataType: "boolean";
176
+ data: boolean;
177
+ driverParam: boolean;
178
+ notNull: true;
179
+ hasDefault: true;
180
+ isPrimaryKey: false;
181
+ isAutoincrement: false;
182
+ hasRuntimeDefault: false;
183
+ enumValues: undefined;
184
+ baseColumn: never;
185
+ identity: undefined;
186
+ generated: undefined;
187
+ }, {}>;
188
+ updatedAt: import("drizzle-orm/pg-core").PgColumn<{
189
+ name: string;
190
+ tableName: "passkey_settings";
191
+ dataType: "object date";
192
+ data: Date;
193
+ driverParam: string;
194
+ notNull: false;
195
+ hasDefault: true;
196
+ isPrimaryKey: false;
197
+ isAutoincrement: false;
198
+ hasRuntimeDefault: false;
199
+ enumValues: undefined;
200
+ baseColumn: never;
201
+ identity: undefined;
202
+ generated: undefined;
203
+ }, {}>;
204
+ };
205
+ dialect: "pg";
206
+ }>;
207
+ export declare const authPasskeySchema: {
208
+ authenticatorTable: import("drizzle-orm/pg-core").PgTableWithColumns<{
209
+ name: "authenticators";
210
+ schema: undefined;
211
+ columns: {
212
+ id: import("drizzle-orm/pg-core").PgColumn<{
213
+ name: string;
214
+ tableName: "authenticators";
215
+ dataType: "string";
216
+ data: string;
217
+ driverParam: string;
218
+ notNull: true;
219
+ hasDefault: false;
220
+ isPrimaryKey: true;
221
+ isAutoincrement: false;
222
+ hasRuntimeDefault: false;
223
+ enumValues: [string, ...string[]];
224
+ baseColumn: never;
225
+ identity: undefined;
226
+ generated: undefined;
227
+ }, {}>;
228
+ name: import("drizzle-orm/pg-core").PgColumn<{
229
+ name: string;
230
+ tableName: "authenticators";
231
+ dataType: "string";
232
+ data: string;
233
+ driverParam: string;
234
+ notNull: false;
235
+ hasDefault: false;
236
+ isPrimaryKey: false;
237
+ isAutoincrement: false;
238
+ hasRuntimeDefault: false;
239
+ enumValues: [string, ...string[]];
240
+ baseColumn: never;
241
+ identity: undefined;
242
+ generated: undefined;
243
+ }, {}>;
244
+ credentialPublicKey: import("drizzle-orm/pg-core").PgColumn<{
245
+ name: string;
246
+ tableName: "authenticators";
247
+ dataType: "object buffer";
248
+ data: Buffer<ArrayBufferLike>;
249
+ driverParam: Buffer<ArrayBufferLike>;
250
+ notNull: true;
251
+ hasDefault: false;
252
+ isPrimaryKey: false;
253
+ isAutoincrement: false;
254
+ hasRuntimeDefault: false;
255
+ enumValues: undefined;
256
+ baseColumn: never;
257
+ identity: undefined;
258
+ generated: undefined;
259
+ }, {}>;
260
+ counter: import("drizzle-orm/pg-core").PgColumn<{
261
+ name: string;
262
+ tableName: "authenticators";
263
+ dataType: "number int32";
264
+ data: number;
265
+ driverParam: string | number;
266
+ notNull: true;
267
+ hasDefault: false;
268
+ isPrimaryKey: false;
269
+ isAutoincrement: false;
270
+ hasRuntimeDefault: false;
271
+ enumValues: undefined;
272
+ baseColumn: never;
273
+ identity: undefined;
274
+ generated: undefined;
275
+ }, {}>;
276
+ credentialDeviceType: import("drizzle-orm/pg-core").PgColumn<{
277
+ name: string;
278
+ tableName: "authenticators";
279
+ dataType: "string";
280
+ data: string;
281
+ driverParam: string;
282
+ notNull: true;
283
+ hasDefault: false;
284
+ isPrimaryKey: false;
285
+ isAutoincrement: false;
286
+ hasRuntimeDefault: false;
287
+ enumValues: [string, ...string[]];
288
+ baseColumn: never;
289
+ identity: undefined;
290
+ generated: undefined;
291
+ }, {}>;
292
+ credentialBackedUp: import("drizzle-orm/pg-core").PgColumn<{
293
+ name: string;
294
+ tableName: "authenticators";
295
+ dataType: "boolean";
296
+ data: boolean;
297
+ driverParam: boolean;
298
+ notNull: true;
299
+ hasDefault: false;
300
+ isPrimaryKey: false;
301
+ isAutoincrement: false;
302
+ hasRuntimeDefault: false;
303
+ enumValues: undefined;
304
+ baseColumn: never;
305
+ identity: undefined;
306
+ generated: undefined;
307
+ }, {}>;
308
+ transports: import("drizzle-orm/pg-core").PgColumn<{
309
+ name: string;
310
+ tableName: "authenticators";
311
+ dataType: "string";
312
+ data: string;
313
+ driverParam: string;
314
+ notNull: false;
315
+ hasDefault: false;
316
+ isPrimaryKey: false;
317
+ isAutoincrement: false;
318
+ hasRuntimeDefault: false;
319
+ enumValues: [string, ...string[]];
320
+ baseColumn: never;
321
+ identity: undefined;
322
+ generated: undefined;
323
+ }, {}>;
324
+ userId: import("drizzle-orm/pg-core").PgColumn<{
325
+ name: string;
326
+ tableName: "authenticators";
327
+ dataType: "string";
328
+ data: string;
329
+ driverParam: string;
330
+ notNull: true;
331
+ hasDefault: false;
332
+ isPrimaryKey: false;
333
+ isAutoincrement: false;
334
+ hasRuntimeDefault: false;
335
+ enumValues: [string, ...string[]];
336
+ baseColumn: never;
337
+ identity: undefined;
338
+ generated: undefined;
339
+ }, {}>;
340
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
341
+ name: string;
342
+ tableName: "authenticators";
343
+ dataType: "object date";
344
+ data: Date;
345
+ driverParam: string;
346
+ notNull: true;
347
+ hasDefault: true;
348
+ isPrimaryKey: false;
349
+ isAutoincrement: false;
350
+ hasRuntimeDefault: false;
351
+ enumValues: undefined;
352
+ baseColumn: never;
353
+ identity: undefined;
354
+ generated: undefined;
355
+ }, {}>;
356
+ };
357
+ dialect: "pg";
358
+ }>;
359
+ passkeySettingsTable: import("drizzle-orm/pg-core").PgTableWithColumns<{
360
+ name: "passkey_settings";
361
+ schema: undefined;
362
+ columns: {
363
+ userId: import("drizzle-orm/pg-core").PgColumn<{
364
+ name: string;
365
+ tableName: "passkey_settings";
366
+ dataType: "string";
367
+ data: string;
368
+ driverParam: string;
369
+ notNull: true;
370
+ hasDefault: false;
371
+ isPrimaryKey: true;
372
+ isAutoincrement: false;
373
+ hasRuntimeDefault: false;
374
+ enumValues: [string, ...string[]];
375
+ baseColumn: never;
376
+ identity: undefined;
377
+ generated: undefined;
378
+ }, {}>;
379
+ twoFactorEnabled: import("drizzle-orm/pg-core").PgColumn<{
380
+ name: string;
381
+ tableName: "passkey_settings";
382
+ dataType: "boolean";
383
+ data: boolean;
384
+ driverParam: boolean;
385
+ notNull: true;
386
+ hasDefault: true;
387
+ isPrimaryKey: false;
388
+ isAutoincrement: false;
389
+ hasRuntimeDefault: false;
390
+ enumValues: undefined;
391
+ baseColumn: never;
392
+ identity: undefined;
393
+ generated: undefined;
394
+ }, {}>;
395
+ updatedAt: import("drizzle-orm/pg-core").PgColumn<{
396
+ name: string;
397
+ tableName: "passkey_settings";
398
+ dataType: "object date";
399
+ data: Date;
400
+ driverParam: string;
401
+ notNull: false;
402
+ hasDefault: true;
403
+ isPrimaryKey: false;
404
+ isAutoincrement: false;
405
+ hasRuntimeDefault: false;
406
+ enumValues: undefined;
407
+ baseColumn: never;
408
+ identity: undefined;
409
+ generated: undefined;
410
+ }, {}>;
411
+ };
412
+ dialect: "pg";
413
+ }>;
414
+ };
415
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAY7B,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAO/B,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAG7B,CAAC"}
package/dist/schema.js ADDED
@@ -0,0 +1,28 @@
1
+ import { boolean, bytea, integer, pgTable, text, timestamp, } from "drizzle-orm/pg-core";
2
+ import { userTable } from "@vilio/core/server";
3
+ export const authenticatorTable = pgTable("authenticators", {
4
+ id: text("id").primaryKey(), // Credential ID (base64url)
5
+ name: text("name"), // Optional label like "iPhone", "MacBook"
6
+ credentialPublicKey: bytea("credential_public_key").notNull(),
7
+ counter: integer("counter").notNull(),
8
+ credentialDeviceType: text("credential_device_type").notNull(),
9
+ credentialBackedUp: boolean("credential_backed_up").notNull(),
10
+ transports: text("transports"), // JSON string array
11
+ userId: text("user_id")
12
+ .notNull()
13
+ .references(() => userTable.id, { onDelete: "cascade" }),
14
+ createdAt: timestamp("created_at").notNull().defaultNow(),
15
+ });
16
+ export const passkeySettingsTable = pgTable("passkey_settings", {
17
+ userId: text("user_id")
18
+ .notNull()
19
+ .primaryKey()
20
+ .references(() => userTable.id, { onDelete: "cascade" }),
21
+ twoFactorEnabled: boolean("two_factor_enabled").notNull().default(false),
22
+ updatedAt: timestamp("updated_at").defaultNow(),
23
+ });
24
+ export const authPasskeySchema = {
25
+ authenticatorTable,
26
+ passkeySettingsTable,
27
+ };
28
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EACP,KAAK,EACL,OAAO,EACP,OAAO,EACP,IAAI,EACJ,SAAS,GACV,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,MAAM,CAAC,MAAM,kBAAkB,GAAG,OAAO,CAAC,gBAAgB,EAAE;IAC1D,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,4BAA4B;IACzD,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,0CAA0C;IAC9D,mBAAmB,EAAE,KAAK,CAAC,uBAAuB,CAAC,CAAC,OAAO,EAAE;IAC7D,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE;IACrC,oBAAoB,EAAE,IAAI,CAAC,wBAAwB,CAAC,CAAC,OAAO,EAAE;IAC9D,kBAAkB,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC,OAAO,EAAE;IAC7D,UAAU,EAAE,IAAI,CAAC,YAAY,CAAC,EAAE,oBAAoB;IACpD,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC;SACpB,OAAO,EAAE;SACT,UAAU,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;IAC1D,SAAS,EAAE,SAAS,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,UAAU,EAAE;CAC1D,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,oBAAoB,GAAG,OAAO,CAAC,kBAAkB,EAAE;IAC9D,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC;SACpB,OAAO,EAAE;SACT,UAAU,EAAE;SACZ,UAAU,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;IAC1D,gBAAgB,EAAE,OAAO,CAAC,oBAAoB,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IACxE,SAAS,EAAE,SAAS,CAAC,YAAY,CAAC,CAAC,UAAU,EAAE;CAChD,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,kBAAkB;IAClB,oBAAoB;CACrB,CAAC"}
@@ -0,0 +1,8 @@
1
+ export declare function getRegistrationOptions(userId: string, userEmail: string): Promise<import("@simplewebauthn/server").PublicKeyCredentialCreationOptionsJSON>;
2
+ export declare function verifyRegistration(userId: string, body: any): Promise<import("@simplewebauthn/server").VerifiedRegistrationResponse>;
3
+ export declare function getLoginOptions(): Promise<import("@simplewebauthn/server").PublicKeyCredentialRequestOptionsJSON>;
4
+ export declare function verifyLogin(body: any): Promise<{
5
+ verification: import("@simplewebauthn/server").VerifiedAuthenticationResponse;
6
+ userId: string;
7
+ }>;
8
+ //# sourceMappingURL=passkey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"passkey.d.ts","sourceRoot":"","sources":["../../src/server/passkey.ts"],"names":[],"mappings":"AAYA,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,oFAmClB;AAED,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,0EAyCjE;AAED,wBAAsB,eAAe,oFAgBpC;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,GAAG;;;GAoD1C"}
@@ -0,0 +1,126 @@
1
+ import { generateAuthenticationOptions, generateRegistrationOptions, verifyAuthenticationResponse, verifyRegistrationResponse, } from "@simplewebauthn/server";
2
+ import { db } from "@vilio/core/server";
3
+ import { eq } from "drizzle-orm";
4
+ import { cookies } from "next/headers";
5
+ import { authenticatorTable } from "../schema";
6
+ import { getPasskeyConfig } from "../actions/settings";
7
+ export async function getRegistrationOptions(userId, userEmail) {
8
+ const config = await getPasskeyConfig();
9
+ const userAuthenticators = await db
10
+ .select()
11
+ .from(authenticatorTable)
12
+ .where(eq(authenticatorTable.userId, userId));
13
+ const options = await generateRegistrationOptions({
14
+ rpName: config.rpName,
15
+ rpID: config.rpId,
16
+ userID: new TextEncoder().encode(userId),
17
+ userName: userEmail,
18
+ attestationType: "none",
19
+ excludeCredentials: userAuthenticators.map((auth) => ({
20
+ id: auth.id,
21
+ type: "public-key",
22
+ transports: auth.transports ? JSON.parse(auth.transports) : undefined,
23
+ })),
24
+ authenticatorSelection: {
25
+ residentKey: "preferred",
26
+ userVerification: "preferred",
27
+ authenticatorAttachment: "platform",
28
+ },
29
+ });
30
+ const cookieStore = await cookies();
31
+ cookieStore.set("passkey_registration_challenge", options.challenge, {
32
+ httpOnly: true,
33
+ secure: process.env.NODE_ENV === "production",
34
+ sameSite: "lax",
35
+ maxAge: 60 * 5, // 5 minutes
36
+ });
37
+ return options;
38
+ }
39
+ export async function verifyRegistration(userId, body) {
40
+ const config = await getPasskeyConfig();
41
+ const cookieStore = await cookies();
42
+ const expectedChallenge = cookieStore.get("passkey_registration_challenge")?.value;
43
+ if (!expectedChallenge) {
44
+ throw new Error("Registration challenge not found");
45
+ }
46
+ const verification = await verifyRegistrationResponse({
47
+ response: body,
48
+ expectedChallenge,
49
+ expectedOrigin: config.origin,
50
+ expectedRPID: config.rpId,
51
+ requireUserVerification: false,
52
+ });
53
+ console.log("[PasskeyAuth] Verification result:", JSON.stringify(verification, null, 2));
54
+ if (verification.verified && verification.registrationInfo) {
55
+ const { credential, credentialDeviceType, credentialBackedUp } = verification.registrationInfo;
56
+ const { id, publicKey, counter } = credential;
57
+ await db.insert(authenticatorTable).values({
58
+ id: id,
59
+ credentialPublicKey: Buffer.from(publicKey),
60
+ counter,
61
+ credentialDeviceType,
62
+ credentialBackedUp,
63
+ userId,
64
+ transports: JSON.stringify(body.response.transports || []),
65
+ });
66
+ }
67
+ return verification;
68
+ }
69
+ export async function getLoginOptions() {
70
+ const config = await getPasskeyConfig();
71
+ const options = await generateAuthenticationOptions({
72
+ rpID: config.rpId,
73
+ userVerification: "preferred",
74
+ });
75
+ const cookieStore = await cookies();
76
+ cookieStore.set("passkey_login_challenge", options.challenge, {
77
+ httpOnly: true,
78
+ secure: process.env.NODE_ENV === "production",
79
+ sameSite: "lax",
80
+ maxAge: 60 * 5,
81
+ });
82
+ return options;
83
+ }
84
+ export async function verifyLogin(body) {
85
+ const config = await getPasskeyConfig();
86
+ const cookieStore = await cookies();
87
+ const expectedChallenge = cookieStore.get("passkey_login_challenge")?.value;
88
+ if (!expectedChallenge) {
89
+ throw new Error("Login challenge not found");
90
+ }
91
+ const [authenticator] = await db
92
+ .select()
93
+ .from(authenticatorTable)
94
+ .where(eq(authenticatorTable.id, body.id));
95
+ if (!authenticator) {
96
+ throw new Error("Authenticator not found");
97
+ }
98
+ console.log("[PasskeyAuth] Authenticator from DB:", {
99
+ id: authenticator.id,
100
+ counter: authenticator.counter,
101
+ publicKeyType: typeof authenticator.credentialPublicKey,
102
+ isBuffer: Buffer.isBuffer(authenticator.credentialPublicKey),
103
+ });
104
+ const verification = await verifyAuthenticationResponse({
105
+ response: body,
106
+ expectedChallenge,
107
+ expectedOrigin: config.origin,
108
+ expectedRPID: config.rpId,
109
+ requireUserVerification: false,
110
+ credential: {
111
+ id: authenticator.id,
112
+ publicKey: authenticator.credentialPublicKey,
113
+ counter: authenticator.counter,
114
+ },
115
+ });
116
+ console.log("[PasskeyAuth] Login Verification result:", JSON.stringify(verification, null, 2));
117
+ if (verification.verified && verification.authenticationInfo) {
118
+ const { newCounter } = verification.authenticationInfo;
119
+ await db
120
+ .update(authenticatorTable)
121
+ .set({ counter: newCounter })
122
+ .where(eq(authenticatorTable.id, authenticator.id));
123
+ }
124
+ return { verification, userId: authenticator.userId };
125
+ }
126
+ //# sourceMappingURL=passkey.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"passkey.js","sourceRoot":"","sources":["../../src/server/passkey.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,6BAA6B,EAC7B,2BAA2B,EAC3B,4BAA4B,EAC5B,0BAA0B,GAC3B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,MAAc,EACd,SAAiB;IAEjB,MAAM,MAAM,GAAG,MAAM,gBAAgB,EAAE,CAAC;IACxC,MAAM,kBAAkB,GAAG,MAAM,EAAE;SAChC,MAAM,EAAE;SACR,IAAI,CAAC,kBAAkB,CAAC;SACxB,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAEhD,MAAM,OAAO,GAAG,MAAM,2BAA2B,CAAC;QAChD,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,MAAM,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC;QACxC,QAAQ,EAAE,SAAS;QACnB,eAAe,EAAE,MAAM;QACvB,kBAAkB,EAAE,kBAAkB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACpD,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,IAAI,EAAE,YAAY;YAClB,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS;SACtE,CAAC,CAAC;QACH,sBAAsB,EAAE;YACtB,WAAW,EAAE,WAAW;YACxB,gBAAgB,EAAE,WAAW;YAC7B,uBAAuB,EAAE,UAAU;SACpC;KACF,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,MAAM,OAAO,EAAE,CAAC;IACpC,WAAW,CAAC,GAAG,CAAC,gCAAgC,EAAE,OAAO,CAAC,SAAS,EAAE;QACnE,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY;QAC7C,QAAQ,EAAE,KAAK;QACf,MAAM,EAAE,EAAE,GAAG,CAAC,EAAE,YAAY;KAC7B,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAAc,EAAE,IAAS;IAChE,MAAM,MAAM,GAAG,MAAM,gBAAgB,EAAE,CAAC;IACxC,MAAM,WAAW,GAAG,MAAM,OAAO,EAAE,CAAC;IACpC,MAAM,iBAAiB,GAAG,WAAW,CAAC,GAAG,CACvC,gCAAgC,CACjC,EAAE,KAAK,CAAC;IAET,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,0BAA0B,CAAC;QACpD,QAAQ,EAAE,IAAI;QACd,iBAAiB;QACjB,cAAc,EAAE,MAAM,CAAC,MAAM;QAC7B,YAAY,EAAE,MAAM,CAAC,IAAI;QACzB,uBAAuB,EAAE,KAAK;KAC/B,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CACT,oCAAoC,EACpC,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CACtC,CAAC;IAEF,IAAI,YAAY,CAAC,QAAQ,IAAI,YAAY,CAAC,gBAAgB,EAAE,CAAC;QAC3D,MAAM,EAAE,UAAU,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,GAC5D,YAAY,CAAC,gBAAgB,CAAC;QAChC,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,UAAU,CAAC;QAE9C,MAAM,EAAE,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,MAAM,CAAC;YACzC,EAAE,EAAE,EAAE;YACN,mBAAmB,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;YAC3C,OAAO;YACP,oBAAoB;YACpB,kBAAkB;YAClB,MAAM;YACN,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,IAAI,EAAE,CAAC;SAC3D,CAAC,CAAC;IACL,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,MAAM,GAAG,MAAM,gBAAgB,EAAE,CAAC;IACxC,MAAM,OAAO,GAAG,MAAM,6BAA6B,CAAC;QAClD,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,gBAAgB,EAAE,WAAW;KAC9B,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,MAAM,OAAO,EAAE,CAAC;IACpC,WAAW,CAAC,GAAG,CAAC,yBAAyB,EAAE,OAAO,CAAC,SAAS,EAAE;QAC5D,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY;QAC7C,QAAQ,EAAE,KAAK;QACf,MAAM,EAAE,EAAE,GAAG,CAAC;KACf,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAS;IACzC,MAAM,MAAM,GAAG,MAAM,gBAAgB,EAAE,CAAC;IACxC,MAAM,WAAW,GAAG,MAAM,OAAO,EAAE,CAAC;IACpC,MAAM,iBAAiB,GAAG,WAAW,CAAC,GAAG,CAAC,yBAAyB,CAAC,EAAE,KAAK,CAAC;IAE5E,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC/C,CAAC;IAED,MAAM,CAAC,aAAa,CAAC,GAAG,MAAM,EAAE;SAC7B,MAAM,EAAE;SACR,IAAI,CAAC,kBAAkB,CAAC;SACxB,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAE7C,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,sCAAsC,EAAE;QAClD,EAAE,EAAE,aAAa,CAAC,EAAE;QACpB,OAAO,EAAE,aAAa,CAAC,OAAO;QAC9B,aAAa,EAAE,OAAO,aAAa,CAAC,mBAAmB;QACvD,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,mBAAmB,CAAC;KAC7D,CAAC,CAAC;IAEH,MAAM,YAAY,GAAG,MAAM,4BAA4B,CAAC;QACtD,QAAQ,EAAE,IAAI;QACd,iBAAiB;QACjB,cAAc,EAAE,MAAM,CAAC,MAAM;QAC7B,YAAY,EAAE,MAAM,CAAC,IAAI;QACzB,uBAAuB,EAAE,KAAK;QAC9B,UAAU,EAAE;YACV,EAAE,EAAE,aAAa,CAAC,EAAE;YACpB,SAAS,EAAE,aAAa,CAAC,mBAA8C;YACvE,OAAO,EAAE,aAAa,CAAC,OAAO;SAC/B;KACF,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CACT,0CAA0C,EAC1C,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CACtC,CAAC;IAEF,IAAI,YAAY,CAAC,QAAQ,IAAI,YAAY,CAAC,kBAAkB,EAAE,CAAC;QAC7D,MAAM,EAAE,UAAU,EAAE,GAAG,YAAY,CAAC,kBAAkB,CAAC;QACvD,MAAM,EAAE;aACL,MAAM,CAAC,kBAAkB,CAAC;aAC1B,GAAG,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;aAC5B,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAAC,EAAE,EAAE,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC;IACxD,CAAC;IAED,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,CAAC,MAAM,EAAE,CAAC;AACxD,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function PasskeyLoginButton(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=passkey-button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"passkey-button.d.ts","sourceRoot":"","sources":["../../src/ui/passkey-button.tsx"],"names":[],"mappings":"AASA,wBAAgB,kBAAkB,4CA8DjC"}
@@ -0,0 +1,56 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useTranslation } from "@vilio/intl";
4
+ import { Button } from "@vilio/ui";
5
+ import { Fingerprint } from "lucide-react";
6
+ import { startAuthentication } from "@simplewebauthn/browser";
7
+ import { toast } from "sonner";
8
+ import { useState } from "react";
9
+ export function PasskeyLoginButton() {
10
+ const { t } = useTranslation();
11
+ const [loading, setLoading] = useState(false);
12
+ const handleLogin = async () => {
13
+ setLoading(true);
14
+ try {
15
+ // 1. Get options from server
16
+ const resp = await fetch("/api/auth/passkey/login-options");
17
+ if (!resp.ok) {
18
+ const err = await resp.json();
19
+ throw new Error(err.message || t("Failed to get login options"));
20
+ }
21
+ const opts = await resp.json();
22
+ // 2. Start authentication
23
+ const asseResp = await startAuthentication(opts);
24
+ // 3. Verify response on server
25
+ const verifyResp = await fetch("/api/auth/passkey/login-verify", {
26
+ method: "POST",
27
+ headers: { "Content-Type": "application/json" },
28
+ body: JSON.stringify(asseResp),
29
+ });
30
+ if (!verifyResp.ok) {
31
+ const err = await verifyResp.json();
32
+ throw new Error(err.message || t("Verification failed"));
33
+ }
34
+ const verification = await verifyResp.json();
35
+ if (verification.verified) {
36
+ toast.success(t("Logged in successfully!"));
37
+ setLoading(false);
38
+ setTimeout(() => {
39
+ window.location.href = "/";
40
+ }, 1500);
41
+ }
42
+ else {
43
+ toast.error(t("Login failed."));
44
+ }
45
+ }
46
+ catch (err) {
47
+ console.error(err);
48
+ toast.error(err.message || t("Login failed."));
49
+ }
50
+ finally {
51
+ setLoading(false);
52
+ }
53
+ };
54
+ return (_jsxs(Button, { type: "button", variant: "outline", className: "w-full gap-2", onClick: handleLogin, children: [_jsx(Fingerprint, { className: "size-4" }), t("Continue with Passkey")] }));
55
+ }
56
+ //# sourceMappingURL=passkey-button.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"passkey-button.js","sourceRoot":"","sources":["../../src/ui/passkey-button.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { Session } from "@vilio/core";
2
+ export declare function Passkey2FAVerifiedBadge({ session }: {
3
+ session: Session;
4
+ }): import("react/jsx-runtime").JSX.Element | null;
5
+ //# sourceMappingURL=session-badge.d.ts.map