// // 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.RootIndex = 4 client.Logger = func(r *http.Request, err error) { } client.GenSubPathFunc = func(r *http.Request) (string, error) { // /:aid/*p uid, root := getid(r.URL.Path, prefix) if root == "/" { if !utils.FileExists(tmp + "/" + uid) { os.MkdirAll(tmp+"/"+uid, 0744) } } if r.Method == "OPTIONS" { return "", nil } payload, err := getToken(r) if err != nil { return "", err } if payload.Access.CheckPrefix("fs", root, auth.Do) && payload.UID == uid { return "", nil } return "", errs.AuthNoPerm } return client.ServeHTTP } func getid(url, prefix string) (string, string) { if strings.HasSuffix(prefix, "/") { prefix = prefix[:len(prefix)-1] } dir := strings.TrimPrefix(url, prefix) dirs := strings.Split(dir[1:], "/") id := "" root := "/" if len(dirs) > 0 { id = dirs[0] } if len(dirs) > 1 { root = "/" + strings.Join(dirs[1:], "/") } return id, root } 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 }