| @@ -5,6 +5,7 @@ import ( |
| 5 | 5 | "fmt" |
| 6 | 6 | "io" |
| 7 | 7 | "strconv" |
| 8 | "strings" |
| 8 | 9 | |
| 9 | 10 | "gitbay.org/gitbay/internal/policy" |
| 10 | 11 | "gitbay.org/gitbay/internal/protocol" |
| @@ -15,13 +16,17 @@ import ( |
| 15 | 16 | func init() { |
| 16 | 17 | register(Command{Path: []string{"webhook", "add"}, |
| 17 | 18 | Summary: "add a webhook", |
| 18 | | Usage: "webhook add <owner/name> <url> [--secret <s>] [--events push,issue.created|*]", |
| 19 | Usage: "webhook add <owner/name> <url> [--secret -] [--events push,issue.created|*]", |
| 19 | 20 | Flags: []Flag{ |
| 20 | | {"--secret", "<s>", "signs deliveries so the receiver can verify them", ""}, |
| 21 | {"--secret", "-", "read the secret that signs deliveries from stdin", ""}, |
| 21 | 22 | {"--events", "push,issue.created|*", "which events to send", "*"}, |
| 22 | 23 | }, |
| 23 | | Examples: []string{"webhook add krz/gitbay https://ci.example.org/hook --events push"}, |
| 24 | | Run: runWebhookAdd}) |
| 24 | Examples: []string{ |
| 25 | "webhook add krz/gitbay https://ci.example.org/hook --events push", |
| 26 | "webhook add krz/gitbay https://ci.example.org/hook --secret - < secret.txt", |
| 27 | }, |
| 28 | ReadsStdin: true, |
| 29 | Run: runWebhookAdd}) |
| 25 | 30 | register(Command{Path: []string{"webhook", "list"}, |
| 26 | 31 | Summary: "list webhooks", |
| 27 | 32 | Usage: "webhook list <owner/name>", |
| @@ -45,17 +50,21 @@ func init() { |
| 45 | 50 | } |
| 46 | 51 | |
| 47 | 52 | func runWebhookAdd(c *Ctx, args []string) int { |
| 48 | | f, err := c.parseArgs(args, flagSpec{Values: []string{"--secret", "--events"}, MaxPos: 2, Usage: "webhook add <owner/name> <url> [--secret <s>] [--events push,issue.created|*]"}) |
| 53 | f, err := c.parseArgs(args, flagSpec{Values: []string{"--secret", "--events"}, MaxPos: 2, Usage: "webhook add <owner/name> <url> [--secret -] [--events push,issue.created|*]"}) |
| 49 | 54 | if err != nil { |
| 50 | 55 | return c.fail(protocol.ExitUsage, "%v", err) |
| 51 | 56 | } |
| 52 | | path, url, secret, events := f.pos(0), f.pos(1), f.Value("--secret"), "*" |
| 57 | path, url, events := f.pos(0), f.pos(1), "*" |
| 53 | 58 | if f.Has("--events") { |
| 54 | 59 | events = f.Value("--events") |
| 55 | 60 | } |
| 56 | 61 | if path == "" || url == "" { |
| 57 | 62 | return c.usage() |
| 58 | 63 | } |
| 64 | // Secrets travel on stdin: argv shows in /proc and in shell history. |
| 65 | if f.Has("--secret") && f.Value("--secret") != "-" { |
| 66 | return c.fail(protocol.ExitUsage, "the secret is read from stdin, never argv: pipe it and pass --secret - (printf %%s SECRET | ... --secret -)") |
| 67 | } |
| 59 | 68 | repo, code := resolveRepo(c, path, policy.CanAdmin) |
| 60 | 69 | if code >= 0 { |
| 61 | 70 | return code |
| @@ -71,6 +80,17 @@ func runWebhookAdd(c *Ctx, args []string) int { |
| 71 | 80 | // Exit 1 carries the reason to every client verbatim (#187). |
| 72 | 81 | return c.fail(protocol.ExitFailure, "%v", err) |
| 73 | 82 | } |
| 83 | secret := "" |
| 84 | if f.Has("--secret") { |
| 85 | raw, err := io.ReadAll(io.LimitReader(c.Stdin, 64<<10)) |
| 86 | if err != nil { |
| 87 | return c.fail(protocol.ExitFailure, "reading secret: %v", err) |
| 88 | } |
| 89 | secret = strings.TrimRight(string(raw), "\n") |
| 90 | if secret == "" { |
| 91 | return c.fail(protocol.ExitUsage, "no secret on stdin (pipe it: printf %%s SECRET | ... --secret -)") |
| 92 | } |
| 93 | } |
| 74 | 94 | id, err := c.Store.AddWebhook(repo.ID, url, secret, events) |
| 75 | 95 | if err != nil { |
| 76 | 96 | return c.fail(protocol.ExitFailure, "%v", err) |