@@ -4,7 +4,6 @@ import { createLogger } from '@sim/logger'
44import { hmacSha256Hex } from '@sim/security/hmac'
55import { getErrorMessage } from '@sim/utils/errors'
66import { and , eq , gt , inArray , lte , sql } from 'drizzle-orm'
7- import { isSignInProviderAllowed , SIGN_IN_PROVIDER_IDS } from '@/lib/auth/constants'
87import { env } from '@/lib/core/config/env'
98import { isBillingEnabled } from '@/lib/core/config/env-flags'
109import type { DbOrTx } from '@/lib/db/types'
@@ -14,7 +13,7 @@ import type { DbOrTx } from '@/lib/db/types'
1413 *
1514 * The free allowance is a one-time grant per person, but deletion erases the
1615 * account row and the usage ledger with it, so without this a person could
17- * delete and re-register the same Google , GitHub, or email identity for a fresh
16+ * delete and re-register the same email , GitHub, or Microsoft identity for a fresh
1817 * allowance each time. Deletion keeps only keyed one-way digests of the
1918 * account's sign-in identities; a new account on a matching identity is created
2019 * normally but without the free allowance. This is the "one free trial per
@@ -35,10 +34,12 @@ const logger = createLogger('DeletedAccountIdentity')
3534
3635/**
3736 * How long a deleted account's identity digests are kept, and so how long they
38- * withhold the free allowance from new accounts on the same identity: 365 days.
39- * Each recorded deletion restarts the window for the identities it records.
37+ * withhold the free allowance from new accounts on the same identity: 30 days,
38+ * inside the privacy policy's stated retention of Account Data "for 30 days
39+ * after a deletion request". Each recorded deletion restarts the window for
40+ * the identities it records.
4041 */
41- const DELETED_IDENTITY_RETENTION_MS = 365 * 24 * 60 * 60 * 1000
42+ const DELETED_IDENTITY_RETENTION_MS = 30 * 24 * 60 * 60 * 1000
4243
4344/** Expired rows removed per recorded deletion, which keeps the table bounded without a cron. */
4445const EXPIRED_PURGE_BATCH = 100
@@ -66,11 +67,17 @@ const PLUS_ADDRESSING_DOMAINS = new Set([
6667] )
6768
6869/**
69- * One social sign-in identity: the provider and that provider's stable subject
70- * id. Only `SIGN_IN_PROVIDER_IDS` count; integration connections share the
71- * `account` table but carry per-connection ids, and the email/password row's
72- * `accountId` is the user id itself.
70+ * Sign-in providers whose subject ids are recorded and matched. Google is left
71+ * out: the privacy policy keeps Google API data only 7 days after deletion, and
72+ * a Google re-signup is still caught by its email digest. Integration
73+ * connections share the `account` table but carry per-connection ids, and the
74+ * email/password row's `accountId` is the user id itself, so neither counts.
7375 */
76+ const RECORDED_SIGN_IN_PROVIDER_IDS = [ 'github' , 'microsoft' ] as const
77+
78+ const recordedSignInProviderIdSet : ReadonlySet < string > = new Set ( RECORDED_SIGN_IN_PROVIDER_IDS )
79+
80+ /** One social sign-in identity: the provider and that provider's stable subject id. */
7481interface OAuthSubject {
7582 providerId : string
7683 accountId : string
@@ -114,7 +121,7 @@ function identityHashes(identity: SignInIdentity): string[] {
114121 const email = identity . email ? canonicalizeEmail ( identity . email ) : null
115122 if ( email ) preimages . push ( `email:${ email } ` )
116123 for ( const subject of identity . oauthSubjects ?? [ ] ) {
117- if ( ! isSignInProviderAllowed ( subject . providerId ) || ! subject . accountId ) continue
124+ if ( ! recordedSignInProviderIdSet . has ( subject . providerId ) || ! subject . accountId ) continue
118125 preimages . push ( `oauth:${ subject . providerId } :${ subject . accountId } ` )
119126 }
120127 const key = getIdentityKey ( )
@@ -131,7 +138,12 @@ async function loadSignInIdentity(executor: DbOrTx, userId: string): Promise<Sig
131138 const oauthSubjects = await executor
132139 . select ( { providerId : account . providerId , accountId : account . accountId } )
133140 . from ( account )
134- . where ( and ( eq ( account . userId , userId ) , inArray ( account . providerId , [ ...SIGN_IN_PROVIDER_IDS ] ) ) )
141+ . where (
142+ and (
143+ eq ( account . userId , userId ) ,
144+ inArray ( account . providerId , [ ...RECORDED_SIGN_IN_PROVIDER_IDS ] )
145+ )
146+ )
135147 return { email : profile ?. email , oauthSubjects }
136148}
137149
0 commit comments