From 66aeaef3c5844313c60a5e97e01b5531a43c5727 Mon Sep 17 00:00:00 2001 From: Gab <24553253+gabrix73@users.noreply.github.com> Date: Tue, 25 Nov 2025 20:21:26 +0100 Subject: Delete noshitalk-web-client.go --- noshitalk-web-client.go | 851 ------------------------------------------------ 1 file changed, 851 deletions(-) delete mode 100644 noshitalk-web-client.go (limited to 'noshitalk-web-client.go') diff --git a/noshitalk-web-client.go b/noshitalk-web-client.go deleted file mode 100644 index b72b977..0000000 --- a/noshitalk-web-client.go +++ /dev/null @@ -1,851 +0,0 @@ -package main - -import ( - "crypto/rand" - "encoding/hex" - "encoding/json" - "log" - "net/http" - "sync" - "time" - - "github.com/gorilla/websocket" -) - -// Message types -const ( - MsgTypeHandshake = "handshake" - MsgTypePublic = "public" - MsgTypePrivate = "private" - MsgTypeSystem = "system" - MsgTypeUserJoin = "user_join" - MsgTypeUserLeave = "user_leave" - MsgTypeUsersList = "users_list" -) - -// User represents a connected user -type User struct { - ID string - Name string - Avatar string - Fingerprint string - Conn *websocket.Conn - LastSeen time.Time - mu sync.Mutex -} - -// Message represents a chat message -type Message struct { - Type string `json:"type"` - From string `json:"from,omitempty"` - FromName string `json:"from_name,omitempty"` - FromAvatar string `json:"from_avatar,omitempty"` - To string `json:"to,omitempty"` - Text string `json:"text,omitempty"` - Timestamp time.Time `json:"timestamp,omitempty"` -} - -// UserInfo for user list -type UserInfo struct { - ID string `json:"id"` - Name string `json:"name"` - Avatar string `json:"avatar"` - Status string `json:"status"` -} - -// Server represents the chat server -type Server struct { - users map[string]*User - upgrader websocket.Upgrader - mu sync.RWMutex -} - -var server *Server - -func init() { - server = &Server{ - users: make(map[string]*User), - upgrader: websocket.Upgrader{ - CheckOrigin: func(r *http.Request) bool { - return true - }, - ReadBufferSize: 1024, - WriteBufferSize: 1024, - }, - } -} - -func NewUser(id, name, fingerprint string, conn *websocket.Conn) *User { - avatar := "" - if len(name) > 0 { - avatar = string(name[0]) - } - - return &User{ - ID: id, - Name: name, - Avatar: avatar, - Fingerprint: fingerprint, - Conn: conn, - LastSeen: time.Now(), - } -} - -func (u *User) SendMessage(msg Message) error { - u.mu.Lock() - defer u.mu.Unlock() - return u.Conn.WriteJSON(msg) -} - -func (s *Server) BroadcastPublic(msg Message) { - s.mu.RLock() - defer s.mu.RUnlock() - - for fingerprint, user := range s.users { - if fingerprint != msg.From { - go user.SendMessage(msg) - } - } -} - -func (s *Server) SendPrivate(msg Message) error { - s.mu.RLock() - defer s.mu.RUnlock() - - recipient, exists := s.users[msg.To] - if !exists { - return nil - } - - return recipient.SendMessage(msg) -} - -func (s *Server) AddUser(user *User) { - s.mu.Lock() - s.users[user.Fingerprint] = user - s.mu.Unlock() - - log.Printf("User added: %s (fingerprint: %s, total: %d)", user.Name, user.Fingerprint, len(s.users)) - - joinMsg := Message{ - Type: MsgTypeUserJoin, - From: user.Fingerprint, - FromName: user.Name, - FromAvatar: user.Avatar, - Text: user.Name + " joined the chat", - Timestamp: time.Now(), - } - s.BroadcastPublic(joinMsg) - - s.SendUsersList(user) - s.BroadcastUsersList() -} - -func (s *Server) RemoveUser(fingerprint string) { - s.mu.Lock() - user, exists := s.users[fingerprint] - if exists { - delete(s.users, fingerprint) - } - s.mu.Unlock() - - if exists { - log.Printf("User removed: %s (fingerprint: %s, remaining: %d)", user.Name, fingerprint, len(s.users)) - - leaveMsg := Message{ - Type: MsgTypeUserLeave, - From: fingerprint, - FromName: user.Name, - Text: user.Name + " left the chat", - Timestamp: time.Now(), - } - s.BroadcastPublic(leaveMsg) - s.BroadcastUsersList() - } -} - -func (s *Server) SendUsersList(user *User) { - s.mu.RLock() - defer s.mu.RUnlock() - - users := make([]UserInfo, 0, len(s.users)) - for _, u := range s.users { - if u.Fingerprint != user.Fingerprint { - users = append(users, UserInfo{ - ID: u.Fingerprint, - Name: u.Name, - Avatar: u.Avatar, - Status: "š Encrypted", - }) - } - } - - usersData, _ := json.Marshal(map[string]interface{}{ - "type": MsgTypeUsersList, - "users": users, - }) - - user.mu.Lock() - user.Conn.WriteMessage(websocket.TextMessage, usersData) - user.mu.Unlock() -} - -func (s *Server) BroadcastUsersList() { - s.mu.RLock() - defer s.mu.RUnlock() - - for _, user := range s.users { - go s.SendUsersList(user) - } -} - -func HandleWebSocket(w http.ResponseWriter, r *http.Request) { - conn, err := server.upgrader.Upgrade(w, r, nil) - if err != nil { - log.Printf("WebSocket upgrade error: %v", err) - return - } - - var handshake struct { - Type string `json:"type"` - Name string `json:"name"` - ID string `json:"id"` - Fingerprint string `json:"fingerprint"` - } - - err = conn.ReadJSON(&handshake) - if err != nil { - log.Printf("Handshake error: %v", err) - conn.Close() - return - } - - if handshake.Type != MsgTypeHandshake { - log.Printf("Invalid handshake type: %s", handshake.Type) - conn.Close() - return - } - - if handshake.Fingerprint == "" || len(handshake.Fingerprint) < 8 { - log.Printf("Invalid fingerprint") - conn.Close() - return - } - - server.mu.RLock() - _, exists := server.users[handshake.Fingerprint] - server.mu.RUnlock() - - if exists { - errorMsg := Message{ - Type: MsgTypeSystem, - Text: "Identity already connected. Only one session per identity allowed.", - } - conn.WriteJSON(errorMsg) - conn.Close() - return - } - - user := NewUser(handshake.ID, handshake.Name, handshake.Fingerprint, conn) - server.AddUser(user) - defer server.RemoveUser(user.Fingerprint) - - log.Printf("User connected: %s (%s)", user.Name, user.Fingerprint) - - welcomeMsg := Message{ - Type: MsgTypeSystem, - Text: "Welcome to NoshiTalk! Your identity is cryptographically protected.", - Timestamp: time.Now(), - } - user.SendMessage(welcomeMsg) - - for { - var msg Message - err := conn.ReadJSON(&msg) - if err != nil { - if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) { - log.Printf("WebSocket error: %v", err) - } - break - } - - msg.From = user.Fingerprint - msg.FromName = user.Name - msg.FromAvatar = user.Avatar - msg.Timestamp = time.Now() - - switch msg.Type { - case MsgTypePublic: - server.BroadcastPublic(msg) - log.Printf("Public message from %s: %s", user.Name, msg.Text) - - case MsgTypePrivate: - err := server.SendPrivate(msg) - if err != nil { - log.Printf("Private message error: %v", err) - } else { - log.Printf("Private message from %s to %s", user.Name, msg.To) - } - } - - user.LastSeen = time.Now() - } -} - -func HandleIndex(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "text/html; charset=utf-8") - w.Header().Set("X-Frame-Options", "DENY") - w.Header().Set("X-Content-Type-Options", "nosniff") - w.Header().Set("Referrer-Policy", "no-referrer") - - w.Write([]byte(htmlTemplate)) -} - -func generateChallenge() (string, error) { - b := make([]byte, 32) - _, err := rand.Read(b) - if err != nil { - return "", err - } - return hex.EncodeToString(b), nil -} - -func (s *Server) CleanupInactiveUsers() { - ticker := time.NewTicker(1 * time.Minute) - defer ticker.Stop() - - for range ticker.C { - s.mu.Lock() - now := time.Now() - for fingerprint, user := range s.users { - if now.Sub(user.LastSeen) > 5*time.Minute { - log.Printf("Removing inactive user: %s", user.Name) - delete(s.users, fingerprint) - user.Conn.Close() - } - } - s.mu.Unlock() - } -} - -const htmlTemplate = ` - -
- - -