Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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。
16 changes: 13 additions & 3 deletions auth/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"io"
"net/http"
"strings"

"github.com/sirupsen/logrus"
)

type Client struct {
Expand All @@ -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 {
Expand Down
37 changes: 25 additions & 12 deletions auth/gitee.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"strings"

"github.com/metalogical/BigFiles/config"
"github.com/sirupsen/logrus"
)

var (
Expand All @@ -23,7 +24,6 @@ var (
)

type giteeUser struct {
Login string `json:"login"`
Permission string `json:"permission"`
}

Expand Down Expand Up @@ -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 {
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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)
}
}
4 changes: 2 additions & 2 deletions docs/BasicGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -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远程地址:
Expand All @@ -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追踪的文件
Expand Down
15 changes: 9 additions & 6 deletions docs/QuickStart.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

```
[lfs]
   url = https://openeuler-bigfiles.test.osinfra.cn/{owner}/{repo}
url = https://openeuler-bigfiles.test.osinfra.cn/{owner}/{repo}
```

- 或者通过命令行设置仓库中LFS远程地址:
Expand All @@ -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服务的仓库中的大文件

Expand Down
19 changes: 12 additions & 7 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"net/http"
"os"
"regexp"
"strings"
"time"

"github.com/go-chi/chi"
Expand Down Expand Up @@ -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
}
Expand Down