@revealui/auth 0.3.8 → 0.4.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 +1 @@
1
- {"version":3,"file":"mfa.d.ts","sourceRoot":"","sources":["../../src/server/mfa.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAaH,MAAM,WAAW,SAAS;IACxB,sDAAsD;IACtD,eAAe,EAAE,MAAM,CAAC;IACxB,8EAA8E;IAC9E,gBAAgB,EAAE,MAAM,CAAC;IACzB,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAC;CAChB;AAUD,wBAAgB,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,IAAI,CAEhE;AAED,wBAAgB,cAAc,IAAI,IAAI,CAErC;AA2ED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iCAAiC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAuC7F;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAsC/C;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA+B/C;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAuCxE;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAwBvE;AAED;;;;GAIG;AACH,MAAM,MAAM,eAAe,GACvB;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,IAAI,CAAA;CAAE,CAAC;AAE1C;;GAEG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,eAAe,GACrB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAgD/C;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAUnE"}
1
+ {"version":3,"file":"mfa.d.ts","sourceRoot":"","sources":["../../src/server/mfa.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAcH,MAAM,WAAW,SAAS;IACxB,sDAAsD;IACtD,eAAe,EAAE,MAAM,CAAC;IACxB,8EAA8E;IAC9E,gBAAgB,EAAE,MAAM,CAAC;IACzB,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAC;CAChB;AAUD,wBAAgB,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,IAAI,CAEhE;AAED,wBAAgB,cAAc,IAAI,IAAI,CAErC;AA2ED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iCAAiC;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,yCAAyC;IACzC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CA0C7F;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAyC/C;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAkC/C;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAuCxE;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAwBvE;AAED;;;;GAIG;AACH,MAAM,MAAM,eAAe,GACvB;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,IAAI,CAAA;CAAE,CAAC;AAE1C;;GAEG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,eAAe,GACrB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAgD/C;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAUnE"}
@@ -7,6 +7,7 @@
7
7
  import { randomBytes, timingSafeEqual } from 'node:crypto';
8
8
  import { TwoFactorAuth } from '@revealui/core/security';
9
9
  import { getClient } from '@revealui/db/client';
10
+ import { decryptFieldOrPassthrough, encryptField } from '@revealui/db/crypto';
10
11
  import { users } from '@revealui/db/schema';
11
12
  import bcrypt from 'bcryptjs';
12
13
  import { eq } from 'drizzle-orm';
@@ -100,11 +101,13 @@ export async function initiateMFASetup(userId, email) {
100
101
  const secret = TwoFactorAuth.generateSecret();
101
102
  const { plaintext, hashed } = await generateBackupCodes();
102
103
  const uri = buildProvisioningUri(secret, email);
103
- // Store secret and backup codes (MFA stays disabled until verified)
104
+ // Encrypt TOTP secret before storage (AES-256-GCM, KEK from REVEALUI_KEK)
105
+ const encryptedSecret = encryptField(secret);
106
+ // Store encrypted secret and backup codes (MFA stays disabled until verified)
104
107
  await db
105
108
  .update(users)
106
109
  .set({
107
- mfaSecret: secret,
110
+ mfaSecret: encryptedSecret,
108
111
  mfaBackupCodes: hashed,
109
112
  updatedAt: new Date(),
110
113
  })
@@ -136,8 +139,10 @@ export async function verifyMFASetup(userId, code) {
136
139
  if (!user.mfaSecret) {
137
140
  return { success: false, error: 'MFA setup not initiated' };
138
141
  }
139
- // Verify the TOTP code against the stored secret
140
- const valid = TwoFactorAuth.verifyCode(user.mfaSecret, code);
142
+ // Decrypt TOTP secret (supports legacy plaintext for rolling migration)
143
+ const plainSecret = decryptFieldOrPassthrough(user.mfaSecret);
144
+ // Verify the TOTP code against the decrypted secret
145
+ const valid = TwoFactorAuth.verifyCode(plainSecret, code);
141
146
  if (!valid) {
142
147
  return { success: false, error: 'Invalid verification code' };
143
148
  }
@@ -172,7 +177,9 @@ export async function verifyMFACode(userId, code) {
172
177
  if (!(user?.mfaEnabled && user.mfaSecret)) {
173
178
  return { success: false, error: 'MFA not enabled' };
174
179
  }
175
- const matchedCounter = verifyCodeWithCounter(user.mfaSecret, code);
180
+ // Decrypt TOTP secret (supports legacy plaintext for rolling migration)
181
+ const plainSecret = decryptFieldOrPassthrough(user.mfaSecret);
182
+ const matchedCounter = verifyCodeWithCounter(plainSecret, code);
176
183
  if (matchedCounter === null) {
177
184
  return { success: false, error: 'Invalid code' };
178
185
  }
@@ -55,7 +55,7 @@ export interface UpsertOAuthOptions {
55
55
  * 1. Look up oauth_accounts by (provider, providerUserId) → get userId
56
56
  * 2. If found: refresh metadata + return user
57
57
  * 3. If not found: check users by email → link if match (with consent) or throw
58
- * 4. If no match: create new user (role: 'user', no password)
58
+ * 4. If no match: create new user (role: 'viewer', no password)
59
59
  * 5. Insert oauth_accounts row
60
60
  */
61
61
  export declare function upsertOAuthUser(provider: string, providerUser: ProviderUser, options?: UpsertOAuthOptions): Promise<User>;
@@ -153,7 +153,7 @@ export async function fetchProviderUser(provider, accessToken) {
153
153
  * 1. Look up oauth_accounts by (provider, providerUserId) → get userId
154
154
  * 2. If found: refresh metadata + return user
155
155
  * 3. If not found: check users by email → link if match (with consent) or throw
156
- * 4. If no match: create new user (role: 'user', no password)
156
+ * 4. If no match: create new user (role: 'viewer', no password)
157
157
  * 5. Insert oauth_accounts row
158
158
  */
159
159
  export async function upsertOAuthUser(provider, providerUser, options) {
@@ -227,7 +227,7 @@ export async function upsertOAuthUser(provider, providerUser, options) {
227
227
  email: providerUser.email,
228
228
  avatarUrl: providerUser.avatarUrl,
229
229
  password: null,
230
- role: 'user',
230
+ role: 'viewer',
231
231
  status: 'active',
232
232
  });
233
233
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@revealui/auth",
3
- "version": "0.3.8",
3
+ "version": "0.4.0",
4
4
  "description": "Authentication system for RevealUI - database-backed sessions with Better Auth patterns",
5
5
  "keywords": [
6
6
  "auth",
@@ -14,11 +14,11 @@
14
14
  "bcryptjs": "^3.0.3",
15
15
  "drizzle-orm": "^0.45.2",
16
16
  "zod": "^4.3.6",
17
- "@revealui/config": "0.3.4",
18
- "@revealui/contracts": "1.3.7",
19
- "@revealui/core": "0.5.6",
20
- "@revealui/db": "0.3.7",
21
- "@revealui/security": "0.2.7"
17
+ "@revealui/config": "0.4.0",
18
+ "@revealui/contracts": "1.4.0",
19
+ "@revealui/core": "0.6.0",
20
+ "@revealui/db": "0.4.0",
21
+ "@revealui/security": "0.3.0"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@simplewebauthn/browser": "^13.3.0",
@@ -26,7 +26,7 @@
26
26
  "@types/node": "^25.5.2",
27
27
  "@types/react": "^19.2.14",
28
28
  "@vitest/coverage-v8": "^4.1.3",
29
- "happy-dom": "^20.8.9",
29
+ "happy-dom": "^20.9.0",
30
30
  "react": "^19.2.5",
31
31
  "typescript": "^6.0.2",
32
32
  "vitest": "^4.1.3",