gitlyx / webhook_routes.v
80 lines · 74 sloc · 3.34 KB · 13ca859655a005b2a87a4935764694302b4f2fda
Raw
1// Copyright (c) 2019-2026 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by a GPL license that can be found in the LICENSE file.
3module main
4
5import veb
6import validation
7
8@['/:username/:repo_name/settings/webhooks']
9pub fn (mut app App) repo_webhooks(mut ctx Context, username string, repo_name string) veb.Result {
10 repo := app.find_repo_by_name_and_username(repo_name, username) or { return ctx.not_found() }
11 if !app.can_admin_repo(ctx, repo) {
12 return ctx.redirect_to_repository(username, repo_name)
13 }
14 webhooks := app.list_repo_webhooks(repo.id)
15 return $veb.html('templates/repo/webhooks.html')
16}
17
18@['/:username/:repo_name/settings/webhooks/new']
19pub fn (mut app App) new_webhook(mut ctx Context, username string, repo_name string) veb.Result {
20 repo := app.find_repo_by_name_and_username(repo_name, username) or { return ctx.not_found() }
21 if !app.can_admin_repo(ctx, repo) {
22 return ctx.redirect_to_repository(username, repo_name)
23 }
24 return $veb.html('templates/new/webhook.html')
25}
26
27@['/:username/:repo_name/settings/webhooks'; post]
28pub fn (mut app App) handle_create_webhook(mut ctx Context, username string, repo_name string) veb.Result {
29 repo := app.find_repo_by_name_and_username(repo_name, username) or { return ctx.not_found() }
30 if !app.can_admin_repo(ctx, repo) {
31 return ctx.redirect_to_repository(username, repo_name)
32 }
33 url := ctx.form['url'].trim_space()
34 secret := ctx.form['secret']
35 // Reject empty URLs, non-http(s) schemes, and destinations that resolve to
36 // internal/loopback/link-local addresses (SSRF protection).
37 if validation.is_string_empty(url) || !is_safe_webhook_url(url) {
38 return ctx.redirect('/${username}/${repo_name}/settings/webhooks/new')
39 }
40 mut events := []string{}
41 for ev in ['push', 'issue', 'pr', 'comment', 'release'] {
42 if ctx.form['event_${ev}'] == 'on' {
43 events << ev
44 }
45 }
46 events_str := if events.len == 0 { 'push,issue,pr,comment,release' } else { events.join(',') }
47 app.add_webhook(repo.id, url, secret, events_str) or {
48 ctx.error('Could not create webhook')
49 return ctx.redirect('/${username}/${repo_name}/settings/webhooks/new')
50 }
51 return ctx.redirect('/${username}/${repo_name}/settings/webhooks')
52}
53
54@['/:username/:repo_name/settings/webhooks/:id/delete'; post]
55pub fn (mut app App) handle_delete_webhook(mut ctx Context, username string, repo_name string, id string) veb.Result {
56 repo := app.find_repo_by_name_and_username(repo_name, username) or { return ctx.not_found() }
57 if !app.can_admin_repo(ctx, repo) {
58 return ctx.redirect_to_repository(username, repo_name)
59 }
60 wh := app.find_webhook_by_id(id.int()) or { return ctx.not_found() }
61 if wh.repo_id != repo.id {
62 return ctx.not_found()
63 }
64 app.delete_webhook(wh.id) or {}
65 return ctx.redirect('/${username}/${repo_name}/settings/webhooks')
66}
67
68@['/:username/:repo_name/settings/webhooks/:id']
69pub fn (mut app App) view_webhook(mut ctx Context, username string, repo_name string, id string) veb.Result {
70 repo := app.find_repo_by_name_and_username(repo_name, username) or { return ctx.not_found() }
71 if !app.can_admin_repo(ctx, repo) {
72 return ctx.redirect_to_repository(username, repo_name)
73 }
74 webhook := app.find_webhook_by_id(id.int()) or { return ctx.not_found() }
75 if webhook.repo_id != repo.id {
76 return ctx.not_found()
77 }
78 deliveries := app.recent_webhook_deliveries(webhook.id, 30)
79 return $veb.html('templates/repo/webhook.html')
80}
81