diff --git a/README.md b/README.md index 4a8ff1d..c1be88c 100644 --- a/README.md +++ b/README.md @@ -15,4 +15,5 @@ v2.12.0](https://github.com/git-lfs/git-lfs/tree/v2.12.0/docs/api) server. 5. ~~认证时校验用户在仓库内权限。~~ 6. 支持ssh。 7. ~~仓库添加github action。~~ -8. 添加日志。 +8. ~~添加日志。~~ +9. 支持cdn。 diff --git a/auth/client.go b/auth/client.go index a2a4d68..aa3edf5 100644 --- a/auth/client.go +++ b/auth/client.go @@ -7,6 +7,8 @@ import ( "io" "net/http" "strings" + + "github.com/sirupsen/logrus" ) type Client struct { @@ -19,19 +21,27 @@ func getParsedResponse(method, path string, header http.Header, body io.Reader, panic(err) } req.Header = header - fmt.Println(strings.Split(path, "?")[0]) response, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer response.Body.Close() + + if splitPath := strings.Split(path, "?"); len(splitPath) != 1 { + logrus.Infof("query %s with token | %d", splitPath[0], response.StatusCode) + } else { + logrus.Infof("query %s without token | %d", splitPath[0], response.StatusCode) + } + if response.StatusCode/100 != 2 { if response.StatusCode == http.StatusNotFound { - return errors.New("repository not found") + return errors.New("not_found") } else if response.StatusCode == http.StatusUnauthorized { return errors.New("unauthorized") + } else if response.StatusCode == http.StatusForbidden { + return errors.New("forbidden") } - return errors.New("error occurred accessing gitee") + return fmt.Errorf("system_error: %v", response.StatusCode) } data, err := io.ReadAll(response.Body) if err != nil { diff --git a/auth/gitee.go b/auth/gitee.go index cbf7177..87ca5bb 100644 --- a/auth/gitee.go +++ b/auth/gitee.go @@ -9,6 +9,7 @@ import ( "strings" "github.com/metalogical/BigFiles/config" + "github.com/sirupsen/logrus" ) var ( @@ -23,7 +24,6 @@ var ( ) type giteeUser struct { - Login string `json:"login"` Permission string `json:"permission"` } @@ -101,7 +101,8 @@ func CheckRepoOwner(userInRepo UserInRepo) error { repo := new(Repo) err := getParsedResponse("GET", path, headers, nil, &repo) if err != nil { - return err + msg := err.Error() + ": check repo_id failed" + return errors.New(msg) } for _, allowedRepo := range allowedRepos { if strings.Split(repo.Fullname, "/")[0] == allowedRepo { @@ -116,8 +117,9 @@ func CheckRepoOwner(userInRepo UserInRepo) error { } } } - - return errors.New("your repository does not appear to have permission to use this lfs service") + msg := "forbidden: repo has no permission to use this lfs server" + logrus.Error(fmt.Sprintf("CheckRepoOwner | %s", msg)) + return errors.New(msg) } // getToken gets access_token by username and password @@ -135,7 +137,8 @@ func getToken(username, password string) (string, error) { accessToken := new(AccessToken) err := getParsedResponse("POST", path, headers, strings.NewReader(form.Encode()), &accessToken) if err != nil { - return "", err + msg := err.Error() + ": get token failed. Or may be it is already a token" + return "", errors.New(msg) } return accessToken.Token, nil @@ -156,27 +159,37 @@ func verifyUser(userInRepo UserInRepo) error { giteeUser := new(giteeUser) err := getParsedResponse("GET", path, headers, nil, &giteeUser) if err != nil { - return err + msg := err.Error() + ": verify user permission failed" + logrus.Error(fmt.Sprintf("verifyUser | %s", msg)) + return errors.New(msg) } - if giteeUser.Login != userInRepo.Username { - return errors.New("username does not match") - } if userInRepo.Operation == "upload" { for _, v := range uploadPermissions { if giteeUser.Permission == v { return nil } } - return errors.New("user has no permission uploading to the repository") + msg := fmt.Sprintf("forbidden: user %s has no permission to upload to %s/%s", + userInRepo.Username, userInRepo.Owner, userInRepo.Repo) + remindMsg := " \n如果您正在向fork仓库上传大文件,请确认您已使用如下命令修改了本地仓库的配置:" + + "\n`git config --local lfs.url https://openeuler-bigfiles.test.osinfra.cn/{owner}/{repo}`" + + ",\n其中{owner}/{repo}请改为您fork之后的仓库的名称。" + + "详阅:https://github.com/opensourceways/BigFiles/blob/master/docs/QuickStart.md" + logrus.Error(fmt.Sprintf("verifyUser | %s", msg)) + return errors.New(msg + remindMsg) } else if userInRepo.Operation == "download" { for _, v := range downloadPermissions { if giteeUser.Permission == v { return nil } } - return errors.New("user has no permission downloading in the repository") + msg := fmt.Sprintf("forbidden: user %s has no permission to download", userInRepo.Username) + logrus.Error(fmt.Sprintf("verifyUser | %s", msg)) + return errors.New(msg) } else { - return errors.New("unknow operation") + msg := "system_error: unknow operation" + logrus.Error(fmt.Sprintf("verifyUser | %s", msg)) + return errors.New(msg) } } diff --git a/docs/BasicGuide.md b/docs/BasicGuide.md index f921308..e73ba0a 100644 --- a/docs/BasicGuide.md +++ b/docs/BasicGuide.md @@ -53,7 +53,7 @@ Git LFS initialized. ``` [lfs] -   url = https://openeuler-bigfiles.test.osinfra.cn/{owner}/{repo} + url = https://openeuler-bigfiles.test.osinfra.cn/{owner}/{repo} ``` - 或者通过命令行设置仓库中LFS远程地址: @@ -63,7 +63,7 @@ git config --local lfs.url https://openeuler-bigfiles.test.osinfra.cn/{owner}/{r ``` > - 当存在.lfsconfig文件时,使用命令行进行LFS远程地址设置的优先级将高于.lfsconfig文件。 -> - 在fork一个已经使用第三方LFS服务服务作为LFS远程服务的仓库后,需要手动修改新仓库中LFS远程地址中的{owner}以及{repo},否则会出现权限校验问题,**错误代码401**。 +> - 在fork一个已经使用第三方LFS服务服务作为LFS远程服务的仓库后,需要需手动使用上述命令设置仓库中LFS远程地址,否则可能会出现权限校验问题,**错误代码401**。 > - url中{owner}/{repo}替换为实际的仓库路径,注意仓库路径的大小写。 - 选择要用LFS追踪的文件 diff --git a/docs/QuickStart.md b/docs/QuickStart.md index f45733d..726ed4c 100644 --- a/docs/QuickStart.md +++ b/docs/QuickStart.md @@ -12,7 +12,7 @@ ``` [lfs] -    url = https://openeuler-bigfiles.test.osinfra.cn/{owner}/{repo} + url = https://openeuler-bigfiles.test.osinfra.cn/{owner}/{repo} ``` - 或者通过命令行设置仓库中LFS远程地址: @@ -22,16 +22,19 @@ $ git config --local lfs.url https://openeuler-bigfiles.test.osinfra.cn/{owner}/ ``` > 当存在.lfsconfig文件时,使用命令行进行LFS远程地址设置的优先级将高于.lfsconfig文件。 - url中{owner}/{repo}替换为实际的仓库路径,如:openeuler/lfs。由于Gitee默认会将仓库路径中的大写转化为小写,请确认仓库路径的大小写。 +> url中{owner}/{repo}替换为实际的仓库路径,如:openeuler/lfs。由于Gitee默认会将仓库路径中的大写转化为小写,请确认仓库路径的大小写。 ## 第三方LFS服务与Gitee的使用差异 关于GIT LFS的基本使用请详阅[基础教程](BasicGuide.md)。我们努力使第三方LFS服务与原生LFS服务的使用差异尽可能少,以下是现存的一些差异: -- 当您fork一个仓库: - - 在fork一个已经使用第三方LFS服务作为LFS远程服务的仓库后,需要手动修改新仓库中LFS远程地址中的{owner}以及{repo},否则会出现权限校验问题,**错误代码401**。 -- 当您使用ssh协议进行克隆或推送: - - 在使用SSH对Gitee仓库进行克隆后,在使用第三方LFS服务作为LFS远程服务时,仍然需要输入账户和密码。 +- 当您fork一个仓库:将fork仓库克隆到本地后,需手动使用如下命令修改本地仓库的lfs配置: + + ``` + $ git config --local lfs.url https://openeuler-bigfiles.test.osinfra.cn/{owner}/{repo} + ``` + +- 当您使用ssh协议进行克隆或推送:克隆或推送大文件时仍需输入用户名和密码进行认证。 ## 迁移Gitee中使用LFS服务的仓库中的大文件 diff --git a/server/server.go b/server/server.go index 4e0f1f9..241e493 100644 --- a/server/server.go +++ b/server/server.go @@ -8,6 +8,7 @@ import ( "net/http" "os" "regexp" + "strings" "time" "github.com/go-chi/chi" @@ -139,18 +140,22 @@ func (s *server) handleBatch(w http.ResponseWriter, r *http.Request) { userInRepo.Username = username userInRepo.Password = password err = s.isAuthorized(userInRepo) - // TODO: 若仓库无lfs服务权限,不能返回401,否则会继续提示输入用户名密码。返回403 - if err != nil { - err = fmt.Errorf("unauthorized: %w", err) - } } else { - err = errors.New("Unauthorized") + err = errors.New("unauthorized: cannot get password") } if err != nil { + v := err.Error() + switch { + case strings.HasPrefix(v, "unauthorized") || strings.HasPrefix(v, "not_found"): + w.WriteHeader(401) + case strings.HasPrefix(v, "forbidden"): + w.WriteHeader(403) + default: + w.WriteHeader(500) + } w.Header().Set("LFS-Authenticate", `Basic realm="Git LFS"`) - w.WriteHeader(401) must(json.NewEncoder(w).Encode(batch.ErrorResponse{ - Message: err.Error(), + Message: v, })) return }