2022-12-22 10:54:03 +00:00
package clientapi
import (
"context"
2023-06-22 16:37:21 +00:00
"fmt"
2022-12-22 10:54:03 +00:00
"net/http"
"net/http/httptest"
2023-03-27 13:39:33 +00:00
"reflect"
2022-12-22 10:54:03 +00:00
"testing"
2023-03-22 08:21:32 +00:00
"time"
2022-12-22 10:54:03 +00:00
2023-01-19 20:02:32 +00:00
"github.com/matrix-org/dendrite/federationapi"
2023-03-17 11:09:45 +00:00
"github.com/matrix-org/dendrite/internal/caching"
2023-03-22 08:21:32 +00:00
"github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/internal/sqlutil"
2022-12-22 10:54:03 +00:00
"github.com/matrix-org/dendrite/roomserver"
2023-01-19 20:02:32 +00:00
"github.com/matrix-org/dendrite/roomserver/api"
2023-03-27 13:39:33 +00:00
basepkg "github.com/matrix-org/dendrite/setup/base"
2022-12-22 10:54:03 +00:00
"github.com/matrix-org/dendrite/setup/config"
2023-03-22 08:21:32 +00:00
"github.com/matrix-org/dendrite/setup/jetstream"
2023-01-19 20:02:32 +00:00
"github.com/matrix-org/dendrite/syncapi"
2023-04-06 08:55:01 +00:00
"github.com/matrix-org/gomatrixserverlib/fclient"
2023-04-19 14:50:33 +00:00
"github.com/matrix-org/gomatrixserverlib/spec"
2022-12-22 10:54:03 +00:00
"github.com/matrix-org/util"
"github.com/tidwall/gjson"
2023-06-22 16:37:21 +00:00
capi "github.com/matrix-org/dendrite/clientapi/api"
2022-12-22 10:54:03 +00:00
"github.com/matrix-org/dendrite/test"
"github.com/matrix-org/dendrite/test/testrig"
"github.com/matrix-org/dendrite/userapi"
uapi "github.com/matrix-org/dendrite/userapi/api"
)
2023-06-22 16:37:21 +00:00
func TestAdminCreateToken ( t * testing . T ) {
aliceAdmin := test . NewUser ( t , test . WithAccountType ( uapi . AccountTypeAdmin ) )
bob := test . NewUser ( t , test . WithAccountType ( uapi . AccountTypeUser ) )
ctx := context . Background ( )
test . WithAllDatabases ( t , func ( t * testing . T , dbType test . DBType ) {
cfg , processCtx , close := testrig . CreateConfig ( t , dbType )
cfg . ClientAPI . RegistrationRequiresToken = true
defer close ( )
natsInstance := jetstream . NATSInstance { }
routers := httputil . NewRouters ( )
cm := sqlutil . NewConnectionManager ( processCtx , cfg . Global . DatabaseOptions )
caches := caching . NewRistrettoCache ( 128 * 1024 * 1024 , time . Hour , caching . DisableMetrics )
rsAPI := roomserver . NewInternalAPI ( processCtx , cfg , cm , & natsInstance , caches , caching . DisableMetrics )
2023-07-20 14:06:05 +00:00
rsAPI . SetFederationAPI ( nil , nil )
2023-06-22 16:37:21 +00:00
userAPI := userapi . NewInternalAPI ( processCtx , cfg , cm , & natsInstance , rsAPI , nil )
AddPublicRoutes ( processCtx , routers , cfg , & natsInstance , nil , rsAPI , nil , nil , nil , userAPI , nil , nil , caching . DisableMetrics )
accessTokens := map [ * test . User ] userDevice {
aliceAdmin : { } ,
bob : { } ,
}
createAccessTokens ( t , accessTokens , userAPI , ctx , routers )
testCases := [ ] struct {
name string
requestingUser * test . User
requestOpt test . HTTPRequestOpt
wantOK bool
withHeader bool
} {
{
name : "Missing auth" ,
requestingUser : bob ,
wantOK : false ,
requestOpt : test . WithJSONBody ( t , map [ string ] interface { } {
"token" : "token1" ,
} ,
) ,
} ,
{
name : "Bob is denied access" ,
requestingUser : bob ,
wantOK : false ,
withHeader : true ,
requestOpt : test . WithJSONBody ( t , map [ string ] interface { } {
"token" : "token2" ,
} ,
) ,
} ,
{
name : "Alice can create a token without specifyiing any information" ,
requestingUser : aliceAdmin ,
wantOK : true ,
withHeader : true ,
requestOpt : test . WithJSONBody ( t , map [ string ] interface { } { } ) ,
} ,
{
name : "Alice can to create a token specifying a name" ,
requestingUser : aliceAdmin ,
wantOK : true ,
withHeader : true ,
requestOpt : test . WithJSONBody ( t , map [ string ] interface { } {
"token" : "token3" ,
} ,
) ,
} ,
{
name : "Alice cannot to create a token that already exists" ,
requestingUser : aliceAdmin ,
wantOK : false ,
withHeader : true ,
requestOpt : test . WithJSONBody ( t , map [ string ] interface { } {
"token" : "token3" ,
} ,
) ,
} ,
{
name : "Alice can create a token specifying valid params" ,
requestingUser : aliceAdmin ,
wantOK : true ,
withHeader : true ,
requestOpt : test . WithJSONBody ( t , map [ string ] interface { } {
"token" : "token4" ,
"uses_allowed" : 5 ,
"expiry_time" : time . Now ( ) . Add ( 5 * 24 * time . Hour ) . UnixNano ( ) / int64 ( time . Millisecond ) ,
} ,
) ,
} ,
{
name : "Alice cannot create a token specifying invalid name" ,
requestingUser : aliceAdmin ,
wantOK : false ,
withHeader : true ,
requestOpt : test . WithJSONBody ( t , map [ string ] interface { } {
"token" : "token@" ,
} ,
) ,
} ,
{
name : "Alice cannot create a token specifying invalid uses_allowed" ,
requestingUser : aliceAdmin ,
wantOK : false ,
withHeader : true ,
requestOpt : test . WithJSONBody ( t , map [ string ] interface { } {
"token" : "token5" ,
"uses_allowed" : - 1 ,
} ,
) ,
} ,
{
name : "Alice cannot create a token specifying invalid expiry_time" ,
requestingUser : aliceAdmin ,
wantOK : false ,
withHeader : true ,
requestOpt : test . WithJSONBody ( t , map [ string ] interface { } {
"token" : "token6" ,
"expiry_time" : time . Now ( ) . Add ( - 1 * 5 * 24 * time . Hour ) . UnixNano ( ) / int64 ( time . Millisecond ) ,
} ,
) ,
} ,
{
name : "Alice cannot to create a token specifying invalid length" ,
requestingUser : aliceAdmin ,
wantOK : false ,
withHeader : true ,
requestOpt : test . WithJSONBody ( t , map [ string ] interface { } {
"length" : 80 ,
} ,
) ,
} ,
}
for _ , tc := range testCases {
tc := tc
t . Run ( tc . name , func ( t * testing . T ) {
req := test . NewRequest ( t , http . MethodPost , "/_dendrite/admin/registrationTokens/new" )
if tc . requestOpt != nil {
req = test . NewRequest ( t , http . MethodPost , "/_dendrite/admin/registrationTokens/new" , tc . requestOpt )
}
if tc . withHeader {
req . Header . Set ( "Authorization" , "Bearer " + accessTokens [ tc . requestingUser ] . accessToken )
}
rec := httptest . NewRecorder ( )
routers . DendriteAdmin . ServeHTTP ( rec , req )
t . Logf ( "%s" , rec . Body . String ( ) )
if tc . wantOK && rec . Code != http . StatusOK {
t . Fatalf ( "expected http status %d, got %d: %s" , http . StatusOK , rec . Code , rec . Body . String ( ) )
}
} )
}
} )
}
func TestAdminListRegistrationTokens ( t * testing . T ) {
aliceAdmin := test . NewUser ( t , test . WithAccountType ( uapi . AccountTypeAdmin ) )
bob := test . NewUser ( t , test . WithAccountType ( uapi . AccountTypeUser ) )
ctx := context . Background ( )
test . WithAllDatabases ( t , func ( t * testing . T , dbType test . DBType ) {
cfg , processCtx , close := testrig . CreateConfig ( t , dbType )
cfg . ClientAPI . RegistrationRequiresToken = true
defer close ( )
natsInstance := jetstream . NATSInstance { }
routers := httputil . NewRouters ( )
cm := sqlutil . NewConnectionManager ( processCtx , cfg . Global . DatabaseOptions )
caches := caching . NewRistrettoCache ( 128 * 1024 * 1024 , time . Hour , caching . DisableMetrics )
rsAPI := roomserver . NewInternalAPI ( processCtx , cfg , cm , & natsInstance , caches , caching . DisableMetrics )
2023-07-20 14:06:05 +00:00
rsAPI . SetFederationAPI ( nil , nil )
2023-06-22 16:37:21 +00:00
userAPI := userapi . NewInternalAPI ( processCtx , cfg , cm , & natsInstance , rsAPI , nil )
AddPublicRoutes ( processCtx , routers , cfg , & natsInstance , nil , rsAPI , nil , nil , nil , userAPI , nil , nil , caching . DisableMetrics )
accessTokens := map [ * test . User ] userDevice {
aliceAdmin : { } ,
bob : { } ,
}
tokens := [ ] capi . RegistrationToken {
{
Token : getPointer ( "valid" ) ,
UsesAllowed : getPointer ( int32 ( 10 ) ) ,
ExpiryTime : getPointer ( time . Now ( ) . Add ( 5 * 24 * time . Hour ) . UnixNano ( ) / int64 ( time . Millisecond ) ) ,
Pending : getPointer ( int32 ( 0 ) ) ,
Completed : getPointer ( int32 ( 0 ) ) ,
} ,
{
Token : getPointer ( "invalid" ) ,
UsesAllowed : getPointer ( int32 ( 10 ) ) ,
ExpiryTime : getPointer ( time . Now ( ) . Add ( - 1 * 5 * 24 * time . Hour ) . UnixNano ( ) / int64 ( time . Millisecond ) ) ,
Pending : getPointer ( int32 ( 0 ) ) ,
Completed : getPointer ( int32 ( 0 ) ) ,
} ,
}
for _ , tkn := range tokens {
tkn := tkn
userAPI . PerformAdminCreateRegistrationToken ( ctx , & tkn )
}
createAccessTokens ( t , accessTokens , userAPI , ctx , routers )
testCases := [ ] struct {
name string
requestingUser * test . User
valid string
isValidSpecified bool
wantOK bool
withHeader bool
} {
{
name : "Missing auth" ,
requestingUser : bob ,
wantOK : false ,
isValidSpecified : false ,
} ,
{
name : "Bob is denied access" ,
requestingUser : bob ,
wantOK : false ,
withHeader : true ,
isValidSpecified : false ,
} ,
{
name : "Alice can list all tokens" ,
requestingUser : aliceAdmin ,
wantOK : true ,
withHeader : true ,
} ,
{
name : "Alice can list all valid tokens" ,
requestingUser : aliceAdmin ,
wantOK : true ,
withHeader : true ,
valid : "true" ,
isValidSpecified : true ,
} ,
{
name : "Alice can list all invalid tokens" ,
requestingUser : aliceAdmin ,
wantOK : true ,
withHeader : true ,
valid : "false" ,
isValidSpecified : true ,
} ,
{
name : "No response when valid has a bad value" ,
requestingUser : aliceAdmin ,
wantOK : false ,
withHeader : true ,
valid : "trueee" ,
isValidSpecified : true ,
} ,
}
for _ , tc := range testCases {
tc := tc
t . Run ( tc . name , func ( t * testing . T ) {
var path string
if tc . isValidSpecified {
path = fmt . Sprintf ( "/_dendrite/admin/registrationTokens?valid=%v" , tc . valid )
} else {
path = "/_dendrite/admin/registrationTokens"
}
req := test . NewRequest ( t , http . MethodGet , path )
if tc . withHeader {
req . Header . Set ( "Authorization" , "Bearer " + accessTokens [ tc . requestingUser ] . accessToken )
}
rec := httptest . NewRecorder ( )
routers . DendriteAdmin . ServeHTTP ( rec , req )
t . Logf ( "%s" , rec . Body . String ( ) )
if tc . wantOK && rec . Code != http . StatusOK {
t . Fatalf ( "expected http status %d, got %d: %s" , http . StatusOK , rec . Code , rec . Body . String ( ) )
}
} )
}
} )
}
func TestAdminGetRegistrationToken ( t * testing . T ) {
aliceAdmin := test . NewUser ( t , test . WithAccountType ( uapi . AccountTypeAdmin ) )
bob := test . NewUser ( t , test . WithAccountType ( uapi . AccountTypeUser ) )
ctx := context . Background ( )
test . WithAllDatabases ( t , func ( t * testing . T , dbType test . DBType ) {
cfg , processCtx , close := testrig . CreateConfig ( t , dbType )
cfg . ClientAPI . RegistrationRequiresToken = true
defer close ( )
natsInstance := jetstream . NATSInstance { }
routers := httputil . NewRouters ( )
cm := sqlutil . NewConnectionManager ( processCtx , cfg . Global . DatabaseOptions )
caches := caching . NewRistrettoCache ( 128 * 1024 * 1024 , time . Hour , caching . DisableMetrics )
rsAPI := roomserver . NewInternalAPI ( processCtx , cfg , cm , & natsInstance , caches , caching . DisableMetrics )
2023-07-20 14:06:05 +00:00
rsAPI . SetFederationAPI ( nil , nil )
2023-06-22 16:37:21 +00:00
userAPI := userapi . NewInternalAPI ( processCtx , cfg , cm , & natsInstance , rsAPI , nil )
AddPublicRoutes ( processCtx , routers , cfg , & natsInstance , nil , rsAPI , nil , nil , nil , userAPI , nil , nil , caching . DisableMetrics )
accessTokens := map [ * test . User ] userDevice {
aliceAdmin : { } ,
bob : { } ,
}
tokens := [ ] capi . RegistrationToken {
{
Token : getPointer ( "alice_token1" ) ,
UsesAllowed : getPointer ( int32 ( 10 ) ) ,
ExpiryTime : getPointer ( time . Now ( ) . Add ( 5 * 24 * time . Hour ) . UnixNano ( ) / int64 ( time . Millisecond ) ) ,
Pending : getPointer ( int32 ( 0 ) ) ,
Completed : getPointer ( int32 ( 0 ) ) ,
} ,
{
Token : getPointer ( "alice_token2" ) ,
UsesAllowed : getPointer ( int32 ( 10 ) ) ,
ExpiryTime : getPointer ( time . Now ( ) . Add ( - 1 * 5 * 24 * time . Hour ) . UnixNano ( ) / int64 ( time . Millisecond ) ) ,
Pending : getPointer ( int32 ( 0 ) ) ,
Completed : getPointer ( int32 ( 0 ) ) ,
} ,
}
for _ , tkn := range tokens {
tkn := tkn
userAPI . PerformAdminCreateRegistrationToken ( ctx , & tkn )
}
createAccessTokens ( t , accessTokens , userAPI , ctx , routers )
testCases := [ ] struct {
name string
requestingUser * test . User
token string
wantOK bool
withHeader bool
} {
{
name : "Missing auth" ,
requestingUser : bob ,
wantOK : false ,
} ,
{
name : "Bob is denied access" ,
requestingUser : bob ,
wantOK : false ,
withHeader : true ,
} ,
{
name : "Alice can GET alice_token1" ,
token : "alice_token1" ,
requestingUser : aliceAdmin ,
wantOK : true ,
withHeader : true ,
} ,
{
name : "Alice can GET alice_token2" ,
requestingUser : aliceAdmin ,
wantOK : true ,
withHeader : true ,
token : "alice_token2" ,
} ,
{
name : "Alice cannot GET a token that does not exists" ,
requestingUser : aliceAdmin ,
wantOK : false ,
withHeader : true ,
token : "alice_token3" ,
} ,
}
for _ , tc := range testCases {
tc := tc
t . Run ( tc . name , func ( t * testing . T ) {
path := fmt . Sprintf ( "/_dendrite/admin/registrationTokens/%s" , tc . token )
req := test . NewRequest ( t , http . MethodGet , path )
if tc . withHeader {
req . Header . Set ( "Authorization" , "Bearer " + accessTokens [ tc . requestingUser ] . accessToken )
}
rec := httptest . NewRecorder ( )
routers . DendriteAdmin . ServeHTTP ( rec , req )
t . Logf ( "%s" , rec . Body . String ( ) )
if tc . wantOK && rec . Code != http . StatusOK {
t . Fatalf ( "expected http status %d, got %d: %s" , http . StatusOK , rec . Code , rec . Body . String ( ) )
}
} )
}
} )
}
func TestAdminDeleteRegistrationToken ( t * testing . T ) {
aliceAdmin := test . NewUser ( t , test . WithAccountType ( uapi . AccountTypeAdmin ) )
bob := test . NewUser ( t , test . WithAccountType ( uapi . AccountTypeUser ) )
ctx := context . Background ( )
test . WithAllDatabases ( t , func ( t * testing . T , dbType test . DBType ) {
cfg , processCtx , close := testrig . CreateConfig ( t , dbType )
cfg . ClientAPI . RegistrationRequiresToken = true
defer close ( )
natsInstance := jetstream . NATSInstance { }
routers := httputil . NewRouters ( )
cm := sqlutil . NewConnectionManager ( processCtx , cfg . Global . DatabaseOptions )
caches := caching . NewRistrettoCache ( 128 * 1024 * 1024 , time . Hour , caching . DisableMetrics )
rsAPI := roomserver . NewInternalAPI ( processCtx , cfg , cm , & natsInstance , caches , caching . DisableMetrics )
2023-07-20 14:06:05 +00:00
rsAPI . SetFederationAPI ( nil , nil )
2023-06-22 16:37:21 +00:00
userAPI := userapi . NewInternalAPI ( processCtx , cfg , cm , & natsInstance , rsAPI , nil )
AddPublicRoutes ( processCtx , routers , cfg , & natsInstance , nil , rsAPI , nil , nil , nil , userAPI , nil , nil , caching . DisableMetrics )
accessTokens := map [ * test . User ] userDevice {
aliceAdmin : { } ,
bob : { } ,
}
tokens := [ ] capi . RegistrationToken {
{
Token : getPointer ( "alice_token1" ) ,
UsesAllowed : getPointer ( int32 ( 10 ) ) ,
ExpiryTime : getPointer ( time . Now ( ) . Add ( 5 * 24 * time . Hour ) . UnixNano ( ) / int64 ( time . Millisecond ) ) ,
Pending : getPointer ( int32 ( 0 ) ) ,
Completed : getPointer ( int32 ( 0 ) ) ,
} ,
{
Token : getPointer ( "alice_token2" ) ,
UsesAllowed : getPointer ( int32 ( 10 ) ) ,
ExpiryTime : getPointer ( time . Now ( ) . Add ( - 1 * 5 * 24 * time . Hour ) . UnixNano ( ) / int64 ( time . Millisecond ) ) ,
Pending : getPointer ( int32 ( 0 ) ) ,
Completed : getPointer ( int32 ( 0 ) ) ,
} ,
}
for _ , tkn := range tokens {
tkn := tkn
userAPI . PerformAdminCreateRegistrationToken ( ctx , & tkn )
}
createAccessTokens ( t , accessTokens , userAPI , ctx , routers )
testCases := [ ] struct {
name string
requestingUser * test . User
token string
wantOK bool
withHeader bool
} {
{
name : "Missing auth" ,
requestingUser : bob ,
wantOK : false ,
} ,
{
name : "Bob is denied access" ,
requestingUser : bob ,
wantOK : false ,
withHeader : true ,
} ,
{
name : "Alice can DELETE alice_token1" ,
token : "alice_token1" ,
requestingUser : aliceAdmin ,
wantOK : true ,
withHeader : true ,
} ,
{
name : "Alice can DELETE alice_token2" ,
requestingUser : aliceAdmin ,
wantOK : true ,
withHeader : true ,
token : "alice_token2" ,
} ,
}
for _ , tc := range testCases {
tc := tc
t . Run ( tc . name , func ( t * testing . T ) {
path := fmt . Sprintf ( "/_dendrite/admin/registrationTokens/%s" , tc . token )
req := test . NewRequest ( t , http . MethodDelete , path )
if tc . withHeader {
req . Header . Set ( "Authorization" , "Bearer " + accessTokens [ tc . requestingUser ] . accessToken )
}
rec := httptest . NewRecorder ( )
routers . DendriteAdmin . ServeHTTP ( rec , req )
t . Logf ( "%s" , rec . Body . String ( ) )
if tc . wantOK && rec . Code != http . StatusOK {
t . Fatalf ( "expected http status %d, got %d: %s" , http . StatusOK , rec . Code , rec . Body . String ( ) )
}
} )
}
} )
}
func TestAdminUpdateRegistrationToken ( t * testing . T ) {
aliceAdmin := test . NewUser ( t , test . WithAccountType ( uapi . AccountTypeAdmin ) )
bob := test . NewUser ( t , test . WithAccountType ( uapi . AccountTypeUser ) )
ctx := context . Background ( )
test . WithAllDatabases ( t , func ( t * testing . T , dbType test . DBType ) {
cfg , processCtx , close := testrig . CreateConfig ( t , dbType )
cfg . ClientAPI . RegistrationRequiresToken = true
defer close ( )
natsInstance := jetstream . NATSInstance { }
routers := httputil . NewRouters ( )
cm := sqlutil . NewConnectionManager ( processCtx , cfg . Global . DatabaseOptions )
caches := caching . NewRistrettoCache ( 128 * 1024 * 1024 , time . Hour , caching . DisableMetrics )
rsAPI := roomserver . NewInternalAPI ( processCtx , cfg , cm , & natsInstance , caches , caching . DisableMetrics )
2023-07-20 14:06:05 +00:00
rsAPI . SetFederationAPI ( nil , nil )
2023-06-22 16:37:21 +00:00
userAPI := userapi . NewInternalAPI ( processCtx , cfg , cm , & natsInstance , rsAPI , nil )
AddPublicRoutes ( processCtx , routers , cfg , & natsInstance , nil , rsAPI , nil , nil , nil , userAPI , nil , nil , caching . DisableMetrics )
accessTokens := map [ * test . User ] userDevice {
aliceAdmin : { } ,
bob : { } ,
}
createAccessTokens ( t , accessTokens , userAPI , ctx , routers )
tokens := [ ] capi . RegistrationToken {
{
Token : getPointer ( "alice_token1" ) ,
UsesAllowed : getPointer ( int32 ( 10 ) ) ,
ExpiryTime : getPointer ( time . Now ( ) . Add ( 5 * 24 * time . Hour ) . UnixNano ( ) / int64 ( time . Millisecond ) ) ,
Pending : getPointer ( int32 ( 0 ) ) ,
Completed : getPointer ( int32 ( 0 ) ) ,
} ,
{
Token : getPointer ( "alice_token2" ) ,
UsesAllowed : getPointer ( int32 ( 10 ) ) ,
ExpiryTime : getPointer ( time . Now ( ) . Add ( - 1 * 5 * 24 * time . Hour ) . UnixNano ( ) / int64 ( time . Millisecond ) ) ,
Pending : getPointer ( int32 ( 0 ) ) ,
Completed : getPointer ( int32 ( 0 ) ) ,
} ,
}
for _ , tkn := range tokens {
tkn := tkn
userAPI . PerformAdminCreateRegistrationToken ( ctx , & tkn )
}
testCases := [ ] struct {
name string
requestingUser * test . User
method string
token string
requestOpt test . HTTPRequestOpt
wantOK bool
withHeader bool
} {
{
name : "Missing auth" ,
requestingUser : bob ,
wantOK : false ,
token : "alice_token1" ,
requestOpt : test . WithJSONBody ( t , map [ string ] interface { } {
"uses_allowed" : 10 ,
} ,
) ,
} ,
{
name : "Bob is denied access" ,
requestingUser : bob ,
wantOK : false ,
withHeader : true ,
token : "alice_token1" ,
requestOpt : test . WithJSONBody ( t , map [ string ] interface { } {
"uses_allowed" : 10 ,
} ,
) ,
} ,
{
name : "Alice can UPDATE a token's uses_allowed property" ,
requestingUser : aliceAdmin ,
wantOK : true ,
withHeader : true ,
token : "alice_token1" ,
requestOpt : test . WithJSONBody ( t , map [ string ] interface { } {
"uses_allowed" : 10 ,
} ) ,
} ,
{
name : "Alice can UPDATE a token's expiry_time property" ,
requestingUser : aliceAdmin ,
wantOK : true ,
withHeader : true ,
token : "alice_token2" ,
requestOpt : test . WithJSONBody ( t , map [ string ] interface { } {
"expiry_time" : time . Now ( ) . Add ( 5 * 24 * time . Hour ) . UnixNano ( ) / int64 ( time . Millisecond ) ,
} ,
) ,
} ,
{
name : "Alice can UPDATE a token's uses_allowed and expiry_time property" ,
requestingUser : aliceAdmin ,
wantOK : false ,
withHeader : true ,
token : "alice_token1" ,
requestOpt : test . WithJSONBody ( t , map [ string ] interface { } {
"uses_allowed" : 20 ,
"expiry_time" : time . Now ( ) . Add ( 10 * 24 * time . Hour ) . UnixNano ( ) / int64 ( time . Millisecond ) ,
} ,
) ,
} ,
{
name : "Alice CANNOT update a token with invalid properties" ,
requestingUser : aliceAdmin ,
wantOK : false ,
withHeader : true ,
token : "alice_token2" ,
requestOpt : test . WithJSONBody ( t , map [ string ] interface { } {
"uses_allowed" : - 5 ,
"expiry_time" : time . Now ( ) . Add ( - 1 * 5 * 24 * time . Hour ) . UnixNano ( ) / int64 ( time . Millisecond ) ,
} ,
) ,
} ,
{
name : "Alice CANNOT UPDATE a token that does not exist" ,
requestingUser : aliceAdmin ,
wantOK : false ,
withHeader : true ,
token : "alice_token9" ,
requestOpt : test . WithJSONBody ( t , map [ string ] interface { } {
"uses_allowed" : 100 ,
} ,
) ,
} ,
{
name : "Alice can UPDATE token specifying uses_allowed as null - Valid for infinite uses" ,
requestingUser : aliceAdmin ,
wantOK : false ,
withHeader : true ,
token : "alice_token1" ,
requestOpt : test . WithJSONBody ( t , map [ string ] interface { } {
"uses_allowed" : nil ,
} ,
) ,
} ,
{
name : "Alice can UPDATE token specifying expiry_time AS null - Valid for infinite time" ,
requestingUser : aliceAdmin ,
wantOK : false ,
withHeader : true ,
token : "alice_token1" ,
requestOpt : test . WithJSONBody ( t , map [ string ] interface { } {
"expiry_time" : nil ,
} ,
) ,
} ,
}
for _ , tc := range testCases {
tc := tc
t . Run ( tc . name , func ( t * testing . T ) {
path := fmt . Sprintf ( "/_dendrite/admin/registrationTokens/%s" , tc . token )
req := test . NewRequest ( t , http . MethodPut , path )
if tc . requestOpt != nil {
req = test . NewRequest ( t , http . MethodPut , path , tc . requestOpt )
}
if tc . withHeader {
req . Header . Set ( "Authorization" , "Bearer " + accessTokens [ tc . requestingUser ] . accessToken )
}
rec := httptest . NewRecorder ( )
routers . DendriteAdmin . ServeHTTP ( rec , req )
t . Logf ( "%s" , rec . Body . String ( ) )
if tc . wantOK && rec . Code != http . StatusOK {
t . Fatalf ( "expected http status %d, got %d: %s" , http . StatusOK , rec . Code , rec . Body . String ( ) )
}
} )
}
} )
}
func getPointer [ T any ] ( s T ) * T {
return & s
}
2022-12-22 10:54:03 +00:00
func TestAdminResetPassword ( t * testing . T ) {
aliceAdmin := test . NewUser ( t , test . WithAccountType ( uapi . AccountTypeAdmin ) )
bob := test . NewUser ( t , test . WithAccountType ( uapi . AccountTypeUser ) )
vhUser := & test . User { ID : "@vhuser:vh1" }
ctx := context . Background ( )
test . WithAllDatabases ( t , func ( t * testing . T , dbType test . DBType ) {
2023-03-22 08:21:32 +00:00
cfg , processCtx , close := testrig . CreateConfig ( t , dbType )
defer close ( )
natsInstance := jetstream . NATSInstance { }
2022-12-22 10:54:03 +00:00
// add a vhost
2023-03-22 08:21:32 +00:00
cfg . Global . VirtualHosts = append ( cfg . Global . VirtualHosts , & config . VirtualHost {
2023-04-06 08:55:01 +00:00
SigningIdentity : fclient . SigningIdentity { ServerName : "vh1" } ,
2022-12-22 10:54:03 +00:00
} )
2023-03-22 08:21:32 +00:00
routers := httputil . NewRouters ( )
cm := sqlutil . NewConnectionManager ( processCtx , cfg . Global . DatabaseOptions )
caches := caching . NewRistrettoCache ( 128 * 1024 * 1024 , time . Hour , caching . DisableMetrics )
rsAPI := roomserver . NewInternalAPI ( processCtx , cfg , cm , & natsInstance , caches , caching . DisableMetrics )
2023-07-20 14:06:05 +00:00
rsAPI . SetFederationAPI ( nil , nil )
2022-12-22 10:54:03 +00:00
// Needed for changing the password/login
2023-03-22 08:21:32 +00:00
userAPI := userapi . NewInternalAPI ( processCtx , cfg , cm , & natsInstance , rsAPI , nil )
2022-12-22 10:54:03 +00:00
// We mostly need the userAPI for this test, so nil for other APIs/caches etc.
2023-03-22 08:21:32 +00:00
AddPublicRoutes ( processCtx , routers , cfg , & natsInstance , nil , rsAPI , nil , nil , nil , userAPI , nil , nil , caching . DisableMetrics )
2022-12-22 10:54:03 +00:00
// Create the users in the userapi and login
2023-03-31 08:15:01 +00:00
accessTokens := map [ * test . User ] userDevice {
aliceAdmin : { } ,
bob : { } ,
vhUser : { } ,
2022-12-22 10:54:03 +00:00
}
2023-03-27 13:39:33 +00:00
createAccessTokens ( t , accessTokens , userAPI , ctx , routers )
2022-12-22 10:54:03 +00:00
testCases := [ ] struct {
name string
requestingUser * test . User
userID string
requestOpt test . HTTPRequestOpt
wantOK bool
withHeader bool
} {
{ name : "Missing auth" , requestingUser : bob , wantOK : false , userID : bob . ID } ,
{ name : "Bob is denied access" , requestingUser : bob , wantOK : false , withHeader : true , userID : bob . ID } ,
{ name : "Alice is allowed access" , requestingUser : aliceAdmin , wantOK : true , withHeader : true , userID : bob . ID , requestOpt : test . WithJSONBody ( t , map [ string ] interface { } {
"password" : util . RandomString ( 8 ) ,
} ) } ,
{ name : "missing userID does not call function" , requestingUser : aliceAdmin , wantOK : false , withHeader : true , userID : "" } , // this 404s
{ name : "rejects empty password" , requestingUser : aliceAdmin , wantOK : false , withHeader : true , userID : bob . ID , requestOpt : test . WithJSONBody ( t , map [ string ] interface { } {
"password" : "" ,
} ) } ,
{ name : "rejects unknown server name" , requestingUser : aliceAdmin , wantOK : false , withHeader : true , userID : "@doesnotexist:localhost" , requestOpt : test . WithJSONBody ( t , map [ string ] interface { } { } ) } ,
{ name : "rejects unknown user" , requestingUser : aliceAdmin , wantOK : false , withHeader : true , userID : "@doesnotexist:test" , requestOpt : test . WithJSONBody ( t , map [ string ] interface { } { } ) } ,
{ name : "allows changing password for different vhost" , requestingUser : aliceAdmin , wantOK : true , withHeader : true , userID : vhUser . ID , requestOpt : test . WithJSONBody ( t , map [ string ] interface { } {
"password" : util . RandomString ( 8 ) ,
} ) } ,
{ name : "rejects existing user, missing body" , requestingUser : aliceAdmin , wantOK : false , withHeader : true , userID : bob . ID } ,
{ name : "rejects invalid userID" , requestingUser : aliceAdmin , wantOK : false , withHeader : true , userID : "!notauserid:test" , requestOpt : test . WithJSONBody ( t , map [ string ] interface { } { } ) } ,
{ name : "rejects invalid json" , requestingUser : aliceAdmin , wantOK : false , withHeader : true , userID : bob . ID , requestOpt : test . WithJSONBody ( t , ` { invalidJSON} ` ) } ,
{ name : "rejects too weak password" , requestingUser : aliceAdmin , wantOK : false , withHeader : true , userID : bob . ID , requestOpt : test . WithJSONBody ( t , map [ string ] interface { } {
"password" : util . RandomString ( 6 ) ,
} ) } ,
{ name : "rejects too long password" , requestingUser : aliceAdmin , wantOK : false , withHeader : true , userID : bob . ID , requestOpt : test . WithJSONBody ( t , map [ string ] interface { } {
"password" : util . RandomString ( 513 ) ,
} ) } ,
}
for _ , tc := range testCases {
2023-01-19 20:02:32 +00:00
tc := tc // ensure we don't accidentally only test the last test case
2022-12-22 10:54:03 +00:00
t . Run ( tc . name , func ( t * testing . T ) {
req := test . NewRequest ( t , http . MethodPost , "/_dendrite/admin/resetPassword/" + tc . userID )
if tc . requestOpt != nil {
req = test . NewRequest ( t , http . MethodPost , "/_dendrite/admin/resetPassword/" + tc . userID , tc . requestOpt )
}
if tc . withHeader {
2023-03-31 08:15:01 +00:00
req . Header . Set ( "Authorization" , "Bearer " + accessTokens [ tc . requestingUser ] . accessToken )
2022-12-22 10:54:03 +00:00
}
rec := httptest . NewRecorder ( )
2023-03-22 08:21:32 +00:00
routers . DendriteAdmin . ServeHTTP ( rec , req )
2022-12-22 10:54:03 +00:00
t . Logf ( "%s" , rec . Body . String ( ) )
if tc . wantOK && rec . Code != http . StatusOK {
t . Fatalf ( "expected http status %d, got %d: %s" , http . StatusOK , rec . Code , rec . Body . String ( ) )
}
} )
}
} )
}
2023-01-19 20:02:32 +00:00
func TestPurgeRoom ( t * testing . T ) {
aliceAdmin := test . NewUser ( t , test . WithAccountType ( uapi . AccountTypeAdmin ) )
bob := test . NewUser ( t )
room := test . NewRoom ( t , aliceAdmin , test . RoomPreset ( test . PresetTrustedPrivateChat ) )
// Invite Bob
2023-04-19 14:50:33 +00:00
room . CreateAndInsert ( t , aliceAdmin , spec . MRoomMember , map [ string ] interface { } {
2023-01-19 20:02:32 +00:00
"membership" : "invite" ,
} , test . WithStateKey ( bob . ID ) )
ctx := context . Background ( )
test . WithAllDatabases ( t , func ( t * testing . T , dbType test . DBType ) {
2023-03-22 08:21:32 +00:00
cfg , processCtx , close := testrig . CreateConfig ( t , dbType )
caches := caching . NewRistrettoCache ( 128 * 1024 * 1024 , time . Hour , caching . DisableMetrics )
natsInstance := jetstream . NATSInstance { }
2023-05-30 08:02:53 +00:00
defer func ( ) {
// give components the time to process purge requests
time . Sleep ( time . Millisecond * 50 )
close ( )
} ( )
2023-01-19 20:02:32 +00:00
2023-03-22 08:21:32 +00:00
routers := httputil . NewRouters ( )
cm := sqlutil . NewConnectionManager ( processCtx , cfg . Global . DatabaseOptions )
rsAPI := roomserver . NewInternalAPI ( processCtx , cfg , cm , & natsInstance , caches , caching . DisableMetrics )
2023-01-19 20:02:32 +00:00
// this starts the JetStream consumers
2023-05-02 03:28:10 +00:00
fsAPI := federationapi . NewInternalAPI ( processCtx , cfg , cm , & natsInstance , nil , rsAPI , caches , nil , true )
rsAPI . SetFederationAPI ( fsAPI , nil )
2023-01-19 20:02:32 +00:00
2023-07-20 14:06:05 +00:00
userAPI := userapi . NewInternalAPI ( processCtx , cfg , cm , & natsInstance , rsAPI , nil )
syncapi . AddPublicRoutes ( processCtx , routers , cfg , cm , & natsInstance , userAPI , rsAPI , caches , caching . DisableMetrics )
2023-01-19 20:02:32 +00:00
// Create the room
if err := api . SendEvents ( ctx , rsAPI , api . KindNew , room . Events ( ) , "test" , "test" , "test" , nil , false ) ; err != nil {
t . Fatalf ( "failed to send events: %v" , err )
}
// We mostly need the rsAPI for this test, so nil for other APIs/caches etc.
2023-03-22 08:21:32 +00:00
AddPublicRoutes ( processCtx , routers , cfg , & natsInstance , nil , rsAPI , nil , nil , nil , userAPI , nil , nil , caching . DisableMetrics )
2023-01-19 20:02:32 +00:00
// Create the users in the userapi and login
2023-03-31 08:15:01 +00:00
accessTokens := map [ * test . User ] userDevice {
aliceAdmin : { } ,
2023-01-19 20:02:32 +00:00
}
2023-03-27 13:39:33 +00:00
createAccessTokens ( t , accessTokens , userAPI , ctx , routers )
2023-01-19 20:02:32 +00:00
testCases := [ ] struct {
name string
roomID string
wantOK bool
} {
{ name : "Can purge existing room" , wantOK : true , roomID : room . ID } ,
{ name : "Can not purge non-existent room" , wantOK : false , roomID : "!doesnotexist:localhost" } ,
{ name : "rejects invalid room ID" , wantOK : false , roomID : "@doesnotexist:localhost" } ,
}
for _ , tc := range testCases {
tc := tc // ensure we don't accidentally only test the last test case
t . Run ( tc . name , func ( t * testing . T ) {
req := test . NewRequest ( t , http . MethodPost , "/_dendrite/admin/purgeRoom/" + tc . roomID )
2023-03-31 08:15:01 +00:00
req . Header . Set ( "Authorization" , "Bearer " + accessTokens [ aliceAdmin ] . accessToken )
2023-01-19 20:02:32 +00:00
rec := httptest . NewRecorder ( )
2023-03-22 08:21:32 +00:00
routers . DendriteAdmin . ServeHTTP ( rec , req )
2023-01-19 20:02:32 +00:00
t . Logf ( "%s" , rec . Body . String ( ) )
if tc . wantOK && rec . Code != http . StatusOK {
t . Fatalf ( "expected http status %d, got %d: %s" , http . StatusOK , rec . Code , rec . Body . String ( ) )
}
} )
}
} )
}
2023-03-27 13:39:33 +00:00
func TestAdminEvacuateRoom ( t * testing . T ) {
aliceAdmin := test . NewUser ( t , test . WithAccountType ( uapi . AccountTypeAdmin ) )
bob := test . NewUser ( t )
room := test . NewRoom ( t , aliceAdmin )
// Join Bob
2023-04-19 14:50:33 +00:00
room . CreateAndInsert ( t , bob , spec . MRoomMember , map [ string ] interface { } {
2023-03-27 13:39:33 +00:00
"membership" : "join" ,
} , test . WithStateKey ( bob . ID ) )
ctx := context . Background ( )
test . WithAllDatabases ( t , func ( t * testing . T , dbType test . DBType ) {
cfg , processCtx , close := testrig . CreateConfig ( t , dbType )
caches := caching . NewRistrettoCache ( 128 * 1024 * 1024 , time . Hour , caching . DisableMetrics )
natsInstance := jetstream . NATSInstance { }
defer close ( )
routers := httputil . NewRouters ( )
cm := sqlutil . NewConnectionManager ( processCtx , cfg . Global . DatabaseOptions )
rsAPI := roomserver . NewInternalAPI ( processCtx , cfg , cm , & natsInstance , caches , caching . DisableMetrics )
// this starts the JetStream consumers
fsAPI := federationapi . NewInternalAPI ( processCtx , cfg , cm , & natsInstance , nil , rsAPI , caches , nil , true )
rsAPI . SetFederationAPI ( fsAPI , nil )
2023-07-20 14:06:05 +00:00
userAPI := userapi . NewInternalAPI ( processCtx , cfg , cm , & natsInstance , rsAPI , nil )
2023-03-27 13:39:33 +00:00
// Create the room
if err := api . SendEvents ( ctx , rsAPI , api . KindNew , room . Events ( ) , "test" , "test" , api . DoNotSendToOtherServers , nil , false ) ; err != nil {
t . Fatalf ( "failed to send events: %v" , err )
}
// We mostly need the rsAPI for this test, so nil for other APIs/caches etc.
AddPublicRoutes ( processCtx , routers , cfg , & natsInstance , nil , rsAPI , nil , nil , nil , userAPI , nil , nil , caching . DisableMetrics )
// Create the users in the userapi and login
2023-03-31 08:15:01 +00:00
accessTokens := map [ * test . User ] userDevice {
aliceAdmin : { } ,
2023-03-27 13:39:33 +00:00
}
createAccessTokens ( t , accessTokens , userAPI , ctx , routers )
testCases := [ ] struct {
name string
roomID string
wantOK bool
wantAffected [ ] string
} {
{ name : "Can evacuate existing room" , wantOK : true , roomID : room . ID , wantAffected : [ ] string { aliceAdmin . ID , bob . ID } } ,
{ name : "Can not evacuate non-existent room" , wantOK : false , roomID : "!doesnotexist:localhost" , wantAffected : [ ] string { } } ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
req := test . NewRequest ( t , http . MethodPost , "/_dendrite/admin/evacuateRoom/" + tc . roomID )
2023-03-31 08:15:01 +00:00
req . Header . Set ( "Authorization" , "Bearer " + accessTokens [ aliceAdmin ] . accessToken )
2023-03-27 13:39:33 +00:00
rec := httptest . NewRecorder ( )
routers . DendriteAdmin . ServeHTTP ( rec , req )
t . Logf ( "%s" , rec . Body . String ( ) )
if tc . wantOK && rec . Code != http . StatusOK {
t . Fatalf ( "expected http status %d, got %d: %s" , http . StatusOK , rec . Code , rec . Body . String ( ) )
}
affectedArr := gjson . GetBytes ( rec . Body . Bytes ( ) , "affected" ) . Array ( )
affected := make ( [ ] string , 0 , len ( affectedArr ) )
for _ , x := range affectedArr {
affected = append ( affected , x . Str )
}
if ! reflect . DeepEqual ( affected , tc . wantAffected ) {
t . Fatalf ( "expected affected %#v, but got %#v" , tc . wantAffected , affected )
}
} )
}
2023-04-03 18:19:26 +00:00
// Wait for the FS API to have consumed every message
js , _ := natsInstance . Prepare ( processCtx , & cfg . Global . JetStream )
timeout := time . After ( time . Second )
for {
select {
case <- timeout :
t . Fatalf ( "FS API didn't process all events in time" )
default :
}
info , err := js . ConsumerInfo ( cfg . Global . JetStream . Prefixed ( jetstream . OutputRoomEvent ) , cfg . Global . JetStream . Durable ( "FederationAPIRoomServerConsumer" ) + "Pull" )
if err != nil {
time . Sleep ( time . Millisecond * 10 )
continue
}
if info . NumPending == 0 && info . NumAckPending == 0 {
break
}
}
2023-03-27 13:39:33 +00:00
} )
}
func TestAdminEvacuateUser ( t * testing . T ) {
aliceAdmin := test . NewUser ( t , test . WithAccountType ( uapi . AccountTypeAdmin ) )
bob := test . NewUser ( t )
room := test . NewRoom ( t , aliceAdmin )
room2 := test . NewRoom ( t , aliceAdmin )
// Join Bob
2023-04-19 14:50:33 +00:00
room . CreateAndInsert ( t , bob , spec . MRoomMember , map [ string ] interface { } {
2023-03-27 13:39:33 +00:00
"membership" : "join" ,
} , test . WithStateKey ( bob . ID ) )
2023-04-19 14:50:33 +00:00
room2 . CreateAndInsert ( t , bob , spec . MRoomMember , map [ string ] interface { } {
2023-03-27 13:39:33 +00:00
"membership" : "join" ,
} , test . WithStateKey ( bob . ID ) )
ctx := context . Background ( )
test . WithAllDatabases ( t , func ( t * testing . T , dbType test . DBType ) {
cfg , processCtx , close := testrig . CreateConfig ( t , dbType )
caches := caching . NewRistrettoCache ( 128 * 1024 * 1024 , time . Hour , caching . DisableMetrics )
natsInstance := jetstream . NATSInstance { }
defer close ( )
routers := httputil . NewRouters ( )
cm := sqlutil . NewConnectionManager ( processCtx , cfg . Global . DatabaseOptions )
rsAPI := roomserver . NewInternalAPI ( processCtx , cfg , cm , & natsInstance , caches , caching . DisableMetrics )
// this starts the JetStream consumers
fsAPI := federationapi . NewInternalAPI ( processCtx , cfg , cm , & natsInstance , basepkg . CreateFederationClient ( cfg , nil ) , rsAPI , caches , nil , true )
rsAPI . SetFederationAPI ( fsAPI , nil )
2023-07-20 14:06:05 +00:00
userAPI := userapi . NewInternalAPI ( processCtx , cfg , cm , & natsInstance , rsAPI , nil )
2023-03-27 13:39:33 +00:00
// Create the room
if err := api . SendEvents ( ctx , rsAPI , api . KindNew , room . Events ( ) , "test" , "test" , api . DoNotSendToOtherServers , nil , false ) ; err != nil {
t . Fatalf ( "failed to send events: %v" , err )
}
if err := api . SendEvents ( ctx , rsAPI , api . KindNew , room2 . Events ( ) , "test" , "test" , api . DoNotSendToOtherServers , nil , false ) ; err != nil {
t . Fatalf ( "failed to send events: %v" , err )
}
// We mostly need the rsAPI for this test, so nil for other APIs/caches etc.
AddPublicRoutes ( processCtx , routers , cfg , & natsInstance , nil , rsAPI , nil , nil , nil , userAPI , nil , nil , caching . DisableMetrics )
// Create the users in the userapi and login
2023-03-31 08:15:01 +00:00
accessTokens := map [ * test . User ] userDevice {
aliceAdmin : { } ,
2023-03-27 13:39:33 +00:00
}
createAccessTokens ( t , accessTokens , userAPI , ctx , routers )
testCases := [ ] struct {
name string
userID string
wantOK bool
wantAffectedRooms [ ] string
} {
{ name : "Can evacuate existing user" , wantOK : true , userID : bob . ID , wantAffectedRooms : [ ] string { room . ID , room2 . ID } } ,
{ name : "invalid userID is rejected" , wantOK : false , userID : "!notauserid:test" , wantAffectedRooms : [ ] string { } } ,
{ name : "Can not evacuate user from different server" , wantOK : false , userID : "@doesnotexist:localhost" , wantAffectedRooms : [ ] string { } } ,
{ name : "Can not evacuate non-existent user" , wantOK : false , userID : "@doesnotexist:test" , wantAffectedRooms : [ ] string { } } ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
req := test . NewRequest ( t , http . MethodPost , "/_dendrite/admin/evacuateUser/" + tc . userID )
2023-03-31 08:15:01 +00:00
req . Header . Set ( "Authorization" , "Bearer " + accessTokens [ aliceAdmin ] . accessToken )
2023-03-27 13:39:33 +00:00
rec := httptest . NewRecorder ( )
routers . DendriteAdmin . ServeHTTP ( rec , req )
t . Logf ( "%s" , rec . Body . String ( ) )
if tc . wantOK && rec . Code != http . StatusOK {
t . Fatalf ( "expected http status %d, got %d: %s" , http . StatusOK , rec . Code , rec . Body . String ( ) )
}
affectedArr := gjson . GetBytes ( rec . Body . Bytes ( ) , "affected" ) . Array ( )
affected := make ( [ ] string , 0 , len ( affectedArr ) )
for _ , x := range affectedArr {
affected = append ( affected , x . Str )
}
if ! reflect . DeepEqual ( affected , tc . wantAffectedRooms ) {
t . Fatalf ( "expected affected %#v, but got %#v" , tc . wantAffectedRooms , affected )
}
} )
}
// Wait for the FS API to have consumed every message
js , _ := natsInstance . Prepare ( processCtx , & cfg . Global . JetStream )
timeout := time . After ( time . Second )
for {
select {
case <- timeout :
t . Fatalf ( "FS API didn't process all events in time" )
default :
}
info , err := js . ConsumerInfo ( cfg . Global . JetStream . Prefixed ( jetstream . OutputRoomEvent ) , cfg . Global . JetStream . Durable ( "FederationAPIRoomServerConsumer" ) + "Pull" )
if err != nil {
time . Sleep ( time . Millisecond * 10 )
continue
}
if info . NumPending == 0 && info . NumAckPending == 0 {
break
}
}
} )
}
func TestAdminMarkAsStale ( t * testing . T ) {
aliceAdmin := test . NewUser ( t , test . WithAccountType ( uapi . AccountTypeAdmin ) )
ctx := context . Background ( )
test . WithAllDatabases ( t , func ( t * testing . T , dbType test . DBType ) {
cfg , processCtx , close := testrig . CreateConfig ( t , dbType )
caches := caching . NewRistrettoCache ( 128 * 1024 * 1024 , time . Hour , caching . DisableMetrics )
natsInstance := jetstream . NATSInstance { }
defer close ( )
routers := httputil . NewRouters ( )
cm := sqlutil . NewConnectionManager ( processCtx , cfg . Global . DatabaseOptions )
rsAPI := roomserver . NewInternalAPI ( processCtx , cfg , cm , & natsInstance , caches , caching . DisableMetrics )
2023-07-20 14:06:05 +00:00
rsAPI . SetFederationAPI ( nil , nil )
2023-03-27 13:39:33 +00:00
userAPI := userapi . NewInternalAPI ( processCtx , cfg , cm , & natsInstance , rsAPI , nil )
// We mostly need the rsAPI for this test, so nil for other APIs/caches etc.
AddPublicRoutes ( processCtx , routers , cfg , & natsInstance , nil , rsAPI , nil , nil , nil , userAPI , nil , nil , caching . DisableMetrics )
// Create the users in the userapi and login
2023-03-31 08:15:01 +00:00
accessTokens := map [ * test . User ] userDevice {
aliceAdmin : { } ,
2023-03-27 13:39:33 +00:00
}
createAccessTokens ( t , accessTokens , userAPI , ctx , routers )
testCases := [ ] struct {
name string
userID string
wantOK bool
} {
{ name : "local user is not allowed" , userID : aliceAdmin . ID } ,
{ name : "invalid userID" , userID : "!notvalid:test" } ,
{ name : "remote user is allowed" , userID : "@alice:localhost" , wantOK : true } ,
}
for _ , tc := range testCases {
t . Run ( tc . name , func ( t * testing . T ) {
req := test . NewRequest ( t , http . MethodPost , "/_dendrite/admin/refreshDevices/" + tc . userID )
2023-03-31 08:15:01 +00:00
req . Header . Set ( "Authorization" , "Bearer " + accessTokens [ aliceAdmin ] . accessToken )
2023-03-27 13:39:33 +00:00
rec := httptest . NewRecorder ( )
routers . DendriteAdmin . ServeHTTP ( rec , req )
t . Logf ( "%s" , rec . Body . String ( ) )
if tc . wantOK && rec . Code != http . StatusOK {
t . Fatalf ( "expected http status %d, got %d: %s" , http . StatusOK , rec . Code , rec . Body . String ( ) )
}
} )
}
} )
}