2017-08-04 15:32:10 +00:00
// Copyright 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.
2017-10-11 17:16:53 +00:00
package routing
2017-08-04 15:32:10 +00:00
import (
2017-09-13 12:37:50 +00:00
"context"
2023-05-31 15:27:08 +00:00
"crypto/ed25519"
2022-02-10 10:05:37 +00:00
"fmt"
2017-08-04 15:32:10 +00:00
"net/http"
2018-08-06 13:09:25 +00:00
"time"
2017-08-04 15:32:10 +00:00
2023-04-28 15:46:01 +00:00
"github.com/getsentry/sentry-go"
2018-08-20 09:45:17 +00:00
appserviceAPI "github.com/matrix-org/dendrite/appservice/api"
2017-08-04 15:32:10 +00:00
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
"github.com/matrix-org/dendrite/clientapi/httputil"
2017-09-01 09:13:10 +00:00
"github.com/matrix-org/dendrite/clientapi/threepid"
2020-06-12 13:55:57 +00:00
"github.com/matrix-org/dendrite/internal/eventutil"
2022-05-05 12:17:38 +00:00
"github.com/matrix-org/dendrite/roomserver/api"
2018-08-20 09:45:17 +00:00
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
2023-04-27 11:54:20 +00:00
"github.com/matrix-org/dendrite/roomserver/types"
2020-12-02 17:41:00 +00:00
"github.com/matrix-org/dendrite/setup/config"
2020-06-16 13:10:55 +00:00
userapi "github.com/matrix-org/dendrite/userapi/api"
2023-06-28 18:29:49 +00:00
"github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/gomatrixserverlib/fclient"
"github.com/matrix-org/gomatrixserverlib/spec"
2017-08-04 15:32:10 +00:00
"github.com/matrix-org/util"
)
2020-06-24 17:19:54 +00:00
func SendBan (
2022-05-05 12:17:38 +00:00
req * http . Request , profileAPI userapi . ClientUserAPI , device * userapi . Device ,
2020-08-10 13:18:04 +00:00
roomID string , cfg * config . ClientAPI ,
2022-05-06 11:39:26 +00:00
rsAPI roomserverAPI . ClientRoomserverAPI , asAPI appserviceAPI . AppServiceInternalAPI ,
2017-08-04 15:32:10 +00:00
) util . JSONResponse {
2023-04-03 19:21:06 +00:00
body , evTime , reqErr := extractRequestData ( req )
2020-06-24 17:19:54 +00:00
if reqErr != nil {
return * reqErr
}
2021-07-19 17:33:05 +00:00
2023-04-03 19:21:06 +00:00
if body . UserID == "" {
return util . JSONResponse {
Code : http . StatusBadRequest ,
2023-05-09 22:46:49 +00:00
JSON : spec . BadJSON ( "missing user_id" ) ,
2023-04-03 19:21:06 +00:00
}
}
2023-06-12 11:19:25 +00:00
deviceUserID , err := spec . NewUserID ( device . UserID , true )
2023-06-07 17:14:35 +00:00
if err != nil {
return util . JSONResponse {
Code : http . StatusForbidden ,
JSON : spec . Forbidden ( "You don't have permission to ban this user, bad userID" ) ,
}
}
2023-06-14 14:23:46 +00:00
validRoomID , err := spec . NewRoomID ( roomID )
if err != nil {
return util . JSONResponse {
Code : http . StatusBadRequest ,
JSON : spec . BadJSON ( "RoomID is invalid" ) ,
}
}
senderID , err := rsAPI . QuerySenderIDForUser ( req . Context ( ) , * validRoomID , * deviceUserID )
2023-08-02 10:12:14 +00:00
if err != nil || senderID == nil {
2023-06-07 17:14:35 +00:00
return util . JSONResponse {
Code : http . StatusForbidden ,
JSON : spec . Forbidden ( "You don't have permission to ban this user, unknown senderID" ) ,
}
}
2023-06-12 11:19:25 +00:00
errRes := checkMemberInRoom ( req . Context ( ) , rsAPI , * deviceUserID , roomID )
if errRes != nil {
return * errRes
}
pl , errRes := getPowerlevels ( req , rsAPI , roomID )
if errRes != nil {
return * errRes
}
2023-08-02 10:12:14 +00:00
allowedToBan := pl . UserLevel ( * senderID ) >= pl . Ban
2021-07-19 17:33:05 +00:00
if ! allowedToBan {
return util . JSONResponse {
2023-04-03 19:21:06 +00:00
Code : http . StatusForbidden ,
2023-05-09 22:46:49 +00:00
JSON : spec . Forbidden ( "You don't have permission to ban this user, power level too low." ) ,
2021-07-19 17:33:05 +00:00
}
}
2023-04-19 14:50:33 +00:00
return sendMembership ( req . Context ( ) , profileAPI , device , roomID , spec . Ban , body . Reason , cfg , body . UserID , evTime , rsAPI , asAPI )
2020-06-24 17:19:54 +00:00
}
2022-05-05 12:17:38 +00:00
func sendMembership ( ctx context . Context , profileAPI userapi . ClientUserAPI , device * userapi . Device ,
2020-08-10 13:18:04 +00:00
roomID , membership , reason string , cfg * config . ClientAPI , targetUserID string , evTime time . Time ,
2022-05-06 11:39:26 +00:00
rsAPI roomserverAPI . ClientRoomserverAPI , asAPI appserviceAPI . AppServiceInternalAPI ) util . JSONResponse {
2020-06-24 17:19:54 +00:00
event , err := buildMembershipEvent (
2022-03-24 21:45:44 +00:00
ctx , targetUserID , reason , profileAPI , device , membership ,
2020-06-24 17:19:54 +00:00
roomID , false , cfg , evTime , rsAPI , asAPI ,
)
2023-04-03 19:21:06 +00:00
if err != nil {
2020-06-24 17:19:54 +00:00
util . GetLogger ( ctx ) . WithError ( err ) . Error ( "buildMembershipEvent failed" )
2023-05-17 00:33:27 +00:00
return util . JSONResponse {
Code : http . StatusInternalServerError ,
JSON : spec . InternalServerError { } ,
}
2020-03-27 16:28:22 +00:00
}
2022-10-26 11:59:19 +00:00
serverName := device . UserDomain ( )
2020-09-03 14:22:16 +00:00
if err = roomserverAPI . SendEvents (
2020-06-24 17:19:54 +00:00
ctx , rsAPI ,
2021-09-08 16:31:03 +00:00
roomserverAPI . KindNew ,
2023-04-27 11:54:20 +00:00
[ ] * types . HeaderedEvent { event } ,
2022-11-15 15:05:23 +00:00
device . UserDomain ( ) ,
2022-10-26 11:59:19 +00:00
serverName ,
serverName ,
2020-06-24 17:19:54 +00:00
nil ,
2022-01-05 17:44:49 +00:00
false ,
2020-09-03 14:22:16 +00:00
) ; err != nil {
2020-06-24 17:19:54 +00:00
util . GetLogger ( ctx ) . WithError ( err ) . Error ( "SendEvents failed" )
2023-05-17 00:33:27 +00:00
return util . JSONResponse {
Code : http . StatusInternalServerError ,
JSON : spec . InternalServerError { } ,
}
2020-06-24 17:19:54 +00:00
}
return util . JSONResponse {
Code : http . StatusOK ,
JSON : struct { } { } ,
}
}
func SendKick (
2022-05-05 12:17:38 +00:00
req * http . Request , profileAPI userapi . ClientUserAPI , device * userapi . Device ,
2020-08-10 13:18:04 +00:00
roomID string , cfg * config . ClientAPI ,
2022-05-06 11:39:26 +00:00
rsAPI roomserverAPI . ClientRoomserverAPI , asAPI appserviceAPI . AppServiceInternalAPI ,
2020-06-24 17:19:54 +00:00
) util . JSONResponse {
2023-04-03 19:21:06 +00:00
body , evTime , reqErr := extractRequestData ( req )
2020-06-24 17:19:54 +00:00
if reqErr != nil {
2017-08-29 14:17:26 +00:00
return * reqErr
}
2020-06-24 17:19:54 +00:00
if body . UserID == "" {
return util . JSONResponse {
2023-04-03 19:21:06 +00:00
Code : http . StatusBadRequest ,
2023-05-09 22:46:49 +00:00
JSON : spec . BadJSON ( "missing user_id" ) ,
2020-06-24 17:19:54 +00:00
}
}
2017-08-29 14:17:26 +00:00
2023-06-12 11:19:25 +00:00
deviceUserID , err := spec . NewUserID ( device . UserID , true )
2023-06-07 17:14:35 +00:00
if err != nil {
return util . JSONResponse {
Code : http . StatusForbidden ,
JSON : spec . Forbidden ( "You don't have permission to kick this user, bad userID" ) ,
}
}
2023-06-14 14:23:46 +00:00
validRoomID , err := spec . NewRoomID ( roomID )
if err != nil {
return util . JSONResponse {
Code : http . StatusBadRequest ,
JSON : spec . BadJSON ( "RoomID is invalid" ) ,
}
}
senderID , err := rsAPI . QuerySenderIDForUser ( req . Context ( ) , * validRoomID , * deviceUserID )
2023-08-02 10:12:14 +00:00
if err != nil || senderID == nil {
2023-06-07 17:14:35 +00:00
return util . JSONResponse {
Code : http . StatusForbidden ,
JSON : spec . Forbidden ( "You don't have permission to kick this user, unknown senderID" ) ,
}
}
2023-06-12 11:19:25 +00:00
errRes := checkMemberInRoom ( req . Context ( ) , rsAPI , * deviceUserID , roomID )
if errRes != nil {
return * errRes
}
2023-11-22 12:15:45 +00:00
bodyUserID , err := spec . NewUserID ( body . UserID , true )
if err != nil {
return util . JSONResponse {
Code : http . StatusBadRequest ,
JSON : spec . BadJSON ( "body userID is invalid" ) ,
}
}
2023-06-12 11:19:25 +00:00
pl , errRes := getPowerlevels ( req , rsAPI , roomID )
if errRes != nil {
return * errRes
}
2023-11-22 12:15:45 +00:00
allowedToKick := pl . UserLevel ( * senderID ) >= pl . Kick || bodyUserID . String ( ) == deviceUserID . String ( )
2023-04-03 19:21:06 +00:00
if ! allowedToKick {
return util . JSONResponse {
Code : http . StatusForbidden ,
2023-05-09 22:46:49 +00:00
JSON : spec . Forbidden ( "You don't have permission to kick this user, power level too low." ) ,
2023-04-03 19:21:06 +00:00
}
}
2020-06-24 17:19:54 +00:00
var queryRes roomserverAPI . QueryMembershipForUserResponse
2023-06-07 17:14:35 +00:00
err = rsAPI . QueryMembershipForUser ( req . Context ( ) , & roomserverAPI . QueryMembershipForUserRequest {
2020-06-24 17:19:54 +00:00
RoomID : roomID ,
2023-06-12 11:19:25 +00:00
UserID : * bodyUserID ,
2020-06-24 17:19:54 +00:00
} , & queryRes )
2018-08-22 12:40:25 +00:00
if err != nil {
2020-06-24 17:19:54 +00:00
return util . ErrorResponse ( err )
}
2020-07-27 08:20:09 +00:00
// kick is only valid if the user is not currently banned or left (that is, they are joined or invited)
2023-04-19 14:50:33 +00:00
if queryRes . Membership != spec . Join && queryRes . Membership != spec . Invite {
2018-08-22 12:40:25 +00:00
return util . JSONResponse {
2023-04-03 19:21:06 +00:00
Code : http . StatusForbidden ,
2023-05-09 22:46:49 +00:00
JSON : spec . Unknown ( "cannot /kick banned or left users" ) ,
2018-08-22 12:40:25 +00:00
}
}
2020-06-24 17:19:54 +00:00
// TODO: should we be using SendLeave instead?
2023-04-19 14:50:33 +00:00
return sendMembership ( req . Context ( ) , profileAPI , device , roomID , spec . Leave , body . Reason , cfg , body . UserID , evTime , rsAPI , asAPI )
2020-06-24 17:19:54 +00:00
}
func SendUnban (
2022-05-05 12:17:38 +00:00
req * http . Request , profileAPI userapi . ClientUserAPI , device * userapi . Device ,
2020-08-10 13:18:04 +00:00
roomID string , cfg * config . ClientAPI ,
2022-05-06 11:39:26 +00:00
rsAPI roomserverAPI . ClientRoomserverAPI , asAPI appserviceAPI . AppServiceInternalAPI ,
2020-06-24 17:19:54 +00:00
) util . JSONResponse {
2023-04-03 19:21:06 +00:00
body , evTime , reqErr := extractRequestData ( req )
2020-06-24 17:19:54 +00:00
if reqErr != nil {
return * reqErr
}
if body . UserID == "" {
return util . JSONResponse {
2023-04-03 19:21:06 +00:00
Code : http . StatusBadRequest ,
2023-05-09 22:46:49 +00:00
JSON : spec . BadJSON ( "missing user_id" ) ,
2020-06-24 17:19:54 +00:00
}
}
2023-06-12 11:19:25 +00:00
deviceUserID , err := spec . NewUserID ( device . UserID , true )
if err != nil {
return util . JSONResponse {
Code : http . StatusForbidden ,
JSON : spec . Forbidden ( "You don't have permission to kick this user, bad userID" ) ,
}
}
errRes := checkMemberInRoom ( req . Context ( ) , rsAPI , * deviceUserID , roomID )
2023-04-03 19:21:06 +00:00
if errRes != nil {
return * errRes
}
2023-06-12 11:19:25 +00:00
bodyUserID , err := spec . NewUserID ( body . UserID , true )
if err != nil {
return util . JSONResponse {
Code : http . StatusBadRequest ,
JSON : spec . BadJSON ( "body userID is invalid" ) ,
}
}
2020-06-24 17:19:54 +00:00
var queryRes roomserverAPI . QueryMembershipForUserResponse
2023-06-12 11:19:25 +00:00
err = rsAPI . QueryMembershipForUser ( req . Context ( ) , & roomserverAPI . QueryMembershipForUserRequest {
2020-06-24 17:19:54 +00:00
RoomID : roomID ,
2023-06-12 11:19:25 +00:00
UserID : * bodyUserID ,
2020-06-24 17:19:54 +00:00
} , & queryRes )
if err != nil {
return util . ErrorResponse ( err )
}
2023-04-03 19:21:06 +00:00
2020-06-24 17:19:54 +00:00
// unban is only valid if the user is currently banned
2023-04-19 14:50:33 +00:00
if queryRes . Membership != spec . Ban {
2020-06-24 17:19:54 +00:00
return util . JSONResponse {
2023-04-03 19:21:06 +00:00
Code : http . StatusBadRequest ,
2023-05-09 22:46:49 +00:00
JSON : spec . Unknown ( "can only /unban users that are banned" ) ,
2020-06-24 17:19:54 +00:00
}
}
// TODO: should we be using SendLeave instead?
2023-04-19 14:50:33 +00:00
return sendMembership ( req . Context ( ) , profileAPI , device , roomID , spec . Leave , body . Reason , cfg , body . UserID , evTime , rsAPI , asAPI )
2020-06-24 17:19:54 +00:00
}
func SendInvite (
2022-05-05 12:17:38 +00:00
req * http . Request , profileAPI userapi . ClientUserAPI , device * userapi . Device ,
2020-08-10 13:18:04 +00:00
roomID string , cfg * config . ClientAPI ,
2022-05-06 11:39:26 +00:00
rsAPI roomserverAPI . ClientRoomserverAPI , asAPI appserviceAPI . AppServiceInternalAPI ,
2020-06-24 17:19:54 +00:00
) util . JSONResponse {
2023-04-03 19:21:06 +00:00
body , evTime , reqErr := extractRequestData ( req )
2020-06-24 17:19:54 +00:00
if reqErr != nil {
return * reqErr
}
2018-08-22 12:40:25 +00:00
2019-07-12 13:29:30 +00:00
inviteStored , jsonErrResp := checkAndProcessThreepid (
2022-03-24 21:45:44 +00:00
req , device , body , cfg , rsAPI , profileAPI , roomID , evTime ,
2017-09-11 18:18:19 +00:00
)
2019-07-12 13:29:30 +00:00
if jsonErrResp != nil {
return * jsonErrResp
2017-08-29 14:17:26 +00:00
}
2017-09-11 18:18:19 +00:00
// If an invite has been stored on an identity server, it means that a
// m.room.third_party_invite event has been emitted and that we shouldn't
// emit a m.room.member one.
if inviteStored {
return util . JSONResponse {
2018-03-13 15:55:45 +00:00
Code : http . StatusOK ,
2017-09-11 18:18:19 +00:00
JSON : struct { } { } ,
}
}
2023-04-03 19:21:06 +00:00
if body . UserID == "" {
return util . JSONResponse {
Code : http . StatusBadRequest ,
2023-05-09 22:46:49 +00:00
JSON : spec . BadJSON ( "missing user_id" ) ,
2023-04-03 19:21:06 +00:00
}
}
2023-06-12 11:19:25 +00:00
deviceUserID , err := spec . NewUserID ( device . UserID , true )
if err != nil {
return util . JSONResponse {
Code : http . StatusForbidden ,
JSON : spec . Forbidden ( "You don't have permission to kick this user, bad userID" ) ,
}
}
errRes := checkMemberInRoom ( req . Context ( ) , rsAPI , * deviceUserID , roomID )
2023-04-03 19:21:06 +00:00
if errRes != nil {
return * errRes
}
2022-02-18 15:05:03 +00:00
// We already received the return value, so no need to check for an error here.
2022-03-24 21:45:44 +00:00
response , _ := sendInvite ( req . Context ( ) , profileAPI , device , roomID , body . UserID , body . Reason , cfg , rsAPI , asAPI , evTime )
2022-02-18 15:05:03 +00:00
return response
}
// sendInvite sends an invitation to a user. Returns a JSONResponse and an error
func sendInvite (
ctx context . Context ,
2022-05-05 12:17:38 +00:00
profileAPI userapi . ClientUserAPI ,
2022-02-18 15:05:03 +00:00
device * userapi . Device ,
roomID , userID , reason string ,
cfg * config . ClientAPI ,
2022-05-05 12:17:38 +00:00
rsAPI roomserverAPI . ClientRoomserverAPI ,
2022-05-06 11:39:26 +00:00
asAPI appserviceAPI . AppServiceInternalAPI , evTime time . Time ,
2022-02-18 15:05:03 +00:00
) ( util . JSONResponse , error ) {
2023-07-06 15:15:24 +00:00
validRoomID , err := spec . NewRoomID ( roomID )
if err != nil {
return util . JSONResponse {
Code : http . StatusBadRequest ,
JSON : spec . InvalidParam ( "RoomID is invalid" ) ,
} , err
}
inviter , err := spec . NewUserID ( device . UserID , true )
if err != nil {
return util . JSONResponse {
Code : http . StatusInternalServerError ,
JSON : spec . InternalServerError { } ,
} , err
}
invitee , err := spec . NewUserID ( userID , true )
if err != nil {
return util . JSONResponse {
Code : http . StatusBadRequest ,
JSON : spec . InvalidParam ( "UserID is invalid" ) ,
} , err
}
profile , err := loadProfile ( ctx , userID , cfg , profileAPI , asAPI )
if err != nil {
return util . JSONResponse {
Code : http . StatusInternalServerError ,
JSON : spec . InternalServerError { } ,
} , err
}
identity , err := cfg . Matrix . SigningIdentityFor ( device . UserDomain ( ) )
2023-04-03 19:21:06 +00:00
if err != nil {
2023-05-17 00:33:27 +00:00
return util . JSONResponse {
Code : http . StatusInternalServerError ,
JSON : spec . InternalServerError { } ,
} , err
2017-09-11 18:18:19 +00:00
}
2023-04-28 15:46:01 +00:00
err = rsAPI . PerformInvite ( ctx , & api . PerformInviteRequest {
2023-07-06 15:15:24 +00:00
InviteInput : roomserverAPI . InviteInput {
RoomID : * validRoomID ,
Inviter : * inviter ,
Invitee : * invitee ,
DisplayName : profile . DisplayName ,
AvatarURL : profile . AvatarURL ,
Reason : reason ,
IsDirect : false ,
KeyID : identity . KeyID ,
PrivateKey : identity . PrivateKey ,
EventTime : evTime ,
} ,
2022-05-05 12:17:38 +00:00
InviteRoomState : nil , // ask the roomserver to draw up invite room state for us
2022-10-26 11:59:19 +00:00
SendAsServer : string ( device . UserDomain ( ) ) ,
2023-04-28 15:46:01 +00:00
} )
switch e := err . ( type ) {
case roomserverAPI . ErrInvalidID :
return util . JSONResponse {
Code : http . StatusBadRequest ,
2023-05-09 22:46:49 +00:00
JSON : spec . Unknown ( e . Error ( ) ) ,
2023-04-28 15:46:01 +00:00
} , e
case roomserverAPI . ErrNotAllowed :
return util . JSONResponse {
Code : http . StatusForbidden ,
2023-05-09 22:46:49 +00:00
JSON : spec . Forbidden ( e . Error ( ) ) ,
2023-04-28 15:46:01 +00:00
} , e
case nil :
default :
2022-05-05 12:17:38 +00:00
util . GetLogger ( ctx ) . WithError ( err ) . Error ( "PerformInvite failed" )
2023-04-28 15:46:01 +00:00
sentry . CaptureException ( err )
2020-08-17 10:40:49 +00:00
return util . JSONResponse {
Code : http . StatusInternalServerError ,
2023-05-17 00:33:27 +00:00
JSON : spec . InternalServerError { } ,
2022-02-18 15:05:03 +00:00
} , err
2017-09-11 18:18:19 +00:00
}
2022-05-05 12:17:38 +00:00
return util . JSONResponse {
Code : http . StatusOK ,
JSON : struct { } { } ,
} , nil
2017-09-11 18:18:19 +00:00
}
2023-05-31 15:27:08 +00:00
func buildMembershipEventDirect (
2018-08-06 13:09:25 +00:00
ctx context . Context ,
2023-06-12 11:19:25 +00:00
targetSenderID spec . SenderID , reason string , userDisplayName , userAvatarURL string ,
sender spec . SenderID , senderDomain spec . ServerName ,
2020-05-07 15:46:11 +00:00
membership , roomID string , isDirect bool ,
2023-05-31 15:27:08 +00:00
keyID gomatrixserverlib . KeyID , privateKey ed25519 . PrivateKey , evTime time . Time ,
rsAPI roomserverAPI . ClientRoomserverAPI ,
2023-04-27 11:54:20 +00:00
) ( * types . HeaderedEvent , error ) {
2023-06-12 11:19:25 +00:00
targetSenderString := string ( targetSenderID )
2023-05-04 10:17:42 +00:00
proto := gomatrixserverlib . ProtoEvent {
2023-06-12 11:19:25 +00:00
SenderID : string ( sender ) ,
2017-08-04 15:32:10 +00:00
RoomID : roomID ,
Type : "m.room.member" ,
2023-06-12 11:19:25 +00:00
StateKey : & targetSenderString ,
2017-08-04 15:32:10 +00:00
}
2019-08-15 17:45:11 +00:00
content := gomatrixserverlib . MemberContent {
2017-08-04 15:32:10 +00:00
Membership : membership ,
2023-05-31 15:27:08 +00:00
DisplayName : userDisplayName ,
AvatarURL : userAvatarURL ,
2017-08-04 15:32:10 +00:00
Reason : reason ,
2020-05-07 15:46:11 +00:00
IsDirect : isDirect ,
2017-08-04 15:32:10 +00:00
}
2023-05-31 15:27:08 +00:00
if err := proto . SetContent ( content ) ; err != nil {
return nil , err
}
identity := & fclient . SigningIdentity {
ServerName : senderDomain ,
KeyID : keyID ,
PrivateKey : privateKey ,
}
return eventutil . QueryAndBuildEvent ( ctx , & proto , identity , evTime , rsAPI , nil )
}
func buildMembershipEvent (
ctx context . Context ,
targetUserID , reason string , profileAPI userapi . ClientUserAPI ,
device * userapi . Device ,
membership , roomID string , isDirect bool ,
cfg * config . ClientAPI , evTime time . Time ,
rsAPI roomserverAPI . ClientRoomserverAPI , asAPI appserviceAPI . AppServiceInternalAPI ,
) ( * types . HeaderedEvent , error ) {
profile , err := loadProfile ( ctx , targetUserID , cfg , profileAPI , asAPI )
if err != nil {
2017-09-11 18:18:19 +00:00
return nil , err
2017-08-04 15:32:10 +00:00
}
2023-06-12 11:19:25 +00:00
userID , err := spec . NewUserID ( device . UserID , true )
if err != nil {
return nil , err
}
2023-06-14 14:23:46 +00:00
validRoomID , err := spec . NewRoomID ( roomID )
if err != nil {
return nil , err
}
senderID , err := rsAPI . QuerySenderIDForUser ( ctx , * validRoomID , * userID )
2023-06-12 11:19:25 +00:00
if err != nil {
return nil , err
2023-08-02 10:12:14 +00:00
} else if senderID == nil {
return nil , fmt . Errorf ( "no sender ID for %s in %s" , * userID , * validRoomID )
2023-06-12 11:19:25 +00:00
}
targetID , err := spec . NewUserID ( targetUserID , true )
if err != nil {
return nil , err
}
2023-06-14 14:23:46 +00:00
targetSenderID , err := rsAPI . QuerySenderIDForUser ( ctx , * validRoomID , * targetID )
2023-06-12 11:19:25 +00:00
if err != nil {
return nil , err
2023-08-02 10:12:14 +00:00
} else if targetSenderID == nil {
return nil , fmt . Errorf ( "no sender ID for %s in %s" , * targetID , * validRoomID )
2023-06-12 11:19:25 +00:00
}
2023-06-28 18:29:49 +00:00
identity , err := rsAPI . SigningIdentityFor ( ctx , * validRoomID , * userID )
if err != nil {
return nil , err
}
2023-08-02 10:12:14 +00:00
return buildMembershipEventDirect ( ctx , * targetSenderID , reason , profile . DisplayName , profile . AvatarURL ,
* senderID , device . UserDomain ( ) , membership , roomID , isDirect , identity . KeyID , identity . PrivateKey , evTime , rsAPI )
2017-08-04 15:32:10 +00:00
}
2017-08-29 14:17:26 +00:00
// loadProfile lookups the profile of a given user from the database and returns
// it if the user is local to this server, or returns an empty profile if not.
// Returns an error if the retrieval failed or if the first parameter isn't a
// valid Matrix ID.
2017-09-18 13:15:27 +00:00
func loadProfile (
2018-08-20 09:45:17 +00:00
ctx context . Context ,
userID string ,
2020-08-10 13:18:04 +00:00
cfg * config . ClientAPI ,
2022-05-05 12:17:38 +00:00
profileAPI userapi . ClientUserAPI ,
2022-05-06 11:39:26 +00:00
asAPI appserviceAPI . AppServiceInternalAPI ,
2017-09-18 13:15:27 +00:00
) ( * authtypes . Profile , error ) {
2018-08-20 09:45:17 +00:00
_ , serverName , err := gomatrixserverlib . SplitID ( '@' , userID )
2017-08-29 14:17:26 +00:00
if err != nil {
return nil , err
}
var profile * authtypes . Profile
2022-10-26 11:59:19 +00:00
if cfg . Matrix . IsLocalServerName ( serverName ) {
2022-03-24 21:45:44 +00:00
profile , err = appserviceAPI . RetrieveUserProfile ( ctx , userID , asAPI , profileAPI )
2017-08-29 14:17:26 +00:00
} else {
profile = & authtypes . Profile { }
}
return profile , err
}
2023-04-03 19:21:06 +00:00
func extractRequestData ( req * http . Request ) ( body * threepid . MembershipRequest , evTime time . Time , resErr * util . JSONResponse ) {
2017-08-04 15:32:10 +00:00
2020-06-24 17:19:54 +00:00
if reqErr := httputil . UnmarshalJSONRequest ( req , & body ) ; reqErr != nil {
resErr = reqErr
return
2017-08-04 15:32:10 +00:00
}
2020-06-24 17:19:54 +00:00
evTime , err := httputil . ParseTSParam ( req )
if err != nil {
resErr = & util . JSONResponse {
Code : http . StatusBadRequest ,
2023-05-09 22:46:49 +00:00
JSON : spec . InvalidParam ( err . Error ( ) ) ,
2020-06-24 17:19:54 +00:00
}
return
}
2017-08-04 15:32:10 +00:00
return
}
2019-07-12 13:29:30 +00:00
func checkAndProcessThreepid (
req * http . Request ,
2020-06-16 13:10:55 +00:00
device * userapi . Device ,
2019-07-12 13:29:30 +00:00
body * threepid . MembershipRequest ,
2020-08-10 13:18:04 +00:00
cfg * config . ClientAPI ,
2022-05-05 12:17:38 +00:00
rsAPI roomserverAPI . ClientRoomserverAPI ,
profileAPI userapi . ClientUserAPI ,
2020-06-24 17:19:54 +00:00
roomID string ,
2019-07-12 13:29:30 +00:00
evTime time . Time ,
) ( inviteStored bool , errRes * util . JSONResponse ) {
inviteStored , err := threepid . CheckAndProcessInvite (
2022-03-24 21:45:44 +00:00
req . Context ( ) , device , body , cfg , rsAPI , profileAPI ,
2020-06-24 17:19:54 +00:00
roomID , evTime ,
2019-07-12 13:29:30 +00:00
)
2023-05-17 00:33:27 +00:00
switch e := err . ( type ) {
case nil :
case threepid . ErrMissingParameter :
util . GetLogger ( req . Context ( ) ) . WithError ( err ) . Error ( "threepid.CheckAndProcessInvite failed" )
2019-07-12 13:29:30 +00:00
return inviteStored , & util . JSONResponse {
Code : http . StatusBadRequest ,
2023-05-09 22:46:49 +00:00
JSON : spec . BadJSON ( err . Error ( ) ) ,
2019-07-12 13:29:30 +00:00
}
2023-05-17 00:33:27 +00:00
case threepid . ErrNotTrusted :
util . GetLogger ( req . Context ( ) ) . WithError ( err ) . Error ( "threepid.CheckAndProcessInvite failed" )
2019-07-12 13:29:30 +00:00
return inviteStored , & util . JSONResponse {
Code : http . StatusBadRequest ,
2023-05-09 22:46:49 +00:00
JSON : spec . NotTrusted ( body . IDServer ) ,
2019-07-12 13:29:30 +00:00
}
2023-05-17 00:33:27 +00:00
case eventutil . ErrRoomNoExists :
util . GetLogger ( req . Context ( ) ) . WithError ( err ) . Error ( "threepid.CheckAndProcessInvite failed" )
2019-07-12 13:29:30 +00:00
return inviteStored , & util . JSONResponse {
Code : http . StatusNotFound ,
2023-05-09 22:46:49 +00:00
JSON : spec . NotFound ( err . Error ( ) ) ,
2019-07-12 13:29:30 +00:00
}
2023-05-17 00:33:27 +00:00
case gomatrixserverlib . BadJSONError :
util . GetLogger ( req . Context ( ) ) . WithError ( err ) . Error ( "threepid.CheckAndProcessInvite failed" )
2020-06-04 09:53:39 +00:00
return inviteStored , & util . JSONResponse {
Code : http . StatusBadRequest ,
2023-05-09 22:46:49 +00:00
JSON : spec . BadJSON ( e . Error ( ) ) ,
2020-06-04 09:53:39 +00:00
}
2023-05-17 00:33:27 +00:00
default :
2020-03-02 16:20:44 +00:00
util . GetLogger ( req . Context ( ) ) . WithError ( err ) . Error ( "threepid.CheckAndProcessInvite failed" )
2023-05-17 00:33:27 +00:00
return inviteStored , & util . JSONResponse {
Code : http . StatusInternalServerError ,
JSON : spec . InternalServerError { } ,
}
2019-07-12 13:29:30 +00:00
}
return
}
2020-07-02 14:41:18 +00:00
2023-06-12 11:19:25 +00:00
func checkMemberInRoom ( ctx context . Context , rsAPI roomserverAPI . ClientRoomserverAPI , userID spec . UserID , roomID string ) * util . JSONResponse {
2023-04-03 19:21:06 +00:00
var membershipRes roomserverAPI . QueryMembershipForUserResponse
err := rsAPI . QueryMembershipForUser ( ctx , & roomserverAPI . QueryMembershipForUserRequest {
RoomID : roomID ,
UserID : userID ,
2020-07-02 14:41:18 +00:00
} , & membershipRes )
if err != nil {
2023-04-03 19:21:06 +00:00
util . GetLogger ( ctx ) . WithError ( err ) . Error ( "QueryMembershipForUser: could not query membership for user" )
2023-05-17 00:33:27 +00:00
return & util . JSONResponse {
Code : http . StatusInternalServerError ,
JSON : spec . InternalServerError { } ,
}
2020-08-25 20:04:35 +00:00
}
2023-04-03 19:21:06 +00:00
if ! membershipRes . IsInRoom {
2020-07-02 14:41:18 +00:00
return & util . JSONResponse {
Code : http . StatusForbidden ,
2023-05-09 22:46:49 +00:00
JSON : spec . Forbidden ( "user does not belong to room" ) ,
2020-07-02 14:41:18 +00:00
}
}
return nil
}
2020-11-05 10:19:23 +00:00
func SendForget (
req * http . Request , device * userapi . Device ,
2022-05-05 12:17:38 +00:00
roomID string , rsAPI roomserverAPI . ClientRoomserverAPI ,
2020-11-05 10:19:23 +00:00
) util . JSONResponse {
ctx := req . Context ( )
logger := util . GetLogger ( ctx ) . WithField ( "roomID" , roomID ) . WithField ( "userID" , device . UserID )
2023-06-12 11:19:25 +00:00
deviceUserID , err := spec . NewUserID ( device . UserID , true )
if err != nil {
return util . JSONResponse {
Code : http . StatusForbidden ,
JSON : spec . Forbidden ( "You don't have permission to kick this user, bad userID" ) ,
}
}
2021-09-08 16:31:03 +00:00
var membershipRes roomserverAPI . QueryMembershipForUserResponse
membershipReq := roomserverAPI . QueryMembershipForUserRequest {
2020-11-05 10:19:23 +00:00
RoomID : roomID ,
2023-06-12 11:19:25 +00:00
UserID : * deviceUserID ,
2020-11-05 10:19:23 +00:00
}
2023-06-12 11:19:25 +00:00
err = rsAPI . QueryMembershipForUser ( ctx , & membershipReq , & membershipRes )
2020-11-05 10:19:23 +00:00
if err != nil {
logger . WithError ( err ) . Error ( "QueryMembershipForUser: could not query membership for user" )
2023-05-17 00:33:27 +00:00
return util . JSONResponse {
Code : http . StatusInternalServerError ,
JSON : spec . InternalServerError { } ,
}
2020-11-05 10:19:23 +00:00
}
2022-05-11 10:29:23 +00:00
if ! membershipRes . RoomExists {
return util . JSONResponse {
Code : http . StatusForbidden ,
2023-05-09 22:46:49 +00:00
JSON : spec . Forbidden ( "room does not exist" ) ,
2022-05-11 10:29:23 +00:00
}
}
2020-11-05 10:19:23 +00:00
if membershipRes . IsInRoom {
return util . JSONResponse {
Code : http . StatusBadRequest ,
2023-05-09 22:46:49 +00:00
JSON : spec . Unknown ( fmt . Sprintf ( "User %s is in room %s" , device . UserID , roomID ) ) ,
2020-11-05 10:19:23 +00:00
}
}
2021-09-08 16:31:03 +00:00
request := roomserverAPI . PerformForgetRequest {
2020-11-05 10:19:23 +00:00
RoomID : roomID ,
UserID : device . UserID ,
}
2021-09-08 16:31:03 +00:00
response := roomserverAPI . PerformForgetResponse { }
2020-11-05 10:19:23 +00:00
if err := rsAPI . PerformForget ( ctx , & request , & response ) ; err != nil {
logger . WithError ( err ) . Error ( "PerformForget: unable to forget room" )
2023-05-17 00:33:27 +00:00
return util . JSONResponse {
Code : http . StatusInternalServerError ,
JSON : spec . InternalServerError { } ,
}
2020-11-05 10:19:23 +00:00
}
return util . JSONResponse {
Code : http . StatusOK ,
JSON : struct { } { } ,
}
}
2023-04-03 19:21:06 +00:00
func getPowerlevels ( req * http . Request , rsAPI roomserverAPI . ClientRoomserverAPI , roomID string ) ( * gomatrixserverlib . PowerLevelContent , * util . JSONResponse ) {
plEvent := roomserverAPI . GetStateEvent ( req . Context ( ) , rsAPI , roomID , gomatrixserverlib . StateKeyTuple {
2023-04-19 14:50:33 +00:00
EventType : spec . MRoomPowerLevels ,
2023-04-03 19:21:06 +00:00
StateKey : "" ,
} )
if plEvent == nil {
return nil , & util . JSONResponse {
Code : http . StatusForbidden ,
2023-05-09 22:46:49 +00:00
JSON : spec . Forbidden ( "You don't have permission to perform this action, no power_levels event in this room." ) ,
2023-04-03 19:21:06 +00:00
}
}
pl , err := plEvent . PowerLevels ( )
if err != nil {
return nil , & util . JSONResponse {
Code : http . StatusForbidden ,
2023-05-09 22:46:49 +00:00
JSON : spec . Forbidden ( "You don't have permission to perform this action, the power_levels event for this room is malformed so auth checks cannot be performed." ) ,
2023-04-03 19:21:06 +00:00
}
}
return pl , nil
}