@gatwech/auth 1.0.0-beta.21 → 1.0.0-beta.23

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 (117) hide show
  1. package/dist/adapters/index.d.mts +1 -1
  2. package/dist/adapters/prisma-adapter/index.mjs +1 -1
  3. package/dist/{admin-BzUJL6tr.mjs → admin-rd-xHhnP.mjs} +1 -1
  4. package/dist/{anonymous-BjlTk4gl.mjs → anonymous-qSasVeIe.mjs} +1 -1
  5. package/dist/api/index.d.mts +1 -1
  6. package/dist/api/index.mjs +1 -1
  7. package/dist/{api-Dk8Yj_J5.mjs → api-BV65Y-Rk.mjs} +5 -0
  8. package/dist/{audit-log-DgqHJ-uv.mjs → audit-log-DhRRCMrv.mjs} +21 -6
  9. package/dist/{auth-BoEA9bN7.mjs → auth-DtOjarwu.mjs} +1 -1
  10. package/dist/client/index.d.mts +1 -1
  11. package/dist/client/plugins/index.d.mts +46 -46
  12. package/dist/client/react/index.d.mts +15 -15
  13. package/dist/{client-Da7tq8m6.d.mts → client-CDaFOX7A.d.mts} +4 -4
  14. package/dist/{client-B00gkznv.d.mts → client-D8XKNpua.d.mts} +1 -1
  15. package/dist/cookies/index.d.mts +2 -2
  16. package/dist/db/index.d.mts +1 -1
  17. package/dist/{email-otp-Dw0DypjQ.mjs → email-otp-BmgAht1S.mjs} +1 -1
  18. package/dist/{generic-oauth-DFj27JY8.mjs → generic-oauth-C5_AXj2z.mjs} +1 -1
  19. package/dist/{haveibeenpwned-CzNda7Tn.mjs → haveibeenpwned-_3a5amT-.mjs} +1 -1
  20. package/dist/{index-C-IDh5yy.d.mts → index-382PsmkK.d.mts} +2 -2
  21. package/dist/{index-BjCQ3jmE.d.mts → index-3lfPQHhX.d.mts} +118 -118
  22. package/dist/{index-CMG4Pnen.d.mts → index-B4aWSJEd.d.mts} +6 -6
  23. package/dist/{index-BWYXZVsV.d.mts → index-B5r4oL5q.d.mts} +5 -5
  24. package/dist/{index-BKy-8t2n.d.mts → index-B7iZf_Dl.d.mts} +449 -112
  25. package/dist/{index-VUyESU4p.d.mts → index-BhYE1_9j.d.mts} +1 -1
  26. package/dist/{index-IX1to9TB.d.mts → index-Blq8KrTy.d.mts} +33 -33
  27. package/dist/{index-oNlp4SvD.d.mts → index-C-z4TCHD.d.mts} +10 -10
  28. package/dist/{index-D1OZ2e4m.d.mts → index-C8F7PsET.d.mts} +13 -13
  29. package/dist/{index-TrOnY3pM.d.mts → index-CExSHSFz.d.mts} +169 -169
  30. package/dist/{index-iRoaTsOj.d.mts → index-CIxFDcfQ.d.mts} +2 -2
  31. package/dist/{index-BECNG13R.d.mts → index-COFPq-mg.d.mts} +13 -13
  32. package/dist/{index-YeXSxzhX.d.mts → index-CWwQ1Q7t.d.mts} +17 -17
  33. package/dist/{index-CbBQdS-u.d.mts → index-CWxKeTtE.d.mts} +6 -6
  34. package/dist/{index-cPt-00xm.d.mts → index-D0SgItjY.d.mts} +6 -6
  35. package/dist/{index-Bhc37y9F.d.mts → index-DCliG2n6.d.mts} +3 -3
  36. package/dist/{index-CM1rFdwV.d.mts → index-DPVukjga.d.mts} +9 -9
  37. package/dist/{index-WV7VzW2H.d.mts → index-DUu0ieh6.d.mts} +8 -8
  38. package/dist/{index-Bxive_YT.d.mts → index-De2a2OyC.d.mts} +9 -9
  39. package/dist/{index-CpH-1sse.d.mts → index-Dg6Ftb6f.d.mts} +9 -9
  40. package/dist/{index-Dt2I0G4X.d.mts → index-Dgyj1fTk.d.mts} +7 -7
  41. package/dist/{index-CTqynuxm.d.mts → index-DxIqV3rU.d.mts} +4 -4
  42. package/dist/{index-jEkJ2Zfk.d.mts → index-DxRAXHrZ.d.mts} +6 -6
  43. package/dist/index.d.mts +1 -1
  44. package/dist/index.mjs +2 -2
  45. package/dist/integrations/next-js.d.mts +4 -4
  46. package/dist/integrations/node.d.mts +1 -1
  47. package/dist/integrations/react-start.d.mts +4 -4
  48. package/dist/{jwt-DBN2mu0r.mjs → jwt-Czv-v097.mjs} +1 -1
  49. package/dist/{magic-link-D9Em1aOR.mjs → magic-link-CJgE0Ngn.mjs} +1 -1
  50. package/dist/{multi-session-Dno_8DxC.mjs → multi-session-bveCXtQW.mjs} +1 -1
  51. package/dist/{oauth-proxy-DW-zt8wv.mjs → oauth-proxy-69n1xA8L.mjs} +1 -1
  52. package/dist/oauth2/index.d.mts +1 -1
  53. package/dist/oauth2/index.mjs +1 -1
  54. package/dist/{one-tap-CodeyQb8.mjs → one-tap-Cm1eHuqi.mjs} +1 -1
  55. package/dist/{organization-D4QMpChF.mjs → organization-BK3ks97y.mjs} +1 -1
  56. package/dist/plugins/admin/index.d.mts +2 -2
  57. package/dist/plugins/admin/index.mjs +2 -2
  58. package/dist/plugins/anonymous/index.d.mts +2 -2
  59. package/dist/plugins/anonymous/index.mjs +2 -2
  60. package/dist/plugins/audit-log/client.d.mts +23 -23
  61. package/dist/plugins/audit-log/index.d.mts +22 -22
  62. package/dist/plugins/audit-log/index.mjs +3 -3
  63. package/dist/plugins/bearer/index.d.mts +1 -1
  64. package/dist/plugins/captcha/index.d.mts +1 -1
  65. package/dist/plugins/custom-session/index.d.mts +2 -2
  66. package/dist/plugins/custom-session/index.mjs +1 -1
  67. package/dist/plugins/device-authorization/index.d.mts +1 -1
  68. package/dist/plugins/email-otp/index.d.mts +1 -1
  69. package/dist/plugins/email-otp/index.mjs +2 -2
  70. package/dist/plugins/generic-oauth/index.d.mts +2 -2
  71. package/dist/plugins/generic-oauth/index.mjs +2 -2
  72. package/dist/plugins/haveibeenpwned/index.d.mts +1 -1
  73. package/dist/plugins/haveibeenpwned/index.mjs +2 -2
  74. package/dist/plugins/index.d.mts +22 -22
  75. package/dist/plugins/index.mjs +17 -17
  76. package/dist/plugins/jwt/index.d.mts +2 -2
  77. package/dist/plugins/jwt/index.mjs +2 -2
  78. package/dist/plugins/magic-link/index.d.mts +1 -1
  79. package/dist/plugins/magic-link/index.mjs +2 -2
  80. package/dist/plugins/multi-session/index.d.mts +1 -1
  81. package/dist/plugins/multi-session/index.mjs +2 -2
  82. package/dist/plugins/oauth-proxy/index.d.mts +1 -1
  83. package/dist/plugins/oauth-proxy/index.mjs +2 -2
  84. package/dist/plugins/one-tap/index.d.mts +1 -1
  85. package/dist/plugins/one-tap/index.mjs +2 -2
  86. package/dist/plugins/one-time-token/index.d.mts +2 -2
  87. package/dist/plugins/one-time-token/index.mjs +17 -17
  88. package/dist/plugins/organization/index.d.mts +2 -2
  89. package/dist/plugins/organization/index.mjs +2 -2
  90. package/dist/plugins/passkey/index.d.mts +2 -2
  91. package/dist/plugins/passkey/index.mjs +1 -1
  92. package/dist/plugins/phone-number/index.d.mts +2 -2
  93. package/dist/plugins/phone-number/index.mjs +1 -1
  94. package/dist/plugins/sentinel/client.d.mts +23 -23
  95. package/dist/plugins/sentinel/index.d.mts +22 -22
  96. package/dist/plugins/sentinel/index.mjs +4 -4
  97. package/dist/plugins/two-factor/index.d.mts +2 -2
  98. package/dist/plugins/two-factor/index.mjs +1 -1
  99. package/dist/plugins/username/index.d.mts +1 -1
  100. package/dist/plugins/username/index.mjs +2 -2
  101. package/dist/{plugins-yF8CFUDR.mjs → plugins-RSPSU3ro.mjs} +1 -1
  102. package/dist/{registry-CqG_3Qnx.mjs → registry-GztLf62p.mjs} +14 -2
  103. package/dist/{sentinel-B4Wo79HK.mjs → sentinel-CYtaI3eO.mjs} +264 -9
  104. package/dist/src/plugins/audit-log/events.d.ts +1 -0
  105. package/dist/src/plugins/audit-log/index.d.ts +45 -0
  106. package/dist/src/plugins/sentinel/actions.d.ts +2 -0
  107. package/dist/src/plugins/sentinel/geo.d.ts +11 -0
  108. package/dist/src/plugins/sentinel/index.d.ts +248 -3
  109. package/dist/src/plugins/sentinel/schema.d.ts +37 -0
  110. package/dist/src/plugins/sentinel/store.d.ts +34 -0
  111. package/dist/src/plugins/sentinel/types.d.ts +7 -0
  112. package/dist/src/utils/has-role.d.ts +5 -0
  113. package/dist/test-utils/index.d.mts +1044 -1044
  114. package/dist/test-utils/index.mjs +18 -18
  115. package/dist/types/index.d.mts +1 -1
  116. package/dist/{username-BHNvcvsY.mjs → username-DCp6yugu.mjs} +1 -1
  117. package/package.json +3 -3
@@ -1,4 +1,5 @@
1
1
  import type { AuthContext, GenericEndpointContext } from "@gatwech/core";
2
+ import * as z from "zod";
2
3
  import type { User } from "../../types";
3
4
  import { SENTINEL_ERROR_CODES } from "./actions";
4
5
  import { schema } from "./schema";
@@ -127,6 +128,39 @@ export declare const sentinel: (options?: SentinelOptions | undefined) => {
127
128
  };
128
129
  };
129
130
  };
131
+ sentinelBlock: {
132
+ fields: {
133
+ key: {
134
+ type: "string";
135
+ required: true;
136
+ unique: true;
137
+ };
138
+ feature: {
139
+ type: "string";
140
+ required: true;
141
+ };
142
+ kind: {
143
+ type: "string";
144
+ required: true;
145
+ };
146
+ identifier: {
147
+ type: "string";
148
+ required: true;
149
+ };
150
+ account: {
151
+ type: "string";
152
+ required: false;
153
+ };
154
+ blockedUntil: {
155
+ type: "date";
156
+ required: true;
157
+ };
158
+ createdAt: {
159
+ type: "date";
160
+ required: true;
161
+ };
162
+ };
163
+ };
130
164
  sentinelSignIn: {
131
165
  fields: {
132
166
  userId: {
@@ -210,9 +244,221 @@ export declare const sentinel: (options?: SentinelOptions | undefined) => {
210
244
  };
211
245
  };
212
246
  };
247
+ endpoints: {
248
+ listBlocks: {
249
+ <AsResponse extends boolean = false, ReturnHeaders extends boolean = false>(inputCtx_0?: ({
250
+ body?: undefined;
251
+ } & {
252
+ method?: "GET" | undefined;
253
+ } & {
254
+ query?: {
255
+ limit?: string | number | undefined;
256
+ offset?: string | number | undefined;
257
+ } | undefined;
258
+ } & {
259
+ params?: Record<string, any>;
260
+ } & {
261
+ request?: Request;
262
+ } & {
263
+ headers?: HeadersInit;
264
+ } & {
265
+ asResponse?: boolean;
266
+ returnHeaders?: boolean;
267
+ use?: import("better-call").Middleware[];
268
+ path?: string;
269
+ } & {
270
+ asResponse?: AsResponse | undefined;
271
+ returnHeaders?: ReturnHeaders | undefined;
272
+ }) | undefined): Promise<[AsResponse] extends [true] ? Response : [ReturnHeaders] extends [true] ? {
273
+ headers: Headers;
274
+ response: {
275
+ blocks: {
276
+ id: string;
277
+ key: string;
278
+ feature: string;
279
+ kind: string;
280
+ identifier: string;
281
+ account: string | null;
282
+ blockedUntil: Date;
283
+ createdAt: Date;
284
+ }[];
285
+ total: number;
286
+ limit: number;
287
+ offset: number;
288
+ };
289
+ } : {
290
+ blocks: {
291
+ id: string;
292
+ key: string;
293
+ feature: string;
294
+ kind: string;
295
+ identifier: string;
296
+ account: string | null;
297
+ blockedUntil: Date;
298
+ createdAt: Date;
299
+ }[];
300
+ total: number;
301
+ limit: number;
302
+ offset: number;
303
+ }>;
304
+ options: {
305
+ method: "GET";
306
+ use: ((inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
307
+ session: {
308
+ session: Record<string, any> & {
309
+ id: string;
310
+ createdAt: Date;
311
+ updatedAt: Date;
312
+ userId: string;
313
+ expiresAt: Date;
314
+ token: string;
315
+ ipAddress?: string | null | undefined;
316
+ userAgent?: string | null | undefined;
317
+ };
318
+ user: Record<string, any> & {
319
+ id: string;
320
+ createdAt: Date;
321
+ updatedAt: Date;
322
+ email: string;
323
+ emailVerified: boolean;
324
+ name: string;
325
+ image?: string | null | undefined;
326
+ };
327
+ };
328
+ }>)[];
329
+ query: z.ZodOptional<z.ZodObject<{
330
+ limit: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
331
+ offset: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
332
+ }, z.core.$strip>>;
333
+ metadata: {
334
+ openapi: {
335
+ operationId: string;
336
+ summary: string;
337
+ description: string;
338
+ };
339
+ };
340
+ } & {
341
+ use: any[];
342
+ };
343
+ path: "/sentinel/blocks";
344
+ };
345
+ unblock: {
346
+ <AsResponse extends boolean = false, ReturnHeaders extends boolean = false>(inputCtx_0: {
347
+ body: {
348
+ id: string;
349
+ };
350
+ } & {
351
+ method?: "POST" | undefined;
352
+ } & {
353
+ query?: Record<string, any> | undefined;
354
+ } & {
355
+ params?: Record<string, any>;
356
+ } & {
357
+ request?: Request;
358
+ } & {
359
+ headers?: HeadersInit;
360
+ } & {
361
+ asResponse?: boolean;
362
+ returnHeaders?: boolean;
363
+ use?: import("better-call").Middleware[];
364
+ path?: string;
365
+ } & {
366
+ asResponse?: AsResponse | undefined;
367
+ returnHeaders?: ReturnHeaders | undefined;
368
+ }): Promise<[AsResponse] extends [true] ? Response : [ReturnHeaders] extends [true] ? {
369
+ headers: Headers;
370
+ response: {
371
+ success: boolean;
372
+ };
373
+ } : {
374
+ success: boolean;
375
+ }>;
376
+ options: {
377
+ method: "POST";
378
+ use: ((inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
379
+ session: {
380
+ session: Record<string, any> & {
381
+ id: string;
382
+ createdAt: Date;
383
+ updatedAt: Date;
384
+ userId: string;
385
+ expiresAt: Date;
386
+ token: string;
387
+ ipAddress?: string | null | undefined;
388
+ userAgent?: string | null | undefined;
389
+ };
390
+ user: Record<string, any> & {
391
+ id: string;
392
+ createdAt: Date;
393
+ updatedAt: Date;
394
+ email: string;
395
+ emailVerified: boolean;
396
+ name: string;
397
+ image?: string | null | undefined;
398
+ };
399
+ };
400
+ }>)[];
401
+ body: z.ZodObject<{
402
+ id: z.ZodString;
403
+ }, z.core.$strip>;
404
+ metadata: {
405
+ openapi: {
406
+ operationId: string;
407
+ summary: string;
408
+ description: string;
409
+ };
410
+ };
411
+ } & {
412
+ use: any[];
413
+ };
414
+ path: "/sentinel/unblock";
415
+ };
416
+ deleteExpired: {
417
+ <AsResponse extends boolean = false, ReturnHeaders extends boolean = false>(inputCtx_0?: ({
418
+ body?: undefined;
419
+ } & {
420
+ method?: "POST" | undefined;
421
+ } & {
422
+ query?: Record<string, any> | undefined;
423
+ } & {
424
+ params?: Record<string, any>;
425
+ } & {
426
+ request?: Request;
427
+ } & {
428
+ headers?: HeadersInit;
429
+ } & {
430
+ asResponse?: boolean;
431
+ returnHeaders?: boolean;
432
+ use?: import("better-call").Middleware[];
433
+ path?: string;
434
+ } & {
435
+ asResponse?: AsResponse | undefined;
436
+ returnHeaders?: ReturnHeaders | undefined;
437
+ }) | undefined): Promise<[AsResponse] extends [true] ? Response : [ReturnHeaders] extends [true] ? {
438
+ headers: Headers;
439
+ response: {
440
+ success: boolean;
441
+ };
442
+ } : {
443
+ success: boolean;
444
+ }>;
445
+ options: {
446
+ method: "POST";
447
+ metadata: {
448
+ SERVER_ONLY: true;
449
+ client: boolean;
450
+ };
451
+ } & {
452
+ use: any[];
453
+ };
454
+ path: "/sentinel/delete-expired";
455
+ };
456
+ };
213
457
  $ERROR_CODES: {
214
458
  readonly POW_CHALLENGE_REQUIRED: "Challenge required";
215
459
  readonly SECURITY_BLOCKED: "Request blocked for security reasons";
460
+ readonly SECURITY_ADMIN_REQUIRED: "Only an administrator can manage security blocks";
461
+ readonly BLOCK_NOT_FOUND: "That block doesn't exist or has ended";
216
462
  };
217
463
  options: {
218
464
  failOpen: boolean;
@@ -238,6 +484,7 @@ export declare const sentinel: (options?: SentinelOptions | undefined) => {
238
484
  isBot?: ((request: Request) => boolean | Promise<boolean>) | undefined;
239
485
  resolveGeo?: ((ip: string) => GeoLocation | null | Promise<GeoLocation | null>) | undefined;
240
486
  } | undefined;
487
+ adminRoles?: string[] | undefined;
241
488
  sendNotification?: ((notification: {
242
489
  type: "unknown-device" | "stale-account";
243
490
  recipient: "user" | "admin";
@@ -255,9 +502,7 @@ export declare const sentinel: (options?: SentinelOptions | undefined) => {
255
502
  credentialStuffing?: {
256
503
  enabled: boolean;
257
504
  action?: SecurityAction | undefined;
258
- thresholds
259
- /** Checked with the identification service, rather than taken as sent */
260
- ? /** Checked with the identification service, rather than taken as sent */: {
505
+ thresholds?: {
261
506
  challenge: number;
262
507
  block: number;
263
508
  } | undefined;
@@ -29,6 +29,43 @@ export declare const schema: {
29
29
  };
30
30
  };
31
31
  };
32
+ /** Active blocks, so an admin can list and lift them */
33
+ sentinelBlock: {
34
+ fields: {
35
+ /** The counter the block is kept under, e.g. `cs:ip:203.0.113.1` */
36
+ key: {
37
+ type: "string";
38
+ required: true;
39
+ unique: true;
40
+ };
41
+ feature: {
42
+ type: "string";
43
+ required: true;
44
+ };
45
+ /** What was blocked: a visitor id or an IP address */
46
+ kind: {
47
+ type: "string";
48
+ required: true;
49
+ };
50
+ identifier: {
51
+ type: "string";
52
+ required: true;
53
+ };
54
+ /** The account the attempts were on, when the block is for one */
55
+ account: {
56
+ type: "string";
57
+ required: false;
58
+ };
59
+ blockedUntil: {
60
+ type: "date";
61
+ required: true;
62
+ };
63
+ createdAt: {
64
+ type: "date";
65
+ required: true;
66
+ };
67
+ };
68
+ };
32
69
  sentinelSignIn: {
33
70
  fields: {
34
71
  userId: {
@@ -9,11 +9,26 @@ type StoredChallenge = {
9
9
  visitorId: string | null;
10
10
  expiresAt: Date;
11
11
  };
12
+ type BlockRow = {
13
+ id: string;
14
+ key: string;
15
+ feature: string;
16
+ kind: string;
17
+ identifier: string;
18
+ account: string | null;
19
+ blockedUntil: Date;
20
+ createdAt: Date;
21
+ };
12
22
  /**
13
23
  * Deletes expired counters and challenges from the database, at most every
14
24
  * 10 seconds per auth instance. Secondary storage expires them itself.
15
25
  */
16
26
  export declare function deleteAllExpiredRows(auth: AuthContext, byPassLastCheckTime?: boolean): Promise<void>;
27
+ /**
28
+ * Deletes blocks that ended a while ago, at most every 10 seconds per auth
29
+ * instance. Blocks live in the database even with secondary storage.
30
+ */
31
+ export declare function deleteExpiredBlocks(auth: AuthContext, byPassLastCheckTime?: boolean): Promise<void>;
17
32
  /**
18
33
  * Counters and challenges, kept in secondary storage when it's configured
19
34
  * and in the database otherwise
@@ -32,6 +47,25 @@ export declare function createSentinelStore(auth: AuthContext): {
32
47
  }): Promise<number>;
33
48
  /** Returns a counter's current value, or 0 when it's missing or expired */
34
49
  get(name: string): Promise<number>;
50
+ /** Records a block, replacing an earlier one for the same counter */
51
+ recordBlock(block: {
52
+ key: string;
53
+ feature: string;
54
+ kind: string;
55
+ identifier: string;
56
+ account: string | null;
57
+ blockedUntil: Date;
58
+ }): Promise<void>;
59
+ /** Blocks that haven't ended, the newest first */
60
+ listBlocks(page: {
61
+ limit: number;
62
+ offset: number;
63
+ }): Promise<{
64
+ blocks: BlockRow[];
65
+ total: number;
66
+ }>;
67
+ /** Lifts a block. Returns it, or null when there's no active block with this id. */
68
+ removeBlock(id: string): Promise<BlockRow | null>;
35
69
  reset(name: string): Promise<void>;
36
70
  saveChallenge(challenge: StoredChallenge): Promise<void>;
37
71
  /**
@@ -108,6 +108,13 @@ export interface SentinelOptions {
108
108
  */
109
109
  resolveGeo?: ((ip: string) => GeoLocation | null | Promise<GeoLocation | null>) | undefined;
110
110
  } | undefined;
111
+ /**
112
+ * Roles allowed to list and lift blocks through `/sentinel/blocks` and
113
+ * `/sentinel/unblock`
114
+ *
115
+ * @default ["admin"]
116
+ */
117
+ adminRoles?: string[] | undefined;
111
118
  /**
112
119
  * Send a security notification, e.g. by email. Required for
113
120
  * `unknownDeviceNotification` and the stale account notifications.
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Whether a user's role field, a single role or a comma separated list,
3
+ * includes one of the given roles
4
+ */
5
+ export declare function hasRole(roleField: unknown, roles: string[]): boolean;