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:
@@ -3,7 +3,6 @@ package main
|
|||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -289,8 +288,8 @@ func logsHandler(db *sql.DB) http.HandlerFunc {
|
|||||||
if len(conditions) > 0 {
|
if len(conditions) > 0 {
|
||||||
query += " WHERE " + strings.Join(conditions, " AND ")
|
query += " WHERE " + strings.Join(conditions, " AND ")
|
||||||
}
|
}
|
||||||
query += ` ORDER BY timestamp DESC`
|
query += ` ORDER BY timestamp DESC LIMIT ? OFFSET ?`
|
||||||
query += fmt.Sprintf(` LIMIT %d OFFSET %d`, f.Limit, f.Offset)
|
args = append(args, f.Limit, f.Offset)
|
||||||
|
|
||||||
rows, err := db.Query(query, args...)
|
rows, err := db.Query(query, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"time"
|
"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 {
|
func getEnv(key, defaultValue string) string {
|
||||||
if v := os.Getenv(key); v != "" {
|
if v := os.Getenv(key); v != "" {
|
||||||
return v
|
return v
|
||||||
@@ -39,3 +62,53 @@ func parseDuration(key string, defaultVal time.Duration) time.Duration {
|
|||||||
}
|
}
|
||||||
return defaultVal
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -142,11 +142,7 @@ func IsPermanentWhitelisted(db *sql.DB, ip string) (bool, error) {
|
|||||||
if err := rows.Scan(&entry); err != nil {
|
if err := rows.Scan(&entry); err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
matches, err := ipMatchesEntry(ip, entry)
|
if matches, _ := ipMatchesEntry(ip, entry); matches {
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if matches {
|
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -221,10 +217,8 @@ func CleanupExpiredTemp(db *sql.DB) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := rows.Err(); err != nil {
|
if err := rows.Err(); err != nil {
|
||||||
rows.Close()
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rows.Close()
|
|
||||||
|
|
||||||
_, err = db.Exec(`DELETE FROM temp_whitelist WHERE expires_at <= ?`, time.Now().Format(time.RFC3339))
|
_, err = db.Exec(`DELETE FROM temp_whitelist WHERE expires_at <= ?`, time.Now().Format(time.RFC3339))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
InitEnv()
|
||||||
cfg := loadConfig()
|
cfg := loadConfig()
|
||||||
if cfg.APIToken == "" {
|
if cfg.APIToken == "" {
|
||||||
log.Fatal("AUTH_PROXY_API_TOKEN environment variable is required")
|
log.Fatal("AUTH_PROXY_API_TOKEN environment variable is required")
|
||||||
|
|||||||
Reference in New Issue
Block a user