2021-06-07 14:52:21 +00:00
|
|
|
use std::sync::{Arc, Mutex};
|
2021-04-29 11:28:08 +00:00
|
|
|
|
2021-06-02 13:16:43 +00:00
|
|
|
#[cfg(feature = "actix")]
|
2021-06-07 14:52:21 +00:00
|
|
|
use actix_web::{test as actix_test, App as ActixApp, HttpResponse};
|
2021-04-29 11:28:08 +00:00
|
|
|
use matrix_sdk::{
|
|
|
|
async_trait,
|
|
|
|
room::Room,
|
2021-06-23 10:06:28 +00:00
|
|
|
ruma::{
|
|
|
|
api::appservice::Registration,
|
|
|
|
events::{room::member::MemberEventContent, SyncStateEvent},
|
|
|
|
},
|
2021-06-08 09:18:56 +00:00
|
|
|
ClientConfig, EventHandler, RequestConfig,
|
2021-04-29 11:28:08 +00:00
|
|
|
};
|
|
|
|
use matrix_sdk_appservice::*;
|
2021-06-04 12:16:24 +00:00
|
|
|
use matrix_sdk_test::{appservice::TransactionBuilder, async_test, EventsJson};
|
2021-04-29 11:28:08 +00:00
|
|
|
use serde_json::json;
|
2021-06-03 16:20:07 +00:00
|
|
|
#[cfg(feature = "warp")]
|
2021-06-07 14:52:21 +00:00
|
|
|
use warp::{Filter, Reply};
|
2021-04-29 11:28:08 +00:00
|
|
|
|
|
|
|
fn registration_string() -> String {
|
|
|
|
include_str!("../tests/registration.yaml").to_owned()
|
|
|
|
}
|
|
|
|
|
2021-06-15 10:09:01 +00:00
|
|
|
async fn appservice(registration: Option<Registration>) -> Result<AppService> {
|
2021-06-07 14:52:21 +00:00
|
|
|
// env::set_var(
|
|
|
|
// "RUST_LOG",
|
|
|
|
// "mockito=debug,matrix_sdk=debug,ruma=debug,actix_web=debug,warp=debug",
|
|
|
|
// );
|
2021-04-29 11:28:08 +00:00
|
|
|
let _ = tracing_subscriber::fmt::try_init();
|
|
|
|
|
|
|
|
let registration = match registration {
|
|
|
|
Some(registration) => registration.into(),
|
2021-06-15 10:09:01 +00:00
|
|
|
None => AppServiceRegistration::try_from_yaml_str(registration_string()).unwrap(),
|
2021-04-29 11:28:08 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let homeserver_url = mockito::server_url();
|
|
|
|
let server_name = "localhost";
|
|
|
|
|
2021-06-04 12:16:24 +00:00
|
|
|
let client_config =
|
|
|
|
ClientConfig::default().request_config(RequestConfig::default().disable_retry());
|
2021-04-29 11:28:08 +00:00
|
|
|
|
2021-06-15 10:09:01 +00:00
|
|
|
Ok(AppService::new_with_config(
|
2021-06-04 12:16:24 +00:00
|
|
|
homeserver_url.as_ref(),
|
|
|
|
server_name,
|
|
|
|
registration,
|
|
|
|
client_config,
|
|
|
|
)
|
|
|
|
.await?)
|
2021-04-29 11:28:08 +00:00
|
|
|
}
|
|
|
|
|
2021-06-02 13:16:43 +00:00
|
|
|
#[async_test]
|
2021-06-04 12:16:24 +00:00
|
|
|
async fn test_register_virtual_user() -> Result<()> {
|
2021-06-02 13:16:43 +00:00
|
|
|
let appservice = appservice(None).await?;
|
|
|
|
|
2021-06-04 12:16:24 +00:00
|
|
|
let localpart = "someone";
|
|
|
|
let _mock = mockito::mock("POST", "/_matrix/client/r0/register")
|
|
|
|
.match_query(mockito::Matcher::Missing)
|
|
|
|
.match_header(
|
|
|
|
"authorization",
|
|
|
|
mockito::Matcher::Exact(format!("Bearer {}", appservice.registration().as_token)),
|
|
|
|
)
|
|
|
|
.match_body(mockito::Matcher::Json(json!({
|
|
|
|
"username": localpart.to_owned(),
|
|
|
|
"type": "m.login.application_service"
|
|
|
|
})))
|
|
|
|
.with_body(format!(
|
|
|
|
r#"{{
|
|
|
|
"access_token": "abc123",
|
|
|
|
"device_id": "GHTYAJCE",
|
|
|
|
"user_id": "@{localpart}:localhost"
|
|
|
|
}}"#,
|
|
|
|
localpart = localpart
|
|
|
|
))
|
|
|
|
.create();
|
|
|
|
|
|
|
|
appservice.register_virtual_user(localpart).await?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2021-06-02 13:16:43 +00:00
|
|
|
|
2021-06-04 12:16:24 +00:00
|
|
|
#[async_test]
|
|
|
|
async fn test_put_transaction() -> Result<()> {
|
2021-06-03 16:20:07 +00:00
|
|
|
let uri = "/_matrix/app/v1/transactions/1?access_token=hs_token";
|
2021-06-04 12:16:24 +00:00
|
|
|
|
|
|
|
let mut transaction_builder = TransactionBuilder::new();
|
|
|
|
transaction_builder.add_room_event(EventsJson::Member);
|
|
|
|
let transaction = transaction_builder.build_json_transaction();
|
|
|
|
|
|
|
|
let appservice = appservice(None).await?;
|
2021-06-03 16:20:07 +00:00
|
|
|
|
|
|
|
#[cfg(feature = "warp")]
|
|
|
|
let status = warp::test::request()
|
|
|
|
.method("PUT")
|
|
|
|
.path(uri)
|
2021-06-04 12:16:24 +00:00
|
|
|
.json(&transaction)
|
2021-06-03 16:20:07 +00:00
|
|
|
.filter(&appservice.warp_filter())
|
|
|
|
.await
|
|
|
|
.unwrap()
|
|
|
|
.into_response()
|
|
|
|
.status();
|
2021-06-02 13:16:43 +00:00
|
|
|
|
|
|
|
#[cfg(feature = "actix")]
|
2021-06-03 16:20:07 +00:00
|
|
|
let status = {
|
|
|
|
let app =
|
2021-06-07 14:52:21 +00:00
|
|
|
actix_test::init_service(ActixApp::new().configure(appservice.actix_configure())).await;
|
2021-06-02 13:16:43 +00:00
|
|
|
|
2021-06-04 12:16:24 +00:00
|
|
|
let req = actix_test::TestRequest::put().uri(uri).set_json(&transaction).to_request();
|
2021-06-02 13:16:43 +00:00
|
|
|
|
2021-06-03 16:20:07 +00:00
|
|
|
actix_test::call_service(&app, req).await.status()
|
|
|
|
};
|
|
|
|
|
|
|
|
assert_eq!(status, 200);
|
2021-06-02 13:16:43 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[async_test]
|
2021-06-03 16:20:07 +00:00
|
|
|
async fn test_get_user() -> Result<()> {
|
2021-06-02 13:16:43 +00:00
|
|
|
let appservice = appservice(None).await?;
|
|
|
|
|
2021-06-03 16:20:07 +00:00
|
|
|
let uri = "/_matrix/app/v1/users/%40_botty_1%3Adev.famedly.local?access_token=hs_token";
|
|
|
|
|
|
|
|
#[cfg(feature = "warp")]
|
|
|
|
let status = warp::test::request()
|
|
|
|
.method("GET")
|
|
|
|
.path(uri)
|
|
|
|
.filter(&appservice.warp_filter())
|
|
|
|
.await
|
|
|
|
.unwrap()
|
|
|
|
.into_response()
|
|
|
|
.status();
|
|
|
|
|
2021-06-02 13:16:43 +00:00
|
|
|
#[cfg(feature = "actix")]
|
2021-06-03 16:20:07 +00:00
|
|
|
let status = {
|
2021-06-02 13:16:43 +00:00
|
|
|
let app =
|
2021-06-07 14:52:21 +00:00
|
|
|
actix_test::init_service(ActixApp::new().configure(appservice.actix_configure())).await;
|
2021-06-02 13:16:43 +00:00
|
|
|
|
2021-06-03 16:20:07 +00:00
|
|
|
let req = actix_test::TestRequest::get().uri(uri).to_request();
|
2021-06-02 13:16:43 +00:00
|
|
|
|
2021-06-03 16:20:07 +00:00
|
|
|
actix_test::call_service(&app, req).await.status()
|
|
|
|
};
|
2021-06-02 13:16:43 +00:00
|
|
|
|
2021-06-03 16:20:07 +00:00
|
|
|
assert_eq!(status, 200);
|
2021-06-02 13:16:43 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[async_test]
|
2021-06-03 16:20:07 +00:00
|
|
|
async fn test_get_room() -> Result<()> {
|
2021-06-02 13:16:43 +00:00
|
|
|
let appservice = appservice(None).await?;
|
|
|
|
|
2021-06-03 16:20:07 +00:00
|
|
|
let uri = "/_matrix/app/v1/rooms/%23magicforest%3Aexample.com?access_token=hs_token";
|
|
|
|
|
|
|
|
#[cfg(feature = "warp")]
|
|
|
|
let status = warp::test::request()
|
|
|
|
.method("GET")
|
|
|
|
.path(uri)
|
|
|
|
.filter(&appservice.warp_filter())
|
|
|
|
.await
|
|
|
|
.unwrap()
|
|
|
|
.into_response()
|
|
|
|
.status();
|
|
|
|
|
2021-06-02 13:16:43 +00:00
|
|
|
#[cfg(feature = "actix")]
|
2021-06-03 16:20:07 +00:00
|
|
|
let status = {
|
|
|
|
let app =
|
2021-06-07 14:52:21 +00:00
|
|
|
actix_test::init_service(ActixApp::new().configure(appservice.actix_configure())).await;
|
2021-06-03 16:20:07 +00:00
|
|
|
|
|
|
|
let req = actix_test::TestRequest::get().uri(uri).to_request();
|
|
|
|
|
|
|
|
actix_test::call_service(&app, req).await.status()
|
|
|
|
};
|
|
|
|
|
|
|
|
assert_eq!(status, 200);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[async_test]
|
|
|
|
async fn test_invalid_access_token() -> Result<()> {
|
2021-06-04 12:16:24 +00:00
|
|
|
let uri = "/_matrix/app/v1/transactions/1?access_token=invalid_token";
|
2021-06-02 13:16:43 +00:00
|
|
|
|
2021-06-04 12:16:24 +00:00
|
|
|
let mut transaction_builder = TransactionBuilder::new();
|
|
|
|
let transaction =
|
|
|
|
transaction_builder.add_room_event(EventsJson::Member).build_json_transaction();
|
2021-06-02 13:16:43 +00:00
|
|
|
|
2021-06-04 12:16:24 +00:00
|
|
|
let appservice = appservice(None).await?;
|
2021-06-03 16:20:07 +00:00
|
|
|
|
|
|
|
#[cfg(feature = "warp")]
|
|
|
|
let status = warp::test::request()
|
|
|
|
.method("PUT")
|
|
|
|
.path(uri)
|
2021-06-04 12:16:24 +00:00
|
|
|
.json(&transaction)
|
2021-06-03 16:20:07 +00:00
|
|
|
.filter(&appservice.warp_filter())
|
|
|
|
.await
|
|
|
|
.unwrap()
|
|
|
|
.into_response()
|
|
|
|
.status();
|
2021-06-02 13:16:43 +00:00
|
|
|
|
|
|
|
#[cfg(feature = "actix")]
|
2021-06-03 16:20:07 +00:00
|
|
|
let status = {
|
|
|
|
let app =
|
2021-06-07 14:52:21 +00:00
|
|
|
actix_test::init_service(ActixApp::new().configure(appservice.actix_configure())).await;
|
2021-06-02 13:16:43 +00:00
|
|
|
|
2021-06-04 12:16:24 +00:00
|
|
|
let req = actix_test::TestRequest::put().uri(uri).set_json(&transaction).to_request();
|
2021-06-02 13:16:43 +00:00
|
|
|
|
2021-06-03 16:20:07 +00:00
|
|
|
actix_test::call_service(&app, req).await.status()
|
|
|
|
};
|
|
|
|
|
|
|
|
assert_eq!(status, 401);
|
2021-06-02 13:16:43 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[async_test]
|
|
|
|
async fn test_no_access_token() -> Result<()> {
|
2021-06-04 12:16:24 +00:00
|
|
|
let uri = "/_matrix/app/v1/transactions/1";
|
2021-06-02 13:16:43 +00:00
|
|
|
|
2021-06-04 12:16:24 +00:00
|
|
|
let mut transaction_builder = TransactionBuilder::new();
|
|
|
|
transaction_builder.add_room_event(EventsJson::Member);
|
|
|
|
let transaction = transaction_builder.build_json_transaction();
|
2021-06-02 13:16:43 +00:00
|
|
|
|
2021-06-04 12:16:24 +00:00
|
|
|
let appservice = appservice(None).await?;
|
2021-06-03 16:20:07 +00:00
|
|
|
|
|
|
|
#[cfg(feature = "warp")]
|
|
|
|
{
|
|
|
|
let status = warp::test::request()
|
|
|
|
.method("PUT")
|
|
|
|
.path(uri)
|
2021-06-04 12:16:24 +00:00
|
|
|
.json(&transaction)
|
2021-06-03 16:20:07 +00:00
|
|
|
.filter(&appservice.warp_filter())
|
|
|
|
.await
|
|
|
|
.unwrap()
|
|
|
|
.into_response()
|
|
|
|
.status();
|
|
|
|
|
|
|
|
assert_eq!(status, 401);
|
|
|
|
}
|
|
|
|
|
2021-06-02 13:16:43 +00:00
|
|
|
#[cfg(feature = "actix")]
|
|
|
|
{
|
2021-06-03 16:20:07 +00:00
|
|
|
let app =
|
2021-06-07 14:52:21 +00:00
|
|
|
actix_test::init_service(ActixApp::new().configure(appservice.actix_configure())).await;
|
2021-06-03 16:20:07 +00:00
|
|
|
|
2021-06-04 12:16:24 +00:00
|
|
|
let req = actix_test::TestRequest::put().uri(uri).set_json(&transaction).to_request();
|
2021-06-02 13:16:43 +00:00
|
|
|
|
|
|
|
let resp = actix_test::call_service(&app, req).await;
|
|
|
|
|
|
|
|
// TODO: this should actually return a 401 but is 500 because something in the
|
|
|
|
// extractor fails
|
|
|
|
assert_eq!(resp.status(), 500);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-04-29 11:28:08 +00:00
|
|
|
#[async_test]
|
|
|
|
async fn test_event_handler() -> Result<()> {
|
2021-05-26 12:00:59 +00:00
|
|
|
let mut appservice = appservice(None).await?;
|
2021-04-29 11:28:08 +00:00
|
|
|
|
2021-06-04 12:16:24 +00:00
|
|
|
#[derive(Clone)]
|
|
|
|
struct Example {
|
|
|
|
pub on_state_member: Arc<Mutex<bool>>,
|
|
|
|
}
|
2021-04-29 11:28:08 +00:00
|
|
|
|
|
|
|
impl Example {
|
|
|
|
pub fn new() -> Self {
|
2021-06-07 14:52:21 +00:00
|
|
|
#[allow(clippy::mutex_atomic)]
|
2021-06-04 12:16:24 +00:00
|
|
|
Self { on_state_member: Arc::new(Mutex::new(false)) }
|
2021-04-29 11:28:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[async_trait]
|
|
|
|
impl EventHandler for Example {
|
2021-06-04 12:16:24 +00:00
|
|
|
async fn on_room_member(&self, _: Room, _: &SyncStateEvent<MemberEventContent>) {
|
|
|
|
let on_state_member = self.on_state_member.clone();
|
|
|
|
*on_state_member.lock().unwrap() = true;
|
2021-04-29 11:28:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-04 12:16:24 +00:00
|
|
|
let example = Example::new();
|
|
|
|
appservice.set_event_handler(Box::new(example.clone())).await?;
|
2021-04-29 11:28:08 +00:00
|
|
|
|
2021-06-04 12:16:24 +00:00
|
|
|
let uri = "/_matrix/app/v1/transactions/1?access_token=hs_token";
|
2021-04-29 11:28:08 +00:00
|
|
|
|
2021-06-04 12:16:24 +00:00
|
|
|
let mut transaction_builder = TransactionBuilder::new();
|
|
|
|
transaction_builder.add_room_event(EventsJson::Member);
|
|
|
|
let transaction = transaction_builder.build_json_transaction();
|
|
|
|
|
|
|
|
#[cfg(feature = "warp")]
|
|
|
|
warp::test::request()
|
|
|
|
.method("PUT")
|
|
|
|
.path(uri)
|
|
|
|
.json(&transaction)
|
|
|
|
.filter(&appservice.warp_filter())
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
#[cfg(feature = "actix")]
|
2021-06-07 14:52:21 +00:00
|
|
|
{
|
2021-06-04 12:16:24 +00:00
|
|
|
let app =
|
2021-06-07 14:52:21 +00:00
|
|
|
actix_test::init_service(ActixApp::new().configure(appservice.actix_configure())).await;
|
2021-06-04 12:16:24 +00:00
|
|
|
|
|
|
|
let req = actix_test::TestRequest::put().uri(uri).set_json(&transaction).to_request();
|
|
|
|
|
|
|
|
actix_test::call_service(&app, req).await;
|
|
|
|
};
|
2021-04-29 11:28:08 +00:00
|
|
|
|
2021-06-04 12:16:24 +00:00
|
|
|
let on_room_member_called = *example.on_state_member.lock().unwrap();
|
|
|
|
assert!(on_room_member_called);
|
2021-04-29 11:28:08 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-06-07 14:52:21 +00:00
|
|
|
#[async_test]
|
|
|
|
async fn test_unrelated_path() -> Result<()> {
|
|
|
|
let appservice = appservice(None).await?;
|
|
|
|
|
|
|
|
#[cfg(feature = "warp")]
|
|
|
|
let status = {
|
|
|
|
let consumer_filter = warp::any()
|
|
|
|
.and(appservice.warp_filter())
|
2021-06-08 09:18:56 +00:00
|
|
|
.or(warp::get().and(warp::path("unrelated").map(warp::reply)));
|
2021-06-07 14:52:21 +00:00
|
|
|
|
|
|
|
let response = warp::test::request()
|
|
|
|
.method("GET")
|
|
|
|
.path("/unrelated")
|
|
|
|
.filter(&consumer_filter)
|
|
|
|
.await?
|
|
|
|
.into_response();
|
|
|
|
|
|
|
|
response.status()
|
|
|
|
};
|
|
|
|
|
|
|
|
#[cfg(feature = "actix")]
|
|
|
|
let status = {
|
|
|
|
let app = actix_test::init_service(
|
|
|
|
ActixApp::new()
|
|
|
|
.configure(appservice.actix_configure())
|
|
|
|
.route("/unrelated", actix_web::web::get().to(HttpResponse::Ok)),
|
|
|
|
)
|
|
|
|
.await;
|
|
|
|
|
|
|
|
let req = actix_test::TestRequest::get().uri("/unrelated").to_request();
|
|
|
|
|
|
|
|
actix_test::call_service(&app, req).await.status()
|
|
|
|
};
|
|
|
|
|
|
|
|
assert_eq!(status, 200);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-04-29 11:28:08 +00:00
|
|
|
mod registration {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_registration() -> Result<()> {
|
|
|
|
let registration: Registration = serde_yaml::from_str(®istration_string())?;
|
2021-06-15 10:09:01 +00:00
|
|
|
let registration: AppServiceRegistration = registration.into();
|
2021-04-29 11:28:08 +00:00
|
|
|
|
|
|
|
assert_eq!(registration.id, "appservice");
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_registration_from_yaml_file() -> Result<()> {
|
2021-06-15 10:09:01 +00:00
|
|
|
let registration = AppServiceRegistration::try_from_yaml_file("./tests/registration.yaml")?;
|
2021-04-29 11:28:08 +00:00
|
|
|
|
|
|
|
assert_eq!(registration.id, "appservice");
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_registration_from_yaml_str() -> Result<()> {
|
2021-06-15 10:09:01 +00:00
|
|
|
let registration = AppServiceRegistration::try_from_yaml_str(registration_string())?;
|
2021-04-29 11:28:08 +00:00
|
|
|
|
|
|
|
assert_eq!(registration.id, "appservice");
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|