Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 53 additions & 2 deletions apps/web/app/api/og/route.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { hasVerifiedSession } from "@/lib/verify-session"

interface OGResponse {
title: string
description: string
Expand All @@ -13,6 +15,42 @@ function isValidUrl(urlString: string): boolean {
}
}

const MAX_HTML_BYTES = 2_000_000

// OG parsing only needs <head>, so cap the read rather than buffering the whole body.
async function readBoundedText(
response: Response,
maxBytes = MAX_HTML_BYTES,
): Promise<string | null> {
const contentLength = response.headers.get("content-length")
if (contentLength && Number(contentLength) > maxBytes) {
return null
}
if (!response.body) {
return null
}
const reader = response.body.getReader()
const chunks: Uint8Array[] = []
let total = 0
for (;;) {
const { done, value } = await reader.read()
if (done) break
total += value.byteLength
if (total > maxBytes) {
await reader.cancel().catch(() => {})
return null
}
chunks.push(value)
}
const merged = new Uint8Array(total)
let offset = 0
for (const chunk of chunks) {
merged.set(chunk, offset)
offset += chunk.byteLength
}
return new TextDecoder().decode(merged)
}

function isPrivateIPv4Octets(a: number, b: number): boolean {
// 0.0.0.0/8, 10/8, 100.64/10 (CGNAT), 127/8 (loopback),
// 169.254/16 (link-local / cloud metadata), 172.16/12, 192.168/16
Expand Down Expand Up @@ -247,6 +285,10 @@ function resolveImageUrl(

export async function GET(request: Request) {
try {
if (!(await hasVerifiedSession(request))) {
return Response.json({ error: "Unauthorized" }, { status: 401 })
}

const { searchParams } = new URL(request.url)
const url = searchParams.get("url")

Expand Down Expand Up @@ -332,7 +374,13 @@ export async function GET(request: Request) {
if (contentType && !contentType.includes("text/html")) {
return Response.json({ title: "", description: "" })
}
const html = await secondResponse.text()
const html = await readBoundedText(secondResponse)
if (html === null) {
return Response.json(
{ error: "Response too large" },
{ status: 413 },
)
}
return processHtml(html, redirectUrl)
}
}
Expand All @@ -349,7 +397,10 @@ export async function GET(request: Request) {
return Response.json({ title: "", description: "" })
}

const html = await response.text()
const html = await readBoundedText(response)
if (html === null) {
return Response.json({ error: "Response too large" }, { status: 413 })
}
return processHtml(html, trimmedUrl)
} finally {
clearTimeout(timeoutId)
Expand Down
236 changes: 0 additions & 236 deletions apps/web/app/api/onboarding/account-status/route.ts

This file was deleted.

Loading
Loading