s2s

package
v0.0.0-...-1509966 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 17, 2026 License: MIT Imports: 27 Imported by: 1

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
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"}
)
View Source
var ErrRetry = errors.Newf("retry")
View Source
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

func NoRFC9421

func NoRFC9421(h *Transport) error

Types

type OptionFn

type OptionFn func(transport *Transport) error

func WithActor

func WithActor(act *vocab.Actor, prv crypto.PrivateKey) OptionFn

func WithApplicationTag

func WithApplicationTag(t string) OptionFn

func WithLogger

func WithLogger(l lw.Logger) OptionFn

func WithNonce

func WithNonce(nonceFn func() (string, error)) OptionFn

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

func New(initFns ...OptionFn) *Transport

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

func (s *Transport) RoundTrip(req *http.Request) (*http.Response, error)

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]

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL