// Package handlers implements the HTTP handler functions for the Amnezia Share // Panel web application. Handlers are grouped by domain across several files // (health.go, install.go, login.go, oidc.go, share.go, cabinet.go, faq.go, // admin_*.go) but all live in this single package so they can freely share // small helpers declared in this file. // // The package registers itself onto internal/web via web.RegisterRoutes from // init(), rather than internal/web importing this package directly — that // would create an import cycle, since this package needs *web.App. package handlers import ( "encoding/json" "errors" "net/http" "strconv" "strings" "amnezia-share/internal/web" ) // errUnknownAction is returned by admin/guest POST dispatchers for an // unrecognized "action" form value. var errUnknownAction = errors.New("Неизвестное действие.") func itoaHelper(n int) string { return strconv.Itoa(n) } func formIntFromString(v string, def int) int { v = strings.TrimSpace(v) if v == "" { return def } n, err := strconv.Atoi(v) if err != nil { return def } return n } func init() { web.RegisterRoutes(register) } // register wires every route of the application onto mux. func register(a *web.App, mux *http.ServeMux) { registerHealth(a, mux) registerInstall(a, mux) registerLogin(a, mux) registerOIDC(a, mux) registerShare(a, mux) registerCabinet(a, mux) registerFAQ(a, mux) registerAdmin(a, mux) mux.HandleFunc("GET /{$}", func(w http.ResponseWriter, r *http.Request) { if a.CurrentAdmin(r) != nil { http.Redirect(w, r, a.Cfg.AppURL("admin"), http.StatusSeeOther) return } count, err := a.Auth.AdminCount(r.Context()) if err != nil || count == 0 { http.Redirect(w, r, a.Cfg.AppURL("install"), http.StatusSeeOther) return } http.Redirect(w, r, a.Cfg.AppURL("login"), http.StatusSeeOther) }) } func redirectTo(w http.ResponseWriter, r *http.Request, a *web.App, path string) { http.Redirect(w, r, a.Cfg.AppURL(path), http.StatusSeeOther) } func wantsJSON(r *http.Request) bool { return r.Header.Get("X-Share-Async") == "1" || strings.Contains(r.Header.Get("Accept"), "application/json") } func formInt(r *http.Request, key string, def int) int { v := strings.TrimSpace(r.FormValue(key)) if v == "" { return def } n, err := strconv.Atoi(v) if err != nil { return def } return n } func formInt64(r *http.Request, key string, def int64) int64 { v := strings.TrimSpace(r.FormValue(key)) if v == "" { return def } n, err := strconv.ParseInt(v, 10, 64) if err != nil { return def } return n } func queryInt(r *http.Request, key string, def int) int { v := strings.TrimSpace(r.URL.Query().Get(key)) if v == "" { return def } n, err := strconv.Atoi(v) if err != nil { return def } return n } func errMsg(err error) string { if err == nil { return "" } return err.Error() } func writeJSON(w http.ResponseWriter, status int, v any) { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(status) _ = json.NewEncoder(w).Encode(v) } func writeJSONError(w http.ResponseWriter, status int, msg string) { writeJSON(w, status, map[string]any{"ok": false, "error": msg}) } func writeJSONOK(w http.ResponseWriter, extra map[string]any) { if extra == nil { extra = map[string]any{} } extra["ok"] = true writeJSON(w, http.StatusOK, extra) }