Web UI: setup wizard, auth pages, library browsing, player, admin, streaming, cover art
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"git.noroutes.net/NoRoutes/vibetunes/internal/auth"
|
||||
"git.noroutes.net/NoRoutes/vibetunes/internal/database"
|
||||
)
|
||||
|
||||
func (h *Web) handleSettings(w http.ResponseWriter, r *http.Request) {
|
||||
h.renderSettings(w, r, "", "", "")
|
||||
}
|
||||
|
||||
func (h *Web) renderSettings(w http.ResponseWriter, r *http.Request, newAPIKey, flash, flashKind string) {
|
||||
user := auth.UserFromContext(r.Context())
|
||||
keys, err := database.ListAPIKeysForUser(h.DB, user.ID)
|
||||
if err != nil {
|
||||
http.Error(w, "internal error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
sessions, err := database.ListUserSessions(h.DB, user.ID)
|
||||
if err != nil {
|
||||
http.Error(w, "internal error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
h.flash(w, r, "settings", "", "Settings", flash, flashKind, struct {
|
||||
APIKeys []*database.APIKey
|
||||
Sessions []*database.Session
|
||||
NewAPIKey string
|
||||
}{keys, sessions, newAPIKey})
|
||||
}
|
||||
|
||||
func (h *Web) handlePasswordChange(w http.ResponseWriter, r *http.Request) {
|
||||
user := auth.UserFromContext(r.Context())
|
||||
if err := r.ParseForm(); err != nil {
|
||||
http.Error(w, "bad request", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
current := r.FormValue("current_password")
|
||||
newPassword := r.FormValue("new_password")
|
||||
|
||||
if !user.PasswordHash.Valid {
|
||||
h.renderSettings(w, r, "", "This account has no local password to change (it signs in via external authentication).", "danger")
|
||||
return
|
||||
}
|
||||
ok, err := auth.VerifyPassword(current, user.PasswordHash.String)
|
||||
if err != nil || !ok {
|
||||
h.renderSettings(w, r, "", "Current password is incorrect.", "danger")
|
||||
return
|
||||
}
|
||||
if len(newPassword) < 8 {
|
||||
h.renderSettings(w, r, "", "New password must be at least 8 characters.", "danger")
|
||||
return
|
||||
}
|
||||
hash, err := auth.HashPassword(newPassword)
|
||||
if err != nil {
|
||||
http.Error(w, "internal error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if err := database.SetUserPassword(h.DB, user.ID, hash); err != nil {
|
||||
http.Error(w, "internal error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
_ = database.DeleteUserSessions(h.DB, user.ID)
|
||||
if err := h.Sessions.Issue(w, r, user.ID); err != nil {
|
||||
http.Error(w, "internal error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
h.renderSettings(w, r, "", "Password updated.", "success")
|
||||
}
|
||||
|
||||
func (h *Web) handleAPIKeyCreate(w http.ResponseWriter, r *http.Request) {
|
||||
user := auth.UserFromContext(r.Context())
|
||||
if err := r.ParseForm(); err != nil {
|
||||
http.Error(w, "bad request", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
name := r.FormValue("name")
|
||||
rawKey, err := auth.GenerateAPIKey()
|
||||
if err != nil {
|
||||
http.Error(w, "internal error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if _, err := database.CreateAPIKey(h.DB, user.ID, name, auth.HashAPIKey(rawKey)); err != nil {
|
||||
http.Error(w, "internal error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
h.renderSettings(w, r, rawKey, "", "")
|
||||
}
|
||||
|
||||
func (h *Web) handleAPIKeyRevoke(w http.ResponseWriter, r *http.Request) {
|
||||
user := auth.UserFromContext(r.Context())
|
||||
id := r.PathValue("id")
|
||||
key, err := database.GetAPIKey(h.DB, id)
|
||||
if err != nil || key.UserID != user.ID {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
if err := database.RevokeAPIKey(h.DB, id); err != nil {
|
||||
http.Error(w, "internal error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/settings", http.StatusFound)
|
||||
}
|
||||
|
||||
func (h *Web) handleSessionRevoke(w http.ResponseWriter, r *http.Request) {
|
||||
user := auth.UserFromContext(r.Context())
|
||||
id := r.PathValue("id")
|
||||
sess, err := database.GetSession(h.DB, id)
|
||||
if err != nil || sess.UserID != user.ID {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
if err := database.DeleteSession(h.DB, id); err != nil {
|
||||
http.Error(w, "internal error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/settings", http.StatusFound)
|
||||
}
|
||||
Reference in New Issue
Block a user