Fix response to federation /invite to match the format expected by synapse (#221)

* Fix response to /invite to match the format expected by synapse

* gb vendor update github.com/matrix-org/gomatrixserverlib

* Use gomatrixserverlib.RespInvite

* gb vendor update github.com/matrix-org/gomatrixserverlib
This commit is contained in:
Mark Haines 2017-09-11 18:07:12 +01:00 committed by GitHub
parent 5740cb3e58
commit 6cb9d900b9
21 changed files with 148 additions and 64 deletions

View file

@ -101,6 +101,6 @@ func Invite(
// the other servers in the room that we have been invited.
return util.JSONResponse{
Code: 200,
JSON: &signedEvent,
JSON: gomatrixserverlib.RespInvite{Event: signedEvent},
}
}

2
vendor/manifest vendored
View file

@ -116,7 +116,7 @@
{
"importpath": "github.com/matrix-org/gomatrixserverlib",
"repository": "https://github.com/matrix-org/gomatrixserverlib",
"revision": "2e9caead882bcdeb999cf4677cfff47e39d3271e",
"revision": "fe45d482f2280c9f92f09eb6650e7aa3cca051c5",
"branch": "master"
},
{

View file

@ -114,7 +114,7 @@ func (fc *Client) LookupUserInfo(matrixServer ServerName, token string) (u UserI
var response *http.Response
response, err = fc.client.Get(url.String())
if response != nil {
defer response.Body.Close()
defer response.Body.Close() // nolint: errcheck
}
if err != nil {
return
@ -152,7 +152,7 @@ func (fc *Client) LookupUserInfo(matrixServer ServerName, token string) (u UserI
// return a cached copy of the keys or whether they will need to retrieve a fresh
// copy of the keys.
// Returns the keys or an error if there was a problem talking to the server.
func (fc *Client) LookupServerKeys(
func (fc *Client) LookupServerKeys( // nolint: gocyclo
matrixServer ServerName, keyRequests map[PublicKeyRequest]Timestamp,
) (map[PublicKeyRequest]ServerKeys, error) {
url := url.URL{
@ -185,7 +185,7 @@ func (fc *Client) LookupServerKeys(
response, err := fc.client.Post(url.String(), "application/json", bytes.NewBuffer(requestBytes))
if response != nil {
defer response.Body.Close()
defer response.Body.Close() // nolint: errcheck
}
if err != nil {
return nil, err

View file

@ -21,7 +21,7 @@ import (
"testing"
)
func TestToClientEvent(t *testing.T) {
func TestToClientEvent(t *testing.T) { // nolint: gocyclo
ev, err := NewEventFromTrustedJSON([]byte(`{
"type": "m.room.name",
"state_key": "",

View file

@ -315,6 +315,7 @@ func (e Event) Sign(signingName string, keyID KeyID, privateKey ed25519.PrivateK
return Event{
redacted: e.redacted,
eventJSON: eventJSON,
fields: e.fields,
}
}
@ -361,7 +362,7 @@ const (
// Returns an error if the total length of the event JSON is too long.
// Returns an error if the event ID doesn't match the origin of the event.
// https://matrix.org/docs/spec/client_server/r0.2.0.html#size-limits
func (e Event) CheckFields() error {
func (e Event) CheckFields() error { // nolint: gocyclo
if len(e.eventJSON) > maxEventLength {
return fmt.Errorf(
"gomatrixserverlib: event is too long, length %d > maximum %d",

View file

@ -86,7 +86,7 @@ func (s StateNeeded) Tuples() (res []StateKeyTuple) {
// AuthEventReferences returns the auth_events references for the StateNeeded. Returns an error if the
// provider returns an error. If an event is missing from the provider but is required in StateNeeded, it
// is skipped over: no error is returned.
func (s StateNeeded) AuthEventReferences(provider AuthEventProvider) (refs []EventReference, err error) {
func (s StateNeeded) AuthEventReferences(provider AuthEventProvider) (refs []EventReference, err error) { // nolint: gocyclo
var e *Event
if s.Create {
if e, err = provider.Create(); err != nil {
@ -294,7 +294,7 @@ func (a *AuthEvents) ThirdPartyInvite(stateKey string) (*Event, error) {
func NewAuthEvents(events []*Event) AuthEvents {
a := AuthEvents{make(map[StateKeyTuple]*Event)}
for _, e := range events {
a.AddEvent(e)
a.AddEvent(e) // nolint: errcheck
}
return a
}
@ -775,7 +775,7 @@ type membershipAllower struct {
// newMembershipAllower loads the information needed to authenticate the m.room.member event
// from the auth events.
func newMembershipAllower(authEvents AuthEventProvider, event Event) (m membershipAllower, err error) {
func newMembershipAllower(authEvents AuthEventProvider, event Event) (m membershipAllower, err error) { // nolint: gocyclo
stateKey := event.StateKey()
if stateKey == nil {
err = errorf("m.room.member must be a state event")
@ -816,7 +816,7 @@ func newMembershipAllower(authEvents AuthEventProvider, event Event) (m membersh
}
// membershipAllowed checks whether the membership event is allowed
func (m *membershipAllower) membershipAllowed(event Event) error {
func (m *membershipAllower) membershipAllowed(event Event) error { // nolint: gocyclo
if m.create.roomID != event.RoomID() {
return errorf("create event has different roomID: %q != %q", event.RoomID(), m.create.roomID)
}
@ -896,7 +896,7 @@ func (m *membershipAllower) membershipAllowedFromThirdPartyInvite() error {
}
// membershipAllowedSelf determines if the change made by the user to their own membership is allowed.
func (m *membershipAllower) membershipAllowedSelf() error {
func (m *membershipAllower) membershipAllowedSelf() error { // nolint: gocyclo
if m.newMember.Membership == join {
// A user that is not in the room is allowed to join if the room
// join rules are "public".
@ -930,7 +930,7 @@ func (m *membershipAllower) membershipAllowedSelf() error {
}
// membershipAllowedOther determines if the user is allowed to change the membership of another user.
func (m *membershipAllower) membershipAllowedOther() error {
func (m *membershipAllower) membershipAllowedOther() error { // nolint: gocyclo
senderLevel := m.powerLevels.userLevel(m.senderID)
targetLevel := m.powerLevels.userLevel(m.targetID)

View file

@ -128,7 +128,9 @@ func TestStateNeededForJoin(t *testing.T) {
StateKey: &skey,
Sender: "@u1:a",
}
b.SetContent(memberContent{"join", nil})
if err := b.SetContent(memberContent{"join", nil}); err != nil {
t.Fatal(err)
}
testStateNeededForAuth(t, `[{
"type": "m.room.member",
"state_key": "@u1:a",
@ -149,7 +151,9 @@ func TestStateNeededForInvite(t *testing.T) {
StateKey: &skey,
Sender: "@u1:a",
}
b.SetContent(memberContent{"invite", nil})
if err := b.SetContent(memberContent{"invite", nil}); err != nil {
t.Fatal(err)
}
testStateNeededForAuth(t, `[{
"type": "m.room.member",
"state_key": "@u2:b",
@ -170,11 +174,13 @@ func TestStateNeededForInvite3PID(t *testing.T) {
Sender: "@u1:a",
}
b.SetContent(memberContent{"invite", &memberThirdPartyInvite{
if err := b.SetContent(memberContent{"invite", &memberThirdPartyInvite{
Signed: memberThirdPartyInviteSigned{
Token: "my_token",
},
}})
}}); err != nil {
t.Fatal(err)
}
testStateNeededForAuth(t, `[{
"type": "m.room.member",
"state_key": "@u2:b",

View file

@ -20,6 +20,7 @@ import (
"crypto/sha256"
"encoding/json"
"fmt"
"golang.org/x/crypto/ed25519"
)
@ -98,7 +99,7 @@ func checkEventContentHash(eventJSON []byte) error {
sha256Hash := sha256.Sum256(hashableEventJSON)
if bytes.Compare(sha256Hash[:], []byte(hashes.Sha256)) != 0 {
if !bytes.Equal(sha256Hash[:], []byte(hashes.Sha256)) {
return fmt.Errorf("Invalid Sha256 content hash: %v != %v", sha256Hash[:], []byte(hashes.Sha256))
}
@ -187,7 +188,7 @@ func verifyEventSignature(signingName string, keyID KeyID, publicKey ed25519.Pub
// VerifyEventSignatures checks that each event in a list of events has valid
// signatures from the server that sent it.
func VerifyEventSignatures(events []Event, keyRing KeyRing) error {
func VerifyEventSignatures(events []Event, keyRing KeyRing) error { // nolint: gocyclo
var toVerify []VerifyJSONRequest
for _, event := range events {
redactedJSON, err := redactEvent(event.eventJSON)

View file

@ -18,8 +18,9 @@ package gomatrixserverlib
import (
"bytes"
"encoding/base64"
"golang.org/x/crypto/ed25519"
"testing"
"golang.org/x/crypto/ed25519"
)
func TestVerifyEventSignatureTestVectors(t *testing.T) {

View file

@ -2,11 +2,12 @@ package gomatrixserverlib
import (
"encoding/json"
"github.com/matrix-org/gomatrix"
"golang.org/x/crypto/ed25519"
"io/ioutil"
"net/http"
"net/url"
"github.com/matrix-org/gomatrix"
"golang.org/x/crypto/ed25519"
)
// An FederationClient is a matrix federation client that adds
@ -42,7 +43,7 @@ func (ac *FederationClient) doRequest(r FederationRequest, resBody interface{})
res, err := ac.client.Do(req)
if res != nil {
defer res.Body.Close()
defer res.Body.Close() // nolint: errcheck
}
if err != nil {
@ -76,6 +77,10 @@ func (ac *FederationClient) doRequest(r FederationRequest, resBody interface{})
return err
}
if resBody == nil {
return nil
}
return json.Unmarshal(contents, resBody)
}
@ -124,6 +129,22 @@ func (ac *FederationClient) SendJoin(s ServerName, event Event) (res RespSendJoi
return
}
// ExchangeThirdPartyInvite sends the builder of a m.room.member event of
// "invite" membership derived from a response from invites sent by an identity
// server.
// This is used to exchange a m.room.third_party_invite event for a m.room.member
// one in a room the local server isn't a member of.
func (ac *FederationClient) ExchangeThirdPartyInvite(s ServerName, builder EventBuilder) (err error) {
path := "/_matrix/federation/v1/exchange_third_party_invite/" +
url.PathEscape(builder.RoomID)
req := NewFederationRequest("PUT", s, path)
if err = req.SetContent(builder); err != nil {
return
}
err = ac.doRequest(req, nil)
return
}
// LookupState retrieves the room state for a room at an event from a
// remote matrix server as full matrix events.
func (ac *FederationClient) LookupState(s ServerName, roomID, eventID string) (res RespState, err error) {

View file

@ -185,9 +185,7 @@ func (r RespSendJoin) MarshalJSON() ([]byte, error) {
// (This protocol oddity is the result of a typo in the synapse matrix
// server, and is preserved to maintain compatibility.)
return json.Marshal([]interface{}{200, respSendJoinFields{
r.StateEvents, r.AuthEvents,
}})
return json.Marshal([]interface{}{200, respSendJoinFields(r)})
}
// UnmarshalJSON implements json.Unmarshaller
@ -203,8 +201,7 @@ func (r *RespSendJoin) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(tuple[1], &fields); err != nil {
return err
}
r.StateEvents = fields.StateEvents
r.AuthEvents = fields.AuthEvents
*r = RespSendJoin(fields)
return nil
}
@ -284,3 +281,39 @@ func checkAllowedByAuthEvents(event Event, eventsByID map[string]*Event) error {
}
return nil
}
// RespInvite is the content of a response to PUT /_matrix/federation/v1/invite/{roomID}/{eventID}
type RespInvite struct {
// The invite event signed by recipient server.
Event Event
}
// MarshalJSON implements json.Marshaller
func (r RespInvite) MarshalJSON() ([]byte, error) {
// The wire format of a RespInvite is slightly is sent as the second element
// of a two element list where the first element is the constant integer 200.
// (This protocol oddity is the result of a typo in the synapse matrix
// server, and is preserved to maintain compatibility.)
return json.Marshal([]interface{}{200, respInviteFields(r)})
}
// UnmarshalJSON implements json.Unmarshaller
func (r *RespInvite) UnmarshalJSON(data []byte) error {
var tuple []rawJSON
if err := json.Unmarshal(data, &tuple); err != nil {
return err
}
if len(tuple) != 2 {
return fmt.Errorf("gomatrixserverlib: invalid invite response, invalid length: %d != 2", len(tuple))
}
var fields respInviteFields
if err := json.Unmarshal(tuple[1], &fields); err != nil {
return err
}
*r = RespInvite(fields)
return nil
}
type respInviteFields struct {
Event Event `json:"event"`
}

View file

@ -2,23 +2,17 @@
set -eu
golint ./...
misspell -error .
echo "Installing lint search engine..."
go get github.com/alecthomas/gometalinter/
gometalinter --config=linter.json --install --update
# gofmt doesn't exit with an error code if the files don't match the expected
# format. So we have to run it and see if it outputs anything.
if gofmt -l -s . 2>&1 | read
then
echo "Error: not all code had been formatted with gofmt."
echo "Fixing the following files"
gofmt -s -w -l .
echo
echo "Please add them to the commit"
git status --short
exit 1
fi
echo "Looking for lint..."
gometalinter --config=linter.json
ineffassign .
go tool vet --all --shadow .
gocyclo -over 16 .
go test -timeout 5s . ./...
echo "Double checking spelling..."
misspell -error src *.md
echo "Testing..."
go test
echo "Done!"

View file

@ -2,9 +2,10 @@ package gomatrixserverlib
import (
"fmt"
"golang.org/x/crypto/ed25519"
"strings"
"time"
"golang.org/x/crypto/ed25519"
)
// A PublicKeyRequest is a request for a public key with a particular key ID.
@ -72,7 +73,7 @@ type VerifyJSONResult struct {
// The caller should check the Result field for each entry to see if it was valid.
// Returns an error if there was a problem talking to the database or one of the other methods
// of fetching the public keys.
func (k *KeyRing) VerifyJSONs(requests []VerifyJSONRequest) ([]VerifyJSONResult, error) {
func (k *KeyRing) VerifyJSONs(requests []VerifyJSONRequest) ([]VerifyJSONResult, error) { // nolint: gocyclo
results := make([]VerifyJSONResult, len(requests))
keyIDs := make([][]KeyID, len(requests))

View file

@ -6,7 +6,6 @@ import (
)
var privateKeySeed1 = `QJvXAPj0D9MUb1exkD8pIWmCvT1xajlsB8jRYz/G5HE`
var privateKeySeed2 = `AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA`
// testKeys taken from a copy of synapse.
var testKeys = `{

View file

@ -110,7 +110,7 @@ func FetchKeysDirect(serverName ServerName, addr, sni string) (*ServerKeys, *tls
if err != nil {
return nil, nil, err
}
defer tcpconn.Close()
defer tcpconn.Close() // nolint: errcheck
tlsconn := tls.Client(tcpconn, &tls.Config{
ServerName: sni,
InsecureSkipVerify: true, // This must be specified even though the TLS library will ignore it.
@ -134,7 +134,7 @@ func FetchKeysDirect(serverName ServerName, addr, sni string) (*ServerKeys, *tls
// Read the 200 OK from the server.
response, err := http.ReadResponse(bufio.NewReader(tlsconn), request)
if response != nil {
defer response.Body.Close()
defer response.Body.Close() // nolint: errcheck
}
if err != nil {
return nil, nil, err
@ -164,9 +164,9 @@ type KeyChecks struct {
MatchingServerName bool // Does the server name match what was requested.
FutureValidUntilTS bool // The valid until TS is in the future.
HasEd25519Key bool // The server has at least one ed25519 key.
HasTLSFingerprint bool // The server has at least one fingerprint.
AllEd25519ChecksOK *bool // All the Ed25519 checks are ok. or null if there weren't any to check.
Ed25519Checks map[KeyID]Ed25519Checks // Checks for Ed25519 keys.
HasTLSFingerprint bool // The server has at least one fingerprint.
AllTLSFingerprintChecksOK *bool // All the fingerprint checks are ok.
TLSFingerprintChecks []TLSFingerprintChecks // Checks for TLS fingerprints.
MatchingTLSFingerprint *bool // The TLS fingerprint for the connection matches one of the listed fingerprints.
@ -206,7 +206,7 @@ func checkFingerprint(connState *tls.ConnectionState, sha256Fingerprints []Base6
cert := connState.PeerCertificates[0]
digest := sha256.Sum256(cert.Raw)
for _, fingerprint := range sha256Fingerprints {
if bytes.Compare(digest[:], fingerprint) == 0 {
if bytes.Equal(digest[:], fingerprint) {
return true
}
}

View file

@ -0,0 +1,25 @@
{
"Enable": [
"vet",
"vetshadow",
"gotype",
"deadcode",
"gocyclo",
"golint",
"varcheck",
"structcheck",
"aligncheck",
"ineffassign",
"gas",
"misspell",
"gosimple",
"megacheck",
"unparam",
"goimports",
"goconst",
"unconvert",
"errcheck",
"interfacer",
"testify"
]
}

View file

@ -4,13 +4,14 @@ import (
"bytes"
"encoding/json"
"fmt"
"github.com/matrix-org/util"
"golang.org/x/crypto/ed25519"
"io"
"io/ioutil"
"net/http"
"strings"
"time"
"github.com/matrix-org/util"
"golang.org/x/crypto/ed25519"
)
// A FederationRequest is a request to send to a remote server or a request
@ -156,7 +157,7 @@ func (r *FederationRequest) HTTPRequest() (*http.Request, error) {
//
// qdtext = HTAB / SP / %x21 / %x23-5B / %x5D-7E / %x80-FF
//
func isSafeInHTTPQuotedString(text string) bool {
func isSafeInHTTPQuotedString(text string) bool { // nolint: gocyclo
for i := 0; i < len(text); i++ {
c := text[i]
switch {
@ -234,7 +235,7 @@ func VerifyHTTPRequest(
}
// Returns an error if there was a problem reading the content of the request
func readHTTPRequest(req *http.Request) (*FederationRequest, error) {
func readHTTPRequest(req *http.Request) (*FederationRequest, error) { // nolint: gocyclo
var result FederationRequest
result.fields.Method = req.Method

View file

@ -4,10 +4,11 @@ import (
"bufio"
"bytes"
"encoding/base64"
"golang.org/x/crypto/ed25519"
"net/http"
"testing"
"time"
"golang.org/x/crypto/ed25519"
)
// This GET request is taken from a request made by a synapse run by sytest.
@ -62,7 +63,7 @@ func TestSignGetRequest(t *testing.T) {
t.Fatal(err)
}
got := string(buf.Bytes())
got := buf.String()
want := exampleGetRequest
if want != got {
t.Errorf("Wanted %q got %q", want, got)
@ -121,7 +122,7 @@ func TestSignPutRequest(t *testing.T) {
t.Fatal(err)
}
got := string(buf.Bytes())
got := buf.String()
want := examplePutRequest
if want != got {
t.Errorf("Wanted %q got %q", want, got)
@ -159,7 +160,6 @@ func TestVerifyPutRequest(t *testing.T) {
}
var privateKey1 = mustLoadPrivateKey(privateKeySeed1)
var privateKey2 = mustLoadPrivateKey(privateKeySeed2)
func mustLoadPrivateKey(seed string) ed25519.PrivateKey {
seedBytes, err := base64.RawStdEncoding.DecodeString(seed)

View file

@ -38,12 +38,12 @@ type DNSResult struct {
}
// LookupServer looks up a matrix server in DNS.
func LookupServer(serverName ServerName) (*DNSResult, error) {
func LookupServer(serverName ServerName) (*DNSResult, error) { // nolint: gocyclo
var result DNSResult
result.Hosts = map[string]HostResult{}
hosts := map[string][]net.SRV{}
if strings.Index(string(serverName), ":") == -1 {
if !strings.Contains(string(serverName), ":") {
// If there isn't an explicit port set then try to look up the SRV record.
var err error
result.SRVCName, result.SRVRecords, err = net.LookupSRV("matrix", "tcp", string(serverName))

View file

@ -18,6 +18,7 @@ package gomatrixserverlib
import (
"encoding/json"
"fmt"
"golang.org/x/crypto/ed25519"
)

View file

@ -99,7 +99,7 @@ func (r *stateResolver) Member(key string) (*Event, error) {
return r.resolvedMembers[key], nil
}
func (r *stateResolver) addConflicted(events []Event) {
func (r *stateResolver) addConflicted(events []Event) { // nolint: gocyclo
type conflictKey struct {
eventType string
stateKey string