mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-10-09 02:54:14 +00:00
Merge branch 'hotfix' into dev
This commit is contained in:
commit
856a67edaa
6 changed files with 115 additions and 6 deletions
|
|
@ -1,5 +1,14 @@
|
|||
# Changelog
|
||||
|
||||
## 0.5.4
|
||||
|
||||
- Fix: Recover broken sessions more reliably
|
||||
|
||||
## 0.5.3
|
||||
|
||||
- Hotfix: Fixed stuck Signal sessions
|
||||
- Improve: Gracefully upgrade all sessions to PQXDH
|
||||
|
||||
## 0.5.2
|
||||
|
||||
- Hotfix: Fixed an infinite loop involving delivery receipts
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
ce49e7d90cd902197f9a9cbc84219d23
|
||||
|
|
@ -136,8 +136,10 @@ class MainCameraController {
|
|||
try {
|
||||
await cameraControllerTemp?.stopImageStream();
|
||||
// ignore: empty_catches
|
||||
} catch (e) {}
|
||||
} catch (e) {
|
||||
} finally {
|
||||
await cameraControllerTemp?.dispose();
|
||||
}
|
||||
},
|
||||
);
|
||||
initCameraStarted = false;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ description: "twonly, a privacy-friendly way to connect with friends through sec
|
|||
|
||||
publish_to: 'none'
|
||||
|
||||
version: 0.6.0+173
|
||||
version: 0.6.0+175
|
||||
|
||||
environment:
|
||||
sdk: ^3.11.0
|
||||
|
|
|
|||
|
|
@ -420,9 +420,26 @@ impl ApiClient {
|
|||
break;
|
||||
}
|
||||
// Tungstenite message
|
||||
if let stream_tungstenite::tokio_tungstenite::tungstenite::Message::Binary(bytes) = &*msg {
|
||||
use stream_tungstenite::tokio_tungstenite::tungstenite::Message;
|
||||
match &*msg {
|
||||
Message::Binary(bytes) => {
|
||||
self_clone.handle_incoming(&connection, bytes).await;
|
||||
}
|
||||
// The server's close code tells why it dropped the
|
||||
// connection, e.g. 1013 (outbound queue full) or 4003
|
||||
// (ack timeouts). The disconnect event does not carry it.
|
||||
Message::Close(frame) => match frame {
|
||||
Some(frame) => tracing::info!(
|
||||
"websocket closed by the server with code {}: {}",
|
||||
u16::from(frame.code),
|
||||
frame.reason
|
||||
),
|
||||
None => tracing::info!(
|
||||
"websocket closed by the server without a code"
|
||||
),
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Err(_) => break,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -972,6 +972,88 @@ mod tests {
|
|||
assert!(!bob.reset_session("carol", 1, false).await.unwrap());
|
||||
}
|
||||
|
||||
/// The user-initiated reset: the record is gone, nothing encrypts for the
|
||||
/// peer until a fresh bundle builds a new session, and that one works.
|
||||
#[tokio::test]
|
||||
async fn hard_reset_deletes_and_allows_rebuilding_a_contact_session() {
|
||||
let (alice, _alice_dir) = create_test_engine("alice").await;
|
||||
let (bob, _bob_dir) = create_test_engine("bob").await;
|
||||
|
||||
alice
|
||||
.process_prekey_bundle("bob".to_string(), 1, bob.generate_bundle().await.unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(alice.reset_session("bob", 1, true).await.unwrap());
|
||||
assert!(!alice.reset_session("bob", 1, true).await.unwrap());
|
||||
assert!(alice
|
||||
.encrypt_message("bob".to_string(), 1, b"missing".to_vec())
|
||||
.await
|
||||
.is_err());
|
||||
|
||||
alice
|
||||
.process_prekey_bundle("bob".to_string(), 1, bob.generate_bundle().await.unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(ping(&alice, &bob, "rebuilt").await.unwrap(), b"rebuilt");
|
||||
}
|
||||
|
||||
/// A message decrypted twice is a duplicate, for prekey and whisper
|
||||
/// messages alike, and never reported as an unusable session.
|
||||
#[tokio::test]
|
||||
async fn decrypting_a_message_twice_reports_a_duplicate() {
|
||||
let (alice, _alice_dir) = create_test_engine("alice").await;
|
||||
let (bob, _bob_dir) = create_test_engine("bob").await;
|
||||
|
||||
alice
|
||||
.process_prekey_bundle("bob".to_string(), 1, bob.generate_bundle().await.unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let prekey_message = alice
|
||||
.encrypt_message("bob".to_string(), 1, b"first".to_vec())
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
prekey_message.last(),
|
||||
Some(&(CiphertextMessageType::PreKey as u8))
|
||||
);
|
||||
bob.decrypt_message("alice".to_string(), 1, prekey_message.clone())
|
||||
.await
|
||||
.unwrap();
|
||||
let error = bob
|
||||
.decrypt_message("alice".to_string(), 1, prekey_message)
|
||||
.await
|
||||
.unwrap_err();
|
||||
assert!(
|
||||
matches!(error, TwonlyError::SignalDuplicateMessage(_)),
|
||||
"{error}"
|
||||
);
|
||||
|
||||
// After Bob's reply Alice no longer needs a PreKey message.
|
||||
ping(&bob, &alice, "reply").await.unwrap();
|
||||
let whisper_message = alice
|
||||
.encrypt_message("bob".to_string(), 1, b"second".to_vec())
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
whisper_message.last(),
|
||||
Some(&(CiphertextMessageType::Whisper as u8))
|
||||
);
|
||||
bob.decrypt_message("alice".to_string(), 1, whisper_message.clone())
|
||||
.await
|
||||
.unwrap();
|
||||
let error = bob
|
||||
.decrypt_message("alice".to_string(), 1, whisper_message)
|
||||
.await
|
||||
.unwrap_err();
|
||||
assert!(
|
||||
matches!(error, TwonlyError::SignalDuplicateMessage(_)),
|
||||
"{error}"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_twonly_api_100_messages() -> std::result::Result<(), Box<dyn std::error::Error>> {
|
||||
use crate::database::signal::Database;
|
||||
|
|
|
|||
Loading…
Reference in a new issue