package chat import ( "fmt" "net/http" "strings" "time" "code.nonshy.com/nonshy/website/pkg/config" "code.nonshy.com/nonshy/website/pkg/models" "code.nonshy.com/nonshy/website/pkg/photo" "code.nonshy.com/nonshy/website/pkg/session" "code.nonshy.com/nonshy/website/pkg/templates" "github.com/golang-jwt/jwt/v4" ) // JWT claims. type Claims struct { // Custom claims. IsAdmin bool `json:"op"` Avatar string `json:"img"` ProfileURL string `json:"url"` Nickname string `json:"nick"` // Standard claims. Notes: // subject = username jwt.RegisteredClaims } // Landing page for chat rooms. func Landing() http.HandlerFunc { tmpl := templates.Must("chat.html") return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Get the current user. currentUser, err := session.CurrentUser(r) if err != nil { session.FlashError(w, r, "Couldn't get current user: %s", err) templates.Redirect(w, "/") return } // Are they logging into the chat room? var ( intent = r.FormValue("intent") isShy = currentUser.IsShy() ) if intent == "join" { // If we are shy, block chat for now. if isShy { session.FlashError(w, r, "You have a Shy Account and are not allowed in the chat room at this time where our non-shy members may "+ "be on camera.", ) templates.Redirect(w, "/chat") return } // Get our Chat JWT secret. var ( secret = []byte(config.Current.BareRTC.JWTSecret) chatURL = config.Current.BareRTC.URL ) if len(secret) == 0 || chatURL == "" { session.FlashError(w, r, "Couldn't sign you into the chat: JWT secret key or chat URL not configured!") templates.Redirect(w, r.URL.Path) return } // Avatar URL - masked if non-public. avatar := photo.URLPath(currentUser.ProfilePhoto.CroppedFilename) switch currentUser.ProfilePhoto.Visibility { case models.PhotoPrivate: avatar = "/static/img/shy-private.png" case models.PhotoFriends: avatar = "/static/img/shy-friends.png" } // Create the JWT claims. claims := Claims{ IsAdmin: currentUser.IsAdmin, Avatar: avatar, ProfileURL: "/u/" + currentUser.Username, Nickname: currentUser.NameOrUsername(), RegisteredClaims: jwt.RegisteredClaims{ // TODO: ExpiresAt 60 minutes to work around chat server reliability, // should be shorter like 5 minutes. ExpiresAt: jwt.NewNumericDate(time.Now().Add(60 * time.Minute)), IssuedAt: jwt.NewNumericDate(time.Now()), NotBefore: jwt.NewNumericDate(time.Now()), Issuer: config.Title, Subject: currentUser.Username, ID: fmt.Sprintf("%d", currentUser.ID), }, } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) ss, err := token.SignedString(secret) if err != nil { session.FlashError(w, r, "Couldn't sign you into the chat: %s", err) templates.Redirect(w, r.URL.Path) return } // Redirect them to the chat room. templates.Redirect(w, strings.TrimSuffix(chatURL, "/")+"/?jwt="+ss) return } var vars = map[string]interface{}{ "ChatAPI": strings.TrimSuffix(config.Current.BareRTC.URL, "/") + "/api/statistics", "IsShyUser": isShy, } if err := tmpl.Execute(w, r, vars); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } }) }