| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- package main
- import (
- "bufio"
- "bytes"
- "crypto/x509"
- "encoding/pem"
- "flag"
- "fmt"
- "io"
- "log"
- "net/http"
- "net/http/httputil"
- "net/url"
- "os"
- "strings"
- "time"
- "github.com/go-fed/httpsig"
- configflag "github.com/ncarlier/webhookd/pkg/config/flag"
- )
- type config struct {
- KeyID string `flag:"key-id" desc:"Signature key ID"`
- KeyFile string `flag:"key-file" desc:"Private key file (PEM format)" default:"./key.pem"`
- JSON string `flag:"json" desc:"JSON payload"`
- }
- func main() {
- conf := &config{}
- configflag.Bind(conf, "HTTP_SIG")
- flag.Parse()
- if conf.KeyID == "" {
- log.Fatal("missing key ID")
- }
- args := flag.Args()
- if len(args) <= 0 {
- log.Fatal("missing target URL")
- }
- targetURL := args[0]
- if _, err := url.Parse(targetURL); err != nil {
- log.Fatal("invalid target URL")
- }
- keyBytes, err := os.ReadFile(conf.KeyFile)
- if err != nil {
- log.Fatal(err.Error())
- }
- pemBlock, _ := pem.Decode(keyBytes)
- if pemBlock == nil {
- log.Fatal("invalid PEM format")
- }
- privateKey, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes)
- if err != nil {
- log.Fatal(err.Error())
- }
- var payload io.Reader
- var jsonBytes []byte
- if conf.JSON != "" {
- var err error
- jsonBytes, err = os.ReadFile(conf.JSON)
- if err != nil {
- log.Fatal(err.Error())
- }
- payload = bytes.NewReader(jsonBytes)
- }
- prefs := []httpsig.Algorithm{httpsig.RSA_SHA256}
- digestAlgorithm := httpsig.DigestSha256
- headers := []string{httpsig.RequestTarget, "date"}
- signer, _, err := httpsig.NewSigner(prefs, digestAlgorithm, headers, httpsig.Signature, 0)
- if err != nil {
- log.Fatal(err.Error())
- }
- req, err := http.NewRequest("POST", targetURL, payload)
- if err != nil {
- log.Fatal(err.Error())
- }
- if payload != nil {
- req.Header.Add("content-type", "application/json")
- }
- req.Header.Add("date", time.Now().UTC().Format(http.TimeFormat))
- if err = signer.SignRequest(privateKey, conf.KeyID, req, jsonBytes); err != nil {
- log.Fatal(err.Error())
- }
- dump, err := httputil.DumpRequest(req, true)
- if err != nil {
- log.Fatal(err.Error())
- }
- scanner := bufio.NewScanner(strings.NewReader(string(dump)))
- for scanner.Scan() {
- fmt.Println(">", scanner.Text())
- }
- client := &http.Client{Timeout: 10 * time.Second}
- res, err := client.Do(req)
- if err != nil {
- log.Fatal(err.Error())
- }
- dump, err = httputil.DumpResponse(res, true)
- if err != nil {
- log.Fatal(err.Error())
- }
- scanner = bufio.NewScanner(strings.NewReader(string(dump)))
- for scanner.Scan() {
- fmt.Println("<", scanner.Text())
- }
- }
|