add Cloudflare R2 storage integration and update bug report handling
Some checks failed
Build & Publish Docker Image / build-and-push (push) Failing after 11s

This commit is contained in:
Flavio Fois
2026-05-27 21:35:26 +02:00
parent e6d663f4f2
commit 3ec7bb5222
17 changed files with 841 additions and 54 deletions

View File

@@ -2,6 +2,7 @@ package config
import (
"os"
"regexp"
"strconv"
"strings"
"sync"
@@ -19,16 +20,28 @@ type RateLimitConfig struct {
AuthBanDur time.Duration
}
type R2Config struct {
AccountID string
AccessKeyID string
SecretAccessKey string
BucketName string
Region string
Endpoint string
}
type Config struct {
Port string
DSN string
Database string
APIKey string
AdminKey string
MaxOpenConns int
MaxIdleConns int
ConnMaxLifetime int
RateLimit RateLimitConfig
Port string
DSN string
Database string
APIKey string
AdminKey string
MaxOpenConns int
MaxIdleConns int
ConnMaxLifetime int
UpdatesEnabled bool
UseS3CompatibleStorage bool
RateLimit RateLimitConfig
R2 R2Config
}
var (
@@ -84,20 +97,39 @@ func load() *Config {
if dbName == "" {
panic("DATABASE_NAME environment variable is required")
}
dbNameRegex := regexp.MustCompile("^[a-zA-Z0-9_]+$")
// Test the regex against the dbName, otherwise panic to prevent potential SQL injection
validDbName, err := regexp.Match(dbNameRegex.String(), []byte(dbName))
if err != nil {
panic("failed to validate database name: " + err.Error())
}
if !validDbName {
panic("invalid database name: must match regex " + dbNameRegex.String())
}
if os.Getenv("DB_DSN") == "" {
panic("DB_DSN environment variable is required")
}
return &Config{
Port: port,
DSN: os.Getenv("DB_DSN"),
Database: dbName,
APIKey: apiKey,
AdminKey: adminKey,
MaxOpenConns: maxOpenConns,
MaxIdleConns: maxIdleConns,
ConnMaxLifetime: connMaxLifetime,
Port: port,
DSN: os.Getenv("DB_DSN"),
Database: dbName,
APIKey: apiKey,
AdminKey: adminKey,
MaxOpenConns: maxOpenConns,
MaxIdleConns: maxIdleConns,
ConnMaxLifetime: connMaxLifetime,
UpdatesEnabled: strings.ToLower(strings.TrimSpace(os.Getenv("UPDATES_ENABLED"))) == "true",
UseS3CompatibleStorage: strings.ToLower(strings.TrimSpace(os.Getenv("USE_S3_COMPATIBLE_STORAGE"))) == "true",
R2: R2Config{
AccountID: os.Getenv("CF_ACCOUNT_ID"),
AccessKeyID: os.Getenv("CF_R2_ACCESS_KEY_ID"),
SecretAccessKey: os.Getenv("CF_R2_SECRET_ACCESS_KEY"),
BucketName: os.Getenv("CF_R2_BUCKET_NAME"),
Region: envString("CF_R2_REGION", "auto"),
Endpoint: os.Getenv("CF_R2_ENDPOINT"),
},
RateLimit: RateLimitConfig{
UnauthMaxReqs: envInt("RL_UNAUTH_MAX_REQS", 10),
UnauthWindow: envDuration("RL_UNAUTH_WINDOW", 5*time.Minute),
@@ -111,6 +143,13 @@ func load() *Config {
}
}
func envString(key, fallback string) string {
if s := os.Getenv(key); s != "" {
return s
}
return fallback
}
func envInt(key string, fallback int) int {
if s := os.Getenv(key); s != "" {
if n, err := strconv.Atoi(s); err == nil {