fix(sync): add /api/auth/test endpoint, fix CSS %& vet warnings
- Add handleAuthTest endpoint that validates credentials without creating a device
- Fix resetPasswordHTML to use {TOKEN} placeholder instead of %s
- Remove fmt.Sprintf from admin dashboard (no format args needed)
This commit is contained in:
parent
852d6d373c
commit
f8f9510e2a
|
|
@ -418,6 +418,7 @@ func (s *Server) routes() *http.ServeMux {
|
||||||
mux.HandleFunc("/api/v1/sync/pull", s.handleSyncPull)
|
mux.HandleFunc("/api/v1/sync/pull", s.handleSyncPull)
|
||||||
mux.HandleFunc("/api/v1/blobs/", s.handleBlobs)
|
mux.HandleFunc("/api/v1/blobs/", s.handleBlobs)
|
||||||
mux.HandleFunc("/api/client/pair", s.handleClientPair)
|
mux.HandleFunc("/api/client/pair", s.handleClientPair)
|
||||||
|
mux.HandleFunc("/api/auth/test", s.handleAuthTest)
|
||||||
mux.HandleFunc("/api/client/revoke-current", s.handleClientRevoke)
|
mux.HandleFunc("/api/client/revoke-current", s.handleClientRevoke)
|
||||||
mux.HandleFunc("/api/client/me", s.handleClientMe)
|
mux.HandleFunc("/api/client/me", s.handleClientMe)
|
||||||
mux.HandleFunc("/api/client/revoke-device", s.handleClientRevokeDevice)
|
mux.HandleFunc("/api/client/revoke-device", s.handleClientRevokeDevice)
|
||||||
|
|
@ -827,6 +828,46 @@ func (s *Server) handleClientPair(w http.ResponseWriter, r *http.Request) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleAuthTest(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != "POST" {
|
||||||
|
jsonErr(w, 405, "POST required")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var req struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
jsonErr(w, 400, "bad json")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if req.Username == "" || req.Password == "" {
|
||||||
|
jsonErr(w, 400, "username and password required")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var hash string
|
||||||
|
var confirmed, blocked int
|
||||||
|
err := s.db.QueryRow("SELECT password_hash, confirmed, blocked FROM server_users WHERE username=? OR email=?",
|
||||||
|
req.Username, strings.ToLower(req.Username)).Scan(&hash, &confirmed, &blocked)
|
||||||
|
if err != nil {
|
||||||
|
jsonErr(w, 401, "invalid credentials")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if blocked != 0 {
|
||||||
|
jsonErr(w, 403, "account blocked")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if confirmed == 0 {
|
||||||
|
jsonErr(w, 403, "email not confirmed")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if bcrypt.CompareHashAndPassword([]byte(hash), []byte(req.Password)) != nil {
|
||||||
|
jsonErr(w, 401, "invalid credentials")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
jsonOK(w, map[string]string{"status": "ok"})
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) handleClientRevoke(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) handleClientRevoke(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.Method != "POST" {
|
if r.Method != "POST" {
|
||||||
jsonErr(w, 405, "POST required")
|
jsonErr(w, 405, "POST required")
|
||||||
|
|
@ -1698,7 +1739,7 @@ func (s *Server) handleUserWebReset(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
html := fmt.Sprintf(resetPasswordHTML, token)
|
html := strings.ReplaceAll(resetPasswordHTML, "{TOKEN}", token)
|
||||||
w.Write([]byte(html))
|
w.Write([]byte(html))
|
||||||
case "POST":
|
case "POST":
|
||||||
if err := r.ParseForm(); err != nil {
|
if err := r.ParseForm(); err != nil {
|
||||||
|
|
@ -1941,7 +1982,7 @@ func (s *Server) handleAdminDashboard(w http.ResponseWriter, r *http.Request) {
|
||||||
smtpSecurity := s.smtpGet("smtp_security")
|
smtpSecurity := s.smtpGet("smtp_security")
|
||||||
srvURL := s.smtpGet("server_url")
|
srvURL := s.smtpGet("server_url")
|
||||||
|
|
||||||
html := fmt.Sprintf(`<!DOCTYPE html>
|
html := `<!DOCTYPE html>
|
||||||
<html lang="ru">
|
<html lang="ru">
|
||||||
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
<title>Verstak Sync — Admin</title>
|
<title>Verstak Sync — Admin</title>
|
||||||
|
|
@ -2060,8 +2101,14 @@ function testSMTP(){
|
||||||
<pre id="health-result">Загрузка...</pre>
|
<pre id="health-result">Загрузка...</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
_ = smtpURL
|
||||||
|
_ = smtpUser
|
||||||
|
_ = smtpFrom
|
||||||
|
_ = smtpSecurity
|
||||||
|
_ = smtpHost
|
||||||
|
_ = smtpPort
|
||||||
|
|
||||||
</body></html>`)
|
</body></html>`
|
||||||
w.Write([]byte(html))
|
w.Write([]byte(html))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2762,7 +2809,7 @@ button:hover{background:#4f46e5}
|
||||||
</head><body>
|
</head><body>
|
||||||
<form method="POST">
|
<form method="POST">
|
||||||
<h1>Новый пароль</h1>
|
<h1>Новый пароль</h1>
|
||||||
<input type="hidden" name="token" value="%s">
|
<input type="hidden" name="token" value="{TOKEN}">
|
||||||
<label>Новый пароль</label>
|
<label>Новый пароль</label>
|
||||||
<input type="password" name="password" minlength="8" required autofocus>
|
<input type="password" name="password" minlength="8" required autofocus>
|
||||||
<label>Подтвердите пароль</label>
|
<label>Подтвердите пароль</label>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue