gotosocial/vendor/github.com/SherClockHolmes/webpush-go/vapid.go
dependabot[bot] a773768718
[chore]: Bump github.com/SherClockHolmes/webpush-go from 1.3.0 to 1.4.0 (#3694)
Bumps [github.com/SherClockHolmes/webpush-go](https://github.com/SherClockHolmes/webpush-go) from 1.3.0 to 1.4.0.
- [Release notes](https://github.com/SherClockHolmes/webpush-go/releases)
- [Commits](https://github.com/SherClockHolmes/webpush-go/compare/v1.3.0...v1.4.0)

---
updated-dependencies:
- dependency-name: github.com/SherClockHolmes/webpush-go
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-27 11:08:13 +00:00

119 lines
2.6 KiB
Go

package webpush
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"encoding/base64"
"math/big"
"net/url"
"strings"
"time"
"github.com/golang-jwt/jwt/v5"
)
// GenerateVAPIDKeys will create a private and public VAPID key pair
func GenerateVAPIDKeys() (privateKey, publicKey string, err error) {
// Get the private key from the P256 curve
curve := elliptic.P256()
private, x, y, err := elliptic.GenerateKey(curve, rand.Reader)
if err != nil {
return
}
public := elliptic.Marshal(curve, x, y)
// Convert to base64
publicKey = base64.RawURLEncoding.EncodeToString(public)
privateKey = base64.RawURLEncoding.EncodeToString(private)
return
}
// Generates the ECDSA public and private keys for the JWT encryption
func generateVAPIDHeaderKeys(privateKey []byte) *ecdsa.PrivateKey {
// Public key
curve := elliptic.P256()
px, py := curve.ScalarMult(
curve.Params().Gx,
curve.Params().Gy,
privateKey,
)
pubKey := ecdsa.PublicKey{
Curve: curve,
X: px,
Y: py,
}
// Private key
d := &big.Int{}
d.SetBytes(privateKey)
return &ecdsa.PrivateKey{
PublicKey: pubKey,
D: d,
}
}
// getVAPIDAuthorizationHeader
func getVAPIDAuthorizationHeader(
endpoint,
subscriber,
vapidPublicKey,
vapidPrivateKey string,
expiration time.Time,
) (string, error) {
// Create the JWT token
subURL, err := url.Parse(endpoint)
if err != nil {
return "", err
}
// Unless subscriber is an HTTPS URL, assume an e-mail address
if !strings.HasPrefix(subscriber, "https:") {
subscriber = "mailto:" + subscriber
}
token := jwt.NewWithClaims(jwt.SigningMethodES256, jwt.MapClaims{
"aud": subURL.Scheme + "://" + subURL.Host,
"exp": time.Now().Add(time.Hour * 12).Unix(),
"sub": subscriber,
})
// Decode the VAPID private key
decodedVapidPrivateKey, err := decodeVapidKey(vapidPrivateKey)
if err != nil {
return "", err
}
privKey := generateVAPIDHeaderKeys(decodedVapidPrivateKey)
// Sign token with private key
jwtString, err := token.SignedString(privKey)
if err != nil {
return "", err
}
// Decode the VAPID public key
pubKey, err := decodeVapidKey(vapidPublicKey)
if err != nil {
return "", err
}
return "vapid t=" + jwtString + ", k=" + base64.RawURLEncoding.EncodeToString(pubKey), nil
}
// Need to decode the vapid private key in multiple base64 formats
// Solution from: https://github.com/SherClockHolmes/webpush-go/issues/29
func decodeVapidKey(key string) ([]byte, error) {
bytes, err := base64.URLEncoding.DecodeString(key)
if err == nil {
return bytes, nil
}
return base64.RawURLEncoding.DecodeString(key)
}