Documentation
¶
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // FetchCoveredComponents is the list of components to be used for generating the // RFC9421 Signature Base for GET and HEAD requests. // https://www.rfc-editor.org/rfc/rfc9421.html#name-derived-components FetchCoveredComponents = []string{"@method", "@target-uri"} // PostCoveredComponents is the list of components to be used for generating the // RFC9421 Signature Base for POST, PUT, DELETE requests. PostCoveredComponents = []string{"@method", "@target-uri", "content-type", "content-length", "content-digest"} )
var ErrRetry = errors.Newf("retry")
var HeadersToSign = []string{httpsig.RequestTarget, "host", "date"}
HeadersToSign is the list of headers that will be used to generate the HTTP-Signature
In regular builds, this list contains the "Date" header which makes it compatible with the wider fediverse, at the expense of debuggability.
Functions ¶
Types ¶
type OptionFn ¶
func WithApplicationTag ¶
func WithLogger ¶
func WithTransport ¶
func WithTransport(tr http.RoundTripper) OptionFn
type Transport ¶
type Transport struct {
Base http.RoundTripper
// Tag is an application-specific tag for the signature as a String value.
// This value is used by applications to help identify signatures relevant for specific applications or protocols.
// See: https://www.rfc-editor.org/rfc/rfc9421.html#section-2.3-4.12
Tag string
Key crypto.PrivateKey
Actor *vocab.Actor
// contains filtered or unexported fields
}
func New ¶
New initializes the Transport TODO(marius): we need to add to the return values the errors
that might come from the initialization functions.
func (*Transport) RoundTrip ¶
RoundTrip dispatches the received request after signing it. We currently use the double knocking mechanism Mastodon popularized: * we first attempt to sign the request with RFC9421 compliant signature, * if it failed, we try again using a draft Cavage-12 version signature. Additionally, if everything failed, and we're operating with a fetch request, we make one last, non-signed attempt.
Example (Draft) ¶
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Printf("%s\n", r.Header.Get("Signature"))
w.WriteHeader(http.StatusOK)
}))
defer srv.Close()
tr := New(WithTransport(http.DefaultTransport), WithActor(actorFn, prv), NoRFC9421)
// The below functionality would be equivalent to the following usage:
//http.DefaultClient.Transport = tr
//res, err := http.Get(srv.URL)
req := httptest.NewRequest(http.MethodGet, srv.URL, nil)
host := strings.TrimPrefix(srv.URL, "http://")
host = host[:strings.Index(host, ":")]
req.Header.Set("Host", host)
req.Header.Set("Date", millenium.Format(http.TimeFormat))
_, _ = tr.RoundTrip(req)
Output: keyId="https://example.com/~johndoe#main",algorithm="hs2019",headers="(request-target) host date",signature="PYSZQkKUmr9ZDxuNCLe69krLB/0bsprA/K4p4+l0xIINcUBfhDBJNPkN64Omm1tdraTsWfh2JBWQeIdEAW6mm72ERCvqyOldszpiS/PkkVVApduI8tmhSDaoy0I/E3VGanZomEwER5E3VLerAu7ENy8lZrbsYUP7T+pZ+IeMBlM="
Example (Rfc9421) ¶
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
s, _ := sigset.Unmarshal(r)
if sig, ok := s.Messages["sig1"]; ok {
fmt.Printf("KeyID: %s\n", sig.Input.KeyID)
fmt.Printf("Alg: %s\n", sig.Input.Alg)
fmt.Printf("Nonce: %s\n", sig.Input.Nonce)
fmt.Printf("CoveredComponents: %v\n", sig.Input.CoveredComponents)
}
w.WriteHeader(http.StatusOK)
}))
defer srv.Close()
tr := New(WithTransport(http.DefaultTransport), WithActor(actorFn, prv), WithNonce(sameNonce))
req := httptest.NewRequest(http.MethodPost, srv.URL, nil)
req.Header.Set("Date", millenium.Format(http.TimeFormat))
req.Header.Set("Content-Type", "application/json")
_, _ = tr.RoundTrip(req)
Output: KeyID: https://example.com/~johndoe#main Alg: rsa-v1_5-sha256 Nonce: test CoveredComponents: [@method @target-uri content-type content-length content-digest]