Files
OpenList/internal/model/sharing.go
awaae 78c5d9b60b fix(sharing): count share access atomically per client IP (#3294)
- Atomically reserve sharing access slots in the database.
- Deduplicate access counting by client IP for 30 minutes.
- Separate sharing usability and password validation from access-limit checks.
- Keep browsing and archive metadata operations non-counting.
- Count downloads, link generation, and archive extraction through the unified access flow.
- Coordinate same-IP validation with slot publication to prevent concurrent requests from being rejected during the cache update window.
- Add coverage for database-authoritative access state, concurrent access limits, same-IP deduplication, and cache publication races.
2026-10-29 22:30:16 +08:00

53 lines
1.2 KiB
Go

package model
import "time"
type SharingDB struct {
ID string `json:"id" gorm:"type:varchar(64);primaryKey"`
FilesRaw string `json:"-" gorm:"type:text"`
Expires *time.Time `json:"expires"`
Pwd string `json:"pwd"`
Accessed int `json:"accessed"`
MaxAccessed int `json:"max_accessed"`
CreatorId uint `json:"-"`
Disabled bool `json:"disabled"`
Remark string `json:"remark"`
Readme string `json:"readme" gorm:"type:text"`
Header string `json:"header" gorm:"type:text"`
Sort
}
type Sharing struct {
*SharingDB
Files []string `json:"files"`
Creator *User `json:"-"`
}
func (s *Sharing) Valid() bool {
return s.Usable() && !s.LimitReached()
}
func (s *SharingDB) LimitReached() bool {
return s.MaxAccessed > 0 && s.Accessed >= s.MaxAccessed
}
func (s *Sharing) Usable() bool {
if s.Disabled {
return false
}
if len(s.Files) == 0 {
return false
}
if s.Creator == nil || !s.Creator.CanShare() {
return false
}
if s.Expires != nil && !s.Expires.IsZero() && s.Expires.Before(time.Now()) {
return false
}
return true
}
func (s *Sharing) Verify(pwd string) bool {
return s.Pwd == "" || s.Pwd == pwd
}