Added user profile page, prepped for TOTP 2fa

This commit is contained in:
2026-07-16 22:13:54 +02:00
parent 63deb02d39
commit c8f47768a3
11 changed files with 850 additions and 15 deletions
+98
View File
@@ -0,0 +1,98 @@
package api
import (
"encoding/json"
"errors"
"net/http"
"codeberg.org/SquidSE/ClusterCanvas/service/internal/settings"
)
const (
minIdleTimeoutMinutes = 1
maxIdleTimeoutMinutes = 240 // 4 hours
minSessionLifetimeHours = 1
minReauthGraceMinutes = 0
)
type securityResponse struct {
Security settings.SecuritySettings `json:"security"`
}
type putSecurityRequest struct {
Security settings.SecuritySettings `json:"security"`
}
func securityGetHandler(configDir string) http.HandlerFunc {
return func(writer http.ResponseWriter, request *http.Request) {
settingsPayload, err := loadSettingsOrDefault(configDir)
if err != nil {
writeJSON(writer, http.StatusInternalServerError, apiErrorResponse{Error: err.Error()})
return
}
writeJSON(writer, http.StatusOK, securityResponse{
Security: effectiveSecurity(settingsPayload.Security),
})
}
}
func securityPutHandler(configDir string) http.HandlerFunc {
return func(writer http.ResponseWriter, request *http.Request) {
if err := authorizeSecurityWrite(request); err != nil {
writeJSON(writer, http.StatusForbidden, apiErrorResponse{Error: err.Error()})
return
}
var payload putSecurityRequest
if err := json.NewDecoder(request.Body).Decode(&payload); err != nil {
writeJSON(writer, http.StatusBadRequest, apiErrorResponse{Error: "invalid JSON body"})
return
}
if err := validateSecuritySettings(payload.Security); err != nil {
writeJSON(writer, http.StatusBadRequest, apiErrorResponse{Error: err.Error()})
return
}
settingsPayload, err := loadSettingsOrDefault(configDir)
if err != nil {
writeJSON(writer, http.StatusInternalServerError, apiErrorResponse{Error: err.Error()})
return
}
settingsPayload.Security = payload.Security
if err := settings.SaveSettings(configDir, settingsPayload); err != nil {
writeJSON(writer, http.StatusInternalServerError, apiErrorResponse{Error: err.Error()})
return
}
writeJSON(writer, http.StatusOK, securityResponse{Security: settingsPayload.Security})
}
}
func authorizeSecurityWrite(_ *http.Request) error {
// TODO: integrate authz middleware.
return nil
}
func effectiveSecurity(security settings.SecuritySettings) settings.SecuritySettings {
if err := validateSecuritySettings(security); err != nil {
return settings.DefaultSecuritySettings()
}
return security
}
func validateSecuritySettings(security settings.SecuritySettings) error {
if security.IdleTimeoutMinutes < minIdleTimeoutMinutes ||
security.IdleTimeoutMinutes > maxIdleTimeoutMinutes {
return errors.New("idle_timeout_minutes must be between 1 and 240")
}
if security.SessionLifetimeHours < minSessionLifetimeHours {
return errors.New("session_lifetime_hours must be at least 1")
}
if security.ReauthGraceMinutes < minReauthGraceMinutes {
return errors.New("reauth_grace_minutes must be at least 0")
}
return nil
}