-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: add webhook * feat: switch to non deprecated implementation * feat: upgrade go * feat: install golangci-lint from source * feat: use go version from mod file --------- Co-authored-by: Federico Sordillo <[email protected]>
- Loading branch information
Showing
5 changed files
with
145 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,31 +15,18 @@ jobs: | |
name: lint | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/setup-go@v3 | ||
with: | ||
go-version: 1.17 | ||
- uses: actions/checkout@v3 | ||
- name: golangci-lint | ||
uses: golangci/golangci-lint-action@v3 | ||
- uses: actions/setup-go@v4 | ||
with: | ||
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version | ||
version: v1.29 | ||
|
||
# Optional: working directory, useful for monorepos | ||
# working-directory: somedir | ||
|
||
# Optional: golangci-lint command line arguments. | ||
# args: --issues-exit-code=0 | ||
|
||
# Optional: show only new issues if it's a pull request. The default value is `false`. | ||
# only-new-issues: true | ||
|
||
# Optional: if set to true then the all caching functionality will be complete disabled, | ||
# takes precedence over all other caching options. | ||
# skip-cache: true | ||
|
||
# Optional: if set to true then the action don't cache or restore ~/go/pkg. | ||
# skip-pkg-cache: true | ||
|
||
# Optional: if set to true then the action don't cache or restore ~/.cache/go-build. | ||
# skip-build-cache: true | ||
go-version-file: go.mod | ||
# The builtin cache feature ensures that installing golangci-lint | ||
# is consistently fast. | ||
cache: true | ||
cache-dependency-path: go.sum | ||
- name: install-golangci-lint | ||
# Install golangci-lint from source instead of using | ||
# golangci-lint-action to ensure the golangci-lint binary is built with | ||
# the same Go version we're targeting. | ||
run: go install github.com/golangci/golangci-lint/cmd/[email protected] | ||
- name: golangci-lint | ||
run: golangci-lint run --version --verbose --out-format=github-actions |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
package lago | ||
|
||
import ( | ||
"context" | ||
"crypto/rsa" | ||
"crypto/x509" | ||
"encoding/base64" | ||
"encoding/pem" | ||
"errors" | ||
"fmt" | ||
"net/http" | ||
|
||
jwt "github.com/golang-jwt/jwt/v5" | ||
) | ||
|
||
type WebhookRequest struct { | ||
client *Client | ||
} | ||
|
||
func (c *Client) Webhook() *WebhookRequest { | ||
return &WebhookRequest{ | ||
client: c, | ||
} | ||
} | ||
|
||
func (wr *WebhookRequest) GetPublicKey(ctx context.Context) (*rsa.PublicKey, *Error) { | ||
clientRequest := &ClientRequest{ | ||
Path: "webhooks/public_key", | ||
} | ||
|
||
result, err := wr.client.Get(ctx, clientRequest) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
validatedResult, ok := result.(string) | ||
if !ok { | ||
return nil, &Error{ | ||
Err: errors.New("response is not a string"), | ||
HTTPStatusCode: http.StatusInternalServerError, | ||
Msg: "response is not a string", | ||
} | ||
} | ||
|
||
// Decode the base64-encoded key | ||
bytesResult, decodeErr := base64.StdEncoding.DecodeString(validatedResult) | ||
if err != nil { | ||
return nil, &Error{ | ||
Err: decodeErr, | ||
HTTPStatusCode: http.StatusInternalServerError, | ||
Msg: "cannot decode the key", | ||
} | ||
} | ||
|
||
// Parse the PEM block | ||
block, _ := pem.Decode(bytesResult) | ||
if block == nil || block.Type != "PUBLIC KEY" { | ||
return nil, &Error{ | ||
Err: errors.New("Failed to decode PEM block containing public key"), | ||
HTTPStatusCode: http.StatusInternalServerError, | ||
Msg: "Failed to decode PEM block containing public key", | ||
} | ||
} | ||
|
||
// Parse the DER-encoded public key | ||
publicKey, parseErr := x509.ParsePKIXPublicKey(block.Bytes) | ||
if parseErr != nil { | ||
return nil, &Error{ | ||
Err: parseErr, | ||
HTTPStatusCode: http.StatusInternalServerError, | ||
Msg: "Failed to to parse the public key", | ||
} | ||
} | ||
|
||
rsaPublicKey, ok := publicKey.(*rsa.PublicKey) | ||
if !ok { | ||
return nil, &Error{ | ||
Err: errors.New("Unexpected type of public key"), | ||
HTTPStatusCode: http.StatusInternalServerError, | ||
Msg: "Unexpected type of public key", | ||
} | ||
} | ||
|
||
return rsaPublicKey, nil | ||
} | ||
|
||
func (wr *WebhookRequest) ValidateSignature(ctx context.Context, signature string) (bool, *Error) { | ||
publicKey, err := wr.GetPublicKey(ctx) | ||
if err != nil { | ||
return false, err | ||
} | ||
|
||
token, parseErr := jwt.Parse(signature, func(token *jwt.Token) (interface{}, error) { | ||
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok { | ||
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"]) | ||
} | ||
return publicKey, nil | ||
}) | ||
if parseErr != nil { | ||
return false, &Error{ | ||
Err: parseErr, | ||
HTTPStatusCode: http.StatusInternalServerError, | ||
Msg: "cannot parse token", | ||
} | ||
} | ||
|
||
println(fmt.Printf("token: %+v", token)) | ||
|
||
return token.Valid, nil | ||
} |