fix: address branch review issues (json tags, share lockout, session expiry, file unlink)
This commit is contained in:
@@ -80,9 +80,15 @@ func (s *Server) handleDownload(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func (s *Server) handleDeleteFile(w http.ResponseWriter, r *http.Request) {
|
||||
id := r.PathValue("id")
|
||||
f, err := s.store.FileGet(id)
|
||||
if err != nil {
|
||||
http.Error(w, "Not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
if err := s.store.FileDelete(id); err != nil {
|
||||
http.Error(w, "Failed to delete", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
os.Remove(filepath.Join(s.workspace, f.Dir, f.StorageName))
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
@@ -2,8 +2,11 @@ package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
const sessionMaxAge = 7 * 86400
|
||||
|
||||
func (s *Server) requireAuth(next http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
cookie, err := r.Cookie("ydropbox_session")
|
||||
@@ -13,7 +16,14 @@ func (s *Server) requireAuth(next http.HandlerFunc) http.HandlerFunc {
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
_, exists := s.sessions[cookie.Value]
|
||||
createdAt, exists := s.sessions[cookie.Value]
|
||||
if exists && time.Now().Unix()-createdAt > sessionMaxAge {
|
||||
delete(s.sessions, cookie.Value)
|
||||
exists = false
|
||||
}
|
||||
if exists {
|
||||
s.sessions[cookie.Value] = time.Now().Unix()
|
||||
}
|
||||
s.mu.Unlock()
|
||||
|
||||
if !exists {
|
||||
@@ -34,7 +44,14 @@ func (s *Server) requireAuthPage(next http.HandlerFunc) http.HandlerFunc {
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
_, exists := s.sessions[cookie.Value]
|
||||
createdAt, exists := s.sessions[cookie.Value]
|
||||
if exists && time.Now().Unix()-createdAt > sessionMaxAge {
|
||||
delete(s.sessions, cookie.Value)
|
||||
exists = false
|
||||
}
|
||||
if exists {
|
||||
s.sessions[cookie.Value] = time.Now().Unix()
|
||||
}
|
||||
s.mu.Unlock()
|
||||
|
||||
if !exists {
|
||||
|
||||
@@ -17,6 +17,8 @@ type Server struct {
|
||||
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
|
||||
}
|
||||
@@ -29,6 +31,8 @@ func New(store *store.Store, accessToken string, workspace string) *Server {
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,12 +108,35 @@ func (s *Server) handleSharePassword(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
key := share.ID
|
||||
s.mu.Lock()
|
||||
if lockTime, locked := s.shareLockout[key]; locked && time.Now().Before(lockTime) {
|
||||
s.mu.Unlock()
|
||||
http.Error(w, "Too many attempts, locked for 60s", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
s.mu.Unlock()
|
||||
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
|
||||
password := r.FormValue("password")
|
||||
if err := bcrypt.CompareHashAndPassword([]byte(share.PasswordHash), []byte(password)); err != nil {
|
||||
s.mu.Lock()
|
||||
s.shareAttempts[key]++
|
||||
if s.shareAttempts[key] >= 5 {
|
||||
s.shareLockout[key] = time.Now().Add(60 * time.Second)
|
||||
s.shareAttempts[key] = 0
|
||||
}
|
||||
s.mu.Unlock()
|
||||
http.Error(w, "Wrong password", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
delete(s.shareAttempts, key)
|
||||
delete(s.shareLockout, key)
|
||||
s.mu.Unlock()
|
||||
|
||||
cookieVal := generateSessionID()
|
||||
s.mu.Lock()
|
||||
if s.shareSessions == nil {
|
||||
|
||||
@@ -3,12 +3,12 @@ package store
|
||||
import "database/sql"
|
||||
|
||||
type File struct {
|
||||
ID string
|
||||
OriginalName string
|
||||
StorageName string
|
||||
Dir string
|
||||
Size int64
|
||||
CreatedAt int64
|
||||
ID string `json:"id"`
|
||||
OriginalName string `json:"name"`
|
||||
StorageName string `json:"-"`
|
||||
Dir string `json:"dir"`
|
||||
Size int64 `json:"size"`
|
||||
CreatedAt int64 `json:"created_at"`
|
||||
}
|
||||
|
||||
func (s *Store) FileCreate(f *File) error {
|
||||
|
||||
@@ -60,7 +60,7 @@ func TestIntegration(t *testing.T) {
|
||||
var uploadResp map[string]any
|
||||
json.NewDecoder(uploadRes.Body).Decode(&uploadResp)
|
||||
file := uploadResp["file"].(map[string]any)
|
||||
fileID := file["ID"].(string)
|
||||
fileID := file["id"].(string)
|
||||
|
||||
listReq, _ := http.NewRequest("GET", ts.URL+"/api/files?dir=inbox", nil)
|
||||
for _, cookie := range loginRes.Cookies() {
|
||||
|
||||
Reference in New Issue
Block a user