Skip to content

Commit bd576cd

Browse files
wontoryclaude
andcommitted
fix(orbit): add SVG text escaping, text length limit, and cache headers
Apply security and stability improvements from badge to orbit: escape XML in text output, limit text to 100 characters, add Cache-Control. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 9b944cf commit bd576cd

3 files changed

Lines changed: 14 additions & 2 deletions

File tree

apps/web/app/api/orbit/route.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { resolveSimpleIcon } from '#utils/simple-icon'
44

55
export async function GET(request: NextRequest) {
66
const { searchParams } = request.nextUrl
7-
const text = searchParams.get('text') || ''
7+
const text = (searchParams.get('text') || '').slice(0, 100)
88
const slugs = searchParams.get('slugs') || ''
99

1010
const icons = []
@@ -26,6 +26,7 @@ export async function GET(request: NextRequest) {
2626
return new Response(orbitSvg, {
2727
headers: {
2828
'content-type': 'image/svg+xml',
29+
'cache-control': 'public, max-age=3600, s-maxage=3600',
2930
},
3031
})
3132
}

packages/orbit/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
calculateOrbitRadius,
1212
calculateOuterOrbitIconSize,
1313
calculateSvgDimensions,
14+
escapeXml,
1415
} from '#utils'
1516

1617
const generateGradientDefs = (): string => `
@@ -59,7 +60,7 @@ const generateTextElement = (
5960
text-anchor="middle"
6061
dominant-baseline="middle"
6162
fill="url(#gradient)"
62-
>${text}</text>
63+
>${escapeXml(text)}</text>
6364
`
6465

6566
const generateTextContent = (

packages/orbit/src/utils.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,15 @@ const calculateIconSizeMultiplier = (
6161
orbitIndex: number,
6262
): number => baseMultiplier + incrementFactor * (orbitIndex + 1) ** 1.1
6363

64+
const escapeXml = (text: string): string => {
65+
return text
66+
.replace(/&/g, '&amp;')
67+
.replace(/</g, '&lt;')
68+
.replace(/>/g, '&gt;')
69+
.replace(/"/g, '&quot;')
70+
.replace(/'/g, '&apos;')
71+
}
72+
6473
export {
6574
calculateLargestOrbitRadius,
6675
calculateOuterOrbitIconSize,
@@ -70,4 +79,5 @@ export {
7079
calculateOrbitRadius,
7180
calculateAnimationDuration,
7281
calculateIconSizeMultiplier,
82+
escapeXml,
7383
}

0 commit comments

Comments
 (0)