forked from Nixius/authelia
1
0
Fork 0
ATLAS/docker/ss-atlas/internal/handlers/admin.go

65 lines
1.8 KiB
Go

package handlers
import (
"encoding/json"
"log"
"net/http"
"regexp"
)
var validUsername = regexp.MustCompile(`^[a-z0-9][a-z0-9_-]*$`)
// handleDeleteUser fully deletes an account plus its customer stack and volumes.
// Requires ADMIN_SECRET env set and X-Admin-Secret header. POST /admin/delete-user?user=instance-slug
func (a *App) handleDeleteUser(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
return
}
if a.cfg.AdminSecret == "" {
http.NotFound(w, r)
return
}
secret := r.Header.Get("X-Admin-Secret")
if secret != a.cfg.AdminSecret {
http.Error(w, "forbidden", http.StatusForbidden)
return
}
slug := r.URL.Query().Get("user")
if slug == "" {
slug = r.FormValue("user")
}
if slug == "" {
http.Error(w, "user required", http.StatusBadRequest)
return
}
if !validUsername.MatchString(slug) {
http.Error(w, "invalid username", http.StatusBadRequest)
return
}
inst, err := a.accounts.DeleteAccountByInstanceSlug(r.Context(), slug)
if err != nil {
log.Printf("admin delete-user %s: account: %v", slug, err)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
return
}
if err := a.swarm.RemoveStackAndVolumes(inst.StackName); err != nil {
log.Printf("admin delete-user %s: stack/volumes: %v", slug, err)
// Account already deleted; report but don't fail.
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{
"status": "user deleted",
"warning": "stack/volumes: " + err.Error(),
})
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"status": "deleted", "user": slug})
}