113 lines
2.6 KiB
Go
113 lines
2.6 KiB
Go
package main
|
|
|
|
// Utilities for filesystem, IDs, HTTP scheme detection, and input sanitization.
|
|
// These helpers are used by the HTTP handlers and startup code.
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// MakeDir creates the directory if it does not already exist.
|
|
func MakeDir(dirname string) error {
|
|
if _, err := os.Stat(dirname); os.IsNotExist(err) {
|
|
return os.Mkdir(dirname, 0666)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// DeleteDirContents removes all files and directories inside dirname but not the directory itself.
|
|
func DeleteDirContents(dirname string) error {
|
|
entries, err := os.ReadDir(dirname)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, entry := range entries {
|
|
if entry.IsDir() {
|
|
err := os.RemoveAll(filepath.Join(dirname, entry.Name()))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
err := os.Remove(filepath.Join(dirname, entry.Name()))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// IsUsernameValid validates length, allowed characters, and rejects common placeholder names.
|
|
func IsUsernameValid(username string) bool {
|
|
minLength := 3
|
|
maxLength := 24
|
|
allowedChars := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-"
|
|
disallowedUsernames := []string{
|
|
"admin",
|
|
"user",
|
|
"guest",
|
|
"test",
|
|
"root",
|
|
"system",
|
|
"anonymous",
|
|
"default",
|
|
}
|
|
if len(username) < minLength || len(username) > maxLength {
|
|
return false
|
|
}
|
|
for _, char := range username {
|
|
if !strings.ContainsRune(allowedChars, char) {
|
|
return false
|
|
}
|
|
}
|
|
for _, disallowed := range disallowedUsernames {
|
|
if strings.EqualFold(username, disallowed) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// GenerateId creates a short pseudo-unique ID derived from time and a hash.
|
|
func GenerateId() string {
|
|
timestamp := time.Now().UnixNano()
|
|
randomComponent := time.Now().UnixNano() % 1000000 // Add some randomness
|
|
data := fmt.Sprintf("%d-%d", timestamp, randomComponent)
|
|
hash := sha256.Sum256([]byte(data))
|
|
return hex.EncodeToString(hash[:])[:16]
|
|
}
|
|
|
|
// GetScheme determines the request scheme, respecting TLS and X-Forwarded-Proto.
|
|
func GetScheme(r *http.Request) string {
|
|
if r.URL.Scheme != "" {
|
|
return r.URL.Scheme
|
|
}
|
|
|
|
if r.TLS != nil {
|
|
return "https"
|
|
}
|
|
|
|
proto := r.Header.Get("X-Forwarded-Proto")
|
|
if proto != "" {
|
|
return proto
|
|
}
|
|
|
|
return "http"
|
|
}
|
|
|
|
// SanitizeFilename removes path traversal characters and trims whitespace.
|
|
func SanitizeFilename(filename string) string {
|
|
filename = strings.ReplaceAll(filename, "/", "")
|
|
filename = strings.ReplaceAll(filename, "\\", "")
|
|
filename = strings.ReplaceAll(filename, "..", "")
|
|
filename = strings.TrimSpace(filename)
|
|
|
|
return filename
|
|
}
|