-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathauth-guardrails.ts
More file actions
52 lines (45 loc) · 1.83 KB
/
auth-guardrails.ts
File metadata and controls
52 lines (45 loc) · 1.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import { and, eq, sql } from 'drizzle-orm'
import type { getDb } from '../db/index.js'
import { account, passkeyCredentials, users, walletIdentities } from '../db/schema/index.js'
type Db = Awaited<ReturnType<typeof getDb>>
/**
* Returns true if the user has at least one remaining sign-in method.
* Sign-in methods: users.email, account (OAuth), wallet_identities, passkey_credentials.
*
* When checking before OAuth unlink, pass excludeProviderId to simulate removal of that account.
*/
export async function hasRemainingLoginMethod(
db: Db,
userId: string,
options?: { excludeProviderId?: string },
): Promise<boolean> {
const [user] = await db.select({ email: users.email }).from(users).where(eq(users.id, userId))
if (!user) return false
const hasEmail = user.email != null && user.email !== ''
const [oauthResult, walletResult, passkeyResult] = await Promise.all([
db
.select({ count: sql<number>`count(*)::int` })
.from(account)
.where(eq(account.userId, userId)),
db
.select({ count: sql<number>`count(*)::int` })
.from(walletIdentities)
.where(eq(walletIdentities.userId, userId)),
db
.select({ count: sql<number>`count(*)::int` })
.from(passkeyCredentials)
.where(eq(passkeyCredentials.userId, userId)),
])
let oauthCount = oauthResult[0]?.count ?? 0
const walletCount = walletResult[0]?.count ?? 0
const passkeyCount = passkeyResult[0]?.count ?? 0
if (options?.excludeProviderId && oauthCount > 0) {
const [hasProvider] = await db
.select({ count: sql<number>`count(*)::int` })
.from(account)
.where(and(eq(account.userId, userId), eq(account.providerId, options.excludeProviderId)))
if ((hasProvider?.count ?? 0) > 0) oauthCount -= 1
}
const total = (hasEmail ? 1 : 0) + oauthCount + walletCount + passkeyCount
return total >= 1
}