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