mirror of
https://github.com/element-hq/dendrite.git
synced 2025-09-14 05:12:26 +03:00
gb vendor fetch github.com/matrix-org/gomatrixserverlib/
This commit is contained in:
parent
5b5c2091bf
commit
a45a824f41
28 changed files with 8180 additions and 1 deletions
350
vendor/src/github.com/matrix-org/gomatrixserverlib/eventcontent.go
vendored
Normal file
350
vendor/src/github.com/matrix-org/gomatrixserverlib/eventcontent.go
vendored
Normal file
|
@ -0,0 +1,350 @@
|
|||
/* Copyright 2016-2017 Vector Creations Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package gomatrixserverlib
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// createContent is the JSON content of a m.room.create event along with
|
||||
// the top level keys needed for auth.
|
||||
// See https://matrix.org/docs/spec/client_server/r0.2.0.html#m-room-create for descriptions of the fields.
|
||||
type createContent struct {
|
||||
// We need the domain of the create event when checking federatability.
|
||||
senderDomain string
|
||||
// We need the roomID to check that events are in the same room as the create event.
|
||||
roomID string
|
||||
// We need the eventID to check the first join event in the room.
|
||||
eventID string
|
||||
// The "m.federate" flag tells us whether the room can be federated to other servers.
|
||||
Federate *bool `json:"m.federate"`
|
||||
// The creator of the room tells us what the default power levels are.
|
||||
Creator string `json:"creator"`
|
||||
}
|
||||
|
||||
// newCreateContentFromAuthEvents loads the create event content from the create event in the
|
||||
// auth events.
|
||||
func newCreateContentFromAuthEvents(authEvents AuthEvents) (c createContent, err error) {
|
||||
var createEvent *Event
|
||||
if createEvent, err = authEvents.Create(); err != nil {
|
||||
return
|
||||
}
|
||||
if createEvent == nil {
|
||||
err = errorf("missing create event")
|
||||
return
|
||||
}
|
||||
if err = json.Unmarshal(createEvent.Content(), &c); err != nil {
|
||||
err = errorf("unparsable create event content: %s", err.Error())
|
||||
return
|
||||
}
|
||||
c.roomID = createEvent.RoomID()
|
||||
c.eventID = createEvent.EventID()
|
||||
if c.senderDomain, err = domainFromID(createEvent.Sender()); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// domainAllowed checks whether the domain is allowed in the room by the
|
||||
// "m.federate" flag.
|
||||
func (c *createContent) domainAllowed(domain string) error {
|
||||
if domain == c.senderDomain {
|
||||
// If the domain matches the domain of the create event then the event
|
||||
// is always allowed regardless of the value of the "m.federate" flag.
|
||||
return nil
|
||||
}
|
||||
if c.Federate == nil || *c.Federate {
|
||||
// The m.federate field defaults to true.
|
||||
// If the domains are different then event is only allowed if the
|
||||
// "m.federate" flag is absent or true.
|
||||
return nil
|
||||
}
|
||||
return errorf("room is unfederatable")
|
||||
}
|
||||
|
||||
// userIDAllowed checks whether the domain part of the user ID is allowed in
|
||||
// the room by the "m.federate" flag.
|
||||
func (c *createContent) userIDAllowed(id string) error {
|
||||
domain, err := domainFromID(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.domainAllowed(domain)
|
||||
}
|
||||
|
||||
// domainFromID returns everything after the first ":" character to extract
|
||||
// the domain part of a matrix ID.
|
||||
func domainFromID(id string) (string, error) {
|
||||
// IDs have the format: SIGIL LOCALPART ":" DOMAIN
|
||||
// Split on the first ":" character since the domain can contain ":"
|
||||
// characters.
|
||||
parts := strings.SplitN(id, ":", 2)
|
||||
if len(parts) != 2 {
|
||||
// The ID must have a ":" character.
|
||||
return "", errorf("invalid ID: %q", id)
|
||||
}
|
||||
// Return everything after the first ":" character.
|
||||
return parts[1], nil
|
||||
}
|
||||
|
||||
// memberContent is the JSON content of a m.room.member event needed for auth checks.
|
||||
// See https://matrix.org/docs/spec/client_server/r0.2.0.html#m-room-member for descriptions of the fields.
|
||||
type memberContent struct {
|
||||
// We use the membership key in order to check if the user is in the room.
|
||||
Membership string `json:"membership"`
|
||||
// We use the third_party_invite key to special case thirdparty invites.
|
||||
ThirdPartyInvite json.RawMessage `json:"third_party_invite"`
|
||||
}
|
||||
|
||||
// newMemberContentFromAuthEvents loads the member content from the member event for the user ID in the auth events.
|
||||
// Returns an error if there was an error loading the member event or parsing the event content.
|
||||
func newMemberContentFromAuthEvents(authEvents AuthEvents, userID string) (c memberContent, err error) {
|
||||
var memberEvent *Event
|
||||
if memberEvent, err = authEvents.Member(userID); err != nil {
|
||||
return
|
||||
}
|
||||
if memberEvent == nil {
|
||||
// If there isn't a member event then the membership for the user
|
||||
// defaults to leave.
|
||||
c.Membership = leave
|
||||
return
|
||||
}
|
||||
return newMemberContentFromEvent(*memberEvent)
|
||||
}
|
||||
|
||||
// newMemberContentFromEvent parse the member content from an event.
|
||||
// Returns an error if the content couldn't be parsed.
|
||||
func newMemberContentFromEvent(event Event) (c memberContent, err error) {
|
||||
if err = json.Unmarshal(event.Content(), &c); err != nil {
|
||||
err = errorf("unparsable member event content: %s", err.Error())
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// joinRuleContent is the JSON content of a m.room.join_rules event needed for auth checks.
|
||||
// See https://matrix.org/docs/spec/client_server/r0.2.0.html#m-room-join-rules for descriptions of the fields.
|
||||
type joinRuleContent struct {
|
||||
// We use the join_rule key to check whether join m.room.member events are allowed.
|
||||
JoinRule string `json:"join_rule"`
|
||||
}
|
||||
|
||||
// newJoinRuleContentFromAuthEvents loads the join rule content from the join rules event in the auth event.
|
||||
// Returns an error if there was an error loading the join rule event or parsing the content.
|
||||
func newJoinRuleContentFromAuthEvents(authEvents AuthEvents) (c joinRuleContent, err error) {
|
||||
var joinRulesEvent *Event
|
||||
if joinRulesEvent, err = authEvents.JoinRules(); err != nil {
|
||||
return
|
||||
}
|
||||
if joinRulesEvent == nil {
|
||||
// Default to "invite"
|
||||
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L368
|
||||
c.JoinRule = invite
|
||||
return
|
||||
}
|
||||
if err = json.Unmarshal(joinRulesEvent.Content(), &c); err != nil {
|
||||
err = errorf("unparsable join_rules event content: %s", err.Error())
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// powerLevelContent is the JSON content of a m.room.power_levels event needed for auth checks.
|
||||
// We can't unmarshal the content directly from JSON because we need to set
|
||||
// defaults and convert string values to int values.
|
||||
// See https://matrix.org/docs/spec/client_server/r0.2.0.html#m-room-power-levels for descriptions of the fields.
|
||||
type powerLevelContent struct {
|
||||
banLevel int64
|
||||
inviteLevel int64
|
||||
kickLevel int64
|
||||
redactLevel int64
|
||||
userLevels map[string]int64
|
||||
userDefaultLevel int64
|
||||
eventLevels map[string]int64
|
||||
eventDefaultLevel int64
|
||||
stateDefaultLevel int64
|
||||
}
|
||||
|
||||
// userLevel returns the power level a user has in the room.
|
||||
func (c *powerLevelContent) userLevel(userID string) int64 {
|
||||
level, ok := c.userLevels[userID]
|
||||
if ok {
|
||||
return level
|
||||
}
|
||||
return c.userDefaultLevel
|
||||
}
|
||||
|
||||
// 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" {
|
||||
// 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
|
||||
return c.inviteLevel
|
||||
}
|
||||
level, ok := c.eventLevels[eventType]
|
||||
if ok {
|
||||
return level
|
||||
}
|
||||
if isState {
|
||||
return c.stateDefaultLevel
|
||||
}
|
||||
return c.eventDefaultLevel
|
||||
}
|
||||
|
||||
// newPowerLevelContentFromAuthEvents loads the power level content from the
|
||||
// power level event in the auth events or returns the default values if there
|
||||
// is no power level event.
|
||||
func newPowerLevelContentFromAuthEvents(authEvents AuthEvents, creatorUserID string) (c powerLevelContent, err error) {
|
||||
powerLevelsEvent, err := authEvents.PowerLevels()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if powerLevelsEvent != nil {
|
||||
return newPowerLevelContentFromEvent(*powerLevelsEvent)
|
||||
}
|
||||
|
||||
// If there are no power levels then fall back to defaults.
|
||||
c.defaults()
|
||||
// If there is no power level event then the creator gets level 100
|
||||
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L569
|
||||
c.userLevels = map[string]int64{creatorUserID: 100}
|
||||
return
|
||||
}
|
||||
|
||||
// defaults sets the power levels to their default values.
|
||||
func (c *powerLevelContent) defaults() {
|
||||
// Default invite level is 0.
|
||||
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L426
|
||||
c.inviteLevel = 0
|
||||
// Default ban, kick and redacts levels are 50
|
||||
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L376
|
||||
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L456
|
||||
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L1041
|
||||
c.banLevel = 50
|
||||
c.kickLevel = 50
|
||||
c.redactLevel = 50
|
||||
// Default user level is 0
|
||||
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L558
|
||||
c.userDefaultLevel = 0
|
||||
// Default event level is 0, Default state level is 50
|
||||
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L987
|
||||
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L991
|
||||
c.eventDefaultLevel = 0
|
||||
c.stateDefaultLevel = 50
|
||||
|
||||
}
|
||||
|
||||
// newPowerLevelContentFromEvent loads the power level content from an event.
|
||||
func newPowerLevelContentFromEvent(event Event) (c powerLevelContent, err error) {
|
||||
// Set the levels to their default values.
|
||||
c.defaults()
|
||||
|
||||
// We can't extract the JSON directly to the powerLevelContent because we
|
||||
// need to convert string values to int values.
|
||||
var content struct {
|
||||
InviteLevel levelJSONValue `json:"invite"`
|
||||
BanLevel levelJSONValue `json:"ban"`
|
||||
KickLevel levelJSONValue `json:"kick"`
|
||||
RedactLevel levelJSONValue `json:"redact"`
|
||||
UserLevels map[string]levelJSONValue `json:"users"`
|
||||
UsersDefaultLevel levelJSONValue `json:"users_default"`
|
||||
EventLevels map[string]levelJSONValue `json:"events"`
|
||||
StateDefaultLevel levelJSONValue `json:"state_default"`
|
||||
EventDefaultLevel levelJSONValue `json:"event_default"`
|
||||
}
|
||||
if err = json.Unmarshal(event.Content(), &content); err != nil {
|
||||
err = errorf("unparsable power_levels event content: %s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Update the levels with the values that are present in the event content.
|
||||
content.InviteLevel.assignIfExists(&c.inviteLevel)
|
||||
content.BanLevel.assignIfExists(&c.banLevel)
|
||||
content.KickLevel.assignIfExists(&c.kickLevel)
|
||||
content.RedactLevel.assignIfExists(&c.redactLevel)
|
||||
content.UsersDefaultLevel.assignIfExists(&c.userDefaultLevel)
|
||||
content.StateDefaultLevel.assignIfExists(&c.stateDefaultLevel)
|
||||
content.EventDefaultLevel.assignIfExists(&c.eventDefaultLevel)
|
||||
|
||||
for k, v := range content.UserLevels {
|
||||
if c.userLevels == nil {
|
||||
c.userLevels = make(map[string]int64)
|
||||
}
|
||||
c.userLevels[k] = v.value
|
||||
}
|
||||
|
||||
for k, v := range content.EventLevels {
|
||||
if c.eventLevels == nil {
|
||||
c.eventLevels = make(map[string]int64)
|
||||
}
|
||||
c.eventLevels[k] = v.value
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// A levelJSONValue is used for unmarshalling power levels from JSON.
|
||||
// It is intended to replicate the effects of x = int(content["key"]) in python.
|
||||
type levelJSONValue struct {
|
||||
// Was a value loaded from the JSON?
|
||||
exists bool
|
||||
// The integer value of the power level.
|
||||
value int64
|
||||
}
|
||||
|
||||
func (v *levelJSONValue) UnmarshalJSON(data []byte) error {
|
||||
var stringValue string
|
||||
var int64Value int64
|
||||
var floatValue float64
|
||||
var err error
|
||||
|
||||
// First try to unmarshal as an int64.
|
||||
if err = json.Unmarshal(data, &int64Value); err != nil {
|
||||
// If unmarshalling as an int64 fails try as a string.
|
||||
if err = json.Unmarshal(data, &stringValue); err != nil {
|
||||
// If unmarshalling as a string fails try as a float.
|
||||
if err = json.Unmarshal(data, &floatValue); err != nil {
|
||||
return err
|
||||
}
|
||||
int64Value = int64(floatValue)
|
||||
} else {
|
||||
// If we managed to get a string, try parsing the string as an int.
|
||||
int64Value, err = strconv.ParseInt(stringValue, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
v.exists = true
|
||||
v.value = int64Value
|
||||
return nil
|
||||
}
|
||||
|
||||
// assign the power level if a value was present in the JSON.
|
||||
func (v *levelJSONValue) assignIfExists(to *int64) {
|
||||
if v.exists {
|
||||
*to = v.value
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the user ID is a valid user ID.
|
||||
func isValidUserID(userID string) bool {
|
||||
// TODO: Do we want to add anymore checks beyond checking the sigil and that it has a domain part?
|
||||
return userID[0] == '@' && strings.IndexByte(userID, ':') != -1
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue