mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-10-09 02:54:14 +00:00
fix legacy upgrade issue
This commit is contained in:
parent
c4f99fd96d
commit
c25d1eccbe
20 changed files with 500 additions and 42 deletions
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "DELETE FROM signal_session_resets",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 0
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "0134b965d7cbf9feda5bfc93bc410d91414a44251857ba9b462c99ff88c104f3"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "SELECT group_id FROM groups ORDER BY total_media_counter DESC LIMIT 1",
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "group_id",
|
||||||
|
"ordinal": 0,
|
||||||
|
"type_info": "Text",
|
||||||
|
"origin": {
|
||||||
|
"Table": {
|
||||||
|
"table": "groups",
|
||||||
|
"name": "group_id"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 0
|
||||||
|
},
|
||||||
|
"nullable": [
|
||||||
|
false
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hash": "06fdf3188c162f0cc9240c17506c3f2afc80d819583d005471e2c9968dca85e2"
|
||||||
|
}
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
{
|
|
||||||
"db_name": "SQLite",
|
|
||||||
"query": "\n INSERT OR REPLACE INTO receipts(receipt_id, contact_id, message, contact_will_sends_receipt, wake_receiver)\n VALUES (?, ?, ?, ?, ?)\n ",
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"parameters": {
|
|
||||||
"Right": 5
|
|
||||||
},
|
|
||||||
"nullable": []
|
|
||||||
},
|
|
||||||
"hash": "141c8905f5d1f47fdbd88a007115dda16edadf2e6f92e7b190e99925870bdc18"
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "\n INSERT INTO signal_identities(name, identity_key, timestamp)\n VALUES('restored-peer', x'040506', 1)\n ",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 0
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "1d5f5de6b4d541014f651aa00a2fc91cf407fef2c34a5248fca3f02dc0a4c06e"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "SELECT COUNT(*) AS \"count!: i64\" FROM signal_sessions",
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "count!: i64",
|
||||||
|
"ordinal": 0,
|
||||||
|
"type_info": "Integer",
|
||||||
|
"origin": "Expression"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 0
|
||||||
|
},
|
||||||
|
"nullable": [
|
||||||
|
false
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hash": "34ad29e5771ec73110b509a063ff69e5f4b349c2efab46a250a1952ea4e7ade5"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "\n INSERT INTO receipts(receipt_id, contact_id, message, contact_will_sends_receipt, wake_receiver)\n VALUES (?, ?, ?, ?, ?)\n ON CONFLICT(receipt_id) DO NOTHING\n ",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 5
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "36b3701a17e020cc774c15ea84267e5f99d53ac3aca4adb323697cb87e683b1f"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "\n INSERT INTO legacy_upgrade_requests(contact_id, requested_at)\n VALUES (?, ?)\n ON CONFLICT(contact_id) DO UPDATE SET requested_at = excluded.requested_at\n WHERE legacy_upgrade_requests.requested_at <= ?\n ",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 3
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "420d5c24bbac17a8f4db4088515782c5576ea708c9168ea2d05babd8c5a175f4"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "DELETE FROM signal_sessions",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 0
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "43583f8246016d15d9875c4d33855317c41ae07af5676228c0533724590ec6ed"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "\n INSERT INTO signal_sessions(name, device_id, record_bytes)\n VALUES('restored-peer', 1, x'010203')\n ",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 0
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "74323299e0c048f9395ead9775a1e4b61fcc935db89378e80f30344b8c115a81"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "SELECT identity_key FROM signal_identities WHERE name = 'restored-peer'",
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "identity_key",
|
||||||
|
"ordinal": 0,
|
||||||
|
"type_info": "Blob",
|
||||||
|
"origin": {
|
||||||
|
"Table": {
|
||||||
|
"table": "signal_identities",
|
||||||
|
"name": "identity_key"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 0
|
||||||
|
},
|
||||||
|
"nullable": [
|
||||||
|
false
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hash": "74e4937df433524718139d6868c4fc474939148de0f885103e7a4f39b241b553"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "SELECT COUNT(*) AS \"count!: i64\" FROM signal_session_resets",
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "count!: i64",
|
||||||
|
"ordinal": 0,
|
||||||
|
"type_info": "Integer",
|
||||||
|
"origin": "Expression"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 0
|
||||||
|
},
|
||||||
|
"nullable": [
|
||||||
|
false
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hash": "75f560bc922045cfacf0b5ef1f7772372cea08954859dc64de961c715ce4c55a"
|
||||||
|
}
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
{
|
|
||||||
"db_name": "SQLite",
|
|
||||||
"query": "DELETE FROM receipts WHERE contact_id = ?",
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"parameters": {
|
|
||||||
"Right": 1
|
|
||||||
},
|
|
||||||
"nullable": []
|
|
||||||
},
|
|
||||||
"hash": "83913e710fbd04e98cd6de21e7c917ed6472ef90230a10a69f74cb07d31a99fa"
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "UPDATE groups SET\n flame_counter = ?,\n last_flame_counter_change = ?,\n last_message_send = ?,\n last_message_received = ?\n WHERE group_id = ?",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 5
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "a40ea0dd25f0a1909a08aa2e1db6c5f360646a931a7e747047364a81f1e67ab5"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "SELECT max_flame_counter, max_flame_counter_from FROM groups WHERE group_id = ?",
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "max_flame_counter",
|
||||||
|
"ordinal": 0,
|
||||||
|
"type_info": "Integer",
|
||||||
|
"origin": {
|
||||||
|
"Table": {
|
||||||
|
"table": "groups",
|
||||||
|
"name": "max_flame_counter"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "max_flame_counter_from",
|
||||||
|
"ordinal": 1,
|
||||||
|
"type_info": "Integer",
|
||||||
|
"origin": {
|
||||||
|
"Table": {
|
||||||
|
"table": "groups",
|
||||||
|
"name": "max_flame_counter_from"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 1
|
||||||
|
},
|
||||||
|
"nullable": [
|
||||||
|
false,
|
||||||
|
true
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hash": "b7c5107cc99685fcb27557600950b1abcb5af657b66319a01fbe7512341bdf6b"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "SELECT flame_counter, max_flame_counter, max_flame_counter_from,\n last_message_send, last_message_received, last_flame_counter_change\n FROM groups WHERE group_id = ?",
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "flame_counter",
|
||||||
|
"ordinal": 0,
|
||||||
|
"type_info": "Integer",
|
||||||
|
"origin": {
|
||||||
|
"Table": {
|
||||||
|
"table": "groups",
|
||||||
|
"name": "flame_counter"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "max_flame_counter",
|
||||||
|
"ordinal": 1,
|
||||||
|
"type_info": "Integer",
|
||||||
|
"origin": {
|
||||||
|
"Table": {
|
||||||
|
"table": "groups",
|
||||||
|
"name": "max_flame_counter"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "max_flame_counter_from",
|
||||||
|
"ordinal": 2,
|
||||||
|
"type_info": "Integer",
|
||||||
|
"origin": {
|
||||||
|
"Table": {
|
||||||
|
"table": "groups",
|
||||||
|
"name": "max_flame_counter_from"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "last_message_send",
|
||||||
|
"ordinal": 3,
|
||||||
|
"type_info": "Integer",
|
||||||
|
"origin": {
|
||||||
|
"Table": {
|
||||||
|
"table": "groups",
|
||||||
|
"name": "last_message_send"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "last_message_received",
|
||||||
|
"ordinal": 4,
|
||||||
|
"type_info": "Integer",
|
||||||
|
"origin": {
|
||||||
|
"Table": {
|
||||||
|
"table": "groups",
|
||||||
|
"name": "last_message_received"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "last_flame_counter_change",
|
||||||
|
"ordinal": 5,
|
||||||
|
"type_info": "Integer",
|
||||||
|
"origin": {
|
||||||
|
"Table": {
|
||||||
|
"table": "groups",
|
||||||
|
"name": "last_flame_counter_change"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 1
|
||||||
|
},
|
||||||
|
"nullable": [
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hash": "cb70d13126eded79712bbbfed1ae0d13c4857c1c2442be753d5ba34bf96aceb5"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "\n INSERT INTO signal_session_resets(\n name, device_id, last_reset_at, window_started_at, resets_in_window\n ) VALUES('restored-peer', 1, 1, 1, 1)\n ",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 0
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "db5192b62d8a4f9f23ad7befff1b9e8e463134a2cf90363a4a98d6b5b37fc723"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "SELECT group_id, flame_counter, also_best_friend,\n last_message_send, last_message_received, last_flame_counter_change\n FROM groups",
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "group_id",
|
||||||
|
"ordinal": 0,
|
||||||
|
"type_info": "Text",
|
||||||
|
"origin": {
|
||||||
|
"Table": {
|
||||||
|
"table": "groups",
|
||||||
|
"name": "group_id"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "flame_counter",
|
||||||
|
"ordinal": 1,
|
||||||
|
"type_info": "Integer",
|
||||||
|
"origin": {
|
||||||
|
"Table": {
|
||||||
|
"table": "groups",
|
||||||
|
"name": "flame_counter"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "also_best_friend",
|
||||||
|
"ordinal": 2,
|
||||||
|
"type_info": "Integer",
|
||||||
|
"origin": {
|
||||||
|
"Table": {
|
||||||
|
"table": "groups",
|
||||||
|
"name": "also_best_friend"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "last_message_send",
|
||||||
|
"ordinal": 3,
|
||||||
|
"type_info": "Integer",
|
||||||
|
"origin": {
|
||||||
|
"Table": {
|
||||||
|
"table": "groups",
|
||||||
|
"name": "last_message_send"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "last_message_received",
|
||||||
|
"ordinal": 4,
|
||||||
|
"type_info": "Integer",
|
||||||
|
"origin": {
|
||||||
|
"Table": {
|
||||||
|
"table": "groups",
|
||||||
|
"name": "last_message_received"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "last_flame_counter_change",
|
||||||
|
"ordinal": 5,
|
||||||
|
"type_info": "Integer",
|
||||||
|
"origin": {
|
||||||
|
"Table": {
|
||||||
|
"table": "groups",
|
||||||
|
"name": "last_flame_counter_change"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 0
|
||||||
|
},
|
||||||
|
"nullable": [
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hash": "df4c2b8e3b106c3f91e4d816627c7985c9f56fa459c16357d727fc292d226529"
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"db_name": "SQLite",
|
"db_name": "SQLite",
|
||||||
"query": "SELECT group_id, total_media_counter, last_flame_counter_change,\n last_flame_sync, flame_counter\n FROM groups WHERE last_flame_counter_change IS NOT NULL",
|
"query": "SELECT group_id, total_media_counter, last_flame_counter_change, last_flame_sync\n FROM groups WHERE last_flame_counter_change IS NOT NULL",
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
|
|
@ -46,17 +46,6 @@
|
||||||
"name": "last_flame_sync"
|
"name": "last_flame_sync"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "flame_counter",
|
|
||||||
"ordinal": 4,
|
|
||||||
"type_info": "Integer",
|
|
||||||
"origin": {
|
|
||||||
"Table": {
|
|
||||||
"table": "groups",
|
|
||||||
"name": "flame_counter"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"parameters": {
|
"parameters": {
|
||||||
|
|
@ -66,9 +55,8 @@
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
true,
|
true
|
||||||
false
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"hash": "10facb63e1057c6acfe8b60cfe5f6deb3535eed60977d917f57cae97bb220e30"
|
"hash": "fef6c2ffbb80a5aa1e9cc70e3971cd9dfe0f828b984e18dff15c77389165b27c"
|
||||||
}
|
}
|
||||||
|
|
@ -297,8 +297,9 @@ async fn reset_unusable_session(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rebuilds a v2 Signal session for a peer that still speaks the legacy
|
/// Rebuilds a v2 Signal session for a peer that still speaks the legacy
|
||||||
/// protocol, so the decryption error queued for the message can be answered
|
/// protocol, so what we send them next already goes out as v2. The decryption
|
||||||
/// with a session the peer can upgrade to.
|
/// error answering their legacy message is plaintext and does not use it; see
|
||||||
|
/// [`claim_legacy_upgrade_request`] for how the peer itself is moved to v2.
|
||||||
///
|
///
|
||||||
/// Runs before the inbound transaction opens: it awaits a server round-trip and
|
/// Runs before the inbound transaction opens: it awaits a server round-trip and
|
||||||
/// `establish_signal_session` writes through the pool, and the app database
|
/// `establish_signal_session` writes through the pool, and the app database
|
||||||
|
|
@ -347,6 +348,43 @@ async fn upgrade_legacy_session_to_v2(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// How long a legacy peer is given to move to v2 before it is asked again.
|
||||||
|
const LEGACY_UPGRADE_REQUEST_INTERVAL_SECS: i64 = 60 * 60;
|
||||||
|
|
||||||
|
/// Claims the right to ask a legacy peer to move to v2, at most once per
|
||||||
|
/// [`LEGACY_UPGRADE_REQUEST_INTERVAL_SECS`].
|
||||||
|
///
|
||||||
|
/// Clients before 0.6.0 fetch a fresh prekey bundle only for a
|
||||||
|
/// `PREKEY_UNKNOWN` decryption error, and that bundle is what switches the
|
||||||
|
/// contact to v2 on their side. They answer every decryption error by resending
|
||||||
|
/// the same queued message, still encrypted as v1, so answering each of those
|
||||||
|
/// resends would never end and would spend one of our one-time prekeys per
|
||||||
|
/// round. Leaving the resends unanswered stops the loop: without a reply the
|
||||||
|
/// old client does not send the message again.
|
||||||
|
async fn claim_legacy_upgrade_request(
|
||||||
|
t: &mut Transaction<'_, Sqlite>,
|
||||||
|
contact_id: i64,
|
||||||
|
) -> Result<bool> {
|
||||||
|
let now = crate::utils::current_time().timestamp();
|
||||||
|
let asked_before = now - LEGACY_UPGRADE_REQUEST_INTERVAL_SECS;
|
||||||
|
let claimed = sqlx::query!(
|
||||||
|
r#"
|
||||||
|
INSERT INTO legacy_upgrade_requests(contact_id, requested_at)
|
||||||
|
VALUES (?, ?)
|
||||||
|
ON CONFLICT(contact_id) DO UPDATE SET requested_at = excluded.requested_at
|
||||||
|
WHERE legacy_upgrade_requests.requested_at <= ?
|
||||||
|
"#,
|
||||||
|
contact_id,
|
||||||
|
now,
|
||||||
|
asked_before,
|
||||||
|
)
|
||||||
|
.execute(&mut **t)
|
||||||
|
.await?
|
||||||
|
.rows_affected()
|
||||||
|
> 0;
|
||||||
|
Ok(claimed)
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument(
|
#[tracing::instrument(
|
||||||
skip_all,
|
skip_all,
|
||||||
fields(
|
fields(
|
||||||
|
|
@ -466,7 +504,22 @@ pub async fn handle_decoded_server_message(
|
||||||
handle_sender_delivery_receipt(&mut t, from_user_id, &message.receipt_id).await?;
|
handle_sender_delivery_receipt(&mut t, from_user_id, &message.receipt_id).await?;
|
||||||
}
|
}
|
||||||
Type::Ciphertext | Type::PrekeyBundle => {
|
Type::Ciphertext | Type::PrekeyBundle => {
|
||||||
queue_decryption_error(&mut t, from_user_id, &message.receipt_id, 0).await?;
|
if claim_legacy_upgrade_request(&mut t, from_user_id).await? {
|
||||||
|
tracing::info!("Asking the legacy peer to fetch our v2 prekey bundle");
|
||||||
|
queue_decryption_error(
|
||||||
|
&mut t,
|
||||||
|
from_user_id,
|
||||||
|
&message.receipt_id,
|
||||||
|
DecryptionErrorType::PrekeyUnknown as i32,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
} else {
|
||||||
|
tracing::info!(
|
||||||
|
"Leaving a legacy message unanswered; the peer was already asked to upgrade"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Never acknowledged: the message was not read, so the sender must
|
||||||
|
// not be told it was delivered.
|
||||||
sends_error_response = true;
|
sends_error_response = true;
|
||||||
}
|
}
|
||||||
Type::CiphertextV2 => {
|
Type::CiphertextV2 => {
|
||||||
|
|
@ -913,4 +966,37 @@ mod tests {
|
||||||
.unwrap_or_else(PoisonError::into_inner)
|
.unwrap_or_else(PoisonError::into_inner)
|
||||||
.contains_key(receipt_id));
|
.contains_key(receipt_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An old client resends the same v1 message for every decryption error,
|
||||||
|
/// so only the first one in an interval may be answered.
|
||||||
|
#[tokio::test]
|
||||||
|
async fn a_legacy_peer_is_asked_to_upgrade_once_per_interval() {
|
||||||
|
let directory = tempfile::tempdir().unwrap();
|
||||||
|
let path = directory.path().join("app.sqlite");
|
||||||
|
let database = crate::database::app::AppDatabase::new(path.to_str().unwrap(), None, false)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
database.run_migrations().await.unwrap();
|
||||||
|
sqlx::query("INSERT INTO contacts(user_id, username) VALUES (7, 'alice')")
|
||||||
|
.execute(&database.pool)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut t = database.pool.begin().await.unwrap();
|
||||||
|
assert!(claim_legacy_upgrade_request(&mut t, 7).await.unwrap());
|
||||||
|
assert!(!claim_legacy_upgrade_request(&mut t, 7).await.unwrap());
|
||||||
|
t.commit().await.unwrap();
|
||||||
|
|
||||||
|
// Once the interval has passed without the peer upgrading, it is asked
|
||||||
|
// again, for example because its bundle fetch failed.
|
||||||
|
sqlx::query("UPDATE legacy_upgrade_requests SET requested_at = requested_at - ?")
|
||||||
|
.bind(LEGACY_UPGRADE_REQUEST_INTERVAL_SECS)
|
||||||
|
.execute(&database.pool)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let mut t = database.pool.begin().await.unwrap();
|
||||||
|
assert!(claim_legacy_upgrade_request(&mut t, 7).await.unwrap());
|
||||||
|
assert!(!claim_legacy_upgrade_request(&mut t, 7).await.unwrap());
|
||||||
|
t.commit().await.unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
-- When a peer still sending legacy (v1) Signal messages was last asked to move
|
||||||
|
-- to v2. Older clients retry every decryption error with the same v1
|
||||||
|
-- ciphertext, so the request is answered once per interval and the retries in
|
||||||
|
-- between are left unanswered, which is what ends that loop.
|
||||||
|
CREATE TABLE legacy_upgrade_requests (
|
||||||
|
contact_id INTEGER PRIMARY KEY REFERENCES contacts(user_id) ON DELETE CASCADE,
|
||||||
|
requested_at INTEGER NOT NULL
|
||||||
|
);
|
||||||
Loading…
Reference in a new issue