// // user.go // Copyright (C) 2024 veypi // 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 }