|
|
|
//
|
|
|
|
// user.go
|
|
|
|
// Copyright (C) 2024 veypi <i@veypi.com>
|
|
|
|
// 2024-10-22 15:49
|
|
|
|
// Distributed under terms of the GPL license.
|
|
|
|
//
|
|
|
|
|
|
|
|
package fs
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"encoding/base64"
|
|
|
|
"net/http"
|
|
|
|
"oa/cfg"
|
|
|
|
"oa/errs"
|
|
|
|
"oa/libs/auth"
|
|
|
|
"oa/libs/webdav"
|
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/veypi/utils"
|
|
|
|
"github.com/veypi/utils/logv"
|
|
|
|
)
|
|
|
|
|
|
|
|
func NewUserFs(prefix string) func(http.ResponseWriter, *http.Request) {
|
|
|
|
if strings.HasSuffix(prefix, "/") {
|
|
|
|
prefix = prefix[:len(prefix)-1]
|
|
|
|
}
|
|
|
|
tmp := utils.PathJoin(cfg.Config.FsPath, "u")
|
|
|
|
if !utils.FileExists(tmp) {
|
|
|
|
logv.AssertError(os.MkdirAll(tmp, 0744))
|
|
|
|
}
|
|
|
|
|
|
|
|
client := webdav.NewWebdav(tmp)
|
|
|
|
client.Prefix = prefix
|
|
|
|
client.Logger = func(r *http.Request, err error) {
|
|
|
|
}
|
|
|
|
client.GenSubPathFunc = func(r *http.Request) (string, error) {
|
|
|
|
dir := strings.TrimPrefix(r.URL.Path, prefix)
|
|
|
|
logv.Warn().Msg(dir)
|
|
|
|
payload, err := getToken(r)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
if !strings.HasPrefix(dir, "/") {
|
|
|
|
dir = "/" + dir
|
|
|
|
}
|
|
|
|
if payload.Access.CheckPrefix("fs", dir, auth.Do) {
|
|
|
|
if dir == "/" {
|
|
|
|
if !utils.FileExists(tmp + "/" + payload.UID) {
|
|
|
|
os.MkdirAll(tmp+"/"+payload.UID, 0744)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return "/" + payload.UID + dir, nil
|
|
|
|
}
|
|
|
|
return "", errs.AuthNoPerm
|
|
|
|
}
|
|
|
|
return client.ServeHTTP
|
|
|
|
}
|
|
|
|
|
|
|
|
func getToken(r *http.Request) (*auth.Claims, error) {
|
|
|
|
authHeader := r.Header.Get("Authorization")
|
|
|
|
token := ""
|
|
|
|
if authHeader != "" {
|
|
|
|
typ := ""
|
|
|
|
if tags := strings.Split(authHeader, " "); len(tags) > 1 {
|
|
|
|
typ = strings.ToLower(tags[0])
|
|
|
|
}
|
|
|
|
if typ == "basic" {
|
|
|
|
decodedAuth, err := base64.StdEncoding.DecodeString(authHeader[6:])
|
|
|
|
if err != nil {
|
|
|
|
return nil, errs.AuthInvalid
|
|
|
|
}
|
|
|
|
// 通常认证信息格式为 username:password
|
|
|
|
credentials := string(decodedAuth)
|
|
|
|
reader := bufio.NewReader(strings.NewReader(credentials))
|
|
|
|
username, _ := reader.ReadString(':')
|
|
|
|
password := credentials[len(username):]
|
|
|
|
|
|
|
|
username = strings.TrimSuffix(username, "\n")
|
|
|
|
username = strings.TrimSuffix(username, ":")
|
|
|
|
token = strings.TrimPrefix(password, "\n")
|
|
|
|
} else if typ == "bearer" {
|
|
|
|
token = authHeader[7:]
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
acookie, err := r.Cookie("fstoken")
|
|
|
|
if err == nil {
|
|
|
|
token = acookie.Value
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if token == "" {
|
|
|
|
return nil, errs.AuthNotFound
|
|
|
|
}
|
|
|
|
payload, err := auth.ParseJwt(token)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return payload, nil
|
|
|
|
}
|