@absolutejs/auth 0.48.7 → 0.49.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.
@@ -1,6 +1,6 @@
1
1
  import { Elysia } from 'elysia';
2
2
  import { type MfaRouteProps } from './config';
3
- export declare const mfaChallenge: <UserType>({ authSessionStore, challengeRoute, cookieSecure, encryptionKey, getChallengeUser, getUserId, mfaStore, onMfaChallengeError, onMfaChallengeSuccess, sessionDurationMs }: MfaRouteProps<UserType>) => Elysia<"", {
3
+ export declare const mfaChallenge: <UserType>({ authSessionStore, challengeRoute, cookieSecure, encryptionKey, getChallengeUser, getUserId, mfaStore, onMfaChallengeError, onMfaChallengeSuccess, onSendSmsCode, sessionDurationMs, smsCodeLength, smsCodeTtlMs, smsMaxAttempts }: MfaRouteProps<UserType>) => Elysia<"", {
4
4
  decorator: {};
5
5
  store: {
6
6
  session: import("..").SessionRecord<UserType>;
@@ -22,14 +22,19 @@ export declare const mfaChallenge: <UserType>({ authSessionStore, challengeRoute
22
22
  [x: string]: {
23
23
  post: {
24
24
  body: {
25
- code: string;
25
+ code?: string | undefined;
26
+ action?: "verify" | "send" | undefined;
27
+ factor?: "sms" | undefined;
26
28
  };
27
29
  params: {};
28
30
  query: unknown;
29
31
  headers: unknown;
30
32
  response: {
31
- 401: "No MFA challenge in progress" | "Invalid MFA code";
33
+ 400: "SMS code required" | "No SMS code in progress";
34
+ 401: "SMS code expired" | "Too many attempts" | "No MFA challenge in progress" | "Invalid MFA code";
32
35
  200: {
36
+ readonly status: "sent";
37
+ } | {
33
38
  readonly status: "authenticated";
34
39
  };
35
40
  422: {
@@ -4,6 +4,14 @@ import type { MFAStore } from './types';
4
4
  export declare const DEFAULT_BACKUP_CODE_COUNT = 10;
5
5
  export declare const DEFAULT_MFA_ISSUER = "AbsoluteAuth";
6
6
  export declare const DEFAULT_MFA_SESSION_TTL_MS: number;
7
+ export declare const DEFAULT_SMS_CODE_LENGTH = 6;
8
+ export declare const DEFAULT_SMS_CODE_TTL_MS: number;
9
+ export declare const DEFAULT_SMS_MAX_ATTEMPTS = 3;
10
+ export type SmsCodeMessage = {
11
+ code: string;
12
+ expiresAt: number;
13
+ phone: string;
14
+ };
7
15
  export type MfaConfig<UserType> = {
8
16
  mfaStore: MFAStore;
9
17
  getUserId: (user: UserType) => string;
@@ -23,7 +31,13 @@ export type MfaConfig<UserType> = {
23
31
  onMfaEnrolled?: (context: {
24
32
  userId: string;
25
33
  }) => void | Promise<void>;
34
+ onSendSmsCode?: (message: SmsCodeMessage) => void | Promise<void>;
26
35
  sessionDurationMs?: number;
36
+ smsCodeLength?: number;
37
+ smsCodeTtlMs?: number;
38
+ smsMaxAttempts?: number;
39
+ smsSetupRoute?: RouteString;
40
+ smsVerifyRoute?: RouteString;
27
41
  totpSetupRoute?: RouteString;
28
42
  totpVerifyRoute?: RouteString;
29
43
  };
@@ -49,6 +49,81 @@ export declare const mfaEnrollmentsTable: import("drizzle-orm/pg-core").PgTableW
49
49
  identity: undefined;
50
50
  generated: undefined;
51
51
  }>;
52
+ sms_failed_attempts: import("drizzle-orm/pg-core").PgBuildColumn<"auth_mfa_enrollments", import("drizzle-orm/pg-core").SetHasDefault<import("drizzle-orm/pg-core").SetNotNull<import("drizzle-orm/pg-core").PgSmallIntBuilder>>, {
53
+ name: string;
54
+ tableName: "auth_mfa_enrollments";
55
+ dataType: "number int16";
56
+ data: number;
57
+ driverParam: string | number;
58
+ notNull: true;
59
+ hasDefault: true;
60
+ isPrimaryKey: false;
61
+ isAutoincrement: false;
62
+ hasRuntimeDefault: false;
63
+ enumValues: undefined;
64
+ identity: undefined;
65
+ generated: undefined;
66
+ }>;
67
+ sms_pending_code_expires_at_ms: import("drizzle-orm/pg-core").PgBuildColumn<"auth_mfa_enrollments", import("drizzle-orm/pg-core").PgBigInt53Builder, {
68
+ name: string;
69
+ tableName: "auth_mfa_enrollments";
70
+ dataType: "number int53";
71
+ data: number;
72
+ driverParam: string | number;
73
+ notNull: false;
74
+ hasDefault: false;
75
+ isPrimaryKey: false;
76
+ isAutoincrement: false;
77
+ hasRuntimeDefault: false;
78
+ enumValues: undefined;
79
+ identity: undefined;
80
+ generated: undefined;
81
+ }>;
82
+ sms_pending_code_hash: import("drizzle-orm/pg-core").PgBuildColumn<"auth_mfa_enrollments", import("drizzle-orm/pg-core").PgTextBuilder<[string, ...string[]]>, {
83
+ name: string;
84
+ tableName: "auth_mfa_enrollments";
85
+ dataType: "string";
86
+ data: string;
87
+ driverParam: string;
88
+ notNull: false;
89
+ hasDefault: false;
90
+ isPrimaryKey: false;
91
+ isAutoincrement: false;
92
+ hasRuntimeDefault: false;
93
+ enumValues: undefined;
94
+ identity: undefined;
95
+ generated: undefined;
96
+ }>;
97
+ sms_phone: import("drizzle-orm/pg-core").PgBuildColumn<"auth_mfa_enrollments", import("drizzle-orm/pg-core").PgVarcharBuilder<[string, ...string[]]>, {
98
+ name: string;
99
+ tableName: "auth_mfa_enrollments";
100
+ dataType: "string";
101
+ data: string;
102
+ driverParam: string;
103
+ notNull: false;
104
+ hasDefault: false;
105
+ isPrimaryKey: false;
106
+ isAutoincrement: false;
107
+ hasRuntimeDefault: false;
108
+ enumValues: undefined;
109
+ identity: undefined;
110
+ generated: undefined;
111
+ }>;
112
+ sms_verified: import("drizzle-orm/pg-core").PgBuildColumn<"auth_mfa_enrollments", import("drizzle-orm/pg-core").SetHasDefault<import("drizzle-orm/pg-core").SetNotNull<import("drizzle-orm/pg-core").PgBooleanBuilder>>, {
113
+ name: string;
114
+ tableName: "auth_mfa_enrollments";
115
+ dataType: "boolean";
116
+ data: boolean;
117
+ driverParam: boolean;
118
+ notNull: true;
119
+ hasDefault: true;
120
+ isPrimaryKey: false;
121
+ isAutoincrement: false;
122
+ hasRuntimeDefault: false;
123
+ enumValues: undefined;
124
+ identity: undefined;
125
+ generated: undefined;
126
+ }>;
52
127
  totp_secret_ciphertext: import("drizzle-orm/pg-core").PgBuildColumn<"auth_mfa_enrollments", import("drizzle-orm/pg-core").PgTextBuilder<[string, ...string[]]>, {
53
128
  name: string;
54
129
  tableName: "auth_mfa_enrollments";
@@ -70,6 +70,34 @@ export declare const mfaRoutes: <UserType>(config: MfaRouteProps<UserType>) => E
70
70
  };
71
71
  };
72
72
  };
73
+ } & {
74
+ [x: string]: {
75
+ post: {
76
+ body: {
77
+ phone: string;
78
+ };
79
+ params: {};
80
+ query: unknown;
81
+ headers: unknown;
82
+ response: {
83
+ 400: "Phone must be in E.164 format";
84
+ 401: "Authentication required";
85
+ 501: "SMS MFA is not configured";
86
+ 200: {
87
+ readonly phone: string;
88
+ };
89
+ 422: {
90
+ type: "validation";
91
+ on: string;
92
+ summary?: string;
93
+ message?: string;
94
+ found?: unknown;
95
+ property?: string;
96
+ expected?: string;
97
+ };
98
+ };
99
+ };
100
+ };
73
101
  } & {
74
102
  [x: string]: {
75
103
  post: {
@@ -80,8 +108,41 @@ export declare const mfaRoutes: <UserType>(config: MfaRouteProps<UserType>) => E
80
108
  query: unknown;
81
109
  headers: unknown;
82
110
  response: {
83
- 401: "No MFA challenge in progress" | "Invalid MFA code";
111
+ 400: "No SMS enrollment in progress" | "SMS code expired" | "Invalid SMS code";
112
+ 401: "Authentication required";
113
+ 200: {
114
+ readonly status: "enrolled";
115
+ };
116
+ 422: {
117
+ type: "validation";
118
+ on: string;
119
+ summary?: string;
120
+ message?: string;
121
+ found?: unknown;
122
+ property?: string;
123
+ expected?: string;
124
+ };
125
+ 429: "Too many attempts";
126
+ };
127
+ };
128
+ };
129
+ } & {
130
+ [x: string]: {
131
+ post: {
132
+ body: {
133
+ code?: string | undefined;
134
+ action?: "verify" | "send" | undefined;
135
+ factor?: "sms" | undefined;
136
+ };
137
+ params: {};
138
+ query: unknown;
139
+ headers: unknown;
140
+ response: {
141
+ 400: "SMS code required" | "No SMS code in progress";
142
+ 401: "SMS code expired" | "Too many attempts" | "No MFA challenge in progress" | "Invalid MFA code";
84
143
  200: {
144
+ readonly status: "sent";
145
+ } | {
85
146
  readonly status: "authenticated";
86
147
  };
87
148
  422: {
@@ -0,0 +1,105 @@
1
+ import { Elysia } from 'elysia';
2
+ import { type MfaRouteProps, type SmsCodeMessage } from './config';
3
+ import type { MfaEnrollment, MFAStore } from './types';
4
+ export declare const isE164Phone: (phone: string) => boolean;
5
+ export declare const issueAndStoreSmsCode: ({ codeLength, enrollment, mfaStore, onSendSmsCode, ttlMs }: {
6
+ codeLength: number;
7
+ enrollment: MfaEnrollment;
8
+ mfaStore: MFAStore;
9
+ onSendSmsCode?: (message: SmsCodeMessage) => void | Promise<void>;
10
+ ttlMs: number;
11
+ }) => Promise<number | undefined>;
12
+ export declare const maskPhone: (phone: string) => string;
13
+ export declare const mfaSmsRoutes: <UserType>({ authSessionStore, getUserId, mfaStore, onMfaEnrolled, onSendSmsCode, smsCodeLength, smsCodeTtlMs, smsMaxAttempts, smsSetupRoute, smsVerifyRoute }: MfaRouteProps<UserType>) => Elysia<"", {
14
+ decorator: {};
15
+ store: {
16
+ session: import("..").SessionRecord<UserType>;
17
+ unregisteredSession: import("..").UnregisteredSessionRecord;
18
+ };
19
+ derive: {};
20
+ resolve: {};
21
+ }, {
22
+ typebox: {};
23
+ error: {};
24
+ }, {
25
+ schema: {};
26
+ standaloneSchema: {};
27
+ macro: {};
28
+ macroFn: {};
29
+ parser: {};
30
+ response: {};
31
+ }, {
32
+ [x: string]: {
33
+ post: {
34
+ body: {
35
+ phone: string;
36
+ };
37
+ params: {};
38
+ query: unknown;
39
+ headers: unknown;
40
+ response: {
41
+ 400: "Phone must be in E.164 format";
42
+ 401: "Authentication required";
43
+ 501: "SMS MFA is not configured";
44
+ 200: {
45
+ readonly phone: string;
46
+ };
47
+ 422: {
48
+ type: "validation";
49
+ on: string;
50
+ summary?: string;
51
+ message?: string;
52
+ found?: unknown;
53
+ property?: string;
54
+ expected?: string;
55
+ };
56
+ };
57
+ };
58
+ };
59
+ } & {
60
+ [x: string]: {
61
+ post: {
62
+ body: {
63
+ code: string;
64
+ };
65
+ params: {};
66
+ query: unknown;
67
+ headers: unknown;
68
+ response: {
69
+ 400: "No SMS enrollment in progress" | "SMS code expired" | "Invalid SMS code";
70
+ 401: "Authentication required";
71
+ 200: {
72
+ readonly status: "enrolled";
73
+ };
74
+ 422: {
75
+ type: "validation";
76
+ on: string;
77
+ summary?: string;
78
+ message?: string;
79
+ found?: unknown;
80
+ property?: string;
81
+ expected?: string;
82
+ };
83
+ 429: "Too many attempts";
84
+ };
85
+ };
86
+ };
87
+ }, {
88
+ derive: {};
89
+ resolve: {};
90
+ schema: {};
91
+ standaloneSchema: {};
92
+ response: {};
93
+ }, {
94
+ derive: {};
95
+ resolve: {};
96
+ schema: {};
97
+ standaloneSchema: {};
98
+ response: {};
99
+ } & {
100
+ derive: {};
101
+ resolve: {};
102
+ schema: {};
103
+ standaloneSchema: {};
104
+ response: {};
105
+ }>;
@@ -1,8 +1,13 @@
1
- export type MfaFactorType = 'backup_codes' | 'totp';
1
+ export type MfaFactorType = 'backup_codes' | 'sms' | 'totp';
2
2
  export type MfaEnrollment = {
3
3
  backupCodeHashes: string[];
4
4
  createdAt: number;
5
5
  lastUsedAt?: number;
6
+ smsFailedAttempts?: number;
7
+ smsPendingCodeHash?: string;
8
+ smsPendingCodeExpiresAt?: number;
9
+ smsPhone?: string;
10
+ smsVerified: boolean;
6
11
  totpSecretCiphertext?: string;
7
12
  totpVerified: boolean;
8
13
  updatedAt: number;
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.48.7",
2
+ "version": "0.49.0",
3
3
  "name": "@absolutejs/auth",
4
4
  "description": "An authorization library for absolutejs",
5
5
  "repository": {