Skip to content

Instantly share code, notes, and snippets.

@tapir
Created November 21, 2018 14:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tapir/fe23c024f4eeeb4e8c608b21f298b0ef to your computer and use it in GitHub Desktop.
Save tapir/fe23c024f4eeeb4e8c608b21f298b0ef to your computer and use it in GitHub Desktop.
Paddle webhook verification
package main
import (
"bytes"
"crypto"
"crypto/rsa"
"crypto/sha1"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt"
"io/ioutil"
"net/url"
"sort"
"unicode/utf8"
)
func verify(pubFile string, data url.Values) (bool, error) {
// Read public key from file
pub, err := ioutil.ReadFile(pubFile)
if err != nil {
return false, err
}
block, _ := pem.Decode(pub)
if block == nil {
return false, fmt.Errorf("Can't decode public key")
}
// Parse public key from PEM block
pubKey, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return false, err
}
var (
keys []string
buffer bytes.Buffer
)
// Decode signature
signature, err := base64.StdEncoding.DecodeString(data["p_signature"][0])
if err != nil {
return false, err
}
// Sort data
for k := range data {
if k != "p_signature" {
keys = append(keys, k)
}
}
sort.Strings(keys)
// Serialize
buffer.WriteString(fmt.Sprintf("a:%d:{", len(keys)))
for _, k := range keys {
v := data[k][0]
buffer.WriteString(fmt.Sprintf("s:%d:\"%s\";", utf8.RuneCountInString(k), k))
buffer.WriteString(fmt.Sprintf("s:%d:\"%s\";", utf8.RuneCountInString(v), v))
}
buffer.WriteString("}")
// SHA1 sum of data
hashed := sha1.Sum(buffer.Bytes())
// Verify
if err := rsa.VerifyPKCS1v15(pubKey.(*rsa.PublicKey), crypto.SHA1, hashed[:], signature); err != nil {
return false, nil
}
return true, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment