mirror of
https://github.com/hoernschen/dendrite.git
synced 2025-07-29 12:42:46 +00:00
Start implementing /join for room aliases for rooms the server is not in. (#115)
* Start implementing the join room API * Hacks to get join room working * Make the TLS fingerprint configurable * Fix the client API proxy to handle '#' correctly * Return a 200 OK response * Write the join event along with current state to the room server * Comment on the error handling * Fix typos * Fix tab * Add TODO for moving authEventIDs to gomatrixserverlib * Comment on why we ignore the key ID argument for local keys * Avoid 'preceeded' * Neaten the control flow * Neaten the control flow even more * Return pointers * Rename err to lastErr for the loop
This commit is contained in:
parent
445dce14ae
commit
84ad4ff9f6
15 changed files with 528 additions and 66 deletions
2
vendor/manifest
vendored
2
vendor/manifest
vendored
|
@ -98,7 +98,7 @@
|
|||
{
|
||||
"importpath": "github.com/matrix-org/gomatrixserverlib",
|
||||
"repository": "https://github.com/matrix-org/gomatrixserverlib",
|
||||
"revision": "9cefcd6c3a00bff51e719a33e19a16edf52cdd6f",
|
||||
"revision": "c396ef3cc1e546729f7052f1f48e345cc59269f4",
|
||||
"branch": "master"
|
||||
},
|
||||
{
|
||||
|
|
|
@ -386,7 +386,7 @@ func (e Event) CheckFields() error {
|
|||
// 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
|
||||
if e.fields.Type != "m.room.member" {
|
||||
if e.fields.Type != MRoomMember {
|
||||
return fmt.Errorf(
|
||||
"gomatrixserverlib: sender domain doesn't match origin: %q != %q",
|
||||
eventDomain, e.fields.Origin,
|
||||
|
|
|
@ -28,6 +28,22 @@ const (
|
|||
leave = "leave"
|
||||
invite = "invite"
|
||||
public = "public"
|
||||
// MRoomCreate https://matrix.org/docs/spec/client_server/r0.2.0.html#m-room-create
|
||||
MRoomCreate = "m.room.create"
|
||||
// MRoomJoinRules https://matrix.org/docs/spec/client_server/r0.2.0.html#m-room-join-rules
|
||||
MRoomJoinRules = "m.room.join_rules"
|
||||
// MRoomPowerLevels https://matrix.org/docs/spec/client_server/r0.2.0.html#m-room-power-levels
|
||||
MRoomPowerLevels = "m.room.power_levels"
|
||||
// MRoomMember https://matrix.org/docs/spec/client_server/r0.2.0.html#m-room-member
|
||||
MRoomMember = "m.room.member"
|
||||
// MRoomThirdPartyInvite https://matrix.org/docs/spec/client_server/r0.2.0.html#m-room-third-party-invite
|
||||
MRoomThirdPartyInvite = "m.room.third_party_invite"
|
||||
// MRoomAliases https://matrix.org/docs/spec/client_server/r0.2.0.html#m-room-aliases
|
||||
MRoomAliases = "m.room.aliases"
|
||||
// MRoomHistoryVisibility https://matrix.org/docs/spec/client_server/r0.2.0.html#m-room-history-visibility
|
||||
MRoomHistoryVisibility = "m.room.history_visibility"
|
||||
// MRoomRedaction https://matrix.org/docs/spec/client_server/r0.2.0.html#id21
|
||||
MRoomRedaction = "m.room.redaction"
|
||||
)
|
||||
|
||||
// StateNeeded lists the event types and state_keys needed to authenticate an event.
|
||||
|
@ -47,19 +63,19 @@ type StateNeeded struct {
|
|||
// Tuples returns the needed state key tuples for performing auth on an event.
|
||||
func (s StateNeeded) Tuples() (res []StateKeyTuple) {
|
||||
if s.Create {
|
||||
res = append(res, StateKeyTuple{"m.room.create", ""})
|
||||
res = append(res, StateKeyTuple{MRoomCreate, ""})
|
||||
}
|
||||
if s.JoinRules {
|
||||
res = append(res, StateKeyTuple{"m.room.join_rules", ""})
|
||||
res = append(res, StateKeyTuple{MRoomJoinRules, ""})
|
||||
}
|
||||
if s.PowerLevels {
|
||||
res = append(res, StateKeyTuple{"m.room.power_levels", ""})
|
||||
res = append(res, StateKeyTuple{MRoomPowerLevels, ""})
|
||||
}
|
||||
for _, userID := range s.Member {
|
||||
res = append(res, StateKeyTuple{"m.room.member", userID})
|
||||
res = append(res, StateKeyTuple{MRoomMember, userID})
|
||||
}
|
||||
for _, token := range s.ThirdPartyInvite {
|
||||
res = append(res, StateKeyTuple{"m.room.third_party_invite", token})
|
||||
res = append(res, StateKeyTuple{MRoomThirdPartyInvite, token})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -114,7 +130,7 @@ func (s StateNeeded) AuthEventReferences(provider AuthEventProvider) (refs []Eve
|
|||
func StateNeededForEventBuilder(builder *EventBuilder) (result StateNeeded, err error) {
|
||||
// Extract the 'content' object from the event if it is m.room.member as we need to know 'membership'
|
||||
var content *memberContent
|
||||
if builder.Type == "m.room.member" {
|
||||
if builder.Type == MRoomMember {
|
||||
if err = json.Unmarshal(builder.Content, &content); err != nil {
|
||||
err = errorf("unparsable member event content: %s", err.Error())
|
||||
return
|
||||
|
@ -132,7 +148,7 @@ func StateNeededForAuth(events []Event) (result StateNeeded) {
|
|||
for _, event := range events {
|
||||
// Extract the 'content' object from the event if it is m.room.member as we need to know 'membership'
|
||||
var content *memberContent
|
||||
if event.Type() == "m.room.member" {
|
||||
if event.Type() == MRoomMember {
|
||||
c, err := newMemberContentFromEvent(event)
|
||||
if err == nil {
|
||||
content = &c
|
||||
|
@ -151,17 +167,17 @@ func StateNeededForAuth(events []Event) (result StateNeeded) {
|
|||
|
||||
func accumulateStateNeeded(result *StateNeeded, eventType, sender string, stateKey *string, content *memberContent) (err error) {
|
||||
switch eventType {
|
||||
case "m.room.create":
|
||||
case MRoomCreate:
|
||||
// The create event doesn't require any state to authenticate.
|
||||
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L123
|
||||
case "m.room.aliases":
|
||||
case MRoomAliases:
|
||||
// Alias events need:
|
||||
// * The create event.
|
||||
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L128
|
||||
// Alias events need no further authentication.
|
||||
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L160
|
||||
result.Create = true
|
||||
case "m.room.member":
|
||||
case MRoomMember:
|
||||
// Member events need:
|
||||
// * The previous membership of the target.
|
||||
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L355
|
||||
|
@ -255,27 +271,27 @@ func (a *AuthEvents) AddEvent(event *Event) error {
|
|||
|
||||
// Create implements AuthEventProvider
|
||||
func (a *AuthEvents) Create() (*Event, error) {
|
||||
return a.events[StateKeyTuple{"m.room.create", ""}], nil
|
||||
return a.events[StateKeyTuple{MRoomCreate, ""}], nil
|
||||
}
|
||||
|
||||
// JoinRules implements AuthEventProvider
|
||||
func (a *AuthEvents) JoinRules() (*Event, error) {
|
||||
return a.events[StateKeyTuple{"m.room.join_rules", ""}], nil
|
||||
return a.events[StateKeyTuple{MRoomJoinRules, ""}], nil
|
||||
}
|
||||
|
||||
// PowerLevels implements AuthEventProvider
|
||||
func (a *AuthEvents) PowerLevels() (*Event, error) {
|
||||
return a.events[StateKeyTuple{"m.room.power_levels", ""}], nil
|
||||
return a.events[StateKeyTuple{MRoomPowerLevels, ""}], nil
|
||||
}
|
||||
|
||||
// Member implements AuthEventProvider
|
||||
func (a *AuthEvents) Member(stateKey string) (*Event, error) {
|
||||
return a.events[StateKeyTuple{"m.room.member", stateKey}], nil
|
||||
return a.events[StateKeyTuple{MRoomMember, stateKey}], nil
|
||||
}
|
||||
|
||||
// ThirdPartyInvite implements AuthEventProvider
|
||||
func (a *AuthEvents) ThirdPartyInvite(stateKey string) (*Event, error) {
|
||||
return a.events[StateKeyTuple{"m.room.third_party_invite", stateKey}], nil
|
||||
return a.events[StateKeyTuple{MRoomThirdPartyInvite, stateKey}], nil
|
||||
}
|
||||
|
||||
// NewAuthEvents returns an AuthEventProvider backed by the given events. New events can be added by
|
||||
|
@ -306,15 +322,15 @@ func errorf(message string, args ...interface{}) error {
|
|||
// If there was an error loading the auth events then it returns that error.
|
||||
func Allowed(event Event, authEvents AuthEventProvider) error {
|
||||
switch event.Type() {
|
||||
case "m.room.create":
|
||||
case MRoomCreate:
|
||||
return createEventAllowed(event)
|
||||
case "m.room.aliases":
|
||||
case MRoomAliases:
|
||||
return aliasEventAllowed(event, authEvents)
|
||||
case "m.room.member":
|
||||
case MRoomMember:
|
||||
return memberEventAllowed(event, authEvents)
|
||||
case "m.room.power_levels":
|
||||
case MRoomPowerLevels:
|
||||
return powerLevelsEventAllowed(event, authEvents)
|
||||
case "m.room.redaction":
|
||||
case MRoomRedaction:
|
||||
return redactEventAllowed(event, authEvents)
|
||||
default:
|
||||
return defaultEventAllowed(event, authEvents)
|
||||
|
|
|
@ -191,7 +191,7 @@ func (c *powerLevelContent) userLevel(userID string) int64 {
|
|||
|
||||
// eventLevel returns the power level needed to send an event in the room.
|
||||
func (c *powerLevelContent) eventLevel(eventType string, isState bool) int64 {
|
||||
if eventType == "m.room.third_party_invite" {
|
||||
if eventType == MRoomThirdPartyInvite {
|
||||
// Special case third_party_invite events to have the same level as
|
||||
// m.room.member invite events.
|
||||
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L182
|
||||
|
|
|
@ -201,9 +201,9 @@ func VerifyEventSignatures(events []Event, keyRing KeyRing) error {
|
|||
}
|
||||
toVerify = append(toVerify, v)
|
||||
|
||||
// "m.room.member" invite events are signed by both the server sending
|
||||
// MRoomMember invite events are signed by both the server sending
|
||||
// the invite and the server the invite is for.
|
||||
if event.Type() == "m.room.member" && event.StateKey() != nil {
|
||||
if event.Type() == MRoomMember && event.StateKey() != nil {
|
||||
targetDomain, err := domainFromID(*event.StateKey())
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -34,6 +34,78 @@ type RespState struct {
|
|||
AuthEvents []Event `json:"auth_chain"`
|
||||
}
|
||||
|
||||
// Events combines the auth events and the state events and returns
|
||||
// them in an order where every event comes after its auth events.
|
||||
// Each event will only appear once in the output list.
|
||||
// Returns an error if there are missing auth events or if there is
|
||||
// a cycle in the auth events.
|
||||
func (r RespState) Events() ([]Event, error) {
|
||||
eventsByID := map[string]*Event{}
|
||||
// Collect a map of event reference to event
|
||||
for i := range r.StateEvents {
|
||||
eventsByID[r.StateEvents[i].EventID()] = &r.StateEvents[i]
|
||||
}
|
||||
for i := range r.AuthEvents {
|
||||
eventsByID[r.AuthEvents[i].EventID()] = &r.AuthEvents[i]
|
||||
}
|
||||
|
||||
queued := map[*Event]bool{}
|
||||
outputted := map[*Event]bool{}
|
||||
var result []Event
|
||||
for _, event := range eventsByID {
|
||||
if outputted[event] {
|
||||
// If we've already written the event then we can skip it.
|
||||
continue
|
||||
}
|
||||
|
||||
// The code below does a depth first scan through the auth events
|
||||
// looking for events that can be appended to the output.
|
||||
|
||||
// We use an explicit stack rather than using recursion so
|
||||
// that we can check we aren't creating cycles.
|
||||
stack := []*Event{event}
|
||||
|
||||
LoopProcessTopOfStack:
|
||||
for len(stack) > 0 {
|
||||
top := stack[len(stack)-1]
|
||||
// Check if we can output the top of the stack.
|
||||
// We can output it if we have outputted all of its auth_events.
|
||||
for _, ref := range top.AuthEvents() {
|
||||
authEvent := eventsByID[ref.EventID]
|
||||
if authEvent == nil {
|
||||
return nil, fmt.Errorf(
|
||||
"gomatrixserverlib: missing auth event with ID %q for event %q",
|
||||
ref.EventID, top.EventID(),
|
||||
)
|
||||
}
|
||||
if outputted[authEvent] {
|
||||
continue
|
||||
}
|
||||
if queued[authEvent] {
|
||||
return nil, fmt.Errorf(
|
||||
"gomatrixserverlib: auth event cycle for ID %q",
|
||||
ref.EventID,
|
||||
)
|
||||
}
|
||||
// If we haven't visited the auth event yet then we need to
|
||||
// process it before processing the event currently on top of
|
||||
// the stack.
|
||||
stack = append(stack, authEvent)
|
||||
queued[authEvent] = true
|
||||
continue LoopProcessTopOfStack
|
||||
}
|
||||
// If we've processed all the auth events for the event on top of
|
||||
// the stack then we can append it to the result and try processing
|
||||
// the item below it in the stack.
|
||||
result = append(result, *top)
|
||||
outputted[top] = true
|
||||
stack = stack[:len(stack)-1]
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Check that a response to /state is valid.
|
||||
func (r RespState) Check(keyRing KeyRing) error {
|
||||
var allEvents []Event
|
||||
|
|
|
@ -140,17 +140,17 @@ func redactEvent(eventJSON []byte) ([]byte, error) {
|
|||
// Copy the content fields that we should keep for the event type.
|
||||
// By default we copy nothing leaving the content object empty.
|
||||
switch event.Type {
|
||||
case "m.room.create":
|
||||
case MRoomCreate:
|
||||
newContent.createContent = event.Content.createContent
|
||||
case "m.room.member":
|
||||
case MRoomMember:
|
||||
newContent.memberContent = event.Content.memberContent
|
||||
case "m.room.join_rules":
|
||||
case MRoomJoinRules:
|
||||
newContent.joinRulesContent = event.Content.joinRulesContent
|
||||
case "m.room.power_levels":
|
||||
case MRoomPowerLevels:
|
||||
newContent.powerLevelContent = event.Content.powerLevelContent
|
||||
case "m.room.history_visibility":
|
||||
case MRoomHistoryVisibility:
|
||||
newContent.historyVisibilityContent = event.Content.historyVisibilityContent
|
||||
case "m.room.aliases":
|
||||
case MRoomAliases:
|
||||
newContent.aliasesContent = event.Content.aliasesContent
|
||||
}
|
||||
// Replace the content with our new filtered content.
|
||||
|
|
|
@ -114,24 +114,24 @@ func (r *stateResolver) addConflicted(events []Event) {
|
|||
// By default we add the event to a block in the others list.
|
||||
blockList := &r.others
|
||||
switch key.eventType {
|
||||
case "m.room.create":
|
||||
case MRoomCreate:
|
||||
if key.stateKey == "" {
|
||||
r.creates = append(r.creates, event)
|
||||
continue
|
||||
}
|
||||
case "m.room.power_levels":
|
||||
case MRoomPowerLevels:
|
||||
if key.stateKey == "" {
|
||||
r.powerLevels = append(r.powerLevels, event)
|
||||
continue
|
||||
}
|
||||
case "m.room.join_rules":
|
||||
case MRoomJoinRules:
|
||||
if key.stateKey == "" {
|
||||
r.joinRules = append(r.joinRules, event)
|
||||
continue
|
||||
}
|
||||
case "m.room.member":
|
||||
case MRoomMember:
|
||||
blockList = &r.members
|
||||
case "m.room.third_party_invite":
|
||||
case MRoomThirdPartyInvite:
|
||||
blockList = &r.thirdPartyInvites
|
||||
}
|
||||
// We need to find an entry for the state key in a block list.
|
||||
|
@ -153,21 +153,21 @@ func (r *stateResolver) addConflicted(events []Event) {
|
|||
// Add an event to the resolved auth events.
|
||||
func (r *stateResolver) addAuthEvent(event *Event) {
|
||||
switch event.Type() {
|
||||
case "m.room.create":
|
||||
case MRoomCreate:
|
||||
if event.StateKeyEquals("") {
|
||||
r.resolvedCreate = event
|
||||
}
|
||||
case "m.room.power_levels":
|
||||
case MRoomPowerLevels:
|
||||
if event.StateKeyEquals("") {
|
||||
r.resolvedPowerLevels = event
|
||||
}
|
||||
case "m.room.join_rules":
|
||||
case MRoomJoinRules:
|
||||
if event.StateKeyEquals("") {
|
||||
r.resolvedJoinRules = event
|
||||
}
|
||||
case "m.room.member":
|
||||
case MRoomMember:
|
||||
r.resolvedMembers[*event.StateKey()] = event
|
||||
case "m.room.third_party_invite":
|
||||
case MRoomThirdPartyInvite:
|
||||
r.resolvedThirdPartyInvites[*event.StateKey()] = event
|
||||
default:
|
||||
panic(fmt.Errorf("Unexpected auth event with type %q", event.Type()))
|
||||
|
@ -177,21 +177,21 @@ func (r *stateResolver) addAuthEvent(event *Event) {
|
|||
// Remove the auth event with the given type and state key.
|
||||
func (r *stateResolver) removeAuthEvent(eventType, stateKey string) {
|
||||
switch eventType {
|
||||
case "m.room.create":
|
||||
case MRoomCreate:
|
||||
if stateKey == "" {
|
||||
r.resolvedCreate = nil
|
||||
}
|
||||
case "m.room.power_levels":
|
||||
case MRoomPowerLevels:
|
||||
if stateKey == "" {
|
||||
r.resolvedPowerLevels = nil
|
||||
}
|
||||
case "m.room.join_rules":
|
||||
case MRoomJoinRules:
|
||||
if stateKey == "" {
|
||||
r.resolvedJoinRules = nil
|
||||
}
|
||||
case "m.room.member":
|
||||
case MRoomMember:
|
||||
r.resolvedMembers[stateKey] = nil
|
||||
case "m.room.third_party_invite":
|
||||
case MRoomThirdPartyInvite:
|
||||
r.resolvedThirdPartyInvites[stateKey] = nil
|
||||
default:
|
||||
panic(fmt.Errorf("Unexpected auth event with type %q", eventType))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue