Fix tests for HTTP Signatures.

Also, bugfix the time.Now calls to use the federator's clock instead.
This is how it should have been done in the beginning, but is necessary
for the tests since the HTTP Signatures by default sign the dates in the
headers. And I noticed said dates were being populated by time.Now
instead of the mock-able Clock.
このコミットが含まれているのは:
Cory Slep 2018-05-19 22:16:37 +02:00
コミット b9606f06f2
2個のファイルの変更166行の追加23行の削除

ファイルの表示

@ -3,10 +3,14 @@ package pub
import (
"bytes"
"context"
"crypto"
"crypto/rand"
"crypto/rsa"
"encoding/json"
"fmt"
"github.com/go-fed/activity/streams"
"github.com/go-fed/activity/vocab"
"github.com/go-fed/httpsig"
"io/ioutil"
"net/http"
"net/http/httptest"
@ -34,6 +38,8 @@ const (
noteName = "A Note"
otherOriginIRIString = "https://foo.net/activity/112358"
otherOriginActorIRIString = "https://foo.net/peyton"
testPublicKeyID = "publicKeyId"
)
var (
@ -85,6 +91,8 @@ var (
testClientExpectedLike *vocab.Like
testClientExpectedUndo *vocab.Undo
testClientExpectedBlock *vocab.Block
testPrivateKey *rsa.PrivateKey
)
func init() {
@ -391,6 +399,11 @@ func init() {
testClientExpectedBlock.SetId(*testNewIRI)
testClientExpectedBlock.AddActorObject(sallyActor)
testClientExpectedBlock.AddObject(samActor)
testPrivateKey, err = rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
}
func Must(l *time.Location, e error) *time.Location {
@ -734,6 +747,8 @@ type MockFederateApp struct {
unblocked func(c context.Context, actorIRIs []url.URL) error
getFollowing func(c context.Context, actor url.URL) (vocab.CollectionType, error)
filterForwarding func(c context.Context, activity vocab.ActivityType, iris []url.URL) ([]url.URL, error)
newSigner func() (httpsig.Signer, error)
privateKey func(boxIRI url.URL) (crypto.PrivateKey, string, error)
}
func (m *MockFederateApp) CanAdd(c context.Context, obj vocab.ObjectType, target vocab.ObjectType) bool {
@ -778,6 +793,20 @@ func (m *MockFederateApp) FilterForwarding(c context.Context, activity vocab.Act
return m.filterForwarding(c, activity, iris)
}
func (m *MockFederateApp) NewSigner() (httpsig.Signer, error) {
if m.newSigner == nil {
m.t.Fatal("unexpected call to MockFederateApp NewSigner")
}
return m.newSigner()
}
func (m *MockFederateApp) PrivateKey(boxIRI url.URL) (privKey crypto.PrivateKey, pubKeyId string, err error) {
if m.privateKey == nil {
m.t.Fatal("unexpected call to MockFederateApp PrivateKey")
}
return m.privateKey(boxIRI)
}
var _ Deliverer = &MockDeliverer{}
type MockDeliverer struct {
@ -861,6 +890,16 @@ func PreparePostOutboxTest(t *testing.T, app *MockApplication, socialApp *MockSo
socialApp.postOutboxAuthorized = func(c context.Context, r *http.Request) (bool, error) {
return true, nil
}
fedApp.newSigner = func() (httpsig.Signer, error) {
s, _, err := httpsig.NewSigner([]httpsig.Algorithm{httpsig.RSA_SHA256}, nil, httpsig.Signature)
if err != nil {
t.Fatal(err)
}
return s, err
}
fedApp.privateKey = func(boxIRI url.URL) (crypto.PrivateKey, string, error) {
return testPrivateKey, testPublicKeyID, nil
}
app.newId = func(c context.Context, t Typer) url.URL {
return *testNewIRI
}
@ -1324,7 +1363,7 @@ func TestPubber_GetInbox(t *testing.T) {
}
func TestPubber_PostOutbox(t *testing.T) {
app, socialApp, _, socialCb, _, d, httpClient, p := NewPubberTest(t)
app, socialApp, fedApp, socialCb, _, d, httpClient, p := NewPubberTest(t)
resp := httptest.NewRecorder()
req := ActivityPubRequest(httptest.NewRequest("POST", testOutboxURI, bytes.NewBuffer(MustSerialize(testCreateNote))))
gotPostOutboxAuthorized := 0
@ -1332,6 +1371,22 @@ func TestPubber_PostOutbox(t *testing.T) {
gotPostOutboxAuthorized++
return true, nil
}
gotNewSigner := 0
fedApp.newSigner = func() (httpsig.Signer, error) {
gotNewSigner++
s, _, err := httpsig.NewSigner([]httpsig.Algorithm{httpsig.RSA_SHA256}, nil, httpsig.Signature)
if err != nil {
t.Fatal(err)
}
return s, err
}
gotPrivateKey := 0
var gotPrivateKeyIRI url.URL
fedApp.privateKey = func(boxIRI url.URL) (crypto.PrivateKey, string, error) {
gotPrivateKey++
gotPrivateKeyIRI = boxIRI
return testPrivateKey, testPublicKeyID, nil
}
gotNewId := 0
app.newId = func(c context.Context, t Typer) url.URL {
gotNewId++
@ -1411,6 +1466,12 @@ func TestPubber_PostOutbox(t *testing.T) {
t.Fatalf("expected %d, got %d", 1, gotPostOutboxAuthorized)
} else if gotNewId != 1 {
t.Fatalf("expected %d, got %d", 1, gotNewId)
} else if gotNewSigner != 1 {
t.Fatalf("expected %d, got %d", 1, gotNewSigner)
} else if gotPrivateKey != 1 {
t.Fatalf("expected %d, got %d", 1, gotPrivateKey)
} else if s := (&gotPrivateKeyIRI).String(); s != testOutboxURI {
t.Fatalf("expected %s, got %s", testOutboxURI, s)
} else if gotOutbox != 1 {
t.Fatalf("expected %d, got %d", 1, gotOutbox)
} else if gotSet != 2 {
@ -1454,6 +1515,14 @@ func TestPubber_PostOutbox(t *testing.T) {
} else if resp.Code != http.StatusCreated {
t.Fatalf("expected %d, got %d", http.StatusCreated, resp.Code)
}
verif, err := httpsig.NewVerifier(httpDeliveryRequest)
if err != nil {
t.Fatal(err)
} else if verif.KeyId() != testPublicKeyID {
t.Fatalf("expected %s, got %s", testPublicKeyID, verif.KeyId())
} else if err := verif.Verify(testPrivateKey.Public(), httpsig.RSA_SHA256); err != nil {
t.Fatal(err)
}
}
func TestPubber_GetOutbox(t *testing.T) {
@ -2094,6 +2163,22 @@ func TestPostInbox_Follow_AutoReject(t *testing.T) {
gotOnFollow++
return AutomaticReject
}
gotNewSigner := 0
fedApp.newSigner = func() (httpsig.Signer, error) {
gotNewSigner++
s, _, err := httpsig.NewSigner([]httpsig.Algorithm{httpsig.RSA_SHA256}, nil, httpsig.Signature)
if err != nil {
t.Fatal(err)
}
return s, err
}
gotPrivateKey := 0
var gotPrivateKeyIRI url.URL
fedApp.privateKey = func(boxIRI url.URL) (crypto.PrivateKey, string, error) {
gotPrivateKey++
gotPrivateKeyIRI = boxIRI
return testPrivateKey, testPublicKeyID, nil
}
fedCb.follow = func(c context.Context, s *streams.Follow) error {
return nil
}
@ -2145,6 +2230,12 @@ func TestPostInbox_Follow_AutoReject(t *testing.T) {
t.Fatal(err)
} else if !handled {
t.Fatalf("expected handled, got !handled")
} else if gotNewSigner != 1 {
t.Fatalf("expected %d, got %d", 1, gotNewSigner)
} else if gotPrivateKey != 1 {
t.Fatalf("expected %d, got %d", 1, gotPrivateKey)
} else if s := (&gotPrivateKeyIRI).String(); s != testInboxURI {
t.Fatalf("expected %s, got %s", testInboxURI, s)
} else if gotOnFollow != 1 {
t.Fatalf("expected %d, got %d", 1, gotOnFollow)
} else if gotHttpDo != 2 {
@ -2176,6 +2267,22 @@ func TestPostInbox_Follow_AutoAccept(t *testing.T) {
gotOnFollow++
return AutomaticAccept
}
gotNewSigner := 0
fedApp.newSigner = func() (httpsig.Signer, error) {
gotNewSigner++
s, _, err := httpsig.NewSigner([]httpsig.Algorithm{httpsig.RSA_SHA256}, nil, httpsig.Signature)
if err != nil {
t.Fatal(err)
}
return s, err
}
gotPrivateKey := 0
var gotPrivateKeyIRI url.URL
fedApp.privateKey = func(boxIRI url.URL) (crypto.PrivateKey, string, error) {
gotPrivateKey++
gotPrivateKeyIRI = boxIRI
return testPrivateKey, testPublicKeyID, nil
}
fedCb.follow = func(c context.Context, s *streams.Follow) error {
return nil
}
@ -2255,6 +2362,12 @@ func TestPostInbox_Follow_AutoAccept(t *testing.T) {
t.Fatalf("expected handled, got !handled")
} else if gotOnFollow != 1 {
t.Fatalf("expected %d, got %d", 1, gotOnFollow)
} else if gotNewSigner != 1 {
t.Fatalf("expected %d, got %d", 1, gotNewSigner)
} else if gotPrivateKey != 1 {
t.Fatalf("expected %d, got %d", 1, gotPrivateKey)
} else if s := (&gotPrivateKeyIRI).String(); s != testInboxURI {
t.Fatalf("expected %s, got %s", testInboxURI, s)
} else if gotHttpDo != 2 {
t.Fatalf("expected %d, got %d", 2, gotHttpDo)
} else if s := httpActorRequest.URL.String(); s != sallyIRIString {
@ -2290,6 +2403,16 @@ func TestPostInbox_Follow_DoesNotAddForAutoAcceptIfAlreadyPresent(t *testing.T)
fedApp.onFollow = func(c context.Context, s *streams.Follow) FollowResponse {
return AutomaticAccept
}
fedApp.newSigner = func() (httpsig.Signer, error) {
s, _, err := httpsig.NewSigner([]httpsig.Algorithm{httpsig.RSA_SHA256}, nil, httpsig.Signature)
if err != nil {
t.Fatal(err)
}
return s, err
}
fedApp.privateKey = func(boxIRI url.URL) (crypto.PrivateKey, string, error) {
return testPrivateKey, testPublicKeyID, nil
}
fedCb.follow = func(c context.Context, s *streams.Follow) error {
return nil
}
@ -2363,6 +2486,16 @@ func TestPostInbox_Follow_AutoAcceptFollowersIsOrderedCollection(t *testing.T) {
fedApp.onFollow = func(c context.Context, s *streams.Follow) FollowResponse {
return AutomaticAccept
}
fedApp.newSigner = func() (httpsig.Signer, error) {
s, _, err := httpsig.NewSigner([]httpsig.Algorithm{httpsig.RSA_SHA256}, nil, httpsig.Signature)
if err != nil {
t.Fatal(err)
}
return s, err
}
fedApp.privateKey = func(boxIRI url.URL) (crypto.PrivateKey, string, error) {
return testPrivateKey, testPublicKeyID, nil
}
fedCb.follow = func(c context.Context, s *streams.Follow) error {
return nil
}
@ -2432,6 +2565,16 @@ func TestPostInbox_Follow_AutoAcceptFollowersIsIRI(t *testing.T) {
fedApp.onFollow = func(c context.Context, s *streams.Follow) FollowResponse {
return AutomaticAccept
}
fedApp.newSigner = func() (httpsig.Signer, error) {
s, _, err := httpsig.NewSigner([]httpsig.Algorithm{httpsig.RSA_SHA256}, nil, httpsig.Signature)
if err != nil {
t.Fatal(err)
}
return s, err
}
fedApp.privateKey = func(boxIRI url.URL) (crypto.PrivateKey, string, error) {
return testPrivateKey, testPublicKeyID, nil
}
fedCb.follow = func(c context.Context, s *streams.Follow) error {
return nil
}

ファイルの表示

@ -73,7 +73,7 @@ func addJSONLDContext(m map[string]interface{}) {
// ActivityStream representation.
//
// creds is allowed to be nil.
func dereference(c HttpClient, u url.URL, agent string, creds *creds) ([]byte, error) {
func dereference(c HttpClient, u url.URL, agent string, creds *creds, clock Clock) ([]byte, error) {
// TODO: (section 7.1) The server MUST dereference the collection (with the user's credentials)
req, err := http.NewRequest("GET", u.String(), nil)
if err != nil {
@ -81,7 +81,7 @@ func dereference(c HttpClient, u url.URL, agent string, creds *creds) ([]byte, e
}
req.Header.Add(acceptHeader, getAcceptHeader)
req.Header.Add("Accept-Charset", "utf-8")
req.Header.Add("Date", time.Now().UTC().Format("Mon, 02 Jan 2006 15:04:05")+" GMT")
req.Header.Add("Date", clock.Now().UTC().Format("Mon, 02 Jan 2006 15:04:05")+" GMT")
req.Header.Add("User-Agent", fmt.Sprintf("%s (go-fed ActivityPub)", agent))
if creds != nil {
err := creds.signer.SignRequest(creds.privKey, creds.pubKeyId, req)
@ -111,7 +111,7 @@ type creds struct {
// body set to the provided bytes.
//
// creds is able to be nil.
func postToOutbox(c HttpClient, b []byte, to url.URL, agent string, creds *creds) error {
func postToOutbox(c HttpClient, b []byte, to url.URL, agent string, creds *creds, clock Clock) error {
byteCopy := make([]byte, 0, len(b))
copy(b, byteCopy)
buf := bytes.NewBuffer(byteCopy)
@ -121,7 +121,7 @@ func postToOutbox(c HttpClient, b []byte, to url.URL, agent string, creds *creds
}
req.Header.Add(contentTypeHeader, postContentTypeHeader)
req.Header.Add("Accept-Charset", "utf-8")
req.Header.Add("Date", time.Now().UTC().Format("Mon, 02 Jan 2006 15:04:05")+" GMT")
req.Header.Add("Date", clock.Now().UTC().Format("Mon, 02 Jan 2006 15:04:05")+" GMT")
req.Header.Add("User-Agent", fmt.Sprintf("%s (go-fed ActivityPub)", agent))
if creds != nil {
err := creds.signer.SignRequest(creds.privKey, creds.pubKeyId, req)
@ -509,7 +509,7 @@ func (f *federator) deliver(obj vocab.ActivityType, boxIRI url.URL) error {
if err != nil {
return err
}
var creds *creds
creds := &creds{}
creds.signer, err = f.FederateApp.NewSigner()
if err != nil {
return err
@ -535,7 +535,7 @@ func (f *federator) deliverToRecipients(obj vocab.ActivityType, recipients []url
}
for _, to := range recipients {
f.deliverer.Do(b, to, func(b []byte, u url.URL) error {
return postToOutbox(f.Client, b, u, f.Agent, creds)
return postToOutbox(f.Client, b, u, f.Agent, creds, f.Clock)
})
}
return nil
@ -620,7 +620,7 @@ func (c *federator) resolveInboxes(boxIRI url.URL, r []url.URL, depth int, max i
uris = getURIsInItemer(c)
return nil
}
err := doForCollectionPage(c.Client, c.Agent, cb, cp.Raw(), cr)
err := doForCollectionPage(c.Client, c.Agent, cb, cp.Raw(), cr, c.Clock)
if err != nil {
return nil, err
}
@ -634,7 +634,7 @@ func (c *federator) resolveInboxes(boxIRI url.URL, r []url.URL, depth int, max i
uris = getURIsInOrderedItemer(c)
return nil
}
err := doForOrderedCollectionPage(c.Client, c.Agent, cb, ocp.Raw(), cr)
err := doForOrderedCollectionPage(c.Client, c.Agent, cb, ocp.Raw(), cr, c.Clock)
if err != nil {
return nil, err
}
@ -654,7 +654,7 @@ func (c *federator) dereferenceForResolvingInboxes(u, boxIRI url.URL, cr *creds)
// To pass back to calling function, since may be set recursively:
cred = cr
var resp []byte
resp, err = dereference(c.Client, u, c.Agent, cr)
resp, err = dereference(c.Client, u, c.Agent, cr, c.Clock)
if err != nil {
return
}
@ -806,7 +806,7 @@ func (f *federator) dedupeOrderedItems(oc vocab.OrderedCollectionType) (vocab.Or
id = pIri.String()
} else if oc.IsOrderedItemsIRI(i) {
removeFn = oc.RemoveOrderedItemsIRI
b, err := dereference(f.Client, oc.GetOrderedItemsIRI(i), f.Agent, nil)
b, err := dereference(f.Client, oc.GetOrderedItemsIRI(i), f.Agent, nil, f.Clock)
var m map[string]interface{}
if err := json.Unmarshal(b, &m); err != nil {
return oc, err
@ -944,7 +944,7 @@ func getAudienceIRIs(o deliverableObject) []url.URL {
// doForCollectionPage applies a function over a collection and its subsequent
// pages recursively. It returns the first non-nil error it encounters.
func doForCollectionPage(h HttpClient, agent string, cb func(c vocab.CollectionPageType) error, c vocab.CollectionPageType, creds *creds) error {
func doForCollectionPage(h HttpClient, agent string, cb func(c vocab.CollectionPageType) error, c vocab.CollectionPageType, creds *creds, clock Clock) error {
err := cb(c)
if err != nil {
return err
@ -952,12 +952,12 @@ func doForCollectionPage(h HttpClient, agent string, cb func(c vocab.CollectionP
if c.IsNextCollectionPage() {
// Handle this one weird trick that other peers HATE federating
// with.
return doForCollectionPage(h, agent, cb, c.GetNextCollectionPage(), creds)
return doForCollectionPage(h, agent, cb, c.GetNextCollectionPage(), creds, clock)
} else if c.IsNextLink() {
l := c.GetNextLink()
if l.HasHref() {
u := l.GetHref()
resp, err := dereference(h, u, agent, creds)
resp, err := dereference(h, u, agent, creds, clock)
if err != nil {
return err
}
@ -971,12 +971,12 @@ func doForCollectionPage(h HttpClient, agent string, cb func(c vocab.CollectionP
return err
}
if next != nil {
return doForCollectionPage(h, agent, cb, next.Raw(), creds)
return doForCollectionPage(h, agent, cb, next.Raw(), creds, clock)
}
}
} else if c.IsNextIRI() {
u := c.GetNextIRI()
resp, err := dereference(h, u, agent, creds)
resp, err := dereference(h, u, agent, creds, clock)
if err != nil {
return err
}
@ -990,7 +990,7 @@ func doForCollectionPage(h HttpClient, agent string, cb func(c vocab.CollectionP
return err
}
if next != nil {
return doForCollectionPage(h, agent, cb, next.Raw(), creds)
return doForCollectionPage(h, agent, cb, next.Raw(), creds, clock)
}
}
return nil
@ -999,7 +999,7 @@ func doForCollectionPage(h HttpClient, agent string, cb func(c vocab.CollectionP
// doForOrderedCollectionPage applies a function over a collection and its
// subsequent pages recursively. It returns the first non-nil error it
// encounters.
func doForOrderedCollectionPage(h HttpClient, agent string, cb func(c vocab.OrderedCollectionPageType) error, c vocab.OrderedCollectionPageType, creds *creds) error {
func doForOrderedCollectionPage(h HttpClient, agent string, cb func(c vocab.OrderedCollectionPageType) error, c vocab.OrderedCollectionPageType, creds *creds, clock Clock) error {
err := cb(c)
if err != nil {
return err
@ -1007,12 +1007,12 @@ func doForOrderedCollectionPage(h HttpClient, agent string, cb func(c vocab.Orde
if c.IsNextOrderedCollectionPage() {
// Handle this one weird trick that other peers HATE federating
// with.
return doForOrderedCollectionPage(h, agent, cb, c.GetNextOrderedCollectionPage(), creds)
return doForOrderedCollectionPage(h, agent, cb, c.GetNextOrderedCollectionPage(), creds, clock)
} else if c.IsNextLink() {
l := c.GetNextLink()
if l.HasHref() {
u := l.GetHref()
resp, err := dereference(h, u, agent, creds)
resp, err := dereference(h, u, agent, creds, clock)
if err != nil {
return err
}
@ -1026,12 +1026,12 @@ func doForOrderedCollectionPage(h HttpClient, agent string, cb func(c vocab.Orde
return err
}
if next != nil {
return doForOrderedCollectionPage(h, agent, cb, next.Raw(), creds)
return doForOrderedCollectionPage(h, agent, cb, next.Raw(), creds, clock)
}
}
} else if c.IsNextIRI() {
u := c.GetNextIRI()
resp, err := dereference(h, u, agent, creds)
resp, err := dereference(h, u, agent, creds, clock)
if err != nil {
return err
}
@ -1045,7 +1045,7 @@ func doForOrderedCollectionPage(h HttpClient, agent string, cb func(c vocab.Orde
return err
}
if next != nil {
return doForOrderedCollectionPage(h, agent, cb, next.Raw(), creds)
return doForOrderedCollectionPage(h, agent, cb, next.Raw(), creds, clock)
}
}
return nil