Skip to content
Merged
28 changes: 28 additions & 0 deletions routers/api/v1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,15 @@ func reqRepoWriter(unitTypes ...unit.Type) func(ctx *context.APIContext) {
ctx.Error(http.StatusForbidden, "reqRepoWriter", "user should have a permission to write to a repo")
return
}

for _, unitType := range unitTypes {
if ctx.Repo.CanWrite(unitType) {
checkPublicOnly(ctx, unitType)
if ctx.Written() {
return
}
}
}
}
}

Expand All @@ -398,6 +407,23 @@ func reqRepoBranchWriter(ctx *context.APIContext) {
ctx.Error(http.StatusForbidden, "reqRepoBranchWriter", "user should have a permission to write to this branch")
return
}

checkPublicOnly(ctx, unit.TypeCode)
}

func checkPublicOnly(ctx *context.APIContext, unitType unit.Type) {
if true == ctx.Data["IsApiToken"] {
switch unitType {
case unit.TypeCode:
publicRepo, pubRepoExists := ctx.Data["ApiTokenScopePublicRepoOnly"]

if pubRepoExists && publicRepo.(bool) &&
ctx.Repo.Repository != nil && ctx.Repo.Repository.IsPrivate {
ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public repos")
return
}
}
}
}

// reqRepoReader user should have specific read permission or be a repo admin or a site admin
Expand All @@ -407,6 +433,8 @@ func reqRepoReader(unitType unit.Type) func(ctx *context.APIContext) {
ctx.Error(http.StatusForbidden, "reqRepoReader", "user should have specific read permission or be a repo admin or a site admin")
return
}

checkPublicOnly(ctx, unitType)
}
}

Expand Down
11 changes: 10 additions & 1 deletion tests/integration/api_repo_branch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,13 @@ func TestAPIRepoBranchesPlain(t *testing.T) {
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3})
user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
session := loginUser(t, user1.LowerName)
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)

// public only token should be forbidden
publicOnlyToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopePublicOnly, auth_model.AccessTokenScopeWriteRepository)
link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/org3/%s/branches", repo3.Name)) // a plain repo
MakeRequest(t, NewRequest(t, "GET", link.String()).AddTokenAuth(publicOnlyToken), http.StatusForbidden)

token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository)
resp := MakeRequest(t, NewRequest(t, "GET", link.String()).AddTokenAuth(token), http.StatusOK)
bs, err := io.ReadAll(resp.Body)
assert.NoError(t, err)
Expand All @@ -42,13 +46,17 @@ func TestAPIRepoBranchesPlain(t *testing.T) {
assert.EqualValues(t, "master", branches[1].Name)

link2, _ := url.Parse(fmt.Sprintf("/api/v1/repos/org3/%s/branches/test_branch", repo3.Name))
MakeRequest(t, NewRequest(t, "GET", link2.String()).AddTokenAuth(publicOnlyToken), http.StatusForbidden)

resp = MakeRequest(t, NewRequest(t, "GET", link2.String()).AddTokenAuth(token), http.StatusOK)
bs, err = io.ReadAll(resp.Body)
assert.NoError(t, err)
var branch api.Branch
assert.NoError(t, json.Unmarshal(bs, &branch))
assert.EqualValues(t, "test_branch", branch.Name)

MakeRequest(t, NewRequest(t, "POST", link.String()).AddTokenAuth(publicOnlyToken), http.StatusForbidden)

req := NewRequest(t, "POST", link.String()).AddTokenAuth(token)
req.Header.Add("Content-Type", "application/json")
req.Body = io.NopCloser(bytes.NewBufferString(`{"new_branch_name":"test_branch2", "old_branch_name": "test_branch", "old_ref_name":"refs/heads/test_branch"}`))
Expand All @@ -73,6 +81,7 @@ func TestAPIRepoBranchesPlain(t *testing.T) {

link3, _ := url.Parse(fmt.Sprintf("/api/v1/repos/org3/%s/branches/test_branch2", repo3.Name))
MakeRequest(t, NewRequest(t, "DELETE", link3.String()), http.StatusNotFound)
MakeRequest(t, NewRequest(t, "DELETE", link3.String()).AddTokenAuth(publicOnlyToken), http.StatusForbidden)

MakeRequest(t, NewRequest(t, "DELETE", link3.String()).AddTokenAuth(token), http.StatusNoContent)
assert.NoError(t, err)
Expand Down
Loading