kopia lustrzana https://github.com/reiver/greatape
96 wiersze
2.1 KiB
Go
96 wiersze
2.1 KiB
Go
package httpsig
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
var (
|
|
// Rand is a hookable reader used as a random byte source.
|
|
Rand io.Reader = rand.Reader
|
|
)
|
|
|
|
// requestPath returns the :path pseudo header according to the HTTP/2 spec.
|
|
func requestPath(req *http.Request) string {
|
|
path := req.URL.Path
|
|
if path == "" {
|
|
path = "/"
|
|
}
|
|
if req.URL.RawQuery != "" {
|
|
path += "?" + req.URL.RawQuery
|
|
}
|
|
return path
|
|
}
|
|
|
|
// BuildSignatureString constructs a signature string following section 2.3
|
|
func BuildSignatureString(req *http.Request, headers []string) string {
|
|
if len(headers) == 0 {
|
|
headers = []string{"date"}
|
|
}
|
|
values := make([]string, 0, len(headers))
|
|
for _, h := range headers {
|
|
switch h {
|
|
case "(request-target)":
|
|
values = append(values, fmt.Sprintf("%s: %s %s",
|
|
h, strings.ToLower(req.Method), requestPath(req)))
|
|
case "host":
|
|
values = append(values, fmt.Sprintf("%s: %s", h, req.Host))
|
|
case "date":
|
|
if req.Header.Get(h) == "" {
|
|
req.Header.Set(h, time.Now().UTC().Format(http.TimeFormat))
|
|
}
|
|
values = append(values, fmt.Sprintf("%s: %s", h, req.Header.Get(h)))
|
|
default:
|
|
for _, value := range req.Header[http.CanonicalHeaderKey(h)] {
|
|
values = append(values,
|
|
fmt.Sprintf("%s: %s", h, strings.TrimSpace(value)))
|
|
}
|
|
}
|
|
}
|
|
return strings.Join(values, "\n")
|
|
}
|
|
|
|
// BuildSignatureData is a convenience wrapper around BuildSignatureString that
|
|
// returns []byte instead of a string.
|
|
func BuildSignatureData(req *http.Request, headers []string) []byte {
|
|
return []byte(BuildSignatureString(req, headers))
|
|
}
|
|
|
|
func toRSAPrivateKey(key interface{}) *rsa.PrivateKey {
|
|
switch k := key.(type) {
|
|
case *rsa.PrivateKey:
|
|
return k
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func toRSAPublicKey(key interface{}) *rsa.PublicKey {
|
|
switch k := key.(type) {
|
|
case *rsa.PublicKey:
|
|
return k
|
|
case *rsa.PrivateKey:
|
|
return &k.PublicKey
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func toHMACKey(key interface{}) []byte {
|
|
switch k := key.(type) {
|
|
case []byte:
|
|
return k
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func unsupportedAlgorithm(a Algorithm) error {
|
|
return fmt.Errorf("key does not support algorithm %q", a.Name())
|
|
}
|