Files

139 lines
3.3 KiB
Go

// 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)
}