mirror of
https://github.com/chatmail/core.git
synced 2026-06-10 09:36:30 +03:00
Compare commits
1 Commits
iequidoo/d
...
simon/webx
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
907728731e |
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -62,7 +62,7 @@ jobs:
|
||||
with:
|
||||
show-progress: false
|
||||
persist-credentials: false
|
||||
- uses: EmbarkStudios/cargo-deny-action@a531616d8ce3b9177443e48a1159bc945a099823
|
||||
- uses: EmbarkStudios/cargo-deny-action@6c8f9facfa5047ec02d8485b6bf52b587b7777d1
|
||||
with:
|
||||
arguments: --workspace --all-features --locked
|
||||
command: check
|
||||
@@ -146,7 +146,7 @@ jobs:
|
||||
cache-bin: false
|
||||
|
||||
- name: Install nextest
|
||||
uses: taiki-e/install-action@60ae4ce63c7aeb6e96d7f572c1ec7fafbb17ca80
|
||||
uses: taiki-e/install-action@213ccc1a076163c093f914550b94feb90fab916d
|
||||
with:
|
||||
tool: nextest
|
||||
|
||||
|
||||
102
Cargo.lock
generated
102
Cargo.lock
generated
@@ -391,28 +391,6 @@ version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "aws-lc-rs"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ec2f1fc3ec205783a5da9a7e6c1509cc69dedf09a1949e412c1e18469326d00"
|
||||
dependencies = [
|
||||
"aws-lc-sys",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aws-lc-sys"
|
||||
version = "0.41.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a2f9779ce85b93ab6170dd940ad0169b5766ff848247aff13bb788b832fe3f4"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cmake",
|
||||
"dunce",
|
||||
"fs_extra",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backon"
|
||||
version = "1.5.0"
|
||||
@@ -785,13 +763,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.63"
|
||||
version = "1.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f"
|
||||
checksum = "0c3d1b2e905a3a7b00a6141adb0e4c0bb941d11caf55349d863942a1cc44e3c9"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"jobserver",
|
||||
"libc",
|
||||
"shlex",
|
||||
]
|
||||
|
||||
@@ -945,15 +920,6 @@ dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cmake"
|
||||
version = "0.1.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cobs"
|
||||
version = "0.2.3"
|
||||
@@ -1710,7 +1676,7 @@ dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.61.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1760,12 +1726,6 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dunce"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
|
||||
|
||||
[[package]]
|
||||
name = "dyn-clone"
|
||||
version = "1.0.18"
|
||||
@@ -2091,12 +2051,6 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
|
||||
|
||||
[[package]]
|
||||
name = "fixedbitset"
|
||||
version = "0.5.7"
|
||||
@@ -2154,12 +2108,6 @@ dependencies = [
|
||||
name = "format-flowed"
|
||||
version = "1.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "fs_extra"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
|
||||
|
||||
[[package]]
|
||||
name = "funty"
|
||||
version = "2.0.0"
|
||||
@@ -2733,7 +2681,7 @@ dependencies = [
|
||||
"hyper",
|
||||
"libc",
|
||||
"pin-project-lite",
|
||||
"socket2 0.5.9",
|
||||
"socket2 0.6.3",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
@@ -3286,16 +3234,6 @@ version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
|
||||
dependencies = [
|
||||
"getrandom 0.3.3",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.77"
|
||||
@@ -3436,9 +3374,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.31"
|
||||
version = "0.4.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "113b30b4cd05f7c06868fdb2854f66a7b9fece9a48425351cd532e810d74024f"
|
||||
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
||||
|
||||
[[package]]
|
||||
name = "loom"
|
||||
@@ -3880,7 +3818,7 @@ version = "0.50.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.61.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4365,18 +4303,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.1.13"
|
||||
version = "1.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924"
|
||||
checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517"
|
||||
dependencies = [
|
||||
"pin-project-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "1.1.13"
|
||||
version = "1.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b"
|
||||
checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -5281,7 +5219,7 @@ dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.12.1",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.61.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5290,7 +5228,6 @@ version = "0.23.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4"
|
||||
dependencies = [
|
||||
"aws-lc-rs",
|
||||
"log",
|
||||
"once_cell",
|
||||
"ring",
|
||||
@@ -5336,7 +5273,6 @@ version = "0.103.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e"
|
||||
dependencies = [
|
||||
"aws-lc-rs",
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"untrusted",
|
||||
@@ -5581,9 +5517,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.150"
|
||||
version = "1.0.149"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
|
||||
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
@@ -5759,9 +5695,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "2.0.1"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
@@ -6147,7 +6083,7 @@ dependencies = [
|
||||
"getrandom 0.3.3",
|
||||
"once_cell",
|
||||
"rustix 1.1.4",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.61.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6295,9 +6231,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.52.3"
|
||||
version = "1.52.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe"
|
||||
checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"libc",
|
||||
|
||||
@@ -101,7 +101,7 @@ tagger = "4.3.4"
|
||||
textwrap = "0.16.2"
|
||||
thiserror = { workspace = true }
|
||||
tokio-io-timeout = "1.2.1"
|
||||
tokio-rustls = { version = "0.26.2", default-features = false, features = ["aws-lc-rs", "tls12"] }
|
||||
tokio-rustls = { version = "0.26.2", default-features = false }
|
||||
tokio-stream = { version = "0.1.17", features = ["fs"] }
|
||||
astral-tokio-tar = { version = "0.6.2", default-features = false }
|
||||
tokio-util = { workspace = true }
|
||||
|
||||
71
src/chat.rs
71
src/chat.rs
@@ -3738,19 +3738,17 @@ pub(crate) async fn update_chat_contacts_table(
|
||||
id: ChatId,
|
||||
contacts: &BTreeSet<ContactId>,
|
||||
) -> Result<()> {
|
||||
// See add_to_chat_contacts_table() for reasoning.
|
||||
let limit = cmp::max(time().saturating_add(TIMESTAMP_SENT_TOLERANCE), timestamp);
|
||||
context
|
||||
.sql
|
||||
.transaction(move |transaction| {
|
||||
// Bump `remove_timestamp` even for members from `contacts`.
|
||||
// Bump `remove_timestamp` to at least `now`
|
||||
// even for members from `contacts`.
|
||||
// We add members from `contacts` back below.
|
||||
transaction.execute(
|
||||
"UPDATE chats_contacts SET
|
||||
add_timestamp=MIN(add_timestamp, ?1),
|
||||
remove_timestamp=MAX(MIN(remove_timestamp,?1), MIN(add_timestamp,?1)+1, ?)
|
||||
"UPDATE chats_contacts
|
||||
SET remove_timestamp=MAX(add_timestamp+1, ?)
|
||||
WHERE chat_id=?",
|
||||
(limit, timestamp, id),
|
||||
(timestamp, id),
|
||||
)?;
|
||||
|
||||
if !contacts.is_empty() {
|
||||
@@ -3762,8 +3760,9 @@ pub(crate) async fn update_chat_contacts_table(
|
||||
)?;
|
||||
|
||||
for contact_id in contacts {
|
||||
// We bumped `remove_timestamp` for existing rows above,
|
||||
// so on conflict it is enough to set `add_timestamp = remove_timestamp`.
|
||||
// We bumped `add_timestamp` for existing rows above,
|
||||
// so on conflict it is enough to set `add_timestamp = remove_timestamp`
|
||||
// and this guarantees that `add_timestamp` is no less than `timestamp`.
|
||||
statement.execute((id, contact_id, timestamp))?;
|
||||
}
|
||||
}
|
||||
@@ -3780,24 +3779,17 @@ pub(crate) async fn add_to_chat_contacts_table(
|
||||
chat_id: ChatId,
|
||||
contact_ids: &[ContactId],
|
||||
) -> Result<()> {
|
||||
// Our clock may be slow, so limit stored timestamps with `timestamp` if it's bigger. This way
|
||||
// we only cap remote timestamps if, in addition, remote changes arrive reordered or we do local
|
||||
// changes. Also allow some tolerance, moreover, previous removals might lend time from the
|
||||
// future.
|
||||
let limit = cmp::max(time().saturating_add(TIMESTAMP_SENT_TOLERANCE), timestamp);
|
||||
context
|
||||
.sql
|
||||
.transaction(move |transaction| {
|
||||
let mut add_statement = transaction.prepare(
|
||||
"INSERT INTO chats_contacts (chat_id, contact_id, add_timestamp) VALUES(?1, ?2, ?3)
|
||||
ON CONFLICT (chat_id, contact_id)
|
||||
DO UPDATE SET
|
||||
remove_timestamp=MIN(remove_timestamp, ?4),
|
||||
add_timestamp=MIN(MAX(add_timestamp,remove_timestamp,?3), ?4)",
|
||||
DO UPDATE SET add_timestamp=MAX(remove_timestamp, ?3)",
|
||||
)?;
|
||||
|
||||
for contact_id in contact_ids {
|
||||
add_statement.execute((chat_id, contact_id, timestamp, limit))?;
|
||||
add_statement.execute((chat_id, contact_id, timestamp))?;
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
@@ -3808,34 +3800,26 @@ pub(crate) async fn add_to_chat_contacts_table(
|
||||
|
||||
/// Removes a contact from the chat
|
||||
/// by updating the `remove_timestamp`.
|
||||
/// Returns whether the contact has been a chat member recently. If so, a removal message should be
|
||||
/// sent.
|
||||
pub(crate) async fn remove_from_chat_contacts_table(
|
||||
context: &Context,
|
||||
chat_id: ChatId,
|
||||
contact_id: ContactId,
|
||||
) -> Result<bool> {
|
||||
) -> Result<()> {
|
||||
let now = time();
|
||||
// See add_to_chat_contacts_table() for reasoning.
|
||||
let limit = now.saturating_add(TIMESTAMP_SENT_TOLERANCE);
|
||||
let is_past_member = context
|
||||
context
|
||||
.sql
|
||||
.execute(
|
||||
"UPDATE chats_contacts SET
|
||||
add_timestamp=MIN(add_timestamp, ?1),
|
||||
remove_timestamp=MAX(MIN(remove_timestamp,?1), MIN(add_timestamp,?1)+1, ?)
|
||||
"UPDATE chats_contacts
|
||||
SET remove_timestamp=MAX(add_timestamp+1, ?)
|
||||
WHERE chat_id=? AND contact_id=?",
|
||||
(limit, now, chat_id, contact_id),
|
||||
(now, chat_id, contact_id),
|
||||
)
|
||||
.await?
|
||||
> 0;
|
||||
Ok(is_past_member)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Removes a contact from the chat
|
||||
/// without leaving a trace in the db.
|
||||
/// Returns whether the contact was removed, even if it was a past contact. If so, a removal message
|
||||
/// should be sent if the removal is issued by this device.
|
||||
/// without leaving a trace.
|
||||
///
|
||||
/// Note that if we call this function,
|
||||
/// and then receive a message from another device
|
||||
@@ -3845,17 +3829,17 @@ pub(crate) async fn remove_from_chat_contacts_table_without_trace(
|
||||
context: &Context,
|
||||
chat_id: ChatId,
|
||||
contact_id: ContactId,
|
||||
) -> Result<bool> {
|
||||
let removed = context
|
||||
) -> Result<()> {
|
||||
context
|
||||
.sql
|
||||
.execute(
|
||||
"DELETE FROM chats_contacts
|
||||
WHERE chat_id=? AND contact_id=?",
|
||||
(chat_id, contact_id),
|
||||
)
|
||||
.await?
|
||||
> 0;
|
||||
Ok(removed)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Adds a contact to the chat.
|
||||
@@ -4175,13 +4159,10 @@ pub async fn remove_contact_from_chat(
|
||||
|
||||
let mut sync = Nosync;
|
||||
|
||||
let removed = if chat.is_promoted() && chat.typ != Chattype::OutBroadcast {
|
||||
remove_from_chat_contacts_table(context, chat_id, contact_id).await?
|
||||
if chat.is_promoted() && chat.typ != Chattype::OutBroadcast {
|
||||
remove_from_chat_contacts_table(context, chat_id, contact_id).await?;
|
||||
} else {
|
||||
remove_from_chat_contacts_table_without_trace(context, chat_id, contact_id).await?
|
||||
};
|
||||
if !removed {
|
||||
return Ok(());
|
||||
remove_from_chat_contacts_table_without_trace(context, chat_id, contact_id).await?;
|
||||
}
|
||||
|
||||
// We do not return an error if the contact does not exist in the database.
|
||||
|
||||
@@ -2800,30 +2800,6 @@ async fn test_can_send_group() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_cant_remove_nonmember() -> Result<()> {
|
||||
let mut tcm = TestContextManager::new();
|
||||
let alice = &tcm.alice().await;
|
||||
let bob = &tcm.bob().await;
|
||||
let charlie = &tcm.charlie().await;
|
||||
|
||||
let alice_broadcast_id = create_broadcast(alice, "Channel".to_string()).await?;
|
||||
let qr = get_securejoin_qr(alice, Some(alice_broadcast_id))
|
||||
.await
|
||||
.unwrap();
|
||||
tcm.exec_securejoin_qr(bob, alice, &qr).await;
|
||||
|
||||
let alice_charlie_id = alice.add_or_lookup_contact_id(charlie).await;
|
||||
remove_contact_from_chat(alice, alice_broadcast_id, alice_charlie_id).await?;
|
||||
assert!(alice.pop_sent_msg_opt(Duration::ZERO).await.is_none());
|
||||
assert!(!remove_from_chat_contacts_table(alice, alice_broadcast_id, alice_charlie_id).await?);
|
||||
assert!(
|
||||
!remove_from_chat_contacts_table_without_trace(alice, alice_broadcast_id, alice_charlie_id)
|
||||
.await?
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Tests that in a broadcast channel,
|
||||
/// the recipients can't see the identity of their fellow recipients.
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
|
||||
@@ -126,12 +126,9 @@ pub async fn wrap_rustls<'a>(
|
||||
let root_cert_store =
|
||||
rustls::RootCertStore::from_iter(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
|
||||
|
||||
let mut config = rustls::ClientConfig::builder_with_provider(Arc::new(
|
||||
rustls::crypto::aws_lc_rs::default_provider(),
|
||||
))
|
||||
.with_safe_default_protocol_versions()?
|
||||
.with_root_certificates(root_cert_store)
|
||||
.with_no_client_auth();
|
||||
let mut config = rustls::ClientConfig::builder()
|
||||
.with_root_certificates(root_cert_store)
|
||||
.with_no_client_auth();
|
||||
config.alpn_protocols = if alpn.is_empty() {
|
||||
vec![]
|
||||
} else {
|
||||
|
||||
@@ -51,7 +51,7 @@ impl rustls::client::danger::ServerCertVerifier for CustomCertificateVerifier {
|
||||
|
||||
let spki = parsed_certificate.subject_public_key_info();
|
||||
|
||||
let provider = rustls::crypto::aws_lc_rs::default_provider();
|
||||
let provider = rustls::crypto::ring::default_provider();
|
||||
|
||||
if let ServerName::DnsName(dns_name) = server_name
|
||||
&& dns_name.as_ref().starts_with("_")
|
||||
@@ -97,7 +97,7 @@ impl rustls::client::danger::ServerCertVerifier for CustomCertificateVerifier {
|
||||
cert: &CertificateDer<'_>,
|
||||
dss: &rustls::DigitallySignedStruct,
|
||||
) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
|
||||
let provider = rustls::crypto::aws_lc_rs::default_provider();
|
||||
let provider = rustls::crypto::ring::default_provider();
|
||||
let supported_schemes = &provider.signature_verification_algorithms;
|
||||
rustls::crypto::verify_tls12_signature(message, cert, dss, supported_schemes)
|
||||
}
|
||||
@@ -108,13 +108,13 @@ impl rustls::client::danger::ServerCertVerifier for CustomCertificateVerifier {
|
||||
cert: &CertificateDer<'_>,
|
||||
dss: &rustls::DigitallySignedStruct,
|
||||
) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
|
||||
let provider = rustls::crypto::aws_lc_rs::default_provider();
|
||||
let provider = rustls::crypto::ring::default_provider();
|
||||
let supported_schemes = &provider.signature_verification_algorithms;
|
||||
rustls::crypto::verify_tls13_signature(message, cert, dss, supported_schemes)
|
||||
}
|
||||
|
||||
fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
|
||||
let provider = rustls::crypto::aws_lc_rs::default_provider();
|
||||
let provider = rustls::crypto::ring::default_provider();
|
||||
provider
|
||||
.signature_verification_algorithms
|
||||
.supported_schemes()
|
||||
|
||||
@@ -3790,17 +3790,13 @@ async fn apply_out_broadcast_changes(
|
||||
} else if from_id == ContactId::SELF
|
||||
&& let Some(removed_id) = removed_id
|
||||
{
|
||||
if chat::remove_from_chat_contacts_table_without_trace(context, chat.id, removed_id)
|
||||
.await?
|
||||
{
|
||||
better_msg.get_or_insert(
|
||||
stock_str::msg_del_member_local(context, removed_id, ContactId::SELF).await,
|
||||
);
|
||||
added_removed_id = Some(removed_id);
|
||||
} else {
|
||||
info!(context, "No-op broadcast member removal message (TRASH).");
|
||||
better_msg = Some("".to_string());
|
||||
}
|
||||
chat::remove_from_chat_contacts_table_without_trace(context, chat.id, removed_id)
|
||||
.await?;
|
||||
|
||||
better_msg.get_or_insert(
|
||||
stock_str::msg_del_member_local(context, removed_id, ContactId::SELF).await,
|
||||
);
|
||||
added_removed_id = Some(removed_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3874,20 +3870,17 @@ async fn apply_in_broadcast_changes(
|
||||
}
|
||||
chat::delete_broadcast_secret(context, chat.id).await?;
|
||||
|
||||
let removed =
|
||||
chat::remove_from_chat_contacts_table_without_trace(context, chat.id, ContactId::SELF)
|
||||
.await?;
|
||||
if !removed {
|
||||
info!(context, "No-op broadcast SELF-removal message (TRASH).");
|
||||
better_msg = Some("".to_string());
|
||||
} else if from_id == ContactId::SELF {
|
||||
if from_id == ContactId::SELF {
|
||||
better_msg.get_or_insert(stock_str::msg_you_left_broadcast(context));
|
||||
} else {
|
||||
better_msg.get_or_insert(
|
||||
stock_str::msg_del_member_local(context, ContactId::SELF, from_id).await,
|
||||
);
|
||||
}
|
||||
send_event_chat_modified |= removed;
|
||||
|
||||
chat::remove_from_chat_contacts_table_without_trace(context, chat.id, ContactId::SELF)
|
||||
.await?;
|
||||
send_event_chat_modified = true;
|
||||
} else if !chat.is_self_in_chat(context).await? {
|
||||
chat::add_to_chat_contacts_table(
|
||||
context,
|
||||
|
||||
@@ -35,7 +35,6 @@ struct Statistics {
|
||||
core_version: String,
|
||||
number_of_transports: usize,
|
||||
key_create_timestamps: Vec<u32>,
|
||||
number_of_keys: u32,
|
||||
/// OpenPGP version of the key.
|
||||
key_version: u8,
|
||||
key_algorithm: String,
|
||||
@@ -356,11 +355,6 @@ async fn get_stats(context: &Context) -> Result<String> {
|
||||
// `key_create_timestamps` is a `Vec` for historical reasons,
|
||||
// support for using multiple keys is being phased out.
|
||||
let key_create_timestamps: Vec<u32> = vec![self_public_key.created_at().as_secs()];
|
||||
let number_of_keys: u32 = context
|
||||
.sql
|
||||
.query_get_value("SELECT COUNT(*) FROM keypairs", ())
|
||||
.await?
|
||||
.unwrap_or(0);
|
||||
|
||||
let sending_enabled_timestamps =
|
||||
get_timestamps(context, "stats_sending_enabled_events").await?;
|
||||
@@ -371,7 +365,6 @@ async fn get_stats(context: &Context) -> Result<String> {
|
||||
core_version: DC_VERSION_STR.to_string(),
|
||||
number_of_transports: context.count_transports().await?,
|
||||
key_create_timestamps,
|
||||
number_of_keys,
|
||||
key_version: self_public_key.primary_key.version().into(),
|
||||
key_algorithm: format!("{:?}", self_public_key.algorithm()),
|
||||
pubkey_size: DcKey::to_bytes(&self_public_key).len(),
|
||||
|
||||
@@ -847,8 +847,11 @@ fn parse_webxdc_manifest(bytes: &[u8]) -> Result<WebxdcManifest> {
|
||||
}
|
||||
|
||||
async fn get_blob(archive: &mut SeekZipFileReader<BufReader<File>>, name: &str) -> Result<Vec<u8>> {
|
||||
let (i, _) =
|
||||
let (i, entry) =
|
||||
find_zip_entry(archive.file(), name).ok_or_else(|| anyhow!("no entry found for {name}"))?;
|
||||
if entry.dir()? {
|
||||
bail!("'{name}' is a directory not a file.")
|
||||
}
|
||||
let mut reader = archive.reader_with_entry(i).await?;
|
||||
let mut buf = Vec::new();
|
||||
reader.read_to_end_checked(&mut buf).await?;
|
||||
@@ -903,7 +906,28 @@ impl Message {
|
||||
));
|
||||
}
|
||||
|
||||
get_blob(&mut archive, name).await
|
||||
let result = get_blob(&mut archive, name).await;
|
||||
// not found and no extension, then assume directory and try index.html
|
||||
// this mimics how webservers behave.
|
||||
if result.is_err() && !name.contains('.') {
|
||||
let base = if name.ends_with('/') {
|
||||
name.to_string()
|
||||
} else {
|
||||
format!("{name}/")
|
||||
};
|
||||
// ignore first slash. So that requesting "" for index.html works
|
||||
let base = base.trim_start_matches('/');
|
||||
let fallbacks = [format!("{base}index.html"), format!("{base}index.htm")];
|
||||
for fallback in &fallbacks {
|
||||
let result = get_blob(&mut archive, fallback).await;
|
||||
if result.is_ok() {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
result // return orginal error to the path that was requested, not the fallback
|
||||
} else {
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
/// Return info from manifest.toml or from fallbacks.
|
||||
|
||||
@@ -1144,6 +1144,49 @@ async fn test_get_webxdc_blob_with_subdirs() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_get_webxdc_blob_indexhtml_fallback() -> Result<()> {
|
||||
let t = &TestContext::new_alice().await;
|
||||
let chat_id = create_group(t, "foo").await?;
|
||||
let instance = {
|
||||
let mut instance = create_webxdc_instance(
|
||||
t,
|
||||
"indexhtml-fallback.xdc",
|
||||
include_bytes!("../../test-data/webxdc/indexhtml-fallback.xdc"),
|
||||
)?;
|
||||
let instance_msg_id = send_msg(t, chat_id, &mut instance).await?;
|
||||
assert_eq!(instance.viewtype, Viewtype::Webxdc);
|
||||
Message::load_from_db(t, instance_msg_id).await?
|
||||
};
|
||||
|
||||
// "../" links that go back should work
|
||||
assert!(instance.get_webxdc_blob(t, "").await.is_ok());
|
||||
// test falling back to index.html
|
||||
assert!(instance.get_webxdc_blob(t, "/alpha").await.is_ok());
|
||||
assert!(instance.get_webxdc_blob(t, "/alpha/").await.is_ok());
|
||||
// test falling back to index.htm
|
||||
assert!(instance.get_webxdc_blob(t, "/beta").await.is_ok());
|
||||
assert!(instance.get_webxdc_blob(t, "/beta/").await.is_ok());
|
||||
// test that original error is still there when there is no index.htm(l) file
|
||||
assert!(instance.get_webxdc_blob(t, "/control").await.is_err());
|
||||
println!("{:?}", instance.get_webxdc_blob(t, "/control/").await);
|
||||
println!(
|
||||
"{:?}",
|
||||
instance.get_webxdc_blob(t, "/control/were.html").await
|
||||
);
|
||||
|
||||
assert!(instance.get_webxdc_blob(t, "/control/").await.is_err());
|
||||
assert!(
|
||||
!instance
|
||||
.get_webxdc_blob(t, "/control/")
|
||||
.await
|
||||
.expect_err("error expected because there is no index.html")
|
||||
.to_string()
|
||||
.contains("control/index.html")
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_parse_webxdc_manifest() -> Result<()> {
|
||||
let result = parse_webxdc_manifest(r#"key = syntax error"#.as_bytes());
|
||||
|
||||
BIN
test-data/webxdc/indexhtml-fallback.xdc
Normal file
BIN
test-data/webxdc/indexhtml-fallback.xdc
Normal file
Binary file not shown.
Reference in New Issue
Block a user