mirror of
https://github.com/filebrowser/filebrowser.git
synced 2025-05-08 03:12:09 +00:00

This changes allows to password protect shares. It works by: * Allowing to optionally pass a password when creating a share * If set, the password + salt that is configured via a new flag will be hashed via bcrypt and the hash stored together with the rest of the share * Additionally, a random 96 byte long token gets generated and stored as part of the share * When the backend retrieves an unauthenticated request for a share that has authentication configured, it will return a http 401 * The frontend detects this and will show a login prompt * The actual download links are protected via an url arg that contains the previously generated token. This allows us to avoid buffering the download in the browser and allows pasting the link without breaking it
134 lines
2.9 KiB
Go
134 lines
2.9 KiB
Go
package users
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/filebrowser/filebrowser/v2/errors"
|
|
)
|
|
|
|
// StorageBackend is the interface to implement for a users storage.
|
|
type StorageBackend interface {
|
|
GetBy(interface{}) (*User, error)
|
|
Gets() ([]*User, error)
|
|
Save(u *User) error
|
|
Update(u *User, fields ...string) error
|
|
DeleteByID(uint) error
|
|
DeleteByUsername(string) error
|
|
}
|
|
|
|
type Store interface {
|
|
Get(baseScope string, id interface{}) (user *User, err error)
|
|
Gets(baseScope string) ([]*User, error)
|
|
Update(user *User, fields ...string) error
|
|
Save(user *User) error
|
|
Delete(id interface{}) error
|
|
LastUpdate(id uint) int64
|
|
}
|
|
|
|
// Storage is a users storage.
|
|
type Storage struct {
|
|
back StorageBackend
|
|
updated map[uint]int64
|
|
mux sync.RWMutex
|
|
}
|
|
|
|
// NewStorage creates a users storage from a backend.
|
|
func NewStorage(back StorageBackend) *Storage {
|
|
return &Storage{
|
|
back: back,
|
|
updated: map[uint]int64{},
|
|
}
|
|
}
|
|
|
|
// Get allows you to get a user by its name or username. The provided
|
|
// id must be a string for username lookup or a uint for id lookup. If id
|
|
// is neither, a ErrInvalidDataType will be returned.
|
|
func (s *Storage) Get(baseScope string, id interface{}) (user *User, err error) {
|
|
user, err = s.back.GetBy(id)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if err := user.Clean(baseScope); err != nil {
|
|
return nil, err
|
|
}
|
|
return
|
|
}
|
|
|
|
// Gets gets a list of all users.
|
|
func (s *Storage) Gets(baseScope string) ([]*User, error) {
|
|
users, err := s.back.Gets()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, user := range users {
|
|
if err := user.Clean(baseScope); err != nil { //nolint:shadow
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return users, err
|
|
}
|
|
|
|
// Update updates a user in the database.
|
|
func (s *Storage) Update(user *User, fields ...string) error {
|
|
err := user.Clean("", fields...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = s.back.Update(user, fields...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
s.mux.Lock()
|
|
s.updated[user.ID] = time.Now().Unix()
|
|
s.mux.Unlock()
|
|
return nil
|
|
}
|
|
|
|
// Save saves the user in a storage.
|
|
func (s *Storage) Save(user *User) error {
|
|
if err := user.Clean(""); err != nil {
|
|
return err
|
|
}
|
|
|
|
return s.back.Save(user)
|
|
}
|
|
|
|
// Delete allows you to delete a user by its name or username. The provided
|
|
// id must be a string for username lookup or a uint for id lookup. If id
|
|
// is neither, a ErrInvalidDataType will be returned.
|
|
func (s *Storage) Delete(id interface{}) error {
|
|
switch id := id.(type) {
|
|
case string:
|
|
user, err := s.back.GetBy(id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if user.ID == 1 {
|
|
return errors.ErrRootUserDeletion
|
|
}
|
|
return s.back.DeleteByUsername(id)
|
|
case uint:
|
|
if id == 1 {
|
|
return errors.ErrRootUserDeletion
|
|
}
|
|
return s.back.DeleteByID(id)
|
|
default:
|
|
return errors.ErrInvalidDataType
|
|
}
|
|
}
|
|
|
|
// LastUpdate gets the timestamp for the last update of an user.
|
|
func (s *Storage) LastUpdate(id uint) int64 {
|
|
s.mux.RLock()
|
|
defer s.mux.RUnlock()
|
|
if val, ok := s.updated[id]; ok {
|
|
return val
|
|
}
|
|
return 0
|
|
}
|