Skip to content

Users with hidden emails will see a noreply email on their profile #28477

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
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
13 changes: 11 additions & 2 deletions routers/web/shared/user/header.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,20 @@ func prepareContextForCommonProfile(ctx *context.Context) {
// PrepareContextForProfileBigAvatar set the context for big avatar view on the profile page
func PrepareContextForProfileBigAvatar(ctx *context.Context) {
prepareContextForCommonProfile(ctx)
// Used for private organization listings (and showing noreply address on profile if needed)
userViewsOwnProfile := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == ctx.ContextUser.ID)

ctx.Data["IsFollowing"] = ctx.Doer != nil && user_model.IsFollowing(ctx, ctx.Doer.ID, ctx.ContextUser.ID)
ctx.Data["ShowUserEmail"] = setting.UI.ShowUserEmail && ctx.ContextUser.Email != "" && ctx.IsSigned && !ctx.ContextUser.KeepEmailPrivate
// We use this variable so that we can say whether we should show the noreply email address
// to the user's own profile, so as to remind them that Git web operations will be done using it
ctx.Data["ShowUserNoreply"] = ctx.ContextUser.KeepEmailPrivate && userViewsOwnProfile
ctx.Data["UserLocationMapURL"] = setting.Service.UserLocationMapURL
if userViewsOwnProfile && !ctx.ContextUser.KeepEmailPrivate {
ctx.Data["DisplayedEmail"] = ctx.ContextUser.Email
} else {
ctx.Data["DisplayedEmail"] = ctx.ContextUser.GetPlaceholderEmail()
}

// Show OpenID URIs
openIDs, err := user_model.GetUserOpenIDs(ctx, ctx.ContextUser.ID)
Expand All @@ -59,10 +69,9 @@ func PrepareContextForProfileBigAvatar(ctx *context.Context) {
ctx.Data["RenderedDescription"] = content
}

showPrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == ctx.ContextUser.ID)
orgs, err := db.Find[organization.Organization](ctx, organization.FindOrgOptions{
UserID: ctx.ContextUser.ID,
IncludePrivate: showPrivate,
IncludePrivate: userViewsOwnProfile,
})
if err != nil {
ctx.ServerError("FindOrgs", err)
Expand Down
3 changes: 2 additions & 1 deletion templates/shared/user/profile_big_avatar.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@
{{if (eq .SignedUserID .ContextUser.ID)}}
<li>
{{svg "octicon-mail"}}
<a class="gt-f1" href="mailto:{{.ContextUser.Email}}" rel="nofollow">{{.ContextUser.Email}}</a>
{{/* If the email is private, DisplayedEmail will be a noreply address instead. */}}
<a class="gt-f1" {{if not (.ShowUserNoreply)}}href="mailto:{{.DisplayedEmail}}" rel="nofollow"{{end}}>{{.DisplayedEmail}}</a>
<a href="{{AppSubUrl}}/user/settings#privacy-user-settings">
{{if .ShowUserEmail}}
<i data-tooltip-content="{{ctx.Locale.Tr "user.email_visibility.limited"}}">
Expand Down
24 changes: 14 additions & 10 deletions tests/integration/setting_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,47 +44,51 @@ func TestSettingShowUserEmailExplore(t *testing.T) {
func TestSettingShowUserEmailProfile(t *testing.T) {
defer tests.PrepareTestEnv(t)()

showUserEmail := setting.UI.ShowUserEmail

// note: in this scenario, user2's email will always be private
// this setting only controls the email visibility of user1
// user1: keep_email_private = false, user2: keep_email_private = true

setting.UI.ShowUserEmail = true
showUserEmail := setting.UI.ShowUserEmail

// user1 can see own visible email
setting.UI.ShowUserEmail = true
session := loginUser(t, "user1")
req := NewRequest(t, "GET", "/user1")
resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
assert.NotContains(t, htmlDoc.doc.Find(".user.profile").Text(), "user1@noreply.example.org")
assert.Contains(t, htmlDoc.doc.Find(".user.profile").Text(), "user1@example.com")

// user1 can not see user2's hidden email
// user1 can not see user2's placeholder / hidden, primary email
req = NewRequest(t, "GET", "/user2")
resp = session.MakeRequest(t, req, http.StatusOK)
htmlDoc = NewHTMLParser(t, resp.Body)
// Should only contain if the user visits their own profile page
assert.NotContains(t, htmlDoc.doc.Find(".user.profile").Text(), "user2@noreply.example.org")
assert.NotContains(t, htmlDoc.doc.Find(".user.profile").Text(), "user2@example.com")

// user2 can see user1's visible email
session = loginUser(t, "user2")
req = NewRequest(t, "GET", "/user1")
resp = session.MakeRequest(t, req, http.StatusOK)
htmlDoc = NewHTMLParser(t, resp.Body)
assert.NotContains(t, htmlDoc.doc.Find(".user.profile").Text(), "user1@noreply.example.org")
assert.Contains(t, htmlDoc.doc.Find(".user.profile").Text(), "user1@example.com")

// user2 can see own hidden email
// user2's profile only shows a placeholder email
session = loginUser(t, "user2")
req = NewRequest(t, "GET", "/user2")
resp = session.MakeRequest(t, req, http.StatusOK)
htmlDoc = NewHTMLParser(t, resp.Body)
assert.Contains(t, htmlDoc.doc.Find(".user.profile").Text(), "user2@example.com")
assert.Contains(t, htmlDoc.doc.Find(".user.profile").Text(), "user2@noreply.example.org")
assert.NotContains(t, htmlDoc.doc.Find(".user.profile").Text(), "user2@example.com")

// now that user1's email is hidden, user1 should only be
// able to see the placeholder email on their profile
setting.UI.ShowUserEmail = false

// user1 can see own (now hidden) email
session = loginUser(t, "user1")
req = NewRequest(t, "GET", "/user1")
resp = session.MakeRequest(t, req, http.StatusOK)
htmlDoc = NewHTMLParser(t, resp.Body)
assert.NotContains(t, htmlDoc.doc.Find(".user.profile").Text(), "user1@noreply.example.org")
assert.Contains(t, htmlDoc.doc.Find(".user.profile").Text(), "user1@example.com")

setting.UI.ShowUserEmail = showUserEmail
Expand Down