Skip to content

Commit

Permalink
ip limit on create-account
Browse files Browse the repository at this point in the history
  • Loading branch information
dholms committed Feb 7, 2024
1 parent 4518208 commit c296c76
Showing 1 changed file with 31 additions and 1 deletion.
32 changes: 31 additions & 1 deletion packages/pds/src/api/com/atproto/server/createAccount.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import assert from 'node:assert'
import { MINUTE, check } from '@atproto/common'
import { HOUR, MINUTE, check } from '@atproto/common'
import { randomStr } from '@atproto/crypto'
import { AtprotoData, ensureAtpDocument } from '@atproto/identity'
import { XRPCError } from '@atproto/xrpc'
import { InvalidRequestError } from '@atproto/xrpc-server'
import * as plc from '@did-plc/lib'
import disposable from 'disposable-email'
import { RateLimiterRedis } from 'rate-limiter-flexible'
import { normalizeAndValidateHandle } from '../../../../handle'
import * as scrypt from '../../../../db/scrypt'
import { Server } from '../../../../lexicon'
Expand All @@ -23,6 +24,13 @@ import { isThisPds } from '../../../proxy'
import { dbLogger as log } from '../../../../logger'

export default function (server: Server, ctx: AppContext) {
const accountRl = new RateLimiterRedis({
storeClient: ctx.redisScratch,
keyPrefix: 'account-limiter-ip',
duration: HOUR,
points: 2,
})

server.com.atproto.server.createAccount({
rateLimit: {
durationMs: 5 * MINUTE,
Expand All @@ -36,6 +44,13 @@ export default function (server: Server, ctx: AppContext) {
`We've had a burst of activity and are temporarily limiting signups. Please check back soon!`,
)
}
const ip = req.ip
const rlStatus = await accountRl.get(ip)
if ((rlStatus?.remainingPoints ?? 0) < 1) {
throw new InvalidRequestError(
'Sorry! We are temporarily only allowing 2 signups per IP address.',
)
}

const {
did,
Expand Down Expand Up @@ -120,6 +135,14 @@ export default function (server: Server, ctx: AppContext) {
deactivated: !hasAvailability,
})

try {
await accountRl.consume(ip, 1)
} catch {
throw new InvalidRequestError(
'Sorry! We are temporarily only allowing 2 signups per IP address.',
)
}

return {
did,
pdsDid: entrywayAssignedPds?.did ?? null,
Expand Down Expand Up @@ -150,6 +173,7 @@ export default function (server: Server, ctx: AppContext) {
}
} catch (err) {
await cleanupUncreatedAccount(ctx, did)
await accountRl.reward(ip, 1)
throw err
}

Expand Down Expand Up @@ -542,3 +566,9 @@ const cleanupUncreatedAccount = async (
return cleanupUncreatedAccount(ctx, did, tries + 1)
}
}

export class LimitedSignupError extends Error {
constructor() {
super('Sorry! We are temporarily only allowing 2 signups per IP address.')
}
}

0 comments on commit c296c76

Please sign in to comment.