filebrowser/backend/http/public.go

125 lines
3.2 KiB
Go

package http
import (
"errors"
"fmt"
"net/http"
"net/url"
"path"
"strings"
"golang.org/x/crypto/bcrypt"
"github.com/gtsteffaniak/filebrowser/files"
"github.com/gtsteffaniak/filebrowser/settings"
"github.com/gtsteffaniak/filebrowser/share"
"github.com/gtsteffaniak/filebrowser/users"
)
var withHashFile = func(fn handleFunc) handleFunc {
return func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
id, path := ifPathWithName(r)
fmt.Println(id, path)
link, err := d.store.Share.GetByHash(id)
if err != nil {
return errToStatus(err), err
}
if link.Hash != "" {
var status int
status, err = authenticateShareRequest(r, link) // Assign to the existing `err` variable
if err != nil || status != 0 {
return status, err
}
}
d.user = &users.PublicUser
realPath, err := files.GetRealPath(d.user.Scope, link.Path, path)
if err != nil {
return http.StatusNotFound, err
}
file, err := files.FileInfoFaster(files.FileOptions{
Path: realPath,
Modify: d.user.Perm.Modify,
Expand: true,
ReadHeader: d.server.TypeDetectionByHeader,
Checker: d,
Token: link.Token,
})
if err != nil {
return errToStatus(err), err
}
d.raw = file
return fn(w, r, d)
}
}
func ifPathWithName(r *http.Request) (id, filePath string) {
pathElements := strings.Split(r.URL.Path, "/")
id = pathElements[0]
allButFirst := path.Join(pathElements[1:]...)
return id, allButFirst
}
var publicShareHandler = withHashFile(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
file, ok := d.raw.(*files.FileInfo)
if !ok {
return http.StatusInternalServerError, fmt.Errorf("failed to assert type *files.FileInfo")
}
file.Path = strings.TrimPrefix(file.Path, settings.Config.Server.Root)
if file.IsDir {
return renderJSON(w, r, file)
}
return renderJSON(w, r, file)
})
var publicUserGetHandler = func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
// Call the actual handler logic here (e.g., renderJSON, etc.)
// You may need to replace `fn` with the actual handler logic.
return renderJSON(w, r, users.PublicUser)
}
var publicDlHandler = withHashFile(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
file, ok := d.raw.(*files.FileInfo)
if !ok {
return http.StatusInternalServerError, fmt.Errorf("failed to assert type *files.FileInfo")
}
if !file.IsDir {
return rawFileHandler(w, r, file)
}
return rawDirHandler(w, r, d, file)
})
func authenticateShareRequest(r *http.Request, l *share.Link) (int, error) {
if l.PasswordHash == "" {
return 0, nil
}
if r.URL.Query().Get("token") == l.Token {
return 0, nil
}
password := r.Header.Get("X-SHARE-PASSWORD")
password, err := url.QueryUnescape(password)
if err != nil {
return 0, err
}
if password == "" {
return http.StatusUnauthorized, nil
}
if err := bcrypt.CompareHashAndPassword([]byte(l.PasswordHash), []byte(password)); err != nil {
if errors.Is(err, bcrypt.ErrMismatchedHashAndPassword) {
return http.StatusUnauthorized, nil
}
return 0, err
}
return 0, nil
}
func healthHandler(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(`{"status":"OK"}`))
}