summaryrefslogtreecommitdiffstats
path: root/internal
diff options
context:
space:
mode:
authorAhmed AbdelHalim <[email protected]>2025-09-07 17:50:36 +0200
committerAhmed AbdelHalim <[email protected]>2025-09-07 17:50:36 +0200
commitff63742a2fa138c230fb2e080708d03ed888c248 (patch)
tree10a5061a93cd6a91217d837a0a3a22a0bb17c54e /internal
parent17168a489392847794de0aed15fe395230a38261 (diff)
Add basic login and clean up config
Diffstat (limited to 'internal')
-rw-r--r--internal/auth.go107
-rw-r--r--internal/config.go17
2 files changed, 113 insertions, 11 deletions
diff --git a/internal/auth.go b/internal/auth.go
new file mode 100644
index 0000000..6caa785
--- /dev/null
+++ b/internal/auth.go
@@ -0,0 +1,107 @@
+package internal
+
+import (
+ "crypto/rand"
+ "crypto/sha256"
+ "encoding/hex"
+ "fmt"
+ "sync"
+ "time"
+)
+
+type Session struct {
+ Expires time.Time
+}
+
+type SessionManager struct {
+ sessions map[string]*Session
+ mutex sync.RWMutex
+}
+
+func NewSessionManager() *SessionManager {
+ sm := &SessionManager{
+ sessions: make(map[string]*Session),
+ }
+ // Start cleanup goroutine
+ go sm.cleanupExpiredSessions()
+ return sm
+}
+
+// Using the same logic that powers the pi-hole authentication
+// GeneratePasswordHash creates a double SHA256 hash from the password param to
+// validate against config.PasswordHash
+func GeneratePasswordHash(password string) string {
+ first := sha256.Sum256([]byte(password))
+ firstHex := hex.EncodeToString(first[:])
+ second := sha256.Sum256([]byte(firstHex))
+ return hex.EncodeToString(second[:])
+}
+
+func ValidatePassword(password, hash string) bool {
+ return GeneratePasswordHash(password) == hash
+}
+
+func (sm *SessionManager) CreateSession() (string, time.Time, error) {
+ sm.mutex.Lock()
+ defer sm.mutex.Unlock()
+
+ sessionID, err := generateSecureToken()
+ if err != nil {
+ return "", time.Time{}, fmt.Errorf("failed to generate session ID: %w", err)
+ }
+
+ expires := time.Now().Add(1 * time.Hour)
+ sm.sessions[sessionID] = &Session{
+ Expires: expires,
+ }
+
+ return sessionID, expires, nil
+}
+
+func (sm *SessionManager) ValidateSession(sessionID string) (*Session, bool) {
+ sm.mutex.RLock()
+ defer sm.mutex.RUnlock()
+
+ session, exists := sm.sessions[sessionID]
+ if !exists {
+ return nil, false
+ }
+
+ if time.Now().After(session.Expires) {
+ return nil, false
+ }
+
+ return session, true
+}
+
+func (sm *SessionManager) DeleteSession(sessionID string) {
+ sm.mutex.Lock()
+ defer sm.mutex.Unlock()
+ delete(sm.sessions, sessionID)
+}
+
+func generateSecureToken() (string, error) {
+ bytes := make([]byte, 32)
+ _, err := rand.Read(bytes)
+ if err != nil {
+ return "", err
+ }
+ return hex.EncodeToString(bytes), nil
+}
+
+// cleanupExpiredSessions periodically removes expired sessions every 1 hour
+func (sm *SessionManager) cleanupExpiredSessions() {
+ ticker := time.NewTicker(1 * time.Hour)
+ defer ticker.Stop()
+
+ for range ticker.C {
+ sm.mutex.Lock()
+ now := time.Now()
+ for sessionID, session := range sm.sessions {
+ if now.After(session.Expires) {
+ delete(sm.sessions, sessionID)
+ }
+ }
+ sm.mutex.Unlock()
+ }
+}
diff --git a/internal/config.go b/internal/config.go
index 8d9d961..558630d 100644
--- a/internal/config.go
+++ b/internal/config.go
@@ -7,22 +7,17 @@ import (
"gopkg.in/yaml.v3"
)
-type ServerConfig struct {
- Host string `yaml:"host"`
- Port string `yaml:"port"`
- Title string `yaml:"title"`
-}
-
type Config struct {
- Server ServerConfig `yaml:"server"`
+ Host string `yaml:"host"`
+ Port string `yaml:"port"`
+ PasswordHash string `yaml:"password_hash"`
}
// Default configuration values
func DefaultConfig() *Config {
config := &Config{}
- config.Server.Host = "0.0.0.0"
- config.Server.Port = "8080"
- config.Server.Title = "WireGuard Gateway Portal"
+ config.Host = "0.0.0.0"
+ config.Port = "8080"
return config
}
@@ -52,5 +47,5 @@ func LoadConfig(configPath string) (*Config, error) {
// GetAddress returns the server address in host:port format
func (c *Config) GetAddress() string {
- return fmt.Sprintf("%s:%s", c.Server.Host, c.Server.Port)
+ return fmt.Sprintf("%s:%s", c.Host, c.Port)
}