feat: add env file support and parameterize SQL queries

Add .env and .env.local loading with InitEnv() helper that reads
environment variables from config files without overwriting existing
values.

Refactor SQL queries to use parameterized arguments instead of
string formatting for LIMIT/OFFSET clauses, improving query security
and preventing SQL injection vulnerabilities.

Clean up unnecessary rows.Close() calls and simplify error handling
in database query functions.
This commit is contained in:
db123-test
2026-05-05 19:13:42 +03:30
parent ac25f4f4c5
commit c3869f4f10
4 changed files with 77 additions and 10 deletions

View File

@@ -3,7 +3,6 @@ package main
import (
"database/sql"
"encoding/json"
"fmt"
"log/slog"
"net"
"net/http"
@@ -289,8 +288,8 @@ func logsHandler(db *sql.DB) http.HandlerFunc {
if len(conditions) > 0 {
query += " WHERE " + strings.Join(conditions, " AND ")
}
query += ` ORDER BY timestamp DESC`
query += fmt.Sprintf(` LIMIT %d OFFSET %d`, f.Limit, f.Offset)
query += ` ORDER BY timestamp DESC LIMIT ? OFFSET ?`
args = append(args, f.Limit, f.Offset)
rows, err := db.Query(query, args...)
if err != nil {

View File

@@ -2,6 +2,7 @@ package main
import (
"os"
"path/filepath"
"time"
)
@@ -23,6 +24,28 @@ func loadConfig() Config {
}
}
func loadEnvFile(envFile string) {
if _, err := os.Stat(envFile); err != nil {
return
}
data, err := os.ReadFile(envFile)
if err != nil {
return
}
for _, line := range splitLines(data) {
parts := splitKV(line)
if len(parts) == 2 {
key := parts[0]
value := unquote(parts[1])
if os.Getenv(key) == "" {
os.Setenv(key, value)
}
}
}
}
func getEnv(key, defaultValue string) string {
if v := os.Getenv(key); v != "" {
return v
@@ -39,3 +62,53 @@ func parseDuration(key string, defaultVal time.Duration) time.Duration {
}
return defaultVal
}
func splitLines(data []byte) []string {
lines := make([]string, 0)
var line string
for _, b := range data {
if b == '\n' {
lines = append(lines, line)
line = ""
} else if b != '\r' {
line += string(b)
}
}
if line != "" {
lines = append(lines, line)
}
return lines
}
func splitKV(line string) []string {
for i, b := range line {
if b == '=' {
return []string{line[:i], line[i+1:]}
}
}
return nil
}
func unquote(s string) string {
if len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"' {
return s[1 : len(s)-1]
}
if len(s) >= 2 && s[0] == '\'' && s[len(s)-1] == '\'' {
return s[1 : len(s)-1]
}
return s
}
func InitEnv() {
possibleFiles := []string{
".env",
".env.local",
}
for _, f := range possibleFiles {
abs, err := filepath.Abs(f)
if err == nil {
loadEnvFile(abs)
return
}
}
}

View File

@@ -142,11 +142,7 @@ func IsPermanentWhitelisted(db *sql.DB, ip string) (bool, error) {
if err := rows.Scan(&entry); err != nil {
continue
}
matches, err := ipMatchesEntry(ip, entry)
if err != nil {
continue
}
if matches {
if matches, _ := ipMatchesEntry(ip, entry); matches {
return true, nil
}
}
@@ -221,10 +217,8 @@ func CleanupExpiredTemp(db *sql.DB) error {
}
}
if err := rows.Err(); err != nil {
rows.Close()
return err
}
rows.Close()
_, err = db.Exec(`DELETE FROM temp_whitelist WHERE expires_at <= ?`, time.Now().Format(time.RFC3339))
if err != nil {

View File

@@ -12,6 +12,7 @@ import (
)
func main() {
InitEnv()
cfg := loadConfig()
if cfg.APIToken == "" {
log.Fatal("AUTH_PROXY_API_TOKEN environment variable is required")