139 lines
3.3 KiB
Go
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)
|
|
}
|