mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2026-05-12 22:10:25 +00:00
fix: hide user profile anonymous options on public repo APIs
This commit is contained in:
parent
0fe80e0110
commit
f7442ac4c7
3 changed files with 50 additions and 5 deletions
|
|
@ -46,6 +46,7 @@
|
||||||
email: user2@example.com
|
email: user2@example.com
|
||||||
keep_email_private: true
|
keep_email_private: true
|
||||||
keep_pronouns_private: true
|
keep_pronouns_private: true
|
||||||
|
pronouns: he/him
|
||||||
email_notifications_preference: enabled
|
email_notifications_preference: enabled
|
||||||
passwd: ZogKvWdyEx:password
|
passwd: ZogKvWdyEx:password
|
||||||
passwd_hash_algo: dummy
|
passwd_hash_algo: dummy
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
package convert
|
package convert
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
stdCtx "context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"forgejo.org/models"
|
"forgejo.org/models"
|
||||||
|
|
@ -15,14 +15,15 @@ import (
|
||||||
unit_model "forgejo.org/models/unit"
|
unit_model "forgejo.org/models/unit"
|
||||||
"forgejo.org/modules/log"
|
"forgejo.org/modules/log"
|
||||||
api "forgejo.org/modules/structs"
|
api "forgejo.org/modules/structs"
|
||||||
|
"forgejo.org/services/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ToRepo converts a Repository to api.Repository
|
// ToRepo converts a Repository to api.Repository
|
||||||
func ToRepo(ctx context.Context, repo *repo_model.Repository, permissionInRepo access_model.Permission) *api.Repository {
|
func ToRepo(ctx stdCtx.Context, repo *repo_model.Repository, permissionInRepo access_model.Permission) *api.Repository {
|
||||||
return innerToRepo(ctx, repo, permissionInRepo, false)
|
return innerToRepo(ctx, repo, permissionInRepo, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInRepo access_model.Permission, isParent bool) *api.Repository {
|
func innerToRepo(ctx stdCtx.Context, repo *repo_model.Repository, permissionInRepo access_model.Permission, isParent bool) *api.Repository {
|
||||||
var parent *api.Repository
|
var parent *api.Repository
|
||||||
|
|
||||||
if permissionInRepo.Units == nil && permissionInRepo.UnitsMode == nil {
|
if permissionInRepo.Units == nil && permissionInRepo.UnitsMode == nil {
|
||||||
|
|
@ -179,9 +180,19 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR
|
||||||
|
|
||||||
repoAPIURL := repo.APIURL()
|
repoAPIURL := repo.APIURL()
|
||||||
|
|
||||||
|
// Calculate the effective permission for `ToUserWithAccessMode` for the repo owner. When accessing a public repo,
|
||||||
|
// permissionInRepo.AccessMode will be AccessModeRead even for an anonymous user -- in that case, downgrade
|
||||||
|
// `ownerViewPerms` to `AccessModeNone`. `innerToRepo` doesn't have great access to recognize an anonymous user, so
|
||||||
|
// the best-effort made here is to check if `ctx` is an `APIContext`.
|
||||||
|
ownerViewPerms := permissionInRepo.AccessMode
|
||||||
|
apiCtx, ok := ctx.(*context.APIContext)
|
||||||
|
if ok && apiCtx.Doer == nil {
|
||||||
|
ownerViewPerms = perm.AccessModeNone
|
||||||
|
}
|
||||||
|
|
||||||
return &api.Repository{
|
return &api.Repository{
|
||||||
ID: repo.ID,
|
ID: repo.ID,
|
||||||
Owner: ToUserWithAccessMode(ctx, repo.Owner, permissionInRepo.AccessMode),
|
Owner: ToUserWithAccessMode(ctx, repo.Owner, ownerViewPerms),
|
||||||
Name: repo.Name,
|
Name: repo.Name,
|
||||||
FullName: repo.FullName(),
|
FullName: repo.FullName(),
|
||||||
Description: repo.Description,
|
Description: repo.Description,
|
||||||
|
|
@ -246,7 +257,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToRepoTransfer convert a models.RepoTransfer to a structs.RepeTransfer
|
// ToRepoTransfer convert a models.RepoTransfer to a structs.RepeTransfer
|
||||||
func ToRepoTransfer(ctx context.Context, t *models.RepoTransfer) *api.RepoTransfer {
|
func ToRepoTransfer(ctx stdCtx.Context, t *models.RepoTransfer) *api.RepoTransfer {
|
||||||
teams, _ := ToTeams(ctx, t.Teams, false)
|
teams, _ := ToTeams(ctx, t.Teams, false)
|
||||||
|
|
||||||
return &api.RepoTransfer{
|
return &api.RepoTransfer{
|
||||||
|
|
|
||||||
|
|
@ -289,6 +289,39 @@ func TestAPIViewRepo(t *testing.T) {
|
||||||
assert.Equal(t, 1, repo.Stars)
|
assert.Equal(t, 1, repo.Stars)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate that private information on the user profile isn't exposed by way of being an owner of a public repository.
|
||||||
|
func TestAPIViewRepoOwnerSettings(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
var repo api.Repository
|
||||||
|
|
||||||
|
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo1")
|
||||||
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
|
DecodeJSON(t, resp, &repo)
|
||||||
|
assert.EqualValues(t, 1, repo.ID)
|
||||||
|
assert.Equal(t, "user2@noreply.example.org", repo.Owner.Email) // unauthed, always private
|
||||||
|
assert.Empty(t, repo.Owner.Pronouns) // user2.keep_pronouns_private = true
|
||||||
|
|
||||||
|
session := loginUser(t, "user2")
|
||||||
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadRepository)
|
||||||
|
req = NewRequest(t, "GET", "/api/v1/repos/user2/repo1").AddTokenAuth(token)
|
||||||
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
|
DecodeJSON(t, resp, &repo)
|
||||||
|
assert.Equal(t, "user2@noreply.example.org", repo.Owner.Email) // user2.keep_email_private = true
|
||||||
|
assert.Equal(t, "he/him", repo.Owner.Pronouns) // user2.keep_pronouns_private = true
|
||||||
|
|
||||||
|
req = NewRequest(t, "GET", "/api/v1/repos/user12/repo10")
|
||||||
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
|
DecodeJSON(t, resp, &repo)
|
||||||
|
assert.EqualValues(t, 10, repo.ID)
|
||||||
|
assert.Equal(t, "user12@noreply.example.org", repo.Owner.Email) // unauthed, always private
|
||||||
|
|
||||||
|
req = NewRequest(t, "GET", "/api/v1/repos/user12/repo10").AddTokenAuth(token)
|
||||||
|
resp = MakeRequest(t, req, http.StatusOK)
|
||||||
|
DecodeJSON(t, resp, &repo)
|
||||||
|
assert.Equal(t, "user12@example.com", repo.Owner.Email) // user2.keep_email_private = false
|
||||||
|
}
|
||||||
|
|
||||||
func TestAPIOrgRepos(t *testing.T) {
|
func TestAPIOrgRepos(t *testing.T) {
|
||||||
defer tests.PrepareTestEnv(t)()
|
defer tests.PrepareTestEnv(t)()
|
||||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue