mirror of
https://github.com/matrix-org/dendrite.git
synced 2025-12-15 10:53:09 -06:00
Add more sanity checks
Signed-off-by: Alex Chen <minecnly@gmail.com>
This commit is contained in:
parent
632b88252f
commit
ac775bb79d
|
|
@ -81,49 +81,10 @@ func Redact(
|
|||
return httputil.LogThenError(req, err)
|
||||
}
|
||||
|
||||
// Do some basic checks e.g. ensuring the user is in the room and can send m.room.redaction events
|
||||
stateEvents := make([]*gomatrixserverlib.Event, len(queryRes.StateEvents))
|
||||
for i := range queryRes.StateEvents {
|
||||
stateEvents[i] = &queryRes.StateEvents[i]
|
||||
}
|
||||
provider := gomatrixserverlib.NewAuthEvents(stateEvents)
|
||||
if err = gomatrixserverlib.Allowed(*e, &provider); err != nil {
|
||||
// TODO: Is the error returned with suitable HTTP status code?
|
||||
if _, ok := err.(*gomatrixserverlib.NotAllowed); ok {
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusForbidden,
|
||||
JSON: jsonerror.Forbidden(err.Error()),
|
||||
}
|
||||
}
|
||||
|
||||
return httputil.LogThenError(req, err)
|
||||
}
|
||||
|
||||
// Ensure the user can redact the specific event
|
||||
|
||||
eventReq := api.QueryEventsByIDRequest{
|
||||
EventIDs: []string{redactedEventID},
|
||||
}
|
||||
var eventResp api.QueryEventsByIDResponse
|
||||
if err = queryAPI.QueryEventsByID(req.Context(), &eventReq, &eventResp); err != nil {
|
||||
return httputil.LogThenError(req, err)
|
||||
}
|
||||
|
||||
if len(eventResp.Events) == 0 {
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusNotFound,
|
||||
JSON: jsonerror.NotFound("Event to redact not found"),
|
||||
}
|
||||
}
|
||||
|
||||
redactedEvent := eventResp.Events[0]
|
||||
|
||||
if redactedEvent.Sender() != device.UserID {
|
||||
// TODO: Allow power users to redact others' events
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusForbidden,
|
||||
JSON: jsonerror.Forbidden("You are not allowed to redact this event"),
|
||||
}
|
||||
if resErr := checkRedactionAllowed(
|
||||
req, queryAPI, e, queryRes.StateEvents,
|
||||
); resErr != nil {
|
||||
return *resErr
|
||||
}
|
||||
|
||||
// Send the redaction event
|
||||
|
|
@ -150,3 +111,70 @@ func Redact(
|
|||
JSON: redactResponse{eventID},
|
||||
}
|
||||
}
|
||||
|
||||
func checkRedactionAllowed(
|
||||
req *http.Request, queryAPI api.RoomserverQueryAPI,
|
||||
redactionEvent *gomatrixserverlib.Event,
|
||||
stateEvents []gomatrixserverlib.Event,
|
||||
) *util.JSONResponse {
|
||||
// Do some basic checks e.g. ensuring the user is in the room and can send m.room.redaction events
|
||||
statEventPointers := make([]*gomatrixserverlib.Event, len(stateEvents))
|
||||
for i := range stateEvents {
|
||||
statEventPointers[i] = &stateEvents[i]
|
||||
}
|
||||
provider := gomatrixserverlib.NewAuthEvents(statEventPointers)
|
||||
if err := gomatrixserverlib.Allowed(*redactionEvent, &provider); err != nil {
|
||||
// TODO: Is the error returned with suitable HTTP status code?
|
||||
if _, ok := err.(*gomatrixserverlib.NotAllowed); ok {
|
||||
return &util.JSONResponse{
|
||||
Code: http.StatusForbidden,
|
||||
JSON: jsonerror.Forbidden(err.Error()),
|
||||
}
|
||||
}
|
||||
|
||||
res := httputil.LogThenError(req, err)
|
||||
return &res
|
||||
}
|
||||
|
||||
// Ensure the user can redact the specific event
|
||||
|
||||
eventReq := api.QueryEventsByIDRequest{
|
||||
EventIDs: []string{redactionEvent.Redacts()},
|
||||
}
|
||||
var eventResp api.QueryEventsByIDResponse
|
||||
if err := queryAPI.QueryEventsByID(req.Context(), &eventReq, &eventResp); err != nil {
|
||||
res := httputil.LogThenError(req, err)
|
||||
return &res
|
||||
}
|
||||
|
||||
if len(eventResp.Events) == 0 {
|
||||
return &util.JSONResponse{
|
||||
Code: http.StatusNotFound,
|
||||
JSON: jsonerror.NotFound("Event to redact not found"),
|
||||
}
|
||||
}
|
||||
|
||||
redactedEvent := eventResp.Events[0]
|
||||
|
||||
badEvents, _, err := common.ValidateRedaction(&redactedEvent, redactionEvent)
|
||||
if err != nil {
|
||||
res := httputil.LogThenError(req, err)
|
||||
return &res
|
||||
}
|
||||
if badEvents {
|
||||
return &util.JSONResponse{
|
||||
Code: http.StatusBadRequest,
|
||||
JSON: jsonerror.BadJSON("invalid redaction attempt"),
|
||||
}
|
||||
}
|
||||
|
||||
if redactedEvent.Sender() != redactionEvent.Sender() {
|
||||
// TODO: Allow power users to redact others' events
|
||||
return &util.JSONResponse{
|
||||
Code: http.StatusForbidden,
|
||||
JSON: jsonerror.Forbidden("You are not allowed to redact this event"),
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
40
common/redaction.go
Normal file
40
common/redaction.go
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
package common
|
||||
|
||||
import "github.com/matrix-org/gomatrixserverlib"
|
||||
|
||||
func ValidateRedaction(
|
||||
redacted, redaction *gomatrixserverlib.Event,
|
||||
) (badEvents, needPowerLevelCheck bool, err error) {
|
||||
// Don't allow redaction of events in different rooms
|
||||
if redaction.RoomID() != redacted.RoomID() {
|
||||
return true, false, nil
|
||||
}
|
||||
|
||||
// Don't allow an event to redact itself
|
||||
if redaction.Redacts() == redaction.EventID() {
|
||||
return true, false, nil
|
||||
}
|
||||
|
||||
// Don't allow two events to redact each other
|
||||
if redacted.Redacts() == redaction.EventID() {
|
||||
return true, false, nil
|
||||
}
|
||||
|
||||
var expectedDomain, redactorDomain gomatrixserverlib.ServerName
|
||||
if _, expectedDomain, err = gomatrixserverlib.SplitID(
|
||||
'@', redacted.Sender(),
|
||||
); err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
if _, redactorDomain, err = gomatrixserverlib.SplitID(
|
||||
'@', redaction.Sender(),
|
||||
); err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
|
||||
if expectedDomain != redactorDomain {
|
||||
return false, true, err
|
||||
}
|
||||
|
||||
return false, false, nil
|
||||
}
|
||||
|
|
@ -360,20 +360,18 @@ func (d *Database) validateRedactions(
|
|||
) (validatedRedactions map[string]types.EventNID, err error) {
|
||||
validatedRedactions = make(map[string]types.EventNID, len(unvalidatedRedactions))
|
||||
|
||||
var expectedDomain, redactorDomain gomatrixserverlib.ServerName
|
||||
for redactedEventID, redactedByNID := range unvalidatedRedactions {
|
||||
if _, expectedDomain, err = gomatrixserverlib.SplitID(
|
||||
'@', eventIDToEvent[redactedEventID].Sender(),
|
||||
); err != nil {
|
||||
return nil, err
|
||||
badEvents, needPowerLevelCheck, validationErr := common.ValidateRedaction(
|
||||
eventIDToEvent[redactedEventID], redactionNIDToEvent[redactedByNID],
|
||||
)
|
||||
if validationErr != nil {
|
||||
return nil, validationErr
|
||||
}
|
||||
if _, redactorDomain, err = gomatrixserverlib.SplitID(
|
||||
'@', redactionNIDToEvent[redactedByNID].Sender(),
|
||||
); err != nil {
|
||||
return nil, err
|
||||
if badEvents {
|
||||
continue
|
||||
}
|
||||
|
||||
if redactorDomain != expectedDomain {
|
||||
if needPowerLevelCheck {
|
||||
// TODO: Still allow power users to redact
|
||||
continue
|
||||
}
|
||||
|
|
|
|||
|
|
@ -986,20 +986,18 @@ func (d *SyncServerDatasource) validateRedactions(
|
|||
) (validatedRedactions redactedToRedactionMap, err error) {
|
||||
validatedRedactions = make(redactedToRedactionMap, len(unvalidatedRedactions))
|
||||
|
||||
var expectedDomain, redactorDomain gomatrixserverlib.ServerName
|
||||
for redactedEventID, redactedByID := range unvalidatedRedactions {
|
||||
if _, expectedDomain, err = gomatrixserverlib.SplitID(
|
||||
'@', eventIDToEvent[redactedEventID].Sender(),
|
||||
); err != nil {
|
||||
return nil, err
|
||||
badEvents, needPowerLevelCheck, validationErr := common.ValidateRedaction(
|
||||
eventIDToEvent[redactedEventID], redactionIDToEvent[redactedByID],
|
||||
)
|
||||
if validationErr != nil {
|
||||
return nil, validationErr
|
||||
}
|
||||
if _, redactorDomain, err = gomatrixserverlib.SplitID(
|
||||
'@', redactionIDToEvent[redactedByID].Sender(),
|
||||
); err != nil {
|
||||
return nil, err
|
||||
if badEvents {
|
||||
continue
|
||||
}
|
||||
|
||||
if redactorDomain != expectedDomain {
|
||||
if needPowerLevelCheck {
|
||||
// TODO: Still allow power users to redact
|
||||
continue
|
||||
}
|
||||
|
|
|
|||
4
testfile
4
testfile
|
|
@ -156,3 +156,7 @@ User can create and send/receive messages in a room with version 1
|
|||
POST /createRoom ignores attempts to set the room version via creation_content
|
||||
Inbound federation rejects remote attempts to join local users to rooms
|
||||
Inbound federation rejects remote attempts to kick local users to rooms
|
||||
An event which redacts itself should be ignored
|
||||
A pair of events which redact each other should be ignored
|
||||
POST /rooms/:room_id/redact/:event_id as original message sender redacts message
|
||||
POST /rooms/:room_id/redact/:event_id as random user does not redact message
|
||||
|
|
|
|||
Loading…
Reference in a new issue