PushSubscription and EventSource tests passing.
This commit is contained in:
@@ -1,21 +1,16 @@
|
||||
use std::{sync::Arc, time::Duration};
|
||||
use std::sync::Arc;
|
||||
|
||||
use jmap::{
|
||||
mailbox::{INBOX_ID, TRASH_ID},
|
||||
JMAP,
|
||||
};
|
||||
use jmap_client::{
|
||||
client::{Client, Credentials},
|
||||
client::Client,
|
||||
core::{
|
||||
error::{MethodError, MethodErrorType},
|
||||
set::{SetError, SetErrorType},
|
||||
},
|
||||
email::{
|
||||
self,
|
||||
import::EmailImportResponse,
|
||||
query::{Comparator, Filter},
|
||||
Property,
|
||||
},
|
||||
email::{self, import::EmailImportResponse, query::Filter, Property},
|
||||
mailbox::{self, Role},
|
||||
principal::ACL,
|
||||
};
|
||||
@@ -28,56 +23,17 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
// Create a group and three test accounts
|
||||
let inbox_id = Id::new(INBOX_ID as u64).to_string();
|
||||
let trash_id = Id::new(TRASH_ID as u64).to_string();
|
||||
const JOHN_ID: u64 = 1;
|
||||
const JANE_ID: u64 = 2;
|
||||
const BILL_ID: u64 = 3;
|
||||
const SALES_ID: u64 = 4;
|
||||
let john_id = Id::from(JOHN_ID).to_string();
|
||||
let jane_id = Id::from(JANE_ID).to_string();
|
||||
let bill_id = Id::from(BILL_ID).to_string();
|
||||
let sales_id = Id::from(SALES_ID).to_string();
|
||||
|
||||
for (login, secret, name) in [
|
||||
("jdoe@example.com", "12345", "John Doe"),
|
||||
("jane.smith@example.com", "abcde", "Jane Smith"),
|
||||
("bill@example.com", "098765", "Bill Foobar"),
|
||||
("sales@example.com", "Sales Group", ""),
|
||||
] {
|
||||
assert!(
|
||||
server
|
||||
.auth_db
|
||||
.execute(
|
||||
"INSERT OR REPLACE INTO users (login, secret, name) VALUES (?, ?, ?)",
|
||||
vec![login.to_string(), secret.to_string(), name.to_string()].into_iter()
|
||||
)
|
||||
.await
|
||||
);
|
||||
}
|
||||
let john_id = test_account_create(&server, "jdoe@example.com", "12345", "John Doe").await;
|
||||
let jane_id =
|
||||
test_account_create(&server, "jane.smith@example.com", "abcde", "Jane Smith").await;
|
||||
let bill_id = test_account_create(&server, "bill@example.com", "098765", "Bill Foobar").await;
|
||||
let sales_id = test_account_create(&server, "sales@example.com", "", "Sales Group").await;
|
||||
|
||||
// Authenticate all accounts
|
||||
let mut john_client = Client::new()
|
||||
.credentials(Credentials::basic("jdoe@example.com", "12345"))
|
||||
.timeout(Duration::from_secs(60))
|
||||
.accept_invalid_certs(true)
|
||||
.connect("https://127.0.0.1:8899")
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut jane_client = Client::new()
|
||||
.credentials(Credentials::basic("jane.smith@example.com", "abcde"))
|
||||
.timeout(Duration::from_secs(60))
|
||||
.accept_invalid_certs(true)
|
||||
.connect("https://127.0.0.1:8899")
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut bill_client = Client::new()
|
||||
.credentials(Credentials::basic("bill@example.com", "098765"))
|
||||
.timeout(Duration::from_secs(60))
|
||||
.accept_invalid_certs(true)
|
||||
.connect("https://127.0.0.1:8899")
|
||||
.await
|
||||
.unwrap();
|
||||
let mut john_client = test_account_login("jdoe@example.com", "12345").await;
|
||||
let mut jane_client = test_account_login("jane.smith@example.com", "abcde").await;
|
||||
let mut bill_client = test_account_login("bill@example.com", "098765").await;
|
||||
|
||||
// Insert two emails in each account
|
||||
let mut email_ids = AHashMap::default();
|
||||
@@ -92,7 +48,7 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
for (mailbox_id, mailbox_name) in [(&inbox_id, "inbox"), (&trash_id, "trash")] {
|
||||
ids.push(
|
||||
client
|
||||
.set_default_account_id(account_id)
|
||||
.set_default_account_id(account_id.to_string())
|
||||
.email_import(
|
||||
format!(
|
||||
concat!(
|
||||
@@ -133,7 +89,7 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
);
|
||||
assert_forbidden(
|
||||
john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.email_get(
|
||||
email_ids.get("jane").unwrap().first().unwrap(),
|
||||
[Property::Subject].into(),
|
||||
@@ -142,13 +98,13 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
);
|
||||
assert_forbidden(
|
||||
john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.mailbox_get(&inbox_id, None::<Vec<_>>)
|
||||
.await,
|
||||
);
|
||||
assert_forbidden(
|
||||
john_client
|
||||
.set_default_account_id(&sales_id)
|
||||
.set_default_account_id(&sales_id.to_string())
|
||||
.email_get(
|
||||
email_ids.get("sales").unwrap().first().unwrap(),
|
||||
[Property::Subject].into(),
|
||||
@@ -157,13 +113,13 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
);
|
||||
assert_forbidden(
|
||||
john_client
|
||||
.set_default_account_id(&sales_id)
|
||||
.set_default_account_id(&sales_id.to_string())
|
||||
.mailbox_get(&inbox_id, None::<Vec<_>>)
|
||||
.await,
|
||||
);
|
||||
assert_forbidden(
|
||||
john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.email_query(None::<Filter>, None::<Vec<_>>)
|
||||
.await,
|
||||
);
|
||||
@@ -177,7 +133,7 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
// John shoud have ReadItems access to Inbox
|
||||
assert_eq!(
|
||||
john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.email_get(
|
||||
email_ids.get("jane").unwrap().first().unwrap(),
|
||||
[Property::Subject].into(),
|
||||
@@ -191,7 +147,7 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
);
|
||||
assert_eq!(
|
||||
john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.email_query(None::<Filter>, None::<Vec<_>>)
|
||||
.await
|
||||
.unwrap()
|
||||
@@ -202,13 +158,17 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
// John's session resource should contain Jane's account details
|
||||
john_client.refresh_session().await.unwrap();
|
||||
assert_eq!(
|
||||
john_client.session().account(&jane_id).unwrap().name(),
|
||||
john_client
|
||||
.session()
|
||||
.account(&jane_id.to_string())
|
||||
.unwrap()
|
||||
.name(),
|
||||
"jane.smith@example.com"
|
||||
);
|
||||
|
||||
// John should not have access to emails in Jane's Trash folder
|
||||
assert!(john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.email_get(
|
||||
email_ids.get("jane").unwrap().last().unwrap(),
|
||||
[Property::Subject].into(),
|
||||
@@ -228,8 +188,8 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
.unwrap()
|
||||
.take_blob_id();
|
||||
john_client
|
||||
.set_default_account_id(&john_id)
|
||||
.blob_copy(&jane_id, &blob_id)
|
||||
.set_default_account_id(&john_id.to_string())
|
||||
.blob_copy(&jane_id.to_string(), &blob_id)
|
||||
.await
|
||||
.unwrap();
|
||||
let blob_id = jane_client
|
||||
@@ -243,15 +203,15 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
.take_blob_id();
|
||||
assert_forbidden(
|
||||
john_client
|
||||
.set_default_account_id(&john_id)
|
||||
.blob_copy(&jane_id, &blob_id)
|
||||
.set_default_account_id(&john_id.to_string())
|
||||
.blob_copy(&jane_id.to_string(), &blob_id)
|
||||
.await,
|
||||
);
|
||||
|
||||
// John only has ReadItems access to Inbox but no Read access
|
||||
assert_forbidden(
|
||||
john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.mailbox_get(&inbox_id, [mailbox::Property::MyRights].into())
|
||||
.await,
|
||||
);
|
||||
@@ -261,7 +221,7 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.mailbox_get(&inbox_id, [mailbox::Property::MyRights].into())
|
||||
.await
|
||||
.unwrap()
|
||||
@@ -274,9 +234,9 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
|
||||
// Try to add items using import and copy
|
||||
let blob_id = john_client
|
||||
.set_default_account_id(&john_id)
|
||||
.set_default_account_id(&john_id.to_string())
|
||||
.upload(
|
||||
Some(&john_id),
|
||||
Some(&john_id.to_string()),
|
||||
concat!(
|
||||
"From: acl_test@example.com\r\n",
|
||||
"To: jane.smith@example.com\r\n",
|
||||
@@ -291,7 +251,9 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
.await
|
||||
.unwrap()
|
||||
.take_blob_id();
|
||||
let mut request = john_client.set_default_account_id(&jane_id).build();
|
||||
let mut request = john_client
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.build();
|
||||
let email_id = request
|
||||
.import_email()
|
||||
.email(&blob_id)
|
||||
@@ -306,9 +268,9 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
);
|
||||
assert_forbidden(
|
||||
john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.email_copy(
|
||||
&john_id,
|
||||
&john_id.to_string(),
|
||||
email_ids.get("john").unwrap().last().unwrap(),
|
||||
[&inbox_id],
|
||||
None::<Vec<&str>>,
|
||||
@@ -327,7 +289,9 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut request = john_client.set_default_account_id(&jane_id).build();
|
||||
let mut request = john_client
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.build();
|
||||
let email_id = request
|
||||
.import_email()
|
||||
.email(&blob_id)
|
||||
@@ -341,9 +305,9 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
.unwrap()
|
||||
.take_id();
|
||||
let email_id_2 = john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.email_copy(
|
||||
&john_id,
|
||||
&john_id.to_string(),
|
||||
email_ids.get("john").unwrap().last().unwrap(),
|
||||
[&inbox_id],
|
||||
None::<Vec<&str>>,
|
||||
@@ -377,7 +341,7 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
// Try removing items
|
||||
assert_forbidden(
|
||||
john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.email_destroy(&email_id)
|
||||
.await,
|
||||
);
|
||||
@@ -390,7 +354,7 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
.await
|
||||
.unwrap();
|
||||
john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.email_destroy(&email_id)
|
||||
.await
|
||||
.unwrap();
|
||||
@@ -398,7 +362,7 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
// Try to set keywords
|
||||
assert_forbidden(
|
||||
john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.email_set_keyword(&email_id_2, "$seen", true)
|
||||
.await,
|
||||
);
|
||||
@@ -417,12 +381,12 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
.await
|
||||
.unwrap();
|
||||
john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.email_set_keyword(&email_id_2, "$seen", true)
|
||||
.await
|
||||
.unwrap();
|
||||
john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.email_set_keyword(&email_id_2, "my-keyword", true)
|
||||
.await
|
||||
.unwrap();
|
||||
@@ -430,7 +394,7 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
// Try to create a child
|
||||
assert_forbidden(
|
||||
john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.mailbox_create("John's mailbox", None::<&str>, Role::None)
|
||||
.await,
|
||||
);
|
||||
@@ -450,7 +414,7 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
.await
|
||||
.unwrap();
|
||||
let mailbox_id = john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.mailbox_create("John's mailbox", Some(&inbox_id), Role::None)
|
||||
.await
|
||||
.unwrap()
|
||||
@@ -459,7 +423,7 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
// Try renaming a mailbox
|
||||
assert_forbidden(
|
||||
john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.mailbox_rename(&mailbox_id, "John's private mailbox")
|
||||
.await,
|
||||
);
|
||||
@@ -472,7 +436,7 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
.await
|
||||
.unwrap();
|
||||
john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.mailbox_rename(&mailbox_id, "John's private mailbox")
|
||||
.await
|
||||
.unwrap();
|
||||
@@ -480,7 +444,7 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
// Try moving a message
|
||||
assert_forbidden(
|
||||
john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.email_set_mailbox(&email_id_2, &mailbox_id, true)
|
||||
.await,
|
||||
);
|
||||
@@ -493,7 +457,7 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
.await
|
||||
.unwrap();
|
||||
john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.email_set_mailbox(&email_id_2, &mailbox_id, true)
|
||||
.await
|
||||
.unwrap();
|
||||
@@ -501,7 +465,7 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
// Try deleting a mailbox
|
||||
assert_forbidden(
|
||||
john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.mailbox_destroy(&mailbox_id, true)
|
||||
.await,
|
||||
);
|
||||
@@ -521,7 +485,7 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
.unwrap();
|
||||
assert_forbidden(
|
||||
john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.mailbox_destroy(&mailbox_id, true)
|
||||
.await,
|
||||
);
|
||||
@@ -541,7 +505,7 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
.await
|
||||
.unwrap();
|
||||
john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.mailbox_destroy(&mailbox_id, true)
|
||||
.await
|
||||
.unwrap();
|
||||
@@ -549,13 +513,13 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
// Try changing ACL
|
||||
assert_forbidden(
|
||||
john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.mailbox_update_acl(&inbox_id, "bill@example.com", [ACL::Read, ACL::ReadItems])
|
||||
.await,
|
||||
);
|
||||
assert_forbidden(
|
||||
bill_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.email_query(None::<Filter>, None::<Vec<_>>)
|
||||
.await,
|
||||
);
|
||||
@@ -578,7 +542,7 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.mailbox_get(&inbox_id, [mailbox::Property::MyRights].into())
|
||||
.await
|
||||
.unwrap()
|
||||
@@ -596,13 +560,13 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
]
|
||||
);
|
||||
john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.mailbox_update_acl(&inbox_id, "bill@example.com", [ACL::Read, ACL::ReadItems])
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
bill_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.email_query(
|
||||
None::<Filter>,
|
||||
vec![email::query::Comparator::subject()].into()
|
||||
@@ -623,7 +587,7 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
.unwrap();
|
||||
assert_forbidden(
|
||||
john_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.email_get(
|
||||
email_ids.get("jane").unwrap().first().unwrap(),
|
||||
[Property::Subject].into(),
|
||||
@@ -631,10 +595,13 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
.await,
|
||||
);
|
||||
john_client.refresh_session().await.unwrap();
|
||||
assert!(john_client.session().account(&jane_id).is_none());
|
||||
assert!(john_client
|
||||
.session()
|
||||
.account(&jane_id.to_string())
|
||||
.is_none());
|
||||
assert_eq!(
|
||||
bill_client
|
||||
.set_default_account_id(&jane_id)
|
||||
.set_default_account_id(&jane_id.to_string())
|
||||
.email_get(
|
||||
email_ids.get("jane").unwrap().first().unwrap(),
|
||||
[Property::Subject].into(),
|
||||
@@ -648,14 +615,15 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
);
|
||||
|
||||
// Add John and Jane to the Sales group
|
||||
for id in [JANE_ID, JOHN_ID] {
|
||||
for id in [jane_id.id(), john_id.id()] {
|
||||
assert!(
|
||||
server
|
||||
.auth_db
|
||||
.execute(
|
||||
&format!(
|
||||
"INSERT INTO groups (uid, gid) VALUES ({}, {})",
|
||||
id, SALES_ID
|
||||
id,
|
||||
sales_id.id()
|
||||
),
|
||||
Vec::<String>::new().into_iter(),
|
||||
)
|
||||
@@ -667,25 +635,36 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
jane_client.refresh_session().await.unwrap();
|
||||
bill_client.refresh_session().await.unwrap();
|
||||
assert_eq!(
|
||||
john_client.session().account(&sales_id).unwrap().name(),
|
||||
john_client
|
||||
.session()
|
||||
.account(&sales_id.to_string())
|
||||
.unwrap()
|
||||
.name(),
|
||||
"sales@example.com"
|
||||
);
|
||||
assert!(!john_client
|
||||
.session()
|
||||
.account(&sales_id)
|
||||
.account(&sales_id.to_string())
|
||||
.unwrap()
|
||||
.is_personal());
|
||||
assert_eq!(
|
||||
jane_client.session().account(&sales_id).unwrap().name(),
|
||||
jane_client
|
||||
.session()
|
||||
.account(&sales_id.to_string())
|
||||
.unwrap()
|
||||
.name(),
|
||||
"sales@example.com"
|
||||
);
|
||||
assert!(bill_client.session().account(&sales_id).is_none());
|
||||
assert!(bill_client
|
||||
.session()
|
||||
.account(&sales_id.to_string())
|
||||
.is_none());
|
||||
|
||||
// Insert a message in Sales's inbox
|
||||
let blob_id = john_client
|
||||
.set_default_account_id(&sales_id)
|
||||
.set_default_account_id(&sales_id.to_string())
|
||||
.upload(
|
||||
Some(&sales_id),
|
||||
Some(&sales_id.to_string()),
|
||||
concat!(
|
||||
"From: acl_test@example.com\r\n",
|
||||
"To: sales@example.com\r\n",
|
||||
@@ -717,7 +696,7 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
// Both Jane and John should be able to see this message, but not Bill
|
||||
assert_eq!(
|
||||
john_client
|
||||
.set_default_account_id(&sales_id)
|
||||
.set_default_account_id(&sales_id.to_string())
|
||||
.email_get(&email_id, [Property::Subject].into(),)
|
||||
.await
|
||||
.unwrap()
|
||||
@@ -728,7 +707,7 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
);
|
||||
assert_eq!(
|
||||
jane_client
|
||||
.set_default_account_id(&sales_id)
|
||||
.set_default_account_id(&sales_id.to_string())
|
||||
.email_get(&email_id, [Property::Subject].into(),)
|
||||
.await
|
||||
.unwrap()
|
||||
@@ -739,7 +718,7 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
);
|
||||
assert_forbidden(
|
||||
bill_client
|
||||
.set_default_account_id(&sales_id)
|
||||
.set_default_account_id(&sales_id.to_string())
|
||||
.email_get(&email_id, [Property::Subject].into())
|
||||
.await,
|
||||
);
|
||||
@@ -751,7 +730,8 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
.execute(
|
||||
&format!(
|
||||
"DELETE FROM groups WHERE uid = {} AND gid ={}",
|
||||
JOHN_ID, SALES_ID
|
||||
john_id.id(),
|
||||
sales_id.id()
|
||||
),
|
||||
Vec::<String>::new().into_iter(),
|
||||
)
|
||||
@@ -760,31 +740,22 @@ pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
server.sessions.lock().clear();
|
||||
assert_forbidden(
|
||||
john_client
|
||||
.set_default_account_id(&sales_id)
|
||||
.set_default_account_id(&sales_id.to_string())
|
||||
.email_get(&email_id, [Property::Subject].into())
|
||||
.await,
|
||||
);
|
||||
|
||||
let coco = "fd";
|
||||
// Check that Jane's id is not assigned to new accounts before the
|
||||
// purge has taken place.
|
||||
/*server.store.id_assigner.invalidate_all();
|
||||
let tom_id = admin_client
|
||||
.individual_create("tom@example.com", "098765", "Tom Foobar")
|
||||
.await
|
||||
.unwrap()
|
||||
.take_id();
|
||||
assert_ne!(tom_id, jane_id);
|
||||
|
||||
// Destroy test accounts
|
||||
for principal_id in [tom_id, john_id, bill_id, sales_id, domain_id] {
|
||||
admin_client.principal_destroy(&principal_id).await.unwrap();
|
||||
// Destroy test account data
|
||||
for id in [john_id, bill_id, jane_id, sales_id] {
|
||||
admin_client.set_default_account_id(&id.to_string());
|
||||
destroy_all_mailboxes(admin_client).await;
|
||||
}
|
||||
server.store.principal_purge().unwrap();
|
||||
server.store.assert_is_empty();*/
|
||||
server.store.assert_is_empty().await;
|
||||
}
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
use crate::jmap::{mailbox::destroy_all_mailboxes, test_account_create, test_account_login};
|
||||
pub fn assert_forbidden<T: Debug>(result: Result<T, jmap_client::Error>) {
|
||||
if !matches!(
|
||||
result,
|
||||
|
||||
@@ -5,30 +5,19 @@ use jmap_client::{
|
||||
client::{Client, Credentials},
|
||||
mailbox::{self},
|
||||
};
|
||||
use jmap_proto::types::id::Id;
|
||||
|
||||
pub async fn test(server: Arc<JMAP>, _client: &mut Client) {
|
||||
use crate::jmap::{mailbox::destroy_all_mailboxes, test_account_create};
|
||||
|
||||
pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
println!("Running Authorization tests...");
|
||||
|
||||
// Create test account
|
||||
assert!(
|
||||
server
|
||||
.auth_db
|
||||
.execute(
|
||||
"INSERT OR REPLACE INTO users (login, secret, name) VALUES (?, ?, ?)",
|
||||
vec![
|
||||
"jdoe@example.com".to_string(),
|
||||
"12345".to_string(),
|
||||
"John Doe".to_string()
|
||||
]
|
||||
.into_iter()
|
||||
)
|
||||
.await
|
||||
);
|
||||
let account_id = Id::from(1u64).to_string();
|
||||
let account_id = test_account_create(&server, "jdoe@example.com", "12345", "John Doe")
|
||||
.await
|
||||
.to_string();
|
||||
|
||||
// Wait for rate limit to be restored after running previous tests
|
||||
//tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
|
||||
// Incorrect passwords should be rejected with a 401 error
|
||||
assert!(matches!(
|
||||
@@ -164,13 +153,7 @@ pub async fn test(server: Arc<JMAP>, _client: &mut Client) {
|
||||
Err(jmap_client::Error::Problem(err)) if err.status() == Some(400)));
|
||||
|
||||
// Destroy test accounts
|
||||
let implement = "true";
|
||||
/*admin_client
|
||||
.set_default_account_id(Id::new(SUPERUSER_ID as u64))
|
||||
.principal_destroy(&account_id)
|
||||
.await
|
||||
.unwrap();
|
||||
admin_client.principal_destroy(&domain_id).await.unwrap();
|
||||
server.store.principal_purge().unwrap();
|
||||
server.store.assert_is_empty();*/
|
||||
admin_client.set_default_account_id(&account_id);
|
||||
destroy_all_mailboxes(admin_client).await;
|
||||
server.store.assert_is_empty().await;
|
||||
}
|
||||
|
||||
@@ -9,30 +9,19 @@ use jmap_client::{
|
||||
client::{Client, Credentials},
|
||||
mailbox::query::Filter,
|
||||
};
|
||||
use jmap_proto::types::id::Id;
|
||||
use reqwest::{header, redirect::Policy};
|
||||
use serde::de::DeserializeOwned;
|
||||
use store::ahash::AHashMap;
|
||||
|
||||
use crate::jmap::{mailbox::destroy_all_mailboxes, test_account_create};
|
||||
|
||||
pub async fn test(server: Arc<JMAP>, _client: &mut Client) {
|
||||
println!("Running OAuth tests...");
|
||||
|
||||
// Create test account
|
||||
assert!(
|
||||
server
|
||||
.auth_db
|
||||
.execute(
|
||||
"INSERT OR REPLACE INTO users (login, secret, name) VALUES (?, ?, ?)",
|
||||
vec![
|
||||
"jdoe@example.com".to_string(),
|
||||
"abcde".to_string(),
|
||||
"John Doe".to_string()
|
||||
]
|
||||
.into_iter()
|
||||
)
|
||||
.await
|
||||
);
|
||||
let john_id = Id::from(1u64).to_string();
|
||||
let john_id = test_account_create(&server, "jdoe@example.com", "abcde", "John Doe")
|
||||
.await
|
||||
.to_string();
|
||||
|
||||
// Obtain OAuth metadata
|
||||
let metadata: OAuthMetadata =
|
||||
@@ -216,7 +205,7 @@ pub async fn test(server: Arc<JMAP>, _client: &mut Client) {
|
||||
);
|
||||
|
||||
// Connect to account using token and attempt to search
|
||||
let john_client = Client::new()
|
||||
let mut john_client = Client::new()
|
||||
.credentials(Credentials::bearer(&token))
|
||||
.accept_invalid_certs(true)
|
||||
.connect("https://127.0.0.1:8899")
|
||||
@@ -281,12 +270,8 @@ pub async fn test(server: Arc<JMAP>, _client: &mut Client) {
|
||||
);
|
||||
|
||||
// Destroy test accounts
|
||||
let cleanup = "true";
|
||||
/*for principal_id in [john_id, domain_id] {
|
||||
admin_client.principal_destroy(&principal_id).await.unwrap();
|
||||
}
|
||||
server.store.principal_purge().unwrap();
|
||||
server.store.assert_is_empty();*/
|
||||
destroy_all_mailboxes(&mut john_client).await;
|
||||
server.store.assert_is_empty().await;
|
||||
}
|
||||
|
||||
async fn post_bytes(url: &str, params: &AHashMap<String, String>) -> Bytes {
|
||||
|
||||
135
tests/src/jmap/event_source.rs
Normal file
135
tests/src/jmap/event_source.rs
Normal file
@@ -0,0 +1,135 @@
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
use futures::StreamExt;
|
||||
use jmap::JMAP;
|
||||
use jmap_client::{
|
||||
client::{Client, Credentials},
|
||||
event_source::Changes,
|
||||
mailbox::Role,
|
||||
TypeState,
|
||||
};
|
||||
use jmap_proto::types::id::Id;
|
||||
use store::ahash::AHashSet;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use crate::jmap::{mailbox::destroy_all_mailboxes, test_account_create, test_account_login};
|
||||
|
||||
pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
println!("Running EventSource tests...");
|
||||
|
||||
// Create test account
|
||||
test_account_create(&server, "jdoe@example.com", "12345", "John Doe").await;
|
||||
let mut client = test_account_login("jdoe@example.com", "12345").await;
|
||||
|
||||
let mut changes = client
|
||||
.event_source(None::<Vec<_>>, false, 1.into(), None)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let (event_tx, mut event_rx) = mpsc::channel::<Changes>(100);
|
||||
|
||||
tokio::spawn(async move {
|
||||
while let Some(change) = changes.next().await {
|
||||
if let Err(_err) = event_tx.send(change.unwrap()).await {
|
||||
//println!("Error sending event: {}", _err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
assert_ping(&mut event_rx).await;
|
||||
|
||||
// Create mailbox and expect state change
|
||||
let mailbox_id = client
|
||||
.set_default_account_id(Id::new(1).to_string())
|
||||
.mailbox_create("EventSource Test", None::<String>, Role::None)
|
||||
.await
|
||||
.unwrap()
|
||||
.take_id();
|
||||
assert_state(&mut event_rx, &[TypeState::Mailbox]).await;
|
||||
|
||||
// Multiple changes should be grouped and delivered in intervals
|
||||
for num in 0..5 {
|
||||
client
|
||||
.mailbox_update_sort_order(&mailbox_id, num)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
assert_state(&mut event_rx, &[TypeState::Mailbox]).await;
|
||||
assert_ping(&mut event_rx).await; // Pings are only received in cfg(test)
|
||||
|
||||
// Ingest email and expect state change
|
||||
let implement = "true";
|
||||
/*let mut lmtp = SmtpConnection::connect().await;
|
||||
lmtp.ingest(
|
||||
"bill@example.com",
|
||||
&["jdoe@example.com"],
|
||||
concat!(
|
||||
"From: bill@example.com\r\n",
|
||||
"To: jdoe@example.com\r\n",
|
||||
"Subject: TPS Report\r\n",
|
||||
"\r\n",
|
||||
"I'm going to need those TPS reports ASAP. ",
|
||||
"So, if you could do that, that'd be great."
|
||||
),
|
||||
)
|
||||
.await;
|
||||
lmtp.quit().await;
|
||||
|
||||
assert_state(
|
||||
&mut event_rx,
|
||||
&[
|
||||
TypeState::EmailDelivery,
|
||||
TypeState::Email,
|
||||
TypeState::Thread,
|
||||
TypeState::Mailbox,
|
||||
],
|
||||
)
|
||||
.await;
|
||||
assert_ping(&mut event_rx).await;*/
|
||||
|
||||
// Destroy mailbox
|
||||
client.mailbox_destroy(&mailbox_id, true).await.unwrap();
|
||||
|
||||
/*assert_state(
|
||||
&mut event_rx,
|
||||
&[TypeState::Email, TypeState::Thread, TypeState::Mailbox],
|
||||
)
|
||||
.await;*/
|
||||
let fix = "true";
|
||||
assert_state(&mut event_rx, &[TypeState::Mailbox]).await;
|
||||
assert_ping(&mut event_rx).await;
|
||||
assert_ping(&mut event_rx).await;
|
||||
|
||||
destroy_all_mailboxes(admin_client).await;
|
||||
server.store.assert_is_empty().await;
|
||||
}
|
||||
|
||||
async fn assert_state(event_rx: &mut mpsc::Receiver<Changes>, state: &[TypeState]) {
|
||||
match tokio::time::timeout(Duration::from_millis(700), event_rx.recv()).await {
|
||||
Ok(Some(changes)) => {
|
||||
assert_eq!(
|
||||
changes
|
||||
.changes(&Id::new(1).to_string())
|
||||
.unwrap()
|
||||
.map(|x| x.0)
|
||||
.collect::<AHashSet<&TypeState>>(),
|
||||
state.iter().collect::<AHashSet<&TypeState>>()
|
||||
);
|
||||
}
|
||||
result => {
|
||||
panic!("Timeout waiting for event {:?}: {:?}", state, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn assert_ping(event_rx: &mut mpsc::Receiver<Changes>) {
|
||||
match tokio::time::timeout(Duration::from_millis(1100), event_rx.recv()).await {
|
||||
Ok(Some(changes)) => {
|
||||
assert!(changes.changes("ping").is_some(),);
|
||||
}
|
||||
_ => {
|
||||
panic!("Did not receive ping.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -603,13 +603,7 @@ pub async fn test(server: Arc<JMAP>, client: &mut Client) {
|
||||
["inbox", "sent", "spam"]
|
||||
);
|
||||
|
||||
let mut request = client.build();
|
||||
request.query_mailbox().arguments().sort_as_tree(true);
|
||||
let mut ids = request.send_query_mailbox().await.unwrap().take_ids();
|
||||
ids.reverse();
|
||||
for id in ids {
|
||||
client.mailbox_destroy(&id, true).await.unwrap();
|
||||
}
|
||||
destroy_all_mailboxes(client).await;
|
||||
|
||||
server.store.assert_is_empty().await;
|
||||
}
|
||||
@@ -659,6 +653,16 @@ fn build_create_query(
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn destroy_all_mailboxes(client: &mut Client) {
|
||||
let mut request = client.build();
|
||||
request.query_mailbox().arguments().sort_as_tree(true);
|
||||
let mut ids = request.send_query_mailbox().await.unwrap().take_ids();
|
||||
ids.reverse();
|
||||
for id in ids {
|
||||
client.mailbox_destroy(&id, true).await.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct TestMailbox {
|
||||
id: String,
|
||||
|
||||
@@ -18,7 +18,9 @@ pub mod email_query;
|
||||
pub mod email_query_changes;
|
||||
pub mod email_search_snippet;
|
||||
pub mod email_set;
|
||||
pub mod event_source;
|
||||
pub mod mailbox;
|
||||
pub mod push_subscription;
|
||||
pub mod thread_get;
|
||||
pub mod thread_merge;
|
||||
|
||||
@@ -63,6 +65,16 @@ account.rate = '100/1m'
|
||||
authentication.rate = '100/1m'
|
||||
anonymous.rate = '1000/1m'
|
||||
|
||||
[jmap.event-source]
|
||||
throttle = '500ms'
|
||||
|
||||
[jmap.web-sockets]
|
||||
throttle = '500ms'
|
||||
|
||||
[jmap.push]
|
||||
throttle = '500ms'
|
||||
attempts.interval = '500ms'
|
||||
|
||||
[jmap.auth.database]
|
||||
type = 'sql'
|
||||
address = 'sqlite::memory:'
|
||||
@@ -108,7 +120,9 @@ pub async fn jmap_tests() {
|
||||
//mailbox::test(params.server.clone(), &mut params.client).await;
|
||||
//auth_acl::test(params.server.clone(), &mut params.client).await;
|
||||
//auth_limits::test(params.server.clone(), &mut params.client).await;
|
||||
auth_oauth::test(params.server.clone(), &mut params.client).await;
|
||||
//auth_oauth::test(params.server.clone(), &mut params.client).await;
|
||||
//event_source::test(params.server.clone(), &mut params.client).await;
|
||||
push_subscription::test(params.server.clone(), &mut params.client).await;
|
||||
|
||||
if delete {
|
||||
params.temp_dir.delete();
|
||||
@@ -133,7 +147,7 @@ async fn init_jmap_tests(delete_if_exists: bool) -> JMAPTest {
|
||||
let servers = settings.parse_servers().unwrap();
|
||||
|
||||
// Start JMAP server
|
||||
let manager = SessionManager::from(JMAP::new(&settings).await);
|
||||
let manager = SessionManager::from(JMAP::init(&settings).await);
|
||||
let shutdown_tx = servers.spawn(&settings, |server, shutdown_rx| {
|
||||
server.spawn(manager.clone(), shutdown_rx);
|
||||
});
|
||||
@@ -228,3 +242,25 @@ pub fn replace_blob_ids(string: String) -> String {
|
||||
string
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn test_account_create(jmap: &JMAP, login: &str, secret: &str, name: &str) -> Id {
|
||||
assert!(
|
||||
jmap.auth_db
|
||||
.execute(
|
||||
"INSERT OR REPLACE INTO users (login, secret, name) VALUES (?, ?, ?)",
|
||||
vec![login.to_string(), secret.to_string(), name.to_string()].into_iter()
|
||||
)
|
||||
.await
|
||||
);
|
||||
Id::new(jmap.get_account_id(login).await.unwrap() as u64)
|
||||
}
|
||||
|
||||
pub async fn test_account_login(login: &str, secret: &str) -> Client {
|
||||
Client::new()
|
||||
.credentials(Credentials::basic(login, secret))
|
||||
.timeout(Duration::from_secs(5))
|
||||
.accept_invalid_certs(true)
|
||||
.connect("https://127.0.0.1:8899")
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
347
tests/src/jmap/push_subscription.rs
Normal file
347
tests/src/jmap/push_subscription.rs
Normal file
@@ -0,0 +1,347 @@
|
||||
use std::{
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc,
|
||||
},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use base64::{engine::general_purpose, Engine};
|
||||
use ece::EcKeyComponents;
|
||||
|
||||
use hyper::{body, server::conn::http1, service::service_fn, StatusCode};
|
||||
use jmap::{
|
||||
api::{
|
||||
http::{fetch_body, ToHttpResponse},
|
||||
HtmlResponse, StateChangeResponse,
|
||||
},
|
||||
JMAP,
|
||||
};
|
||||
use jmap_client::{client::Client, mailbox::Role, push_subscription::Keys};
|
||||
use jmap_proto::types::{id::Id, type_state::TypeState};
|
||||
use reqwest::header::CONTENT_ENCODING;
|
||||
use store::ahash::AHashSet;
|
||||
use tokio::{net::TcpStream, sync::mpsc};
|
||||
use utils::listener::SessionData;
|
||||
|
||||
use crate::{
|
||||
add_test_certs,
|
||||
jmap::{mailbox::destroy_all_mailboxes, test_account_create, test_account_login},
|
||||
};
|
||||
|
||||
const SERVER: &str = "
|
||||
[server]
|
||||
hostname = 'jmap-push.example.org'
|
||||
|
||||
[server.listener.jmap]
|
||||
bind = ['127.0.0.1:9000']
|
||||
url = 'https://127.0.0.1:9000'
|
||||
protocol = 'jmap'
|
||||
|
||||
[server.socket]
|
||||
reuse-addr = true
|
||||
|
||||
[server.tls]
|
||||
enable = true
|
||||
implicit = false
|
||||
certificate = 'default'
|
||||
|
||||
[certificate.default]
|
||||
cert = 'file://{CERT}'
|
||||
private-key = 'file://{PK}'
|
||||
";
|
||||
|
||||
pub async fn test(server: Arc<JMAP>, admin_client: &mut Client) {
|
||||
println!("Running Push Subscription tests...");
|
||||
|
||||
// Create test account
|
||||
let account_id = test_account_create(&server, "jdoe@example.com", "12345", "John Doe").await;
|
||||
admin_client.set_default_account_id(account_id);
|
||||
let mut client = test_account_login("jdoe@example.com", "12345").await;
|
||||
|
||||
// Create channels
|
||||
let (event_tx, mut event_rx) = mpsc::channel::<PushMessage>(100);
|
||||
|
||||
// Create subscription keys
|
||||
let (keypair, auth_secret) = ece::generate_keypair_and_auth_secret().unwrap();
|
||||
let pubkey = keypair.pub_as_raw().unwrap();
|
||||
let keys = Keys::new(&pubkey, &auth_secret);
|
||||
|
||||
let push_server = Arc::new(PushServer {
|
||||
keypair: keypair.raw_components().unwrap(),
|
||||
auth_secret: auth_secret.to_vec(),
|
||||
tx: event_tx,
|
||||
fail_requests: false.into(),
|
||||
});
|
||||
|
||||
// Start mock push server
|
||||
let settings = utils::config::Config::parse(&add_test_certs(SERVER)).unwrap();
|
||||
let servers = settings.parse_servers().unwrap();
|
||||
|
||||
// Start JMAP server
|
||||
let manager = SessionManager::from(push_server.clone());
|
||||
let _shutdown_tx = servers.spawn(&settings, |server, shutdown_rx| {
|
||||
server.spawn(manager.clone(), shutdown_rx);
|
||||
});
|
||||
|
||||
// Register push notification (no encryption)
|
||||
let push_id = client
|
||||
.push_subscription_create("123", "https://127.0.0.1:9000/push", None)
|
||||
.await
|
||||
.unwrap()
|
||||
.take_id();
|
||||
|
||||
// Expect push verification
|
||||
let verification = expect_push(&mut event_rx).await.unwrap_verification();
|
||||
assert_eq!(verification.push_subscription_id, push_id);
|
||||
|
||||
// Update verification code
|
||||
client
|
||||
.push_subscription_verify(&push_id, verification.verification_code)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Create a mailbox and expect a state change
|
||||
let mailbox_id = client
|
||||
.set_default_account_id(Id::new(1).to_string())
|
||||
.mailbox_create("PushSubscription Test", None::<String>, Role::None)
|
||||
.await
|
||||
.unwrap()
|
||||
.take_id();
|
||||
|
||||
assert_state(&mut event_rx, &[TypeState::Mailbox]).await;
|
||||
|
||||
// Receive states just for the requested types
|
||||
client
|
||||
.push_subscription_update_types(&push_id, [jmap_client::TypeState::Email].into())
|
||||
.await
|
||||
.unwrap();
|
||||
client
|
||||
.mailbox_update_sort_order(&mailbox_id, 123)
|
||||
.await
|
||||
.unwrap();
|
||||
expect_nothing(&mut event_rx).await;
|
||||
|
||||
// Destroy subscription
|
||||
client.push_subscription_destroy(&push_id).await.unwrap();
|
||||
|
||||
// Only one verification per minute is allowed
|
||||
let push_id = client
|
||||
.push_subscription_create("invalid", "https://127.0.0.1:9000/push", None)
|
||||
.await
|
||||
.unwrap()
|
||||
.take_id();
|
||||
expect_nothing(&mut event_rx).await;
|
||||
client.push_subscription_destroy(&push_id).await.unwrap();
|
||||
|
||||
// Register push notification (with encryption)
|
||||
let push_id = client
|
||||
.push_subscription_create(
|
||||
"123",
|
||||
"https://127.0.0.1:9000/push?skip_checks=true", // skip_checks only works in cfg(test)
|
||||
keys.into(),
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
.take_id();
|
||||
|
||||
// Expect push verification
|
||||
let verification = expect_push(&mut event_rx).await.unwrap_verification();
|
||||
assert_eq!(verification.push_subscription_id, push_id);
|
||||
|
||||
// Update verification code
|
||||
client
|
||||
.push_subscription_verify(&push_id, verification.verification_code)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Failed deliveries should be re-attempted
|
||||
push_server.fail_requests.store(true, Ordering::Relaxed);
|
||||
client
|
||||
.mailbox_update_sort_order(&mailbox_id, 101)
|
||||
.await
|
||||
.unwrap();
|
||||
tokio::time::sleep(Duration::from_millis(200)).await;
|
||||
push_server.fail_requests.store(false, Ordering::Relaxed);
|
||||
assert_state(&mut event_rx, &[TypeState::Mailbox]).await;
|
||||
|
||||
// Make a mailbox change and expect state change
|
||||
client
|
||||
.mailbox_rename(&mailbox_id, "My Mailbox")
|
||||
.await
|
||||
.unwrap();
|
||||
assert_state(&mut event_rx, &[TypeState::Mailbox]).await;
|
||||
//expect_nothing(&mut event_rx).await;
|
||||
|
||||
// Multiple change updates should be grouped and pushed in intervals
|
||||
for num in 0..25 {
|
||||
client
|
||||
.mailbox_update_sort_order(&mailbox_id, num)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
assert_state(&mut event_rx, &[TypeState::Mailbox]).await;
|
||||
expect_nothing(&mut event_rx).await;
|
||||
|
||||
// Destroy mailbox
|
||||
client.push_subscription_destroy(&push_id).await.unwrap();
|
||||
client.mailbox_destroy(&mailbox_id, true).await.unwrap();
|
||||
expect_nothing(&mut event_rx).await;
|
||||
|
||||
destroy_all_mailboxes(admin_client).await;
|
||||
|
||||
server.store.assert_is_empty().await;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SessionManager {
|
||||
pub inner: Arc<PushServer>,
|
||||
}
|
||||
|
||||
impl From<Arc<PushServer>> for SessionManager {
|
||||
fn from(inner: Arc<PushServer>) -> Self {
|
||||
SessionManager { inner }
|
||||
}
|
||||
}
|
||||
pub struct PushServer {
|
||||
keypair: EcKeyComponents,
|
||||
auth_secret: Vec<u8>,
|
||||
tx: mpsc::Sender<PushMessage>,
|
||||
fail_requests: AtomicBool,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug)]
|
||||
#[serde(untagged)]
|
||||
enum PushMessage {
|
||||
StateChange(StateChangeResponse),
|
||||
Verification(PushVerification),
|
||||
}
|
||||
|
||||
impl PushMessage {
|
||||
pub fn unwrap_state_change(self) -> StateChangeResponse {
|
||||
match self {
|
||||
PushMessage::StateChange(state_change) => state_change,
|
||||
_ => panic!("Expected StateChange"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unwrap_verification(self) -> PushVerification {
|
||||
match self {
|
||||
PushMessage::Verification(verification) => verification,
|
||||
_ => panic!("Expected Verification"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug)]
|
||||
enum PushVerificationType {
|
||||
PushVerification,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize, Debug)]
|
||||
struct PushVerification {
|
||||
#[serde(rename = "@type")]
|
||||
_type: PushVerificationType,
|
||||
#[serde(rename = "pushSubscriptionId")]
|
||||
pub push_subscription_id: String,
|
||||
#[serde(rename = "verificationCode")]
|
||||
pub verification_code: String,
|
||||
}
|
||||
|
||||
impl utils::listener::SessionManager for SessionManager {
|
||||
fn spawn(&self, session: SessionData<TcpStream>) {
|
||||
let push = self.inner.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
let _ = http1::Builder::new()
|
||||
.keep_alive(false)
|
||||
.serve_connection(
|
||||
session
|
||||
.instance
|
||||
.tls_acceptor
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.accept(session.stream)
|
||||
.await
|
||||
.unwrap(),
|
||||
service_fn(|mut req: hyper::Request<body::Incoming>| {
|
||||
let push = push.clone();
|
||||
|
||||
async move {
|
||||
if push.fail_requests.load(Ordering::Relaxed) {
|
||||
return Ok(HtmlResponse::with_status(
|
||||
StatusCode::TOO_MANY_REQUESTS,
|
||||
"too many requests".to_string(),
|
||||
)
|
||||
.into_http_response());
|
||||
}
|
||||
let is_encrypted = req
|
||||
.headers()
|
||||
.get(CONTENT_ENCODING)
|
||||
.map_or(false, |encoding| {
|
||||
encoding.to_str().unwrap() == "aes128gcm"
|
||||
});
|
||||
let body = fetch_body(&mut req, 1024 * 1024).await.unwrap();
|
||||
let message = serde_json::from_slice::<PushMessage>(&if is_encrypted {
|
||||
ece::decrypt(
|
||||
&push.keypair,
|
||||
&push.auth_secret,
|
||||
&general_purpose::URL_SAFE.decode(body).unwrap(),
|
||||
)
|
||||
.unwrap()
|
||||
} else {
|
||||
body
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
//println!("Push received ({}): {:?}", is_encrypted, message);
|
||||
|
||||
push.tx.send(message).await.unwrap();
|
||||
|
||||
Ok::<_, hyper::Error>(
|
||||
HtmlResponse::new("ok".to_string()).into_http_response(),
|
||||
)
|
||||
}
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
});
|
||||
}
|
||||
|
||||
fn max_concurrent(&self) -> u64 {
|
||||
100
|
||||
}
|
||||
}
|
||||
|
||||
async fn expect_push(event_rx: &mut mpsc::Receiver<PushMessage>) -> PushMessage {
|
||||
match tokio::time::timeout(Duration::from_millis(1500), event_rx.recv()).await {
|
||||
Ok(Some(push)) => push,
|
||||
result => {
|
||||
panic!("Timeout waiting for push: {:?}", result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn expect_nothing(event_rx: &mut mpsc::Receiver<PushMessage>) {
|
||||
match tokio::time::timeout(Duration::from_millis(1000), event_rx.recv()).await {
|
||||
Err(_) => {}
|
||||
message => {
|
||||
panic!("Received a message when expecting nothing: {:?}", message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn assert_state(event_rx: &mut mpsc::Receiver<PushMessage>, state: &[TypeState]) {
|
||||
assert_eq!(
|
||||
expect_push(event_rx)
|
||||
.await
|
||||
.unwrap_state_change()
|
||||
.changed
|
||||
.get(&Id::new(1))
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|x| x.0)
|
||||
.collect::<AHashSet<&TypeState>>(),
|
||||
state.iter().collect::<AHashSet<&TypeState>>()
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user