Skip to content

Commit

Permalink
RELTEC-12290: implemented github-like webhook secret support
Browse files Browse the repository at this point in the history
  • Loading branch information
mplushnikov committed Nov 27, 2024
1 parent 53c88cc commit ec2adf2
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 14 deletions.
16 changes: 9 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Caddy GitHub Webhook Payload Validation Module

This Caddy handler module validates GitHub webhook payloads by using a shared secret. It ensures that the incoming webhooks are legitimate and come from GitHub, thereby enhancing security for your application.
This Caddy handler module validates all GitHub-Like webhook payloads by using a shared secret. It ensures that the incoming webhooks are legitimate and come from GitHub or for example Spacelift, thereby enhancing security for your application.

## Directive

Expand All @@ -9,6 +9,7 @@ The directive for this module is `validate_github_webhook_payload`.
## Features

- Validates GitHub webhook payloads.
- Validates Spacelift webhook payloads.
- Uses a shared secret to ensure the request integrity.
- Compatible with Caddy v2.

Expand All @@ -22,15 +23,15 @@ To use this module, you will need to build Caddy with the module included. Here'
$ go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
```

2. Build Caddy with the `validate_github_webhook_payload` module:
2. Build Caddy with the `validate_github_like_webhook_payload` module:

```bash
$ xcaddy build --with github.com/Roshick/validate_github_webhook_payload
$ xcaddy build --with github.com/Interhyp/validate_github_like_webhook_payload
```

## Configuration

To configure the `validate_github_webhook_payload` directive in your Caddyfile, provide the secret that you will use to validate the webhook payload.
To configure the `validate_github_like_webhook_payload` directive in your Caddyfile, provide the secret that you will use to validate the webhook payload.

### Caddyfile Example

Expand All @@ -41,7 +42,7 @@ To configure the `validate_github_webhook_payload` directive in your Caddyfile,
:80
validate_github_webhook_payload <your_secret_here>
validate_github_like_webhook_payload <your_secret_here> <signature_header_field_name_here>
route {
# Your other directives
Expand All @@ -50,6 +51,7 @@ route {
```

Replace `<your_secret_here>` with the actual secret that you have configured in your GitHub webhook settings.
Replace `<signature_header_field_name_here>` with the actual name of header transporting signature of webhook payload. It's `X-Signature-256` for Spacelift or `X-Hub-Signature-256` for Github for example.
## Usage
Expand All @@ -75,7 +77,7 @@ The Caddyfile would be:
:80
validate_github_webhook_payload my_super_secret
validate_github_like_webhook_payload my_super_secret X-Hub-Signature-256
route {
handle_path /webhook {
Expand All @@ -86,7 +88,7 @@ route {
```
In this example, Caddy will verify the incoming webhook payloads sent to `/webhook` using the secret `my_super_secret`.
In this example, Caddy will verify the incoming webhook payloads sent to `/webhook` using the secret `my_super_secret` and containg signature inside of `X-Hub-Signature-256` header field.
## Contribution
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module github.com/Roshick/caddy-module-github-webhook-validation-payload
module github.com/Interhyp/caddy-module-github-like-webhook-validation-payload

go 1.22

Expand Down
25 changes: 19 additions & 6 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,30 @@ import (

func init() {
caddy.RegisterModule(Middleware{})
httpcaddyfile.RegisterHandlerDirective("validate_github_webhook_payload", parseCaddyfile)
httpcaddyfile.RegisterHandlerDirective("validate_github_like_webhook_payload", parseCaddyfile)
}

// Middleware implements an HTTP handler.
type Middleware struct {
Secret string `json:"secret,omitempty"`
Secret string `json:"secret,omitempty"`
HeaderName string `json:"headerName,omitempty"`
}

// CaddyModule returns the Caddy module information.
func (Middleware) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{
ID: "http.handlers.github_webhook_validation_payload",
ID: "http.handlers.github_like_webhook_validation_payload",
New: func() caddy.Module { return new(Middleware) },
}
}

// Validate implements caddy.Validator.
func (m *Middleware) Validate() error {
if m.Secret == "" {
return fmt.Errorf("github webhook secret is empty")
return fmt.Errorf("webhook secret is empty")
}
if m.HeaderName == "" {
return fmt.Errorf("webhook headerName is empty")
}

return nil
Expand All @@ -55,7 +59,7 @@ func (m Middleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddy
}
r.Body = io.NopCloser(&buffer)

actual := []byte(strings.TrimPrefix(r.Header.Get("X-Hub-Signature-256"), "sha256="))
actual := []byte(strings.TrimPrefix(r.Header.Get(m.HeaderName), "sha256="))

mac := hmac.New(sha256.New, []byte(m.Secret))
mac.Write(payloadBytes)
Expand All @@ -82,8 +86,17 @@ func (m *Middleware) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return d.ArgErr()
}

// store the argument
// store the secret argument
m.Secret = d.Val()

// headerName is optional argument
if d.NextArg() {
// store the argument
m.HeaderName = d.Val()
} else {
m.HeaderName = "X-Hub-Signature-256"
}

return nil
}

Expand Down

0 comments on commit ec2adf2

Please sign in to comment.