- PlayerHandler with all CRUD routes and tournament player operations - Buy-in flow: register + financial engine + auto-seat suggestion - Bust flow: hitman selection + bounty transfer + re-ranking - Undo bust with full re-ranking and rankings response - Rankings API endpoint returning derived positions - QR code endpoint returns PNG image with Cache-Control header - CSV import via multipart upload (admin only) - Player merge endpoint (admin only) - CSV export safety: formula injection neutralization (tab-prefix =,+,-,@) - Ranking tests: bust order, undo re-ranking, early undo, re-entry, deal positions, auto-close, concurrent busts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
46 lines
1.2 KiB
Go
46 lines
1.2 KiB
Go
package player
|
|
|
|
import (
|
|
"strings"
|
|
)
|
|
|
|
// SanitizeCSVField neutralizes potential formula injection in CSV output.
|
|
// When generating CSV, prefix any cell value starting with =, +, -, or @
|
|
// with a tab character to prevent spreadsheet formula injection when the
|
|
// CSV is opened in Excel/LibreOffice.
|
|
func SanitizeCSVField(value string) string {
|
|
if len(value) == 0 {
|
|
return value
|
|
}
|
|
switch value[0] {
|
|
case '=', '+', '-', '@':
|
|
return "\t" + value
|
|
}
|
|
return value
|
|
}
|
|
|
|
// SanitizeCSVRow sanitizes all fields in a CSV row.
|
|
func SanitizeCSVRow(fields []string) []string {
|
|
sanitized := make([]string, len(fields))
|
|
for i, f := range fields {
|
|
sanitized[i] = SanitizeCSVField(f)
|
|
}
|
|
return sanitized
|
|
}
|
|
|
|
// SanitizeCSVFields sanitizes a map of field names to values.
|
|
func SanitizeCSVFields(fields map[string]string) map[string]string {
|
|
sanitized := make(map[string]string, len(fields))
|
|
for k, v := range fields {
|
|
sanitized[k] = SanitizeCSVField(v)
|
|
}
|
|
return sanitized
|
|
}
|
|
|
|
// IsFormulaInjection checks if a string starts with a formula-injection character.
|
|
func IsFormulaInjection(value string) bool {
|
|
if len(value) == 0 {
|
|
return false
|
|
}
|
|
return strings.ContainsRune("=+-@", rune(value[0]))
|
|
}
|