Harden API security: input validation, safe auth extraction, new tests, and deploy config
Comprehensive security hardening from audit findings: - Add validation tags to all DTO request structs (max lengths, ranges, enums) - Replace unsafe type assertions with MustGetAuthUser helper across all handlers - Remove query-param token auth from admin middleware (prevents URL token leakage) - Add request validation calls in handlers that were missing c.Validate() - Remove goroutines in handlers (timezone update now synchronous) - Add sanitize middleware and path traversal protection (path_utils) - Stop resetting admin passwords on migration restart - Warn on well-known default SECRET_KEY - Add ~30 new test files covering security regressions, auth safety, repos, and services - Add deploy/ config, audit digests, and AUDIT_FINDINGS documentation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -323,10 +323,21 @@ func (c *AppleIAPClient) ValidateReceipt(ctx context.Context, receiptData string
|
||||
}, nil
|
||||
}
|
||||
|
||||
// validateLegacyReceipt uses Apple's legacy verifyReceipt endpoint
|
||||
// validateLegacyReceipt uses Apple's legacy verifyReceipt endpoint.
|
||||
// It delegates to validateLegacyReceiptWithSandbox using the client's
|
||||
// configured sandbox setting. This avoids mutating the struct field
|
||||
// during the sandbox-retry flow, which caused a data race when
|
||||
// multiple goroutines shared the same AppleIAPClient.
|
||||
func (c *AppleIAPClient) validateLegacyReceipt(ctx context.Context, receiptData string) (*AppleValidationResult, error) {
|
||||
return c.validateLegacyReceiptWithSandbox(ctx, receiptData, c.sandbox)
|
||||
}
|
||||
|
||||
// validateLegacyReceiptWithSandbox performs legacy receipt validation against
|
||||
// the specified environment. The sandbox parameter is passed by value (not
|
||||
// stored on the struct) so this function is safe for concurrent use.
|
||||
func (c *AppleIAPClient) validateLegacyReceiptWithSandbox(ctx context.Context, receiptData string, useSandbox bool) (*AppleValidationResult, error) {
|
||||
url := "https://buy.itunes.apple.com/verifyReceipt"
|
||||
if c.sandbox {
|
||||
if useSandbox {
|
||||
url = "https://sandbox.itunes.apple.com/verifyReceipt"
|
||||
}
|
||||
|
||||
@@ -378,12 +389,10 @@ func (c *AppleIAPClient) validateLegacyReceipt(ctx context.Context, receiptData
|
||||
}
|
||||
|
||||
// Status codes: 0 = valid, 21007 = sandbox receipt on production, 21008 = production receipt on sandbox
|
||||
if legacyResponse.Status == 21007 && !c.sandbox {
|
||||
// Retry with sandbox
|
||||
c.sandbox = true
|
||||
result, err := c.validateLegacyReceipt(ctx, receiptData)
|
||||
c.sandbox = false
|
||||
return result, err
|
||||
if legacyResponse.Status == 21007 && !useSandbox {
|
||||
// Retry with sandbox -- pass sandbox=true as a parameter instead of
|
||||
// mutating c.sandbox, which avoids a data race.
|
||||
return c.validateLegacyReceiptWithSandbox(ctx, receiptData, true)
|
||||
}
|
||||
|
||||
if legacyResponse.Status != 0 {
|
||||
|
||||
Reference in New Issue
Block a user