Skip to content

Show real mail in Webhooks #27943

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

Closed
wants to merge 1 commit into from
Closed
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
8 changes: 5 additions & 3 deletions routers/web/repo/setting/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,8 @@ func WebHooksEdit(ctx *context.Context) {

// TestWebhook test if web hook is work fine
func TestWebhook(ctx *context.Context) {
hookCtx := webhook_service.GetWebhookContext(ctx)

hookID := ctx.ParamsInt64(":id")
w, err := webhook.GetWebhookByRepoID(ctx, ctx.Repo.Repository.ID, hookID)
if err != nil {
Expand All @@ -662,7 +664,7 @@ func TestWebhook(ctx *context.Context) {
}
}

apiUser := convert.ToUserWithAccessMode(ctx, ctx.Doer, perm.AccessModeNone)
apiUser := convert.ToUserWithAccessMode(hookCtx, ctx.Doer, perm.AccessModeNone)

apiCommit := &api.PayloadCommit{
ID: commit.ID.String(),
Expand All @@ -687,11 +689,11 @@ func TestWebhook(ctx *context.Context) {
Commits: []*api.PayloadCommit{apiCommit},
TotalCommits: 1,
HeadCommit: apiCommit,
Repo: convert.ToRepo(ctx, ctx.Repo.Repository, access_model.Permission{AccessMode: perm.AccessModeNone}),
Repo: convert.ToRepo(hookCtx, ctx.Repo.Repository, access_model.Permission{AccessMode: perm.AccessModeNone}),
Pusher: apiUser,
Sender: apiUser,
}
if err := webhook_service.PrepareWebhook(ctx, w, webhook_module.HookEventPush, p); err != nil {
if err := webhook_service.PrepareWebhook(hookCtx, w, webhook_module.HookEventPush, p); err != nil {
ctx.Flash.Error("PrepareWebhook: " + err.Error())
ctx.Status(http.StatusInternalServerError)
} else {
Expand Down
17 changes: 16 additions & 1 deletion services/convert/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,21 @@ func ToUserWithAccessMode(ctx context.Context, user *user_model.User, accessMode
return toUser(ctx, user, accessMode != perm.AccessModeNone, false)
}

// isWebhook checks if the context belongs to a Webhook
func isWebhook(ctx context.Context) bool {
value := ctx.Value("IsWebhook")
if value == nil {
return false
}

boolValue, ok := value.(bool)
if !ok {
return false
}

return boolValue
}

// toUser convert user_model.User to api.User
// signed shall only be set if requester is logged in. authed shall only be set if user is site admin or user himself
func toUser(ctx context.Context, user *user_model.User, signed, authed bool) *api.User {
Expand All @@ -67,7 +82,7 @@ func toUser(ctx context.Context, user *user_model.User, signed, authed bool) *ap
result.Visibility = user.Visibility.String()

// hide primary email if API caller is anonymous or user keep email private
if signed && (!user.KeepEmailPrivate || authed) {
if (signed || isWebhook(ctx)) && (!user.KeepEmailPrivate || authed) {
result.Email = user.Email
}

Expand Down
61 changes: 61 additions & 0 deletions services/webhook/notifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ func NewNotifier() notify_service.Notifier {
}

func (m *webhookNotifier) IssueClearLabels(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) {
ctx = GetWebhookContext(ctx)

if err := issue.LoadPoster(ctx); err != nil {
log.Error("LoadPoster: %v", err)
return
Expand Down Expand Up @@ -78,6 +80,8 @@ func (m *webhookNotifier) IssueClearLabels(ctx context.Context, doer *user_model
}

func (m *webhookNotifier) ForkRepository(ctx context.Context, doer *user_model.User, oldRepo, repo *repo_model.Repository) {
ctx = GetWebhookContext(ctx)

oldPermission, _ := access_model.GetUserRepoPermission(ctx, oldRepo, doer)
permission, _ := access_model.GetUserRepoPermission(ctx, repo, doer)

Expand Down Expand Up @@ -106,6 +110,8 @@ func (m *webhookNotifier) ForkRepository(ctx context.Context, doer *user_model.U
}

func (m *webhookNotifier) CreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository) {
ctx = GetWebhookContext(ctx)

// Add to hook queue for created repo after session commit.
if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventRepository, &api.RepositoryPayload{
Action: api.HookRepoCreated,
Expand All @@ -118,6 +124,8 @@ func (m *webhookNotifier) CreateRepository(ctx context.Context, doer, u *user_mo
}

func (m *webhookNotifier) DeleteRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository) {
ctx = GetWebhookContext(ctx)

if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventRepository, &api.RepositoryPayload{
Action: api.HookRepoDeleted,
Repository: convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeOwner}),
Expand All @@ -129,6 +137,8 @@ func (m *webhookNotifier) DeleteRepository(ctx context.Context, doer *user_model
}

func (m *webhookNotifier) MigrateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository) {
ctx = GetWebhookContext(ctx)

// Add to hook queue for created repo after session commit.
if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventRepository, &api.RepositoryPayload{
Action: api.HookRepoCreated,
Expand All @@ -141,6 +151,8 @@ func (m *webhookNotifier) MigrateRepository(ctx context.Context, doer, u *user_m
}

func (m *webhookNotifier) IssueChangeAssignee(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment) {
ctx = GetWebhookContext(ctx)

if issue.IsPull {
permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, doer)

Expand Down Expand Up @@ -186,6 +198,8 @@ func (m *webhookNotifier) IssueChangeAssignee(ctx context.Context, doer *user_mo
}

func (m *webhookNotifier) IssueChangeTitle(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldTitle string) {
ctx = GetWebhookContext(ctx)

permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, issue.Poster)
var err error
if issue.IsPull {
Expand Down Expand Up @@ -226,6 +240,8 @@ func (m *webhookNotifier) IssueChangeTitle(ctx context.Context, doer *user_model
}

func (m *webhookNotifier) IssueChangeStatus(ctx context.Context, doer *user_model.User, commitID string, issue *issues_model.Issue, actionComment *issues_model.Comment, isClosed bool) {
ctx = GetWebhookContext(ctx)

permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, issue.Poster)
var err error
if issue.IsPull {
Expand Down Expand Up @@ -268,6 +284,8 @@ func (m *webhookNotifier) IssueChangeStatus(ctx context.Context, doer *user_mode
}

func (m *webhookNotifier) NewIssue(ctx context.Context, issue *issues_model.Issue, mentions []*user_model.User) {
ctx = GetWebhookContext(ctx)

if err := issue.LoadRepo(ctx); err != nil {
log.Error("issue.LoadRepo: %v", err)
return
Expand All @@ -290,6 +308,8 @@ func (m *webhookNotifier) NewIssue(ctx context.Context, issue *issues_model.Issu
}

func (m *webhookNotifier) NewPullRequest(ctx context.Context, pull *issues_model.PullRequest, mentions []*user_model.User) {
ctx = GetWebhookContext(ctx)

if err := pull.LoadIssue(ctx); err != nil {
log.Error("pull.LoadIssue: %v", err)
return
Expand All @@ -316,6 +336,8 @@ func (m *webhookNotifier) NewPullRequest(ctx context.Context, pull *issues_model
}

func (m *webhookNotifier) IssueChangeContent(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldContent string) {
ctx = GetWebhookContext(ctx)

if err := issue.LoadRepo(ctx); err != nil {
log.Error("LoadRepo: %v", err)
return
Expand Down Expand Up @@ -360,6 +382,8 @@ func (m *webhookNotifier) IssueChangeContent(ctx context.Context, doer *user_mod
}

func (m *webhookNotifier) UpdateComment(ctx context.Context, doer *user_model.User, c *issues_model.Comment, oldContent string) {
ctx = GetWebhookContext(ctx)

if err := c.LoadPoster(ctx); err != nil {
log.Error("LoadPoster: %v", err)
return
Expand Down Expand Up @@ -402,6 +426,8 @@ func (m *webhookNotifier) UpdateComment(ctx context.Context, doer *user_model.Us
func (m *webhookNotifier) CreateIssueComment(ctx context.Context, doer *user_model.User, repo *repo_model.Repository,
issue *issues_model.Issue, comment *issues_model.Comment, mentions []*user_model.User,
) {
ctx = GetWebhookContext(ctx)

var eventType webhook_module.HookEventType
if issue.IsPull {
eventType = webhook_module.HookEventPullRequestComment
Expand All @@ -423,6 +449,8 @@ func (m *webhookNotifier) CreateIssueComment(ctx context.Context, doer *user_mod
}

func (m *webhookNotifier) DeleteComment(ctx context.Context, doer *user_model.User, comment *issues_model.Comment) {
ctx = GetWebhookContext(ctx)

var err error

if err = comment.LoadPoster(ctx); err != nil {
Expand Down Expand Up @@ -460,6 +488,8 @@ func (m *webhookNotifier) DeleteComment(ctx context.Context, doer *user_model.Us
}

func (m *webhookNotifier) NewWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page, comment string) {
ctx = GetWebhookContext(ctx)

// Add to hook queue for created wiki page.
if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventWiki, &api.WikiPayload{
Action: api.HookWikiCreated,
Expand All @@ -473,6 +503,8 @@ func (m *webhookNotifier) NewWikiPage(ctx context.Context, doer *user_model.User
}

func (m *webhookNotifier) EditWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page, comment string) {
ctx = GetWebhookContext(ctx)

// Add to hook queue for edit wiki page.
if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventWiki, &api.WikiPayload{
Action: api.HookWikiEdited,
Expand All @@ -486,6 +518,8 @@ func (m *webhookNotifier) EditWikiPage(ctx context.Context, doer *user_model.Use
}

func (m *webhookNotifier) DeleteWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page string) {
ctx = GetWebhookContext(ctx)

// Add to hook queue for edit wiki page.
if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventWiki, &api.WikiPayload{
Action: api.HookWikiDeleted,
Expand All @@ -500,6 +534,8 @@ func (m *webhookNotifier) DeleteWikiPage(ctx context.Context, doer *user_model.U
func (m *webhookNotifier) IssueChangeLabels(ctx context.Context, doer *user_model.User, issue *issues_model.Issue,
addedLabels, removedLabels []*issues_model.Label,
) {
ctx = GetWebhookContext(ctx)

var err error

if err = issue.LoadRepo(ctx); err != nil {
Expand Down Expand Up @@ -544,6 +580,9 @@ func (m *webhookNotifier) IssueChangeLabels(ctx context.Context, doer *user_mode
}

func (m *webhookNotifier) IssueChangeMilestone(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64) {
ctx = GetWebhookContext(ctx)
ctx = GetWebhookContext(ctx)

var hookAction api.HookIssueAction
var err error
if issue.MilestoneID > 0 {
Expand Down Expand Up @@ -586,6 +625,8 @@ func (m *webhookNotifier) IssueChangeMilestone(ctx context.Context, doer *user_m
}

func (m *webhookNotifier) PushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) {
ctx = GetWebhookContext(ctx)

apiPusher := convert.ToUser(ctx, pusher, nil)
apiCommits, apiHeadCommit, err := commits.ToAPIPayloadCommits(ctx, repo.RepoPath(), repo.HTMLURL())
if err != nil {
Expand Down Expand Up @@ -615,6 +656,8 @@ func (m *webhookNotifier) AutoMergePullRequest(ctx context.Context, doer *user_m
}

func (*webhookNotifier) MergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) {
ctx = GetWebhookContext(ctx)

// Reload pull request information.
if err := pr.LoadAttributes(ctx); err != nil {
log.Error("LoadAttributes: %v", err)
Expand Down Expand Up @@ -652,6 +695,8 @@ func (*webhookNotifier) MergePullRequest(ctx context.Context, doer *user_model.U
}

func (m *webhookNotifier) PullRequestChangeTargetBranch(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest, oldBranch string) {
ctx = GetWebhookContext(ctx)

if err := pr.LoadIssue(ctx); err != nil {
log.Error("LoadIssue: %v", err)
return
Expand All @@ -677,6 +722,8 @@ func (m *webhookNotifier) PullRequestChangeTargetBranch(ctx context.Context, doe
}

func (m *webhookNotifier) PullRequestReview(ctx context.Context, pr *issues_model.PullRequest, review *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) {
ctx = GetWebhookContext(ctx)

var reviewHookType webhook_module.HookEventType

switch review.Type {
Expand Down Expand Up @@ -718,6 +765,8 @@ func (m *webhookNotifier) PullRequestReview(ctx context.Context, pr *issues_mode
}

func (m *webhookNotifier) PullRequestReviewRequest(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, reviewer *user_model.User, isRequest bool, comment *issues_model.Comment) {
ctx = GetWebhookContext(ctx)

if !issue.IsPull {
log.Warn("PullRequestReviewRequest: issue is not a pull request: %v", issue.ID)
return
Expand Down Expand Up @@ -746,6 +795,8 @@ func (m *webhookNotifier) PullRequestReviewRequest(ctx context.Context, doer *us
}

func (m *webhookNotifier) CreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refFullName git.RefName, refID string) {
ctx = GetWebhookContext(ctx)

apiPusher := convert.ToUser(ctx, pusher, nil)
apiRepo := convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeNone})
refName := refFullName.ShortName()
Expand All @@ -762,6 +813,8 @@ func (m *webhookNotifier) CreateRef(ctx context.Context, pusher *user_model.User
}

func (m *webhookNotifier) PullRequestSynchronized(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) {
ctx = GetWebhookContext(ctx)

if err := pr.LoadIssue(ctx); err != nil {
log.Error("LoadIssue: %v", err)
return
Expand All @@ -783,6 +836,8 @@ func (m *webhookNotifier) PullRequestSynchronized(ctx context.Context, doer *use
}

func (m *webhookNotifier) DeleteRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refFullName git.RefName) {
ctx = GetWebhookContext(ctx)

apiPusher := convert.ToUser(ctx, pusher, nil)
apiRepo := convert.ToRepo(ctx, repo, access_model.Permission{AccessMode: perm.AccessModeOwner})
refName := refFullName.ShortName()
Expand All @@ -799,6 +854,8 @@ func (m *webhookNotifier) DeleteRef(ctx context.Context, pusher *user_model.User
}

func sendReleaseHook(ctx context.Context, doer *user_model.User, rel *repo_model.Release, action api.HookReleaseAction) {
ctx = GetWebhookContext(ctx)

if err := rel.LoadAttributes(ctx); err != nil {
log.Error("LoadAttributes: %v", err)
return
Expand Down Expand Up @@ -828,6 +885,8 @@ func (m *webhookNotifier) DeleteRelease(ctx context.Context, doer *user_model.Us
}

func (m *webhookNotifier) SyncPushCommits(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, opts *repository.PushUpdateOptions, commits *repository.PushCommits) {
ctx = GetWebhookContext(ctx)

apiPusher := convert.ToUser(ctx, pusher, nil)
apiCommits, apiHeadCommit, err := commits.ToAPIPayloadCommits(ctx, repo.RepoPath(), repo.HTMLURL())
if err != nil {
Expand Down Expand Up @@ -868,6 +927,8 @@ func (m *webhookNotifier) PackageDelete(ctx context.Context, doer *user_model.Us
}

func notifyPackage(ctx context.Context, sender *user_model.User, pd *packages_model.PackageDescriptor, action api.HookPackageAction) {
ctx = GetWebhookContext(ctx)

source := EventSource{
Repository: pd.Repository,
Owner: pd.Owner,
Expand Down
7 changes: 7 additions & 0 deletions services/webhook/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,11 @@ func checkBranch(w *webhook_model.Webhook, branch string) bool {
return g.Match(branch)
}

// GetWebhookCOntext marks that the context belongs to a webhook
func GetWebhookContext(ctx context.Context) context.Context {
return context.WithValue(ctx, "IsWebhook", true)
}

// PrepareWebhook creates a hook task and enqueues it for processing
func PrepareWebhook(ctx context.Context, w *webhook_model.Webhook, event webhook_module.HookEventType, p api.Payloader) error {
// Skip sending if webhooks are disabled.
Expand Down Expand Up @@ -219,6 +224,8 @@ func PrepareWebhook(ctx context.Context, w *webhook_model.Webhook, event webhook
func PrepareWebhooks(ctx context.Context, source EventSource, event webhook_module.HookEventType, p api.Payloader) error {
owner := source.Owner

ctx = GetWebhookContext(ctx)

var ws []*webhook_model.Webhook

if source.Repository != nil {
Expand Down
12 changes: 12 additions & 0 deletions services/webhook/webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@ import (
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
webhook_model "code.gitea.io/gitea/models/webhook"
api "code.gitea.io/gitea/modules/structs"
webhook_module "code.gitea.io/gitea/modules/webhook"
"code.gitea.io/gitea/services/convert"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestWebhook_GetSlackHook(t *testing.T) {
Expand All @@ -28,6 +31,15 @@ func TestWebhook_GetSlackHook(t *testing.T) {
})
}

func TestGetWebhookContextUserMail(t *testing.T) {
require.NoError(t, unittest.PrepareTestDatabase())

user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})

assert.Equal(t, user.GetPlaceholderEmail(), convert.ToUser(db.DefaultContext, user, nil).Email)
assert.Equal(t, user.Email, convert.ToUser(GetWebhookContext(db.DefaultContext), user, nil).Email)
}

func TestPrepareWebhooks(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())

Expand Down