Skip to content

Commit 5b2011b

Browse files
committed
fix(api): properly validate bagde colors
1 parent 6ee90ed commit 5b2011b

1 file changed

Lines changed: 27 additions & 22 deletions

File tree

server/api/registry/badge/[type]/[...pkg].get.ts

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,17 @@ const BUNDLEPHOBIA_API = 'https://bundlephobia.com/api/size'
1414
const NPMS_API = 'https://api.npms.io/v2/package'
1515

1616
const SafeStringSchema = v.pipe(v.string(), v.regex(/^[^<>"&]*$/, 'Invalid characters'))
17+
const SafeColorSchema = v.pipe(
18+
v.string(),
19+
v.transform(value => (value.startsWith('#') ? value : `#${value}`)),
20+
v.hexColor(),
21+
)
1722

1823
const QUERY_SCHEMA = v.object({
19-
color: v.optional(SafeStringSchema),
2024
name: v.optional(v.string()),
21-
labelColor: v.optional(SafeStringSchema),
2225
label: v.optional(SafeStringSchema),
26+
color: v.optional(SafeColorSchema),
27+
labelColor: v.optional(SafeColorSchema),
2328
})
2429

2530
const COLORS = {
@@ -184,26 +189,26 @@ function renderShieldsBadgeSvg(params: {
184189
const rightTextLengthAttr = rightTextLength * 10
185190

186191
return `
187-
<svg xmlns="http://www.w3.org/2000/svg" width="${totalWidth}" height="${height}" role="img" aria-label="${title}">
188-
<linearGradient id="s" x2="0" y2="100%">
189-
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
190-
<stop offset="1" stop-opacity=".1"/>
191-
</linearGradient>
192-
<clipPath id="r">
193-
<rect width="${totalWidth}" height="${height}" rx="3" fill="#fff"/>
194-
</clipPath>
195-
<g clip-path="url(#r)">
196-
<rect width="${leftWidth}" height="${height}" fill="${finalLabelColor}"/>
197-
<rect x="${leftWidth}" width="${rightWidth}" height="${height}" fill="${finalColor}"/>
198-
<rect width="${totalWidth}" height="${height}" fill="url(#s)"/>
199-
</g>
200-
<g text-anchor="middle" font-family="Verdana, Geneva, DejaVu Sans, sans-serif" text-rendering="geometricPrecision" font-size="110">
201-
<text aria-hidden="true" x="${leftCenter}" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="${leftTextLengthAttr}">${escapedLabel}</text>
202-
<text x="${leftCenter}" y="140" transform="scale(.1)" fill="${labelTextColor}" textLength="${leftTextLengthAttr}">${escapedLabel}</text>
203-
<text aria-hidden="true" x="${rightCenter}" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="${rightTextLengthAttr}">${escapedValue}</text>
204-
<text x="${rightCenter}" y="140" transform="scale(.1)" fill="${valueTextColor}" textLength="${rightTextLengthAttr}">${escapedValue}</text>
205-
</g>
206-
</svg>
192+
<svg xmlns="http://www.w3.org/2000/svg" width="${totalWidth}" height="${height}" role="img" aria-label="${title}">
193+
<linearGradient id="s" x2="0" y2="100%">
194+
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
195+
<stop offset="1" stop-opacity=".1"/>
196+
</linearGradient>
197+
<clipPath id="r">
198+
<rect width="${totalWidth}" height="${height}" rx="3" fill="#fff"/>
199+
</clipPath>
200+
<g clip-path="url(#r)">
201+
<rect width="${leftWidth}" height="${height}" fill="${finalLabelColor}"/>
202+
<rect x="${leftWidth}" width="${rightWidth}" height="${height}" fill="${finalColor}"/>
203+
<rect width="${totalWidth}" height="${height}" fill="url(#s)"/>
204+
</g>
205+
<g text-anchor="middle" font-family="Verdana, Geneva, DejaVu Sans, sans-serif" text-rendering="geometricPrecision" font-size="110">
206+
<text aria-hidden="true" x="${leftCenter}" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="${leftTextLengthAttr}">${escapedLabel}</text>
207+
<text x="${leftCenter}" y="140" transform="scale(.1)" fill="${labelTextColor}" textLength="${leftTextLengthAttr}">${escapedLabel}</text>
208+
<text aria-hidden="true" x="${rightCenter}" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="${rightTextLengthAttr}">${escapedValue}</text>
209+
<text x="${rightCenter}" y="140" transform="scale(.1)" fill="${valueTextColor}" textLength="${rightTextLengthAttr}">${escapedValue}</text>
210+
</g>
211+
</svg>
207212
`.trim()
208213
}
209214

0 commit comments

Comments
 (0)