Skip to content

Commit 67b6a5e

Browse files
committed
fix: cap MX cache size, deduplicate validateCallbackUrl, add slug duplicate guard
1 parent 947349f commit 67b6a5e

3 files changed

Lines changed: 21 additions & 5 deletions

File tree

apps/sim/app/(auth)/login/login-form.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,13 +106,13 @@ export default function LoginPage({
106106
const buttonClass = useBrandedButtonClass()
107107

108108
const callbackUrlParam = searchParams?.get('callbackUrl')
109+
const isValidCallbackUrl = callbackUrlParam ? validateCallbackUrl(callbackUrlParam) : false
109110
const invalidCallbackRef = useRef(false)
110-
if (callbackUrlParam && !validateCallbackUrl(callbackUrlParam) && !invalidCallbackRef.current) {
111+
if (callbackUrlParam && !isValidCallbackUrl && !invalidCallbackRef.current) {
111112
invalidCallbackRef.current = true
112113
logger.warn('Invalid callback URL detected and blocked:', { url: callbackUrlParam })
113114
}
114-
const callbackUrl =
115-
callbackUrlParam && validateCallbackUrl(callbackUrlParam) ? callbackUrlParam : '/workspace'
115+
const callbackUrl = isValidCallbackUrl ? callbackUrlParam! : '/workspace'
116116
const isInviteFlow = searchParams?.get('invite_flow') === 'true'
117117

118118
const [forgotPasswordOpen, setForgotPasswordOpen] = useState(false)

apps/sim/app/(landing)/integrations/[slug]/page.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ const byName = new Map(allIntegrations.map((i) => [i.name, i]))
1818
const bySlug = new Map(allIntegrations.map((i) => [i.slug, i]))
1919
const byType = new Map(allIntegrations.map((i) => [i.type, i]))
2020

21+
if (process.env.NODE_ENV === 'development') {
22+
const slugsSeen = new Set<string>()
23+
for (const i of allIntegrations) {
24+
if (slugsSeen.has(i.slug)) throw new Error(`Duplicate integration slug: ${i.slug}`)
25+
slugsSeen.add(i.slug)
26+
}
27+
}
28+
2129
/** Returns workflow pairs that feature the given integration on either side. */
2230
function getPairsFor(name: string) {
2331
return POPULAR_WORKFLOWS.filter((p) => p.from === name || p.to === name)

apps/sim/lib/messaging/email/validation.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,14 @@ const DISPOSABLE_MX_BACKENDS = new Set(['in.mail.gw', 'smtp.catchmail.io', 'mx.y
6464

6565
/** Per-domain MX result cache — avoids redundant DNS queries for concurrent or repeated sign-ups */
6666
const mxCache = new Map<string, { result: boolean; expires: number }>()
67+
const MX_CACHE_MAX = 1_000
68+
69+
function setMxCache(domain: string, entry: { result: boolean; expires: number }) {
70+
if (mxCache.size >= MX_CACHE_MAX) {
71+
mxCache.delete(mxCache.keys().next().value!)
72+
}
73+
mxCache.set(domain, entry)
74+
}
6775

6876
/**
6977
* Validates email syntax using RFC 5322 compliant regex
@@ -135,10 +143,10 @@ export async function isDisposableMxBackend(email: string): Promise<boolean> {
135143
}
136144
)
137145
const result = await Promise.race([mxCheckPromise, timeoutPromise])
138-
mxCache.set(domain, { result: result.isDisposableBackend, expires: now + 5 * 60 * 1000 })
146+
setMxCache(domain, { result: result.isDisposableBackend, expires: now + 5 * 60 * 1000 })
139147
return result.isDisposableBackend
140148
} catch {
141-
mxCache.set(domain, { result: false, expires: now + 60 * 1000 })
149+
setMxCache(domain, { result: false, expires: now + 60 * 1000 })
142150
return false
143151
} finally {
144152
clearTimeout(timeoutId)

0 commit comments

Comments
 (0)