diff --git a/packages/pds/src/api/com/atproto/server/createAccount.ts b/packages/pds/src/api/com/atproto/server/createAccount.ts index 77af9a180bb..1f487c2b770 100644 --- a/packages/pds/src/api/com/atproto/server/createAccount.ts +++ b/packages/pds/src/api/com/atproto/server/createAccount.ts @@ -44,33 +44,11 @@ export default function (server: Server, ctx: AppContext) { const now = new Date().toISOString() const passwordScrypt = await scrypt.genSaltAndHash(password) - let verificationPhone: string | undefined = undefined - if (ctx.cfg.phoneVerification.required && ctx.twilio) { - if (!input.body.verificationPhone) { - throw new InvalidRequestError( - `Text verification is now required on this server. Please make sure you're using the latest version of the Bluesky app.`, - 'InvalidPhoneVerification', - ) - } else if (!input.body.verificationCode) { - throw new InvalidRequestError( - `Text verification is now required on this server. Please make sure you're using the latest version of the Bluesky app.`, - 'InvalidPhoneVerification', - ) - } - verificationPhone = ctx.twilio.normalizePhoneNumber( - input.body.verificationPhone, - ) - const verified = await ctx.twilio.verifyCode( - verificationPhone, - input.body.verificationCode.trim(), - ) - if (!verified) { - throw new InvalidRequestError( - 'Could not verify phone number. Please try again.', - 'InvalidPhoneVerification', - ) - } - } + const verificationPhone = await ensurePhoneVerification( + ctx, + input.body.verificationPhone, + input.body.verificationCode?.trim(), + ) const result = await ctx.db.transaction(async (dbTxn) => { const actorTxn = ctx.services.account(dbTxn) @@ -491,6 +469,42 @@ const ensureUnusedHandleAndEmail = async ( } } +const ensurePhoneVerification = async ( + ctx: AppContext, + phone?: string, + code?: string, +): Promise => { + if (!ctx.cfg.phoneVerification.required || !ctx.twilio) { + return + } + + if (!phone) { + throw new InvalidRequestError( + `Text verification is now required on this server. Please make sure you're using the latest version of the Bluesky app.`, + 'InvalidPhoneVerification', + ) + } + if (ctx.cfg.phoneVerification.bypassPhoneNumber === phone) { + return undefined + } + + if (!code) { + throw new InvalidRequestError( + `Text verification is now required on this server. Please make sure you're using the latest version of the Bluesky app.`, + 'InvalidPhoneVerification', + ) + } + const normalizedPhone = ctx.twilio.normalizePhoneNumber(phone) + const verified = await ctx.twilio.verifyCode(normalizedPhone, code) + if (!verified) { + throw new InvalidRequestError( + 'Could not verify phone number. Please try again.', + 'InvalidPhoneVerification', + ) + } + return normalizedPhone +} + const randomIndexByWeight = (weights) => { let sum = 0 const cumulative = weights.map((weight) => { diff --git a/packages/pds/src/config/config.ts b/packages/pds/src/config/config.ts index 6652a2a29eb..a96462e05ab 100644 --- a/packages/pds/src/config/config.ts +++ b/packages/pds/src/config/config.ts @@ -137,6 +137,7 @@ export const envToCfg = (env: ServerEnvironment): ServerConfig => { twilioAccountSid: env.twilioAccountSid, twilioServiceSid: env.twilioServiceSid, accountsPerPhoneNumber: env.accountsPerPhoneNumber ?? 3, + bypassPhoneNumber: env.bypassPhoneNumber, } } @@ -322,6 +323,7 @@ export type PhoneVerificationConfig = twilioAccountSid: string twilioServiceSid: string accountsPerPhoneNumber: number + bypassPhoneNumber?: string } | { required: false diff --git a/packages/pds/src/config/env.ts b/packages/pds/src/config/env.ts index 1d332f9b8ff..324d74889db 100644 --- a/packages/pds/src/config/env.ts +++ b/packages/pds/src/config/env.ts @@ -52,6 +52,7 @@ export const readEnv = (): ServerEnvironment => { // phone verification phoneVerificationRequired: envBool('PDS_PHONE_VERIFICATION_REQUIRED'), accountsPerPhoneNumber: envInt('PDS_ACCOUNTS_PER_PHONE_NUMBER'), + bypassPhoneNumber: envStr('PDS_BYPASS_PHONE_NUMBER'), twilioAccountSid: envStr('PDS_TWILIO_ACCOUNT_SID'), twilioAuthToken: envStr('PDS_TWILIO_AUTH_TOKEN'), twilioServiceSid: envStr('PDS_TWILIO_SERVICE_SID'), @@ -166,6 +167,7 @@ export type ServerEnvironment = { // phone verification phoneVerificationRequired?: boolean accountsPerPhoneNumber?: number + bypassPhoneNumber?: string twilioAccountSid?: string twilioAuthToken?: string twilioServiceSid?: string