diff --git a/lib/svg/generator.ts b/lib/svg/generator.ts index d3a096c..653e6f8 100644 --- a/lib/svg/generator.ts +++ b/lib/svg/generator.ts @@ -15,7 +15,14 @@ function deterministicRandom(seed: string): number { } return (hash >>> 0) / 4294967296; } - +function escapeXML(str: string): string { + return str + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); +} function generateParticles( x: number, y: number, @@ -148,6 +155,7 @@ export function generateSVG( if (params.autoTheme) { return generateAutoThemeSVG(stats, params, calendar); } + const safeUser = escapeXML(params.user || 'GitHub User'); const bg = `#${(params.bg || '0d1117').replace('#', '')}`; const accent = `#${(params.accent || '00ffaa').replace('#', '')}`; @@ -216,7 +224,18 @@ export function generateSVG( : ''; return ` - + + CommitPulse Stats for ${safeUser} + + ${params.user || 'This user'} has ${stats.totalContributions} total contributions and a longest streak of ${stats.longestStreak} days. + @@ -287,7 +306,7 @@ export function generateSVG( ${stats.longestStreak} - ${params.user?.toUpperCase() || ''} + ${safeUser.toUpperCase()} @@ -313,6 +332,7 @@ function generateAutoThemeSVG( ): string { const light = AUTO_LIGHT_THEME; const dark = AUTO_DARK_THEME; + const safeUser = escapeXML(params.user || 'GitHub User'); const selectedFont = params.font ? FONT_MAP[params.font.toLowerCase()] || '"JetBrains Mono", monospace' @@ -363,7 +383,18 @@ function generateAutoThemeSVG( } return ` - + + CommitPulse Stats for ${safeUser} + + ${params.user || 'This user'} has ${stats.totalContributions} total contributions and a longest streak of ${stats.longestStreak} days. + @@ -455,7 +486,7 @@ function generateAutoThemeSVG( ${stats.longestStreak} - ${params.user?.toUpperCase() || ''} + ${safeUser.toUpperCase()}