package webshared import ( "crypto/sha256" "net/http" "time" "git.mstar.dev/mstar/goutils/maputils" "git.mstar.dev/mstar/linstrom/config" ) // No init needed, zero value is good var RequestClient http.Client const xRandomHeader = "X-Auth-Random" // Sign a given outbound request for authorized fetch. // At the end, the Signature header will have the signature needed, // nothing else is modified. // If the request is POST, the postBody must contain the raw body of // the request and the Digest header will also be added func SignRequest(r *http.Request, keyId string, privateKeyBytes, postBody []byte) error { method := r.Method headers := r.Header var nowString string if dateString := headers.Get("Date"); dateString != "" { nowString = dateString } else { nowString = time.Now().Format("Mon, 02 Jan 2006 15:04:05 MST") headers.Set("Date", nowString) } var host string if hostString := headers.Get("Host"); hostString != "" { host = hostString } else { host = config.GlobalConfig.General.GetFullDomain() headers.Set("Date", host) } applyBodyHash(headers, postBody) mappedHeaders := maputils.MapSameKeys(headers, func(k string, v []string) string { if len(v) > 0 { return v[0] } else { return "" } }) var signedString string if config.GlobalConfig.Experimental.UseEd25519Keys { tmp, err := CreateSignatureED(method, r.URL.RawPath, mappedHeaders, privateKeyBytes) if err != nil { return err } signedString = tmp } else { tmp, err := CreateSignatureRSA(method, r.URL.RawPath, mappedHeaders, privateKeyBytes) if err != nil { return err } signedString = tmp } signature := CreateSignatureHeaderContent( keyId, signedString, maputils.KeysFromMap(mappedHeaders)..., ) headers.Set("Signature", signature) return nil } func applyBodyHash(headers http.Header, body []byte) error { if body == nil { return nil } hash := sha256.Sum256(body) headers.Set("Digest", string(hash[:])) return nil }