161 lines
3.8 KiB
Go
161 lines
3.8 KiB
Go
package rest
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"strconv"
|
|
"time"
|
|
|
|
"goAuth/internal/auth"
|
|
"goAuth/internal/user"
|
|
)
|
|
|
|
type changeUserPasswordRequest struct {
|
|
Password string `json:"password"`
|
|
}
|
|
|
|
type userResponse struct {
|
|
Id int64 `json:"id"`
|
|
Login string `json:"login"`
|
|
FullName *string `json:"fullName"`
|
|
Email *string `json:"email"`
|
|
IsAdmin bool `json:"isAdmin"`
|
|
CreatedAt time.Time `json:"createdAt"`
|
|
UpdatedAt time.Time `json:"updatedAt"`
|
|
ActivatedAt *time.Time `json:"activatedAt"`
|
|
}
|
|
|
|
func (h *Handler) listUsers(w http.ResponseWriter, r *http.Request) {
|
|
limit, offset := pagination(r)
|
|
|
|
includeInactive := r.URL.Query().Get("includeInactive") == "true"
|
|
|
|
users, err := h.users.Users(r.Context(), includeInactive, limit, offset)
|
|
if err != nil {
|
|
h.fail(w, err)
|
|
return
|
|
}
|
|
|
|
result := make([]userResponse, 0, len(users))
|
|
for _, u := range users {
|
|
result = append(result, newUserResponse(u))
|
|
}
|
|
|
|
writeJson(w, http.StatusOK, result)
|
|
}
|
|
|
|
func (h *Handler) changeUserPassword(w http.ResponseWriter, r *http.Request) {
|
|
id, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadRequest, "invalid user id")
|
|
return
|
|
}
|
|
|
|
var req changeUserPasswordRequest
|
|
if err := decodeJson(r, &req); err != nil {
|
|
writeError(w, http.StatusBadRequest, "invalid request body")
|
|
return
|
|
}
|
|
if !verifyPassword(req.Password) {
|
|
writeError(w, http.StatusBadRequest, "invalid password")
|
|
return
|
|
}
|
|
|
|
u, err := h.users.UserById(r.Context(), id)
|
|
if err != nil {
|
|
h.fail(w, err)
|
|
return
|
|
}
|
|
|
|
if _, err := h.users.SetPassword(r.Context(), u, req.Password); err != nil {
|
|
h.fail(w, err)
|
|
return
|
|
}
|
|
|
|
writeNoContent(w)
|
|
}
|
|
|
|
func (h *Handler) signoutUserSessions(w http.ResponseWriter, r *http.Request) {
|
|
id, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadRequest, "invalid user id")
|
|
return
|
|
}
|
|
|
|
u, err := h.users.UserById(r.Context(), id)
|
|
if err != nil {
|
|
h.fail(w, err)
|
|
return
|
|
}
|
|
|
|
if err := h.sessions.DeleteSessions(r.Context(), u); err != nil {
|
|
h.fail(w, err)
|
|
return
|
|
}
|
|
|
|
if current := userFromRequest(r); current.Id == id {
|
|
auth.SignoutCleanup(w, h.cfg.Cookies.SessionName, h.cfg.Cookies.Secure)
|
|
h.refreshCsrf(w)
|
|
}
|
|
|
|
writeNoContent(w)
|
|
}
|
|
|
|
// getUserAvatar serves any user's avatar without requiring a session. It backs
|
|
// the avatar URL embedded in Jitsi JWTs, which the Jitsi server (a different
|
|
// origin) fetches directly and cannot authenticate to /api/profile/avatar.
|
|
func (h *Handler) getUserAvatar(w http.ResponseWriter, r *http.Request) {
|
|
id, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
|
if err != nil {
|
|
writeError(w, http.StatusBadRequest, "invalid user id")
|
|
return
|
|
}
|
|
|
|
u, err := h.users.UserById(r.Context(), id)
|
|
if err != nil {
|
|
h.fail(w, err)
|
|
return
|
|
}
|
|
|
|
data, err := h.users.Avatar(r.Context(), u)
|
|
if err != nil {
|
|
h.fail(w, err)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", http.DetectContentType(data))
|
|
w.Header().Set("Cache-Control", "public, max-age=300")
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write(data)
|
|
}
|
|
|
|
// avatarURL builds the absolute URL of a user's avatar, preferring the
|
|
// configured PublicBaseURL and falling back to the request's scheme and Host.
|
|
func (h *Handler) avatarURL(r *http.Request, id int64) string {
|
|
base := h.cfg.PublicBaseURL
|
|
if base == "" {
|
|
scheme := "http"
|
|
if r.TLS != nil {
|
|
scheme = "https"
|
|
}
|
|
if proto := r.Header.Get("X-Forwarded-Proto"); proto != "" {
|
|
scheme = proto
|
|
}
|
|
base = scheme + "://" + r.Host
|
|
}
|
|
return fmt.Sprintf("%s/api/users/%d/avatar", base, id)
|
|
}
|
|
|
|
func newUserResponse(u *user.User) userResponse {
|
|
return userResponse{
|
|
Id: u.Id,
|
|
Login: u.Login,
|
|
FullName: u.FullName,
|
|
Email: u.Email,
|
|
IsAdmin: u.IsAdmin,
|
|
CreatedAt: u.CreatedAt,
|
|
UpdatedAt: u.UpdatedAt,
|
|
ActivatedAt: u.ActivatedAt,
|
|
}
|
|
}
|