-
Notifications
You must be signed in to change notification settings - Fork 51
/
load.go
153 lines (132 loc) · 4.77 KB
/
load.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package gomatrixserverlib
import (
"context"
"encoding/json"
"fmt"
"strings"
"github.com/matrix-org/gomatrixserverlib/spec"
)
// EventLoadResult is the result of loading and verifying an event in the EventsLoader.
type EventLoadResult struct {
Event PDU
Error error
SoftFail bool
}
// EventsLoader loads untrusted events and verifies them.
type EventsLoader struct {
roomVer RoomVersion
keyRing JSONVerifier
provider EventProvider
stateProvider StateProvider
// Set to true to do:
// 6. Passes authorization rules based on the current state of the room, otherwise it is "soft failed".
// This is only desirable for live events, not backfilled events hence the flag.
performSoftFailCheck bool
}
// NewEventsLoader returns a new events loader
func NewEventsLoader(roomVer RoomVersion, keyRing JSONVerifier, stateProvider StateProvider, provider EventProvider, performSoftFailCheck bool) *EventsLoader {
return &EventsLoader{
roomVer: roomVer,
keyRing: keyRing,
provider: provider,
stateProvider: stateProvider,
performSoftFailCheck: performSoftFailCheck,
}
}
// LoadAndVerify loads untrusted events and verifies them.
// Checks performed are outlined at https://matrix.org/docs/spec/server_server/latest#checks-performed-on-receipt-of-a-pdu
// The length of the returned slice will always equal the length of rawEvents.
// The order of the returned events depends on `sortOrder`. The events are reverse topologically sorted by the ordering specified. However,
// in order to sort the events must be loaded which could fail. For those events which fail to be loaded, they will
// be put at the end of the returned slice.
func (l *EventsLoader) LoadAndVerify(ctx context.Context, rawEvents []json.RawMessage, sortOrder TopologicalOrder, userIDForSender spec.UserIDForSender) ([]EventLoadResult, error) {
results := make([]EventLoadResult, len(rawEvents))
verImpl, err := GetRoomVersion(l.roomVer)
if err != nil {
return nil, err
}
// 1. Is a valid event, otherwise it is dropped.
// 3. Passes hash checks, otherwise it is redacted before being processed further.
events := make([]PDU, 0, len(rawEvents))
errs := make([]error, 0, len(rawEvents))
for _, rawEv := range rawEvents {
event, err := verImpl.NewEventFromUntrustedJSON(rawEv)
if err != nil {
errs = append(errs, err)
continue
}
events = append(events, event)
}
events = ReverseTopologicalOrdering(events, sortOrder)
// assign the errors to the end of the slice
for i := 0; i < len(errs); i++ {
results[len(results)-len(errs)+i] = EventLoadResult{
Error: errs[i],
}
}
// at this point, the three slices look something like:
// results: [ _ , _ , _ , err1 , err2 ]
// errs: [ err1, err2 ]
// events [ ev1, ev2, ev3 ]
// so we can directly index from events into results from now on.
// 2. Passes signature checks, otherwise it is dropped.
failures := VerifyAllEventSignatures(ctx, events, l.keyRing, userIDForSender)
if len(failures) != len(events) {
return nil, fmt.Errorf("gomatrixserverlib: bulk event signature verification length mismatch: %d != %d", len(failures), len(events))
}
for i := range events {
h := events[i]
results[i] = EventLoadResult{
Event: h,
}
if eventErr := failures[i]; eventErr != nil {
if results[i].Error == nil { // could have failed earlier
results[i].Error = SignatureErr{eventErr}
continue
}
}
// 4. Passes authorization rules based on the event's auth events, otherwise it is rejected.
if err := VerifyEventAuthChain(ctx, h, l.provider, userIDForSender); err != nil {
if results[i].Error == nil { // could have failed earlier
results[i].Error = AuthChainErr{err}
continue
}
}
// 5. Passes authorization rules based on the state at the event, otherwise it is rejected.
if err := VerifyAuthRulesAtState(ctx, l.stateProvider, h, true, userIDForSender); err != nil {
if results[i].Error == nil { // could have failed earlier
results[i].Error = AuthRulesErr{err}
continue
}
}
}
// TODO: performSoftFailCheck, needs forward extremity
return results, nil
}
type SignatureErr struct {
err error
}
func (se SignatureErr) Error() string {
return fmt.Sprintf("SignatureErr: %s", se.err)
}
func (se SignatureErr) Is(target error) bool {
return strings.HasPrefix(target.Error(), "SignatureErr")
}
type AuthChainErr struct {
err error
}
func (se AuthChainErr) Error() string {
return fmt.Sprintf("AuthChainErr: %s", se.err)
}
func (se AuthChainErr) Is(target error) bool {
return strings.HasPrefix(target.Error(), "AuthChainErr")
}
type AuthRulesErr struct {
err error
}
func (se AuthRulesErr) Error() string {
return fmt.Sprintf("AuthRulesErr: %s", se.err)
}
func (se AuthRulesErr) Is(target error) bool {
return strings.HasPrefix(target.Error(), "AuthRulesErr")
}