gb vendor update github.com/matrix-org/gomatrixserverlib
parent
9ed609b9df
commit
f7aa96fc9e
|
@ -116,7 +116,7 @@
|
|||
{
|
||||
"importpath": "github.com/matrix-org/gomatrixserverlib",
|
||||
"repository": "https://github.com/matrix-org/gomatrixserverlib",
|
||||
"revision": "ce6f4766251e31487906dfaaebd7d7cfea147252",
|
||||
"revision": "f3be4cb492f23eb30a9f2ab5fc5bd85ee9c3add6",
|
||||
"branch": "master"
|
||||
},
|
||||
{
|
||||
|
|
|
@ -389,6 +389,8 @@ func (e Event) CheckFields() error { // nolint: gocyclo
|
|||
return err
|
||||
}
|
||||
|
||||
origin := e.fields.Origin
|
||||
|
||||
senderDomain, err := checkID(e.fields.Sender, "user", '@')
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -406,34 +408,33 @@ func (e Event) CheckFields() error { // nolint: gocyclo
|
|||
// Since both domains must be valid domains, and there is no good reason for them
|
||||
// to be different we might as well ensure that they are the same since it
|
||||
// makes the signature checks simpler.
|
||||
if e.fields.Origin != ServerName(eventDomain) {
|
||||
if origin != ServerName(eventDomain) {
|
||||
return fmt.Errorf(
|
||||
"gomatrixserverlib: event ID domain doesn't match origin: %q != %q",
|
||||
eventDomain, e.fields.Origin,
|
||||
eventDomain, origin,
|
||||
)
|
||||
}
|
||||
|
||||
if eventDomain != senderDomain {
|
||||
if origin != ServerName(senderDomain) {
|
||||
// For the most part all events should be sent by a user on the
|
||||
// originating server
|
||||
// originating server.
|
||||
//
|
||||
// However "m.room.member" events created from third-party invites
|
||||
// are allowed to have a different sender because they have the same
|
||||
// sender as the "m.room.third_party_invite" event they derived from.
|
||||
// https://github.com/matrix-org/synapse/blob/v0.21.0/synapse/event_auth.py#L58-L64
|
||||
//
|
||||
// Also, some old versions of synapse had a bug wherein some
|
||||
// joins/leaves used the origin and event id supplied by the helping
|
||||
// server instead of the joining/leaving server.
|
||||
//
|
||||
// So in general we allow the sender to be different from the
|
||||
// origin for m.room.member events. In any case, we check it was
|
||||
// signed by both servers later.
|
||||
if e.fields.Type != MRoomMember {
|
||||
return fmt.Errorf(
|
||||
"gomatrixserverlib: sender domain doesn't match origin: %q != %q",
|
||||
senderDomain, e.fields.Origin,
|
||||
)
|
||||
}
|
||||
c, err := newMemberContentFromEvent(e)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.Membership != invite || c.ThirdPartyInvite == nil {
|
||||
return fmt.Errorf(
|
||||
"gomatrixserverlib: sender domain doesn't match origin: %q != %q",
|
||||
senderDomain, e.fields.Origin,
|
||||
senderDomain, origin,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -189,19 +189,33 @@ 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(ctx context.Context, events []Event, keyRing KeyRing) error { // nolint: gocyclo
|
||||
func VerifyEventSignatures(ctx context.Context, events []Event, keyRing JSONVerifier) error { // nolint: gocyclo
|
||||
var toVerify []VerifyJSONRequest
|
||||
for _, event := range events {
|
||||
redactedJSON, err := redactEvent(event.eventJSON)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v := VerifyJSONRequest{
|
||||
Message: redactedJSON,
|
||||
AtTS: event.OriginServerTS(),
|
||||
ServerName: event.Origin(),
|
||||
|
||||
domains := make(map[ServerName]bool)
|
||||
domains[event.Origin()] = true
|
||||
|
||||
// in general, we expect the domain of the sender id to be the
|
||||
// same as the origin; however there was a bug in an old version
|
||||
// of synapse which meant that some joins/leaves used the origin
|
||||
// and event id supplied by the helping server instead of the
|
||||
// joining/leaving server.
|
||||
//
|
||||
// That's ok, provided it's signed by the sender's server too.
|
||||
//
|
||||
// XXX we may have to exclude 3pid invites here, as per
|
||||
// https://github.com/matrix-org/synapse/blob/v0.21.0/synapse/event_auth.py#L58-L64.
|
||||
//
|
||||
senderDomain, err := domainFromID(event.Sender())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
toVerify = append(toVerify, v)
|
||||
domains[ServerName(senderDomain)] = true
|
||||
|
||||
// MRoomMember invite events are signed by both the server sending
|
||||
// the invite and the server the invite is for.
|
||||
|
@ -216,12 +230,20 @@ func VerifyEventSignatures(ctx context.Context, events []Event, keyRing KeyRing)
|
|||
return err
|
||||
}
|
||||
if c.Membership == invite {
|
||||
v.ServerName = ServerName(targetDomain)
|
||||
domains[ServerName(targetDomain)] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for domain := range domains {
|
||||
v := VerifyJSONRequest{
|
||||
Message: redactedJSON,
|
||||
AtTS: event.OriginServerTS(),
|
||||
ServerName: domain,
|
||||
}
|
||||
toVerify = append(toVerify, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
results, err := keyRing.VerifyJSONs(ctx, toVerify)
|
||||
if err != nil {
|
||||
|
|
|
@ -17,7 +17,10 @@ package gomatrixserverlib
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/crypto/ed25519"
|
||||
|
@ -258,3 +261,127 @@ func TestSignEventTestVectors(t *testing.T) {
|
|||
}
|
||||
}`)
|
||||
}
|
||||
|
||||
type StubVerifier struct {
|
||||
requests []VerifyJSONRequest
|
||||
results []VerifyJSONResult
|
||||
}
|
||||
|
||||
func (v *StubVerifier) VerifyJSONs(ctx context.Context, requests []VerifyJSONRequest) ([]VerifyJSONResult, error) {
|
||||
v.requests = append(v.requests, requests...)
|
||||
return v.results, nil
|
||||
}
|
||||
|
||||
func TestVerifyEventSignatures(t *testing.T) {
|
||||
verifier := StubVerifier{}
|
||||
|
||||
eventJSON := []byte(`{
|
||||
"type": "m.room.name",
|
||||
"state_key": "",
|
||||
"event_id": "$test:localhost",
|
||||
"room_id": "!test:localhost",
|
||||
"sender": "@test:localhost",
|
||||
"origin": "originserver",
|
||||
"content": {
|
||||
"name": "Hello World"
|
||||
},
|
||||
"origin_server_ts": 123456
|
||||
}`)
|
||||
|
||||
var event Event
|
||||
if err := json.Unmarshal(eventJSON, &event.fields); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
event.eventJSON = eventJSON
|
||||
|
||||
events := []Event{event}
|
||||
if err := VerifyEventSignatures(context.Background(), events, &verifier); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// There should be two verification requests
|
||||
if len(verifier.requests) != 2 {
|
||||
t.Fatalf("Number of requests: got %d, want 2", len(verifier.requests))
|
||||
}
|
||||
wantContent, err := redactEvent(eventJSON)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
servers := []string{}
|
||||
|
||||
for i, rq := range verifier.requests {
|
||||
if !bytes.Equal(rq.Message, wantContent) {
|
||||
t.Errorf("Verify content %d: got %s, want %s", i, rq.Message, wantContent)
|
||||
}
|
||||
if rq.AtTS != 123456 {
|
||||
t.Errorf("Verify time %d: got %d, want %d", i, rq.AtTS, 123456)
|
||||
}
|
||||
servers = append(servers, string(rq.ServerName))
|
||||
}
|
||||
|
||||
sort.Strings(servers)
|
||||
if servers[0] != "localhost" {
|
||||
t.Errorf("Verify server 0: got %s, want %s", servers[0], "localhost")
|
||||
}
|
||||
if servers[1] != "originserver" {
|
||||
t.Errorf("Verify server 1: got %s, want %s", servers[1], "originserver")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerifyEventSignaturesForInvite(t *testing.T) {
|
||||
verifier := StubVerifier{}
|
||||
|
||||
eventJSON := []byte(`{
|
||||
"type": "m.room.member",
|
||||
"state_key": "@bob:bobserver",
|
||||
"event_id": "$test:aliceserver",
|
||||
"room_id": "!test:room",
|
||||
"sender": "@alice:aliceserver",
|
||||
"origin": "aliceserver",
|
||||
"content": {
|
||||
"membership": "invite"
|
||||
},
|
||||
"origin_server_ts": 123456
|
||||
}`)
|
||||
|
||||
var event Event
|
||||
if err := json.Unmarshal(eventJSON, &event.fields); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
event.eventJSON = eventJSON
|
||||
|
||||
events := []Event{event}
|
||||
if err := VerifyEventSignatures(context.Background(), events, &verifier); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// There should be two verification requests
|
||||
if len(verifier.requests) != 2 {
|
||||
t.Fatalf("Number of requests: got %d, want 2", len(verifier.requests))
|
||||
}
|
||||
wantContent, err := redactEvent(eventJSON)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
servers := []string{}
|
||||
|
||||
for i, rq := range verifier.requests {
|
||||
if !bytes.Equal(rq.Message, wantContent) {
|
||||
t.Errorf("Verify content %d: got %s, want %s", i, rq.Message, wantContent)
|
||||
}
|
||||
if rq.AtTS != 123456 {
|
||||
t.Errorf("Verify time %d: got %d, want %d", i, rq.AtTS, 123456)
|
||||
}
|
||||
servers = append(servers, string(rq.ServerName))
|
||||
}
|
||||
|
||||
sort.Strings(servers)
|
||||
if servers[0] != "aliceserver" {
|
||||
t.Errorf("Verify server 0: got %s, want %s", servers[0], "aliceserver")
|
||||
}
|
||||
if servers[1] != "bobserver" {
|
||||
t.Errorf("Verify server 1: got %s, want %s", servers[1], "bobserver")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,7 +108,7 @@ func (r RespState) Events() ([]Event, error) {
|
|||
}
|
||||
|
||||
// Check that a response to /state is valid.
|
||||
func (r RespState) Check(ctx context.Context, keyRing KeyRing) error {
|
||||
func (r RespState) Check(ctx context.Context, keyRing JSONVerifier) error {
|
||||
var allEvents []Event
|
||||
for _, event := range r.AuthEvents {
|
||||
if event.StateKey() == nil {
|
||||
|
@ -214,8 +214,10 @@ type respSendJoinFields struct {
|
|||
// Check that a response to /send_join is valid.
|
||||
// This checks that it would be valid as a response to /state
|
||||
// This also checks that the join event is allowed by the state.
|
||||
func (r RespSendJoin) Check(ctx context.Context, keyRing KeyRing, joinEvent Event) error {
|
||||
// First check that the state is valid.
|
||||
func (r RespSendJoin) Check(ctx context.Context, keyRing JSONVerifier, joinEvent Event) error {
|
||||
// First check that the state is valid and that the events in the response
|
||||
// are correctly signed.
|
||||
//
|
||||
// The response to /send_join has the same data as a response to /state
|
||||
// and the checks for a response to /state also apply.
|
||||
if err := RespState(r).Check(ctx, keyRing); err != nil {
|
||||
|
|
|
@ -69,12 +69,18 @@ type VerifyJSONResult struct {
|
|||
Error error
|
||||
}
|
||||
|
||||
// A JSONVerifier is an object which can verify the signatures of JSON messages.
|
||||
type JSONVerifier interface {
|
||||
// VerifyJSONs performs bulk JSON signature verification for a list of VerifyJSONRequests.
|
||||
// Returns a list of VerifyJSONResults with the same length and order as the request list.
|
||||
// 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(ctx context.Context, requests []VerifyJSONRequest) ([]VerifyJSONResult, error) { // nolint: gocyclo
|
||||
VerifyJSONs(ctx context.Context, requests []VerifyJSONRequest) ([]VerifyJSONResult, error)
|
||||
}
|
||||
|
||||
// VerifyJSONs implements JSONVerifier.
|
||||
func (k KeyRing) VerifyJSONs(ctx context.Context, requests []VerifyJSONRequest) ([]VerifyJSONResult, error) { // nolint: gocyclo
|
||||
results := make([]VerifyJSONResult, len(requests))
|
||||
keyIDs := make([][]KeyID, len(requests))
|
||||
|
||||
|
|
|
@ -184,7 +184,7 @@ func isSafeInHTTPQuotedString(text string) bool { // nolint: gocyclo
|
|||
// It consumes the body of the request.
|
||||
// The JSON content can be accessed using FederationRequest.Content()
|
||||
// Returns an 400 error if there was a problem parsing the request.
|
||||
// It authenticates the request using an ed25519 signature using the KeyRing.
|
||||
// It authenticates the request using an ed25519 signature using the JSONVerifier.
|
||||
// The origin server can be accessed using FederationRequest.Origin()
|
||||
// Returns a 401 error if there was a problem authenticating the request.
|
||||
// HTTP handlers using this should be careful that they only use the parts of
|
||||
|
@ -192,7 +192,7 @@ func isSafeInHTTPQuotedString(text string) bool { // nolint: gocyclo
|
|||
// the query parameters, and the JSON content. In particular the version of
|
||||
// HTTP and the headers aren't protected by the signature.
|
||||
func VerifyHTTPRequest(
|
||||
req *http.Request, now time.Time, destination ServerName, keys KeyRing,
|
||||
req *http.Request, now time.Time, destination ServerName, keys JSONVerifier,
|
||||
) (*FederationRequest, util.JSONResponse) {
|
||||
request, err := readHTTPRequest(req)
|
||||
if err != nil {
|
||||
|
|
Loading…
Reference in New Issue