Added option to disable webhooks (#13176)

* Added option to disable web hooks

This mod introduces DISABLE_WEB_HOOKS parameter in [security] section
of app.ini (by default set to false). If set to true it disables web
hooks feature. Any existing undelivered web hook tasks will be cancelled.
Any existing web hook definitions will be left untouched in db but
its delivery tasks will be ignored.

Author-Change-Id: IB#1105130

* Webhook spelling fixed

Webhook spelling fixed.

Fixes: 07df6614dc84cdd2e9f39c57577fa1062bd70012
Related: https://github.com/go-gitea/gitea/pull/13176#pullrequestreview-510868421
Author-Change-Id: IB#1105174

* Parameter description fixed

Parameter description fixed.

Fixes: 07df6614dc84cdd2e9f39c57577fa1062bd70012
Related: https://github.com/go-gitea/gitea/pull/13176#pullrequestreview-514086107
Author-Change-Id: IB#1105174
tokarchuk/v1.17
Paweł Bogusławski 4 years ago committed by GitHub
parent ac701637b4
commit 7d7007dca7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      custom/conf/app.example.ini
  2. 1
      docs/content/doc/advanced/config-cheat-sheet.en-us.md
  3. 2
      modules/setting/setting.go
  4. 3
      modules/templates/helper.go
  5. 30
      routers/api/v1/api.go
  6. 26
      routers/routes/web.go
  7. 4
      services/webhook/deliver.go
  8. 5
      services/webhook/webhook.go
  9. 8
      templates/admin/navbar.tmpl
  10. 2
      templates/org/settings/navbar.tmpl
  11. 2
      templates/repo/settings/nav.tmpl
  12. 8
      templates/repo/settings/navbar.tmpl

@ -556,6 +556,8 @@ IMPORT_LOCAL_PATHS = false
; It also enables them to access other resources available to the user on the operating system that is running the Gitea instance and perform arbitrary actions in the name of the Gitea OS user. ; It also enables them to access other resources available to the user on the operating system that is running the Gitea instance and perform arbitrary actions in the name of the Gitea OS user.
; WARNING: This maybe harmful to you website or your operating system. ; WARNING: This maybe harmful to you website or your operating system.
DISABLE_GIT_HOOKS = true DISABLE_GIT_HOOKS = true
; Set to true to disable webhooks feature.
DISABLE_WEBHOOKS = false
; Set to false to allow pushes to gitea repositories despite having an incomplete environment - NOT RECOMMENDED ; Set to false to allow pushes to gitea repositories despite having an incomplete environment - NOT RECOMMENDED
ONLY_ALLOW_PUSH_IF_GITEA_ENVIRONMENT_SET = true ONLY_ALLOW_PUSH_IF_GITEA_ENVIRONMENT_SET = true
;Comma separated list of character classes required to pass minimum complexity. ;Comma separated list of character classes required to pass minimum complexity.

@ -396,6 +396,7 @@ relation to port exhaustion.
It also enables them to access other resources available to the user on the operating system that is running the It also enables them to access other resources available to the user on the operating system that is running the
Gitea instance and perform arbitrary actions in the name of the Gitea OS user. Gitea instance and perform arbitrary actions in the name of the Gitea OS user.
This maybe harmful to you website or your operating system. This maybe harmful to you website or your operating system.
- `DISABLE_WEBHOOKS`: **false**: Set to `true` to disable webhooks feature.
- `ONLY_ALLOW_PUSH_IF_GITEA_ENVIRONMENT_SET`: **true**: Set to `false` to allow local users to push to gitea-repositories without setting up the Gitea environment. This is not recommended and if you want local users to push to gitea repositories you should set the environment appropriately. - `ONLY_ALLOW_PUSH_IF_GITEA_ENVIRONMENT_SET`: **true**: Set to `false` to allow local users to push to gitea-repositories without setting up the Gitea environment. This is not recommended and if you want local users to push to gitea repositories you should set the environment appropriately.
- `IMPORT_LOCAL_PATHS`: **false**: Set to `false` to prevent all users (including admin) from importing local path on server. - `IMPORT_LOCAL_PATHS`: **false**: Set to `false` to prevent all users (including admin) from importing local path on server.
- `INTERNAL_TOKEN`: **\<random at every install if no uri set\>**: Secret used to validate communication within Gitea binary. - `INTERNAL_TOKEN`: **\<random at every install if no uri set\>**: Secret used to validate communication within Gitea binary.

@ -156,6 +156,7 @@ var (
MinPasswordLength int MinPasswordLength int
ImportLocalPaths bool ImportLocalPaths bool
DisableGitHooks bool DisableGitHooks bool
DisableWebhooks bool
OnlyAllowPushIfGiteaEnvironmentSet bool OnlyAllowPushIfGiteaEnvironmentSet bool
PasswordComplexity []string PasswordComplexity []string
PasswordHashAlgo string PasswordHashAlgo string
@ -801,6 +802,7 @@ func NewContext() {
MinPasswordLength = sec.Key("MIN_PASSWORD_LENGTH").MustInt(6) MinPasswordLength = sec.Key("MIN_PASSWORD_LENGTH").MustInt(6)
ImportLocalPaths = sec.Key("IMPORT_LOCAL_PATHS").MustBool(false) ImportLocalPaths = sec.Key("IMPORT_LOCAL_PATHS").MustBool(false)
DisableGitHooks = sec.Key("DISABLE_GIT_HOOKS").MustBool(true) DisableGitHooks = sec.Key("DISABLE_GIT_HOOKS").MustBool(true)
DisableWebhooks = sec.Key("DISABLE_WEBHOOKS").MustBool(false)
OnlyAllowPushIfGiteaEnvironmentSet = sec.Key("ONLY_ALLOW_PUSH_IF_GITEA_ENVIRONMENT_SET").MustBool(true) OnlyAllowPushIfGiteaEnvironmentSet = sec.Key("ONLY_ALLOW_PUSH_IF_GITEA_ENVIRONMENT_SET").MustBool(true)
PasswordHashAlgo = sec.Key("PASSWORD_HASH_ALGO").MustString("argon2") PasswordHashAlgo = sec.Key("PASSWORD_HASH_ALGO").MustString("argon2")
CSRFCookieHTTPOnly = sec.Key("CSRF_COOKIE_HTTP_ONLY").MustBool(true) CSRFCookieHTTPOnly = sec.Key("CSRF_COOKIE_HTTP_ONLY").MustBool(true)

@ -229,6 +229,9 @@ func NewFuncMap() []template.FuncMap {
"DisableGitHooks": func() bool { "DisableGitHooks": func() bool {
return setting.DisableGitHooks return setting.DisableGitHooks
}, },
"DisableWebhooks": func() bool {
return setting.DisableWebhooks
},
"DisableImportLocal": func() bool { "DisableImportLocal": func() bool {
return !setting.ImportLocalPaths return !setting.ImportLocalPaths
}, },

@ -383,6 +383,16 @@ func reqGitHook() func(ctx *context.APIContext) {
} }
} }
// reqWebhooksEnabled requires webhooks to be enabled by admin.
func reqWebhooksEnabled() func(ctx *context.APIContext) {
return func(ctx *context.APIContext) {
if setting.DisableWebhooks {
ctx.Error(http.StatusForbidden, "", "webhooks disabled by administrator")
return
}
}
}
func orgAssignment(args ...bool) func(ctx *context.APIContext) { func orgAssignment(args ...bool) func(ctx *context.APIContext) {
var ( var (
assignOrg bool assignOrg bool
@ -703,6 +713,14 @@ func Routes() *web.Route {
m.Combo("/notifications"). m.Combo("/notifications").
Get(reqToken(), notify.ListRepoNotifications). Get(reqToken(), notify.ListRepoNotifications).
Put(reqToken(), notify.ReadRepoNotifications) Put(reqToken(), notify.ReadRepoNotifications)
m.Group("/hooks/git", func() {
m.Combo("").Get(repo.ListGitHooks)
m.Group("/{id}", func() {
m.Combo("").Get(repo.GetGitHook).
Patch(bind(api.EditGitHookOption{}), repo.EditGitHook).
Delete(repo.DeleteGitHook)
})
}, reqToken(), reqAdmin(), reqGitHook(), context.ReferencesGitRepo(true))
m.Group("/hooks", func() { m.Group("/hooks", func() {
m.Combo("").Get(repo.ListHooks). m.Combo("").Get(repo.ListHooks).
Post(bind(api.CreateHookOption{}), repo.CreateHook) Post(bind(api.CreateHookOption{}), repo.CreateHook)
@ -712,15 +730,7 @@ func Routes() *web.Route {
Delete(repo.DeleteHook) Delete(repo.DeleteHook)
m.Post("/tests", context.RepoRefForAPI, repo.TestHook) m.Post("/tests", context.RepoRefForAPI, repo.TestHook)
}) })
m.Group("/git", func() { }, reqToken(), reqAdmin(), reqWebhooksEnabled())
m.Combo("").Get(repo.ListGitHooks)
m.Group("/{id}", func() {
m.Combo("").Get(repo.GetGitHook).
Patch(bind(api.EditGitHookOption{}), repo.EditGitHook).
Delete(repo.DeleteGitHook)
})
}, reqGitHook(), context.ReferencesGitRepo(true))
}, reqToken(), reqAdmin())
m.Group("/collaborators", func() { m.Group("/collaborators", func() {
m.Get("", reqAnyRepoReader(), repo.ListCollaborators) m.Get("", reqAnyRepoReader(), repo.ListCollaborators)
m.Combo("/{collaborator}").Get(reqAnyRepoReader(), repo.IsCollaborator). m.Combo("/{collaborator}").Get(reqAnyRepoReader(), repo.IsCollaborator).
@ -984,7 +994,7 @@ func Routes() *web.Route {
m.Combo("/{id}").Get(org.GetHook). m.Combo("/{id}").Get(org.GetHook).
Patch(bind(api.EditHookOption{}), org.EditHook). Patch(bind(api.EditHookOption{}), org.EditHook).
Delete(org.DeleteHook) Delete(org.DeleteHook)
}, reqToken(), reqOrgOwnership()) }, reqToken(), reqOrgOwnership(), reqWebhooksEnabled())
}, orgAssignment(true)) }, orgAssignment(true))
m.Group("/teams/{teamid}", func() { m.Group("/teams/{teamid}", func() {
m.Combo("").Get(org.GetTeam). m.Combo("").Get(org.GetTeam).

@ -248,6 +248,14 @@ func RegisterRoutes(m *web.Route) {
} }
} }
// webhooksEnabled requires webhooks to be enabled by admin.
webhooksEnabled := func(ctx *context.Context) {
if setting.DisableWebhooks {
ctx.Error(403)
return
}
}
// FIXME: not all routes need go through same middleware. // FIXME: not all routes need go through same middleware.
// Especially some AJAX requests, we can reduce middleware number to improve performance. // Especially some AJAX requests, we can reduce middleware number to improve performance.
// Routers. // Routers.
@ -446,7 +454,7 @@ func RegisterRoutes(m *web.Route) {
m.Post("/matrix/{id}", bindIgnErr(auth.NewMatrixHookForm{}), repo.MatrixHooksEditPost) m.Post("/matrix/{id}", bindIgnErr(auth.NewMatrixHookForm{}), repo.MatrixHooksEditPost)
m.Post("/msteams/{id}", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost) m.Post("/msteams/{id}", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
m.Post("/feishu/{id}", bindIgnErr(auth.NewFeishuHookForm{}), repo.FeishuHooksEditPost) m.Post("/feishu/{id}", bindIgnErr(auth.NewFeishuHookForm{}), repo.FeishuHooksEditPost)
}) }, webhooksEnabled)
m.Group("/{configType:default-hooks|system-hooks}", func() { m.Group("/{configType:default-hooks|system-hooks}", func() {
m.Get("/{type}/new", repo.WebhooksNew) m.Get("/{type}/new", repo.WebhooksNew)
@ -568,7 +576,7 @@ func RegisterRoutes(m *web.Route) {
m.Post("/matrix/{id}", bindIgnErr(auth.NewMatrixHookForm{}), repo.MatrixHooksEditPost) m.Post("/matrix/{id}", bindIgnErr(auth.NewMatrixHookForm{}), repo.MatrixHooksEditPost)
m.Post("/msteams/{id}", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost) m.Post("/msteams/{id}", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
m.Post("/feishu/{id}", bindIgnErr(auth.NewFeishuHookForm{}), repo.FeishuHooksEditPost) m.Post("/feishu/{id}", bindIgnErr(auth.NewFeishuHookForm{}), repo.FeishuHooksEditPost)
}) }, webhooksEnabled)
m.Group("/labels", func() { m.Group("/labels", func() {
m.Get("", org.RetrieveLabels, org.Labels) m.Get("", org.RetrieveLabels, org.Labels)
@ -621,6 +629,12 @@ func RegisterRoutes(m *web.Route) {
Post(bindIgnErr(auth.ProtectBranchForm{}), context.RepoMustNotBeArchived(), repo.SettingsProtectedBranchPost) Post(bindIgnErr(auth.ProtectBranchForm{}), context.RepoMustNotBeArchived(), repo.SettingsProtectedBranchPost)
}, repo.MustBeNotEmpty) }, repo.MustBeNotEmpty)
m.Group("/hooks/git", func() {
m.Get("", repo.GitHooks)
m.Combo("/{name}").Get(repo.GitHooksEdit).
Post(repo.GitHooksEditPost)
}, context.GitHookService())
m.Group("/hooks", func() { m.Group("/hooks", func() {
m.Get("", repo.Webhooks) m.Get("", repo.Webhooks)
m.Post("/delete", repo.DeleteWebhook) m.Post("/delete", repo.DeleteWebhook)
@ -645,13 +659,7 @@ func RegisterRoutes(m *web.Route) {
m.Post("/matrix/{id}", bindIgnErr(auth.NewMatrixHookForm{}), repo.MatrixHooksEditPost) m.Post("/matrix/{id}", bindIgnErr(auth.NewMatrixHookForm{}), repo.MatrixHooksEditPost)
m.Post("/msteams/{id}", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost) m.Post("/msteams/{id}", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
m.Post("/feishu/{id}", bindIgnErr(auth.NewFeishuHookForm{}), repo.FeishuHooksEditPost) m.Post("/feishu/{id}", bindIgnErr(auth.NewFeishuHookForm{}), repo.FeishuHooksEditPost)
}, webhooksEnabled)
m.Group("/git", func() {
m.Get("", repo.GitHooks)
m.Combo("/{name}").Get(repo.GitHooksEdit).
Post(repo.GitHooksEditPost)
}, context.GitHookService())
})
m.Group("/keys", func() { m.Group("/keys", func() {
m.Combo("").Get(repo.DeployKeys). m.Combo("").Get(repo.DeployKeys).

@ -141,6 +141,10 @@ func Deliver(t *models.HookTask) error {
} }
}() }()
if setting.DisableWebhooks {
return fmt.Errorf("Webhook task skipped (webhooks disabled): [%d]", t.ID)
}
resp, err := webhookHTTPClient.Do(req) resp, err := webhookHTTPClient.Do(req)
if err != nil { if err != nil {
t.ResponseInfo.Body = fmt.Sprintf("Delivery: %v", err) t.ResponseInfo.Body = fmt.Sprintf("Delivery: %v", err)

@ -120,6 +120,11 @@ func checkBranch(w *models.Webhook, branch string) bool {
} }
func prepareWebhook(w *models.Webhook, repo *models.Repository, event models.HookEventType, p api.Payloader) error { func prepareWebhook(w *models.Webhook, repo *models.Repository, event models.HookEventType, p api.Payloader) error {
// Skip sending if webhooks are disabled.
if setting.DisableWebhooks {
return nil
}
for _, e := range w.EventCheckers() { for _, e := range w.EventCheckers() {
if event == e.Type { if event == e.Type {
if !e.Has() { if !e.Has() {

@ -12,9 +12,11 @@
<a class="{{if .PageIsAdminRepositories}}active{{end}} item" href="{{AppSubUrl}}/admin/repos"> <a class="{{if .PageIsAdminRepositories}}active{{end}} item" href="{{AppSubUrl}}/admin/repos">
{{.i18n.Tr "admin.repositories"}} {{.i18n.Tr "admin.repositories"}}
</a> </a>
<a class="{{if or .PageIsAdminDefaultHooks .PageIsAdminSystemHooks}}active{{end}} item" href="{{AppSubUrl}}/admin/hooks"> {{if not DisableWebhooks}}
{{.i18n.Tr "admin.hooks"}} <a class="{{if or .PageIsAdminDefaultHooks .PageIsAdminSystemHooks}}active{{end}} item" href="{{AppSubUrl}}/admin/hooks">
</a> {{.i18n.Tr "admin.hooks"}}
</a>
{{end}}
<a class="{{if .PageIsAdminAuthentications}}active{{end}} item" href="{{AppSubUrl}}/admin/auths"> <a class="{{if .PageIsAdminAuthentications}}active{{end}} item" href="{{AppSubUrl}}/admin/auths">
{{.i18n.Tr "admin.authentication"}} {{.i18n.Tr "admin.authentication"}}
</a> </a>

@ -4,9 +4,11 @@
<a class="{{if .PageIsSettingsOptions}}active{{end}} item" href="{{.OrgLink}}/settings"> <a class="{{if .PageIsSettingsOptions}}active{{end}} item" href="{{.OrgLink}}/settings">
{{.i18n.Tr "org.settings.options"}} {{.i18n.Tr "org.settings.options"}}
</a> </a>
{{if not DisableWebhooks}}
<a class="{{if .PageIsSettingsHooks}}active{{end}} item" href="{{.OrgLink}}/settings/hooks"> <a class="{{if .PageIsSettingsHooks}}active{{end}} item" href="{{.OrgLink}}/settings/hooks">
{{.i18n.Tr "repo.settings.hooks"}} {{.i18n.Tr "repo.settings.hooks"}}
</a> </a>
{{end}}
<a class="{{if .PageIsOrgSettingsLabels}}active{{end}} item" href="{{.OrgLink}}/settings/labels"> <a class="{{if .PageIsOrgSettingsLabels}}active{{end}} item" href="{{.OrgLink}}/settings/labels">
{{.i18n.Tr "repo.labels"}} {{.i18n.Tr "repo.labels"}}
</a> </a>

@ -5,7 +5,9 @@
<li {{if .PageIsSettingsOptions}}class="current"{{end}}><a href="{{.RepoLink}}/settings">{{.i18n.Tr "repo.settings.options"}}</a></li> <li {{if .PageIsSettingsOptions}}class="current"{{end}}><a href="{{.RepoLink}}/settings">{{.i18n.Tr "repo.settings.options"}}</a></li>
<li {{if .PageIsSettingsCollaboration}}class="current"{{end}}><a href="{{.RepoLink}}/settings/collaboration">{{.i18n.Tr "repo.settings.collaboration"}}</a></li> <li {{if .PageIsSettingsCollaboration}}class="current"{{end}}><a href="{{.RepoLink}}/settings/collaboration">{{.i18n.Tr "repo.settings.collaboration"}}</a></li>
<li {{if .PageIsSettingsBranches}}class="current"{{end}}><a href="{{.RepoLink}}/settings/branches">{{.i18n.Tr "repo.settings.branches"}}</a></li> <li {{if .PageIsSettingsBranches}}class="current"{{end}}><a href="{{.RepoLink}}/settings/branches">{{.i18n.Tr "repo.settings.branches"}}</a></li>
{{if not DisableWebhooks}}
<li {{if .PageIsSettingsHooks}}class="current"{{end}}><a href="{{.RepoLink}}/settings/hooks">{{.i18n.Tr "repo.settings.hooks"}}</a></li> <li {{if .PageIsSettingsHooks}}class="current"{{end}}><a href="{{.RepoLink}}/settings/hooks">{{.i18n.Tr "repo.settings.hooks"}}</a></li>
{{end}}
{{if or .SignedUser.AllowGitHook .SignedUser.IsAdmin}} {{if or .SignedUser.AllowGitHook .SignedUser.IsAdmin}}
<li {{if .PageIsSettingsGitHooks}}class="current"{{end}}><a href="{{.RepoLink}}/settings/hooks/git">{{.i18n.Tr "repo.settings.githooks"}}</a></li> <li {{if .PageIsSettingsGitHooks}}class="current"{{end}}><a href="{{.RepoLink}}/settings/hooks/git">{{.i18n.Tr "repo.settings.githooks"}}</a></li>
{{end}} {{end}}

@ -11,9 +11,11 @@
{{.i18n.Tr "repo.settings.branches"}} {{.i18n.Tr "repo.settings.branches"}}
</a> </a>
{{end}} {{end}}
<a class="{{if .PageIsSettingsHooks}}active{{end}} item" href="{{.RepoLink}}/settings/hooks"> {{if not DisableWebhooks}}
{{.i18n.Tr "repo.settings.hooks"}} <a class="{{if .PageIsSettingsHooks}}active{{end}} item" href="{{.RepoLink}}/settings/hooks">
</a> {{.i18n.Tr "repo.settings.hooks"}}
</a>
{{end}}
{{if .SignedUser.CanEditGitHook}} {{if .SignedUser.CanEditGitHook}}
<a class="{{if .PageIsSettingsGitHooks}}active{{end}} item" href="{{.RepoLink}}/settings/hooks/git"> <a class="{{if .PageIsSettingsGitHooks}}active{{end}} item" href="{{.RepoLink}}/settings/hooks/git">
{{.i18n.Tr "repo.settings.githooks"}} {{.i18n.Tr "repo.settings.githooks"}}

Loading…
Cancel
Save