feat(security): implement brute force rate limit for share passwords and improve UX with inline errors and visibility toggle
All checks were successful
Automated Container Build / build-and-push (push) Successful in 1m21s
All checks were successful
Automated Container Build / build-and-push (push) Successful in 1m21s
This commit is contained in:
parent
5262103a1a
commit
78ba0bf2d5
3 changed files with 65 additions and 14 deletions
|
|
@ -19,6 +19,7 @@ import (
|
|||
type ShareHandler struct {
|
||||
DB *database.DB
|
||||
Config *config.Config
|
||||
Guard *middleware.BruteForceGuard
|
||||
}
|
||||
|
||||
type ShareRequest struct {
|
||||
|
|
@ -197,8 +198,14 @@ func (h *ShareHandler) GetPublicShare(c *fiber.Ctx) error {
|
|||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"require_password": true})
|
||||
}
|
||||
if !verifyPassword(req.Password, *hash) {
|
||||
if h.Guard != nil {
|
||||
h.Guard.RecordFailure(c.IP())
|
||||
}
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "invalid password"})
|
||||
}
|
||||
if h.Guard != nil {
|
||||
h.Guard.RecordSuccess(c.IP())
|
||||
}
|
||||
}
|
||||
|
||||
// Send file info
|
||||
|
|
@ -273,8 +280,14 @@ func (h *ShareHandler) CreateShareToken(c *fiber.Ctx) error {
|
|||
|
||||
if hash != nil {
|
||||
if req.Password == "" || !verifyPassword(req.Password, *hash) {
|
||||
if h.Guard != nil {
|
||||
h.Guard.RecordFailure(c.IP())
|
||||
}
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "invalid password"})
|
||||
}
|
||||
if h.Guard != nil {
|
||||
h.Guard.RecordSuccess(c.IP())
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a short-lived download token with the share ID
|
||||
|
|
|
|||
|
|
@ -67,7 +67,8 @@ func main() {
|
|||
tusHandler := handlers.NewTusHandler(db, cfg)
|
||||
webdavHandler := handlers.NewWebDAVHandler(db, cfg)
|
||||
archiveHandler := &handlers.ArchiveHandler{DB: db, Config: cfg}
|
||||
shareHandler := &handlers.ShareHandler{DB: db, Config: cfg}
|
||||
shareGuard := middleware.NewBruteForceGuard(3, 60)
|
||||
shareHandler := &handlers.ShareHandler{DB: db, Config: cfg, Guard: shareGuard}
|
||||
|
||||
// Initialize background workers
|
||||
workers.InitTaskManager(cfg)
|
||||
|
|
@ -130,8 +131,8 @@ func main() {
|
|||
Max: 500,
|
||||
Expiration: 1 * time.Minute,
|
||||
}))
|
||||
public.Post("/share/:id/token", shareHandler.CreateShareToken)
|
||||
public.Post("/share/:id", shareHandler.GetPublicShare)
|
||||
public.Post("/share/:id/token", shareGuard.Check(), shareHandler.CreateShareToken)
|
||||
public.Post("/share/:id", shareGuard.Check(), shareHandler.GetPublicShare)
|
||||
public.Get("/download/:id", shareHandler.DownloadPublicShare)
|
||||
|
||||
// Auth routes (with brute force protection)
|
||||
|
|
|
|||
Reference in a new issue