- Add i18n (English + 简体中文) with a locale store, $t() magic, and a language toggle (persisted) - Add light/dark/system theme switching via a theme store and [data-theme] token overrides - Set the theme before paint to avoid a flash of the wrong theme - Add frontend version constant web/version.js (window.YDROPBX_VERSION) shown in the app footer - Update AGENTS.md version-control convention to mention web/version.js - Bump version to 0.1.1 across frontend, webui changelog, and backend constant
80 lines
2.3 KiB
Go
80 lines
2.3 KiB
Go
package server
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"net/http"
|
|
"sync"
|
|
"time"
|
|
"yoresee_dropbox/internal/store"
|
|
"yoresee_dropbox/web"
|
|
)
|
|
|
|
type Server struct {
|
|
store *store.Store
|
|
accessToken string
|
|
sessions map[string]int64
|
|
shareSessions map[string]string
|
|
loginAttempts map[string]int
|
|
loginLockout map[string]time.Time
|
|
shareAttempts map[string]int
|
|
shareLockout map[string]time.Time
|
|
mu sync.Mutex
|
|
workspace string
|
|
}
|
|
|
|
func New(store *store.Store, accessToken string, workspace string) *Server {
|
|
return &Server{
|
|
store: store,
|
|
accessToken: accessToken,
|
|
sessions: make(map[string]int64),
|
|
shareSessions: make(map[string]string),
|
|
loginAttempts: make(map[string]int),
|
|
loginLockout: make(map[string]time.Time),
|
|
shareAttempts: make(map[string]int),
|
|
shareLockout: make(map[string]time.Time),
|
|
workspace: workspace,
|
|
}
|
|
}
|
|
|
|
func generateUUID() string {
|
|
b := make([]byte, 16)
|
|
rand.Read(b)
|
|
return hex.EncodeToString(b)
|
|
}
|
|
|
|
func (s *Server) Handler() http.Handler {
|
|
mux := http.NewServeMux()
|
|
|
|
mux.HandleFunc("POST /api/login", s.handleLogin)
|
|
mux.HandleFunc("POST /api/logout", s.requireAuth(s.handleLogout))
|
|
mux.HandleFunc("POST /api/upload", s.requireAuth(s.handleUpload))
|
|
mux.HandleFunc("GET /api/files", s.requireAuth(s.handleListFiles))
|
|
mux.HandleFunc("GET /api/files/{id}/download", s.requireAuth(s.handleDownload))
|
|
mux.HandleFunc("DELETE /api/files/{id}", s.requireAuth(s.handleDeleteFile))
|
|
mux.HandleFunc("POST /api/files/{id}/share", s.requireAuth(s.handleCreateShare))
|
|
mux.HandleFunc("GET /api/shares", s.requireAuth(s.handleListShares))
|
|
mux.HandleFunc("DELETE /api/shares/{id}", s.requireAuth(s.handleDeleteShare))
|
|
|
|
mux.HandleFunc("GET /s/{token}", s.handleShareAccess)
|
|
mux.HandleFunc("POST /s/{token}", s.handleSharePassword)
|
|
|
|
mux.HandleFunc("GET /login", func(w http.ResponseWriter, r *http.Request) {
|
|
data, _ := web.FS.ReadFile("login.html")
|
|
w.Write(data)
|
|
})
|
|
|
|
mux.HandleFunc("GET /{$}", s.requireAuthPage(func(w http.ResponseWriter, r *http.Request) {
|
|
data, _ := web.FS.ReadFile("index.html")
|
|
w.Write(data)
|
|
}))
|
|
|
|
static := http.FileServerFS(web.FS)
|
|
mux.Handle("GET /components/", static)
|
|
mux.Handle("GET /styles/", static)
|
|
mux.Handle("GET /version.js", static)
|
|
mux.Handle("GET /alpine.min.js", static)
|
|
|
|
return mux
|
|
}
|