package server import ( "crypto/rand" "encoding/hex" "encoding/json" "net/http" "time" ) type loginRequest struct { Token string `json:"token"` } func (s *Server) handleLogin(w http.ResponseWriter, r *http.Request) { ip := r.RemoteAddr s.mu.Lock() if lockTime, locked := s.loginLockout[ip]; locked && time.Now().Before(lockTime) { s.mu.Unlock() http.Error(w, "Too many attempts, locked for 60s", http.StatusForbidden) return } s.mu.Unlock() var req loginRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, "Invalid JSON", http.StatusBadRequest) return } if req.Token != s.accessToken { s.mu.Lock() s.loginAttempts[ip]++ if s.loginAttempts[ip] >= 5 { s.loginLockout[ip] = time.Now().Add(60 * time.Second) s.loginAttempts[ip] = 0 } s.mu.Unlock() http.Error(w, "Invalid token", http.StatusUnauthorized) return } s.mu.Lock() delete(s.loginAttempts, ip) delete(s.loginLockout, ip) s.mu.Unlock() sessionID := generateSessionID() s.mu.Lock() s.sessions[sessionID] = time.Now().Unix() s.mu.Unlock() http.SetCookie(w, &http.Cookie{ Name: "ydropbox_session", Value: sessionID, Path: "/", HttpOnly: true, SameSite: http.SameSiteLaxMode, Secure: true, MaxAge: 7 * 24 * 60 * 60, }) w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(map[string]string{}) } func (s *Server) handleLogout(w http.ResponseWriter, r *http.Request) { cookie, err := r.Cookie("ydropbox_session") if err != nil { http.Error(w, "Not logged in", http.StatusUnauthorized) return } s.mu.Lock() delete(s.sessions, cookie.Value) s.mu.Unlock() http.SetCookie(w, &http.Cookie{ Name: "ydropbox_session", Value: "", Path: "/", MaxAge: -1, }) w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(map[string]string{}) } func generateSessionID() string { b := make([]byte, 32) rand.Read(b) return hex.EncodeToString(b) }