2026-10-15 23:25:46 +03:00
|
|
|
package web
|
|
|
|
|
|
|
|
|
|
import (
|
2026-10-16 11:34:34 +03:00
|
|
|
"fmt"
|
2026-10-15 23:25:46 +03:00
|
|
|
"net/http"
|
|
|
|
|
"net/url"
|
|
|
|
|
|
|
|
|
|
"uPortal/internal/auth"
|
2026-10-16 11:34:34 +03:00
|
|
|
|
|
|
|
|
"github.com/mileusna/useragent"
|
2026-10-15 23:25:46 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func (s *WebService) HandleSessions(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
data, ok := s.basicViewData(w, r, "Sessions")
|
|
|
|
|
if !ok {
|
|
|
|
|
http.Redirect(w, r, "/signin", http.StatusSeeOther)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sessions, err := s.auths.GetSessionByUserId(r.Context(), data.User.Id, 100, 0)
|
|
|
|
|
if err != nil {
|
|
|
|
|
s.log.Error("failed to get sessions: %v", err)
|
|
|
|
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
2026-10-16 11:34:34 +03:00
|
|
|
for _, session := range sessions {
|
|
|
|
|
ua := useragent.Parse(session.Device)
|
|
|
|
|
var class string
|
|
|
|
|
if ua.Mobile {
|
|
|
|
|
class = "Mobile"
|
|
|
|
|
}
|
|
|
|
|
if ua.Tablet {
|
|
|
|
|
class = "Tablet"
|
|
|
|
|
}
|
|
|
|
|
if ua.Desktop {
|
|
|
|
|
class = "Desktop"
|
|
|
|
|
}
|
|
|
|
|
if ua.Bot {
|
|
|
|
|
class = "Bot"
|
|
|
|
|
}
|
2026-10-15 23:25:46 +03:00
|
|
|
|
2026-10-16 11:34:34 +03:00
|
|
|
newSession := auth.Session{
|
|
|
|
|
Device: fmt.Sprintf("%s, %s %s, %s %s %s", class, ua.Name, ua.Version, ua.OS, ua.OSVersion, ua.Device),
|
|
|
|
|
Address: session.Address,
|
|
|
|
|
Token: session.Token,
|
|
|
|
|
CreatedAt: session.CreatedAt,
|
|
|
|
|
ExpiresAt: session.ExpiresAt,
|
|
|
|
|
UserId: session.UserId,
|
|
|
|
|
}
|
|
|
|
|
data.Sessions = append(data.Sessions, newSession)
|
|
|
|
|
}
|
2026-10-15 23:25:46 +03:00
|
|
|
s.render(w, r, "session/view.html", data)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *WebService) HandleSessionEnd(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
if err := auth.ValidateCsrf(r, CsrfCookieName, CsrfFieldName); err != nil {
|
|
|
|
|
http.Redirect(w, r, "/sessions", http.StatusSeeOther)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
currentUser, err := s.currentUser(r)
|
|
|
|
|
if err != nil {
|
|
|
|
|
http.Redirect(w, r, "/signin", http.StatusSeeOther)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
token := r.FormValue("token")
|
|
|
|
|
if token == "" {
|
|
|
|
|
http.Redirect(w, r, "/sessions", http.StatusSeeOther)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
session, err := s.auths.GetSessionByToken(r.Context(), token)
|
|
|
|
|
if err != nil {
|
|
|
|
|
http.Redirect(w, r, "/sessions", http.StatusSeeOther)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if session.UserId == currentUser.Id {
|
|
|
|
|
_ = s.auths.DeleteSessionByTokenAndUserId(r.Context(), token, currentUser.Id)
|
|
|
|
|
} else if currentUser.SuperUser {
|
|
|
|
|
_ = s.auths.DeleteSession(r.Context(), token)
|
|
|
|
|
} else {
|
|
|
|
|
http.Error(w, "Forbidden", http.StatusForbidden)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
http.Redirect(w, r, "/sessions", http.StatusSeeOther)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *WebService) HandleSessionEndAll(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
if err := auth.ValidateCsrf(r, CsrfCookieName, CsrfFieldName); err != nil {
|
|
|
|
|
http.Redirect(w, r, "/sessions", http.StatusSeeOther)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u, err := s.currentUser(r)
|
|
|
|
|
if err != nil {
|
|
|
|
|
http.Redirect(w, r, "/signin?redirect="+url.PathEscape(r.URL.RequestURI()), http.StatusSeeOther)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_ = s.auths.DeleteSessionsByUserId(r.Context(), u.Id)
|
|
|
|
|
http.Redirect(w, r, "/sessions", http.StatusSeeOther)
|
|
|
|
|
}
|