Our Personal Data Server from scratch! tranquil.farm
atproto pds rust postgresql fun oauth

feat(signal): add postgres-backed signal protocol store #88

merged opened by oyster.cafe targeting main from feat/signal-client-in-house
Labels

None yet.

assignee

None yet.

Participants 1
AT URI
at://did:plc:3fwecdnvtcscjnrx2p4n7alz/sh.tangled.repo.pull/3mhlxir6eha22
+3397 -104
Diff #0
+12
.sqlx/query-0295414146e4ddacad638486443fd1036609ab8443390820be8696f708be3812.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "DELETE FROM signal_kyber_pre_keys", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [] 8 + }, 9 + "nullable": [] 10 + }, 11 + "hash": "0295414146e4ddacad638486443fd1036609ab8443390820be8696f708be3812" 12 + }
+18
.sqlx/query-0a3eaf432e99ef22aa6b3b43978740b085f6416a058ea2da6d639ea1cf276eda.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "INSERT INTO signal_sender_keys\n (address, device_id, identity, distribution_id, record)\n VALUES ($1, $2, $3, $4, $5)\n ON CONFLICT (address, device_id, identity, distribution_id) DO UPDATE SET record = $5", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [ 8 + "Text", 9 + "Int4", 10 + "Text", 11 + "Uuid", 12 + "Bytea" 13 + ] 14 + }, 15 + "nullable": [] 16 + }, 17 + "hash": "0a3eaf432e99ef22aa6b3b43978740b085f6416a058ea2da6d639ea1cf276eda" 18 + }
+12
.sqlx/query-166ee5a554e3ddc75496616d9fba75a15cc0c072f493f579b881a4f2300f38c8.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "DELETE FROM signal_kv", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [] 8 + }, 9 + "nullable": [] 10 + }, 11 + "hash": "166ee5a554e3ddc75496616d9fba75a15cc0c072f493f579b881a4f2300f38c8" 12 + }
+23
.sqlx/query-1a061c261518573c29aa55c5d8e2181f1728034e723ed0bc836e928b4c69128f.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "SELECT record FROM signal_signed_pre_keys WHERE id = $1 AND identity = $2", 4 + "describe": { 5 + "columns": [ 6 + { 7 + "ordinal": 0, 8 + "name": "record", 9 + "type_info": "Bytea" 10 + } 11 + ], 12 + "parameters": { 13 + "Left": [ 14 + "Int4", 15 + "Text" 16 + ] 17 + }, 18 + "nullable": [ 19 + false 20 + ] 21 + }, 22 + "hash": "1a061c261518573c29aa55c5d8e2181f1728034e723ed0bc836e928b4c69128f" 23 + }
+23
.sqlx/query-1aac5ab7dbc29f0d0937767ae174e8b47d236b3cdc973974cec413dc65198d64.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "SELECT record FROM signal_kyber_pre_keys WHERE id = $1 AND identity = $2", 4 + "describe": { 5 + "columns": [ 6 + { 7 + "ordinal": 0, 8 + "name": "record", 9 + "type_info": "Bytea" 10 + } 11 + ], 12 + "parameters": { 13 + "Left": [ 14 + "Int4", 15 + "Text" 16 + ] 17 + }, 18 + "nullable": [ 19 + false 20 + ] 21 + }, 22 + "hash": "1aac5ab7dbc29f0d0937767ae174e8b47d236b3cdc973974cec413dc65198d64" 23 + }
+16
.sqlx/query-1d4459863eeddea9ccb5ce5c0eaffd39d56a763728ce5b1f76871265e704e241.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "INSERT INTO signal_kyber_pre_keys (id, identity, record, is_last_resort)\n VALUES ($1, $2, $3, FALSE)\n ON CONFLICT (id, identity) DO UPDATE SET record = $3, is_last_resort = FALSE", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [ 8 + "Int4", 9 + "Text", 10 + "Bytea" 11 + ] 12 + }, 13 + "nullable": [] 14 + }, 15 + "hash": "1d4459863eeddea9ccb5ce5c0eaffd39d56a763728ce5b1f76871265e704e241" 16 + }
+15
.sqlx/query-1f464d947e93274cbc974f8a6f31d8a47eb676df857fa83f08ed1937cf8a6d9d.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "DELETE FROM signal_sessions WHERE address = $1 AND identity = $2", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [ 8 + "Text", 9 + "Text" 10 + ] 11 + }, 12 + "nullable": [] 13 + }, 14 + "hash": "1f464d947e93274cbc974f8a6f31d8a47eb676df857fa83f08ed1937cf8a6d9d" 15 + }
+12
.sqlx/query-222836500a964ee6fd238ddb128691215cd15d2ede9a1a19e7a580e4d6644ce8.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "DELETE FROM signal_base_keys_seen", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [] 8 + }, 9 + "nullable": [] 10 + }, 11 + "hash": "222836500a964ee6fd238ddb128691215cd15d2ede9a1a19e7a580e4d6644ce8" 12 + }
+12
.sqlx/query-252d42bb50ef918fe414d036979daba055dbadd3cd7e1bdcce4526867be79930.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "DELETE FROM signal_identities", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [] 8 + }, 9 + "nullable": [] 10 + }, 11 + "hash": "252d42bb50ef918fe414d036979daba055dbadd3cd7e1bdcce4526867be79930" 12 + }
+15
.sqlx/query-29c834b7870cdbcdcc2d2c9259a04326e20433237ebe25e33dbd39952ae9f976.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "INSERT INTO signal_kv (key, value) VALUES ($1, $2)\n ON CONFLICT (key) DO UPDATE SET value = $2", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [ 8 + "Text", 9 + "Bytea" 10 + ] 11 + }, 12 + "nullable": [] 13 + }, 14 + "hash": "29c834b7870cdbcdcc2d2c9259a04326e20433237ebe25e33dbd39952ae9f976" 15 + }
+17
.sqlx/query-31edfe22cdd8e5f62322dad01a65165ec9546eaa92c9e372a5a4fce99d938d22.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "INSERT INTO signal_base_keys_seen\n (kyber_pre_key_id, signed_pre_key_id, identity, base_key)\n VALUES ($1, $2, $3, $4)", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [ 8 + "Int4", 9 + "Int4", 10 + "Text", 11 + "Bytea" 12 + ] 13 + }, 14 + "nullable": [] 15 + }, 16 + "hash": "31edfe22cdd8e5f62322dad01a65165ec9546eaa92c9e372a5a4fce99d938d22" 17 + }
+12
.sqlx/query-374be0bd97ed927b15929e2f86d88913b2fec45ab67e4805fb9f1e39b422ee7f.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "DELETE FROM signal_kv WHERE key = 'registration'", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [] 8 + }, 9 + "nullable": [] 10 + }, 11 + "hash": "374be0bd97ed927b15929e2f86d88913b2fec45ab67e4805fb9f1e39b422ee7f" 12 + }
+15
.sqlx/query-3a3eee11be6a9c5fe012d2a634c7ef514fb695ca6a4ba7631d1c5aba87a854a5.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "DELETE FROM signal_pre_keys WHERE id = $1 AND identity = $2", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [ 8 + "Int4", 9 + "Text" 10 + ] 11 + }, 12 + "nullable": [] 13 + }, 14 + "hash": "3a3eee11be6a9c5fe012d2a634c7ef514fb695ca6a4ba7631d1c5aba87a854a5" 15 + }
+12
.sqlx/query-4011d789a6b619231f4e2b917753f0b4452f21243e1d95d47dbaa91cac019e64.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "DELETE FROM signal_sender_keys", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [] 8 + }, 9 + "nullable": [] 10 + }, 11 + "hash": "4011d789a6b619231f4e2b917753f0b4452f21243e1d95d47dbaa91cac019e64" 12 + }
+22
.sqlx/query-4316de453ec1d5ba65a1dbee29599287d42bf87517936b3b61958c0675ce8115.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "SELECT value FROM signal_kv WHERE key = $1", 4 + "describe": { 5 + "columns": [ 6 + { 7 + "ordinal": 0, 8 + "name": "value", 9 + "type_info": "Bytea" 10 + } 11 + ], 12 + "parameters": { 13 + "Left": [ 14 + "Text" 15 + ] 16 + }, 17 + "nullable": [ 18 + false 19 + ] 20 + }, 21 + "hash": "4316de453ec1d5ba65a1dbee29599287d42bf87517936b3b61958c0675ce8115" 22 + }
+12
.sqlx/query-43583f8246016d15d9875c4d33855317c41ae07af5676228c0533724590ec6ed.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "DELETE FROM signal_sessions", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [] 8 + }, 9 + "nullable": [] 10 + }, 11 + "hash": "43583f8246016d15d9875c4d33855317c41ae07af5676228c0533724590ec6ed" 12 + }
+23
.sqlx/query-4bcd896340fc9178e2d97ad572269e8f57561190ec5f94ccfa06ca93f4827e79.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "SELECT record FROM signal_identities WHERE address = $1 AND identity = $2", 4 + "describe": { 5 + "columns": [ 6 + { 7 + "ordinal": 0, 8 + "name": "record", 9 + "type_info": "Bytea" 10 + } 11 + ], 12 + "parameters": { 13 + "Left": [ 14 + "Text", 15 + "Text" 16 + ] 17 + }, 18 + "nullable": [ 19 + false 20 + ] 21 + }, 22 + "hash": "4bcd896340fc9178e2d97ad572269e8f57561190ec5f94ccfa06ca93f4827e79" 23 + }
+17
.sqlx/query-4d22ba21356bdc84ea549799c77cab8c34ca9a5f0815150254b590fd87509eb8.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "INSERT INTO signal_sessions (address, device_id, identity, record)\n VALUES ($1, $2, $3, $4)\n ON CONFLICT (address, device_id, identity) DO UPDATE SET record = $4", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [ 8 + "Text", 9 + "Int4", 10 + "Text", 11 + "Bytea" 12 + ] 13 + }, 14 + "nullable": [] 15 + }, 16 + "hash": "4d22ba21356bdc84ea549799c77cab8c34ca9a5f0815150254b590fd87509eb8" 17 + }
+23
.sqlx/query-513a0d3b907df1004f2178ebf14fc182f20fc13c5691cbeb7656d428cb6437f9.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "SELECT is_last_resort FROM signal_kyber_pre_keys WHERE id = $1 AND identity = $2", 4 + "describe": { 5 + "columns": [ 6 + { 7 + "ordinal": 0, 8 + "name": "is_last_resort", 9 + "type_info": "Bool" 10 + } 11 + ], 12 + "parameters": { 13 + "Left": [ 14 + "Int4", 15 + "Text" 16 + ] 17 + }, 18 + "nullable": [ 19 + false 20 + ] 21 + }, 22 + "hash": "513a0d3b907df1004f2178ebf14fc182f20fc13c5691cbeb7656d428cb6437f9" 23 + }
+14
.sqlx/query-53814b5db4f051c30573d146007ddc487f4c12c726bb970efe17e325536629e4.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "INSERT INTO signal_kv (key, value) VALUES ('master_key', $1)\n ON CONFLICT (key) DO UPDATE SET value = $1", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [ 8 + "Bytea" 9 + ] 10 + }, 11 + "nullable": [] 12 + }, 13 + "hash": "53814b5db4f051c30573d146007ddc487f4c12c726bb970efe17e325536629e4" 14 + }
+14
.sqlx/query-5cd556968671fc8ecf57dd7fd40f65e3a168f17bd389ce2cf7ddee27d810cf1d.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "INSERT INTO signal_kv (key, value) VALUES ('sender_certificate', $1)\n ON CONFLICT (key) DO UPDATE SET value = $1", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [ 8 + "Bytea" 9 + ] 10 + }, 11 + "nullable": [] 12 + }, 13 + "hash": "5cd556968671fc8ecf57dd7fd40f65e3a168f17bd389ce2cf7ddee27d810cf1d" 14 + }
+16
.sqlx/query-62dc57cf7ad007a6458df06619fe7e0bf5ffeba195e55793f6bf6d170e053226.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "INSERT INTO signal_identities (address, identity, record)\n VALUES ($1, $2, $3)\n ON CONFLICT (address, identity) DO UPDATE SET record = $3", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [ 8 + "Text", 9 + "Text", 10 + "Bytea" 11 + ] 12 + }, 13 + "nullable": [] 14 + }, 15 + "hash": "62dc57cf7ad007a6458df06619fe7e0bf5ffeba195e55793f6bf6d170e053226" 16 + }
+23
.sqlx/query-63ecf786e52a52d83232f6d4c8d93d5d7065f5dbfd3cd1e259d7990d02da1114.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "SELECT COUNT(*) AS \"count!\" FROM signal_kyber_pre_keys\n WHERE identity = $1 AND is_last_resort = $2", 4 + "describe": { 5 + "columns": [ 6 + { 7 + "ordinal": 0, 8 + "name": "count!", 9 + "type_info": "Int8" 10 + } 11 + ], 12 + "parameters": { 13 + "Left": [ 14 + "Text", 15 + "Bool" 16 + ] 17 + }, 18 + "nullable": [ 19 + null 20 + ] 21 + }, 22 + "hash": "63ecf786e52a52d83232f6d4c8d93d5d7065f5dbfd3cd1e259d7990d02da1114" 23 + }
+22
.sqlx/query-6a91d97ed4f955ce0936eced6318c630f39ebebc52cee584f1b0dacefec984cd.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "SELECT record FROM signal_kyber_pre_keys\n WHERE identity = $1 AND is_last_resort = TRUE", 4 + "describe": { 5 + "columns": [ 6 + { 7 + "ordinal": 0, 8 + "name": "record", 9 + "type_info": "Bytea" 10 + } 11 + ], 12 + "parameters": { 13 + "Left": [ 14 + "Text" 15 + ] 16 + }, 17 + "nullable": [ 18 + false 19 + ] 20 + }, 21 + "hash": "6a91d97ed4f955ce0936eced6318c630f39ebebc52cee584f1b0dacefec984cd" 22 + }
+12
.sqlx/query-6cb39ddd462ae93fe97d930ce64425ed16271adc4ca066c4d51bb742beffc22b.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "DELETE FROM signal_kv WHERE key = 'master_key'", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [] 8 + }, 9 + "nullable": [] 10 + }, 11 + "hash": "6cb39ddd462ae93fe97d930ce64425ed16271adc4ca066c4d51bb742beffc22b" 12 + }
+23
.sqlx/query-6cbfcd552a7b4eeb6a1e525f2f11e8f432405e3606e3af7d31b9eca32bc28607.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "SELECT record FROM signal_pre_keys WHERE id = $1 AND identity = $2", 4 + "describe": { 5 + "columns": [ 6 + { 7 + "ordinal": 0, 8 + "name": "record", 9 + "type_info": "Bytea" 10 + } 11 + ], 12 + "parameters": { 13 + "Left": [ 14 + "Int4", 15 + "Text" 16 + ] 17 + }, 18 + "nullable": [ 19 + false 20 + ] 21 + }, 22 + "hash": "6cbfcd552a7b4eeb6a1e525f2f11e8f432405e3606e3af7d31b9eca32bc28607" 23 + }
+14
.sqlx/query-6f14e2d74ed0c1e0946c62da2a3ddd63344892bdd4022073123604ee17114ce0.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "INSERT INTO signal_kv (key, value) VALUES ('registration', $1)\n ON CONFLICT (key) DO UPDATE SET value = $1", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [ 8 + "Bytea" 9 + ] 10 + }, 11 + "nullable": [] 12 + }, 13 + "hash": "6f14e2d74ed0c1e0946c62da2a3ddd63344892bdd4022073123604ee17114ce0" 14 + }
+16
.sqlx/query-811af305fef56437151c1cfe27eaccf6312b8234f1217a81a4d36cd5758fd863.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "INSERT INTO signal_pre_keys (id, identity, record)\n VALUES ($1, $2, $3)\n ON CONFLICT (id, identity) DO UPDATE SET record = $3", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [ 8 + "Int4", 9 + "Text", 10 + "Bytea" 11 + ] 12 + }, 13 + "nullable": [] 14 + }, 15 + "hash": "811af305fef56437151c1cfe27eaccf6312b8234f1217a81a4d36cd5758fd863" 16 + }
+23
.sqlx/query-894169c5a40acade1000869bdde61d09984e17a686c1b487004d79897ecb4e4f.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "INSERT INTO signal_profile_keys (uuid, key) VALUES ($1, $2)\n ON CONFLICT (uuid) DO UPDATE SET key = $2\n RETURNING (xmax = 0) AS \"inserted!\"", 4 + "describe": { 5 + "columns": [ 6 + { 7 + "ordinal": 0, 8 + "name": "inserted!", 9 + "type_info": "Bool" 10 + } 11 + ], 12 + "parameters": { 13 + "Left": [ 14 + "Uuid", 15 + "Bytea" 16 + ] 17 + }, 18 + "nullable": [ 19 + null 20 + ] 21 + }, 22 + "hash": "894169c5a40acade1000869bdde61d09984e17a686c1b487004d79897ecb4e4f" 23 + }
+22
.sqlx/query-9da9a790efa51edd6abcb4b0991b307c3ba7f0a929e114a4e0cb2ffb88adfbbb.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "SELECT MAX(id) FROM signal_kyber_pre_keys\n WHERE identity = $1 AND is_last_resort = TRUE", 4 + "describe": { 5 + "columns": [ 6 + { 7 + "ordinal": 0, 8 + "name": "max", 9 + "type_info": "Int4" 10 + } 11 + ], 12 + "parameters": { 13 + "Left": [ 14 + "Text" 15 + ] 16 + }, 17 + "nullable": [ 18 + null 19 + ] 20 + }, 21 + "hash": "9da9a790efa51edd6abcb4b0991b307c3ba7f0a929e114a4e0cb2ffb88adfbbb" 22 + }
+24
.sqlx/query-9fdcff515573446f0b4340bf94421bb8a425cc65304fa8c3fd153945904136f0.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "SELECT device_id FROM signal_sessions\n WHERE address = $1 AND device_id != $2 AND identity = $3", 4 + "describe": { 5 + "columns": [ 6 + { 7 + "ordinal": 0, 8 + "name": "device_id", 9 + "type_info": "Int4" 10 + } 11 + ], 12 + "parameters": { 13 + "Left": [ 14 + "Text", 15 + "Int4", 16 + "Text" 17 + ] 18 + }, 19 + "nullable": [ 20 + false 21 + ] 22 + }, 23 + "hash": "9fdcff515573446f0b4340bf94421bb8a425cc65304fa8c3fd153945904136f0" 24 + }
+12
.sqlx/query-a403c2982978159b120d4bfa6d6fdca5808b667e54b0765b5ada047ce6dac9d6.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "DELETE FROM signal_profile_keys", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [] 8 + }, 9 + "nullable": [] 10 + }, 11 + "hash": "a403c2982978159b120d4bfa6d6fdca5808b667e54b0765b5ada047ce6dac9d6" 12 + }
+15
.sqlx/query-adabc98c853ae77678ad6cf1747384706154334cc507eb7542a8b5490f5a1e2a.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "UPDATE signal_kyber_pre_keys\n SET stale_at = $1\n WHERE identity = $2 AND is_last_resort = FALSE AND stale_at IS NULL", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [ 8 + "Timestamptz", 9 + "Text" 10 + ] 11 + }, 12 + "nullable": [] 13 + }, 14 + "hash": "adabc98c853ae77678ad6cf1747384706154334cc507eb7542a8b5490f5a1e2a" 15 + }
+16
.sqlx/query-b157b94e003376d827b92eab1ff55caa773ed5691e2e555ab1d1f23fc5adcf8e.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "INSERT INTO signal_kyber_pre_keys (id, identity, record, is_last_resort)\n VALUES ($1, $2, $3, TRUE)\n ON CONFLICT (id, identity) DO UPDATE SET is_last_resort = TRUE, record = $3", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [ 8 + "Int4", 9 + "Text", 10 + "Bytea" 11 + ] 12 + }, 13 + "nullable": [] 14 + }, 15 + "hash": "b157b94e003376d827b92eab1ff55caa773ed5691e2e555ab1d1f23fc5adcf8e" 16 + }
+22
.sqlx/query-b558892051ad793b4ae38a76d072e4ea440092663bd0d4ed9d48f5074788157a.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "SELECT MAX(id) FROM signal_pre_keys WHERE identity = $1", 4 + "describe": { 5 + "columns": [ 6 + { 7 + "ordinal": 0, 8 + "name": "max", 9 + "type_info": "Int4" 10 + } 11 + ], 12 + "parameters": { 13 + "Left": [ 14 + "Text" 15 + ] 16 + }, 17 + "nullable": [ 18 + null 19 + ] 20 + }, 21 + "hash": "b558892051ad793b4ae38a76d072e4ea440092663bd0d4ed9d48f5074788157a" 22 + }
+25
.sqlx/query-b583ea011f17bd703a1dde860d1cc595a18c33dd0e37b575a71fa78f9fddc96f.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "SELECT record FROM signal_sender_keys\n WHERE address = $1 AND device_id = $2 AND identity = $3 AND distribution_id = $4", 4 + "describe": { 5 + "columns": [ 6 + { 7 + "ordinal": 0, 8 + "name": "record", 9 + "type_info": "Bytea" 10 + } 11 + ], 12 + "parameters": { 13 + "Left": [ 14 + "Text", 15 + "Int4", 16 + "Text", 17 + "Uuid" 18 + ] 19 + }, 20 + "nullable": [ 21 + false 22 + ] 23 + }, 24 + "hash": "b583ea011f17bd703a1dde860d1cc595a18c33dd0e37b575a71fa78f9fddc96f" 25 + }
+12
.sqlx/query-c08770c1ca1cb553e9067c26dec9a47d40f4cd3e16461cf0edbbb49020695f18.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "DELETE FROM signal_signed_pre_keys", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [] 8 + }, 9 + "nullable": [] 10 + }, 11 + "hash": "c08770c1ca1cb553e9067c26dec9a47d40f4cd3e16461cf0edbbb49020695f18" 12 + }
+20
.sqlx/query-c130944c8791acb05ebf5f7b5b0f82b8c548ea9d516c0e9310fb46ffd3907977.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "SELECT value FROM signal_kv WHERE key = 'registration'", 4 + "describe": { 5 + "columns": [ 6 + { 7 + "ordinal": 0, 8 + "name": "value", 9 + "type_info": "Bytea" 10 + } 11 + ], 12 + "parameters": { 13 + "Left": [] 14 + }, 15 + "nullable": [ 16 + false 17 + ] 18 + }, 19 + "hash": "c130944c8791acb05ebf5f7b5b0f82b8c548ea9d516c0e9310fb46ffd3907977" 20 + }
+16
.sqlx/query-c30d8f2bb8a20154b565a93108d3871289a752fb8d0de35a2164619da2c03aa0.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "WITH total AS (\n SELECT COUNT(*) AS cnt FROM signal_kyber_pre_keys\n WHERE identity = $1 AND is_last_resort = FALSE\n )\n DELETE FROM signal_kyber_pre_keys\n WHERE identity = $1 AND is_last_resort = FALSE\n AND stale_at IS NOT NULL AND stale_at < $2\n AND (SELECT cnt FROM total) > $3", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [ 8 + "Text", 9 + "Timestamptz", 10 + "Int8" 11 + ] 12 + }, 13 + "nullable": [] 14 + }, 15 + "hash": "c30d8f2bb8a20154b565a93108d3871289a752fb8d0de35a2164619da2c03aa0" 16 + }
+22
.sqlx/query-c5310fca925ec4188e761f218e98c11182e5757c40a70a2aa50af0f2896d98e7.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "SELECT COUNT(*) AS \"count!\" FROM signal_signed_pre_keys WHERE identity = $1", 4 + "describe": { 5 + "columns": [ 6 + { 7 + "ordinal": 0, 8 + "name": "count!", 9 + "type_info": "Int8" 10 + } 11 + ], 12 + "parameters": { 13 + "Left": [ 14 + "Text" 15 + ] 16 + }, 17 + "nullable": [ 18 + null 19 + ] 20 + }, 21 + "hash": "c5310fca925ec4188e761f218e98c11182e5757c40a70a2aa50af0f2896d98e7" 22 + }
+22
.sqlx/query-c67709e3fb975148fa86d9fd5ed5e1ef805b2f57a2ce5d955629d598e1ab2b80.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "SELECT key FROM signal_profile_keys WHERE uuid = $1", 4 + "describe": { 5 + "columns": [ 6 + { 7 + "ordinal": 0, 8 + "name": "key", 9 + "type_info": "Bytea" 10 + } 11 + ], 12 + "parameters": { 13 + "Left": [ 14 + "Uuid" 15 + ] 16 + }, 17 + "nullable": [ 18 + false 19 + ] 20 + }, 21 + "hash": "c67709e3fb975148fa86d9fd5ed5e1ef805b2f57a2ce5d955629d598e1ab2b80" 22 + }
+15
.sqlx/query-c749d53e4e38dd53aa2ac59ba2b15b641ace056515c34ec977bf47d74dfd7072.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "DELETE FROM signal_kyber_pre_keys\n WHERE id = $1 AND identity = $2 AND is_last_resort = FALSE", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [ 8 + "Int4", 9 + "Text" 10 + ] 11 + }, 12 + "nullable": [] 13 + }, 14 + "hash": "c749d53e4e38dd53aa2ac59ba2b15b641ace056515c34ec977bf47d74dfd7072" 15 + }
+20
.sqlx/query-c86da12578b2e53e0bff374121b22244c4663820cbb6edfd8f0b8c9aa583cad2.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "SELECT value FROM signal_kv WHERE key = 'master_key' LIMIT 1", 4 + "describe": { 5 + "columns": [ 6 + { 7 + "ordinal": 0, 8 + "name": "value", 9 + "type_info": "Bytea" 10 + } 11 + ], 12 + "parameters": { 13 + "Left": [] 14 + }, 15 + "nullable": [ 16 + false 17 + ] 18 + }, 19 + "hash": "c86da12578b2e53e0bff374121b22244c4663820cbb6edfd8f0b8c9aa583cad2" 20 + }
+20
.sqlx/query-dded08cb4fd0fc9bca55b3cf0c8d22f4e279bc8aedb72000f4c4bc093f61c750.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "SELECT value FROM signal_kv WHERE key = 'sender_certificate' LIMIT 1", 4 + "describe": { 5 + "columns": [ 6 + { 7 + "ordinal": 0, 8 + "name": "value", 9 + "type_info": "Bytea" 10 + } 11 + ], 12 + "parameters": { 13 + "Left": [] 14 + }, 15 + "nullable": [ 16 + false 17 + ] 18 + }, 19 + "hash": "dded08cb4fd0fc9bca55b3cf0c8d22f4e279bc8aedb72000f4c4bc093f61c750" 20 + }
+16
.sqlx/query-def40c1cfac196a066d81fb0efa0fa7bdf5f242bd13c8b70e47a512c5e9df5b1.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "INSERT INTO signal_signed_pre_keys (id, identity, record)\n VALUES ($1, $2, $3)\n ON CONFLICT (id, identity) DO UPDATE SET record = $3", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [ 8 + "Int4", 9 + "Text", 10 + "Bytea" 11 + ] 12 + }, 13 + "nullable": [] 14 + }, 15 + "hash": "def40c1cfac196a066d81fb0efa0fa7bdf5f242bd13c8b70e47a512c5e9df5b1" 16 + }
+12
.sqlx/query-e2ed0b4bfe13a99be85311fcc6e3c2dbdb789b9a44c0122f736ead48f4713a5b.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "DELETE FROM signal_pre_keys", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [] 8 + }, 9 + "nullable": [] 10 + }, 11 + "hash": "e2ed0b4bfe13a99be85311fcc6e3c2dbdb789b9a44c0122f736ead48f4713a5b" 12 + }
+15
.sqlx/query-eb837730e87ff990c4441d7bdab001d7542d1803702c634a6099365a9740e45a.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "DELETE FROM signal_kyber_pre_keys WHERE id = $1 AND identity = $2", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [ 8 + "Int4", 9 + "Text" 10 + ] 11 + }, 12 + "nullable": [] 13 + }, 14 + "hash": "eb837730e87ff990c4441d7bdab001d7542d1803702c634a6099365a9740e45a" 15 + }
+22
.sqlx/query-eea566212ffce269028a8623a12b553c048ef1ea433aa5567e72b2b639f69b0d.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "SELECT MAX(id) FROM signal_kyber_pre_keys WHERE identity = $1", 4 + "describe": { 5 + "columns": [ 6 + { 7 + "ordinal": 0, 8 + "name": "max", 9 + "type_info": "Int4" 10 + } 11 + ], 12 + "parameters": { 13 + "Left": [ 14 + "Text" 15 + ] 16 + }, 17 + "nullable": [ 18 + null 19 + ] 20 + }, 21 + "hash": "eea566212ffce269028a8623a12b553c048ef1ea433aa5567e72b2b639f69b0d" 22 + }
+16
.sqlx/query-efcf513bba65213ed4b71259a7016ffd7b1b8ff85206416a86beba19323a3be7.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "DELETE FROM signal_sessions WHERE address = $1 AND device_id = $2 AND identity = $3", 4 + "describe": { 5 + "columns": [], 6 + "parameters": { 7 + "Left": [ 8 + "Text", 9 + "Int4", 10 + "Text" 11 + ] 12 + }, 13 + "nullable": [] 14 + }, 15 + "hash": "efcf513bba65213ed4b71259a7016ffd7b1b8ff85206416a86beba19323a3be7" 16 + }
+24
.sqlx/query-f332e618e59a298573c4b6b6c7a12252b461a6676f2d797c5dae5a0baee016a7.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "SELECT record FROM signal_sessions\n WHERE address = $1 AND device_id = $2 AND identity = $3", 4 + "describe": { 5 + "columns": [ 6 + { 7 + "ordinal": 0, 8 + "name": "record", 9 + "type_info": "Bytea" 10 + } 11 + ], 12 + "parameters": { 13 + "Left": [ 14 + "Text", 15 + "Int4", 16 + "Text" 17 + ] 18 + }, 19 + "nullable": [ 20 + false 21 + ] 22 + }, 23 + "hash": "f332e618e59a298573c4b6b6c7a12252b461a6676f2d797c5dae5a0baee016a7" 24 + }
+22
.sqlx/query-f41749b35c081fc9d0881c7e2fc988e7c4d164ab5996f18e9f3a29fe4d183db9.json
··· 1 + { 2 + "db_name": "PostgreSQL", 3 + "query": "SELECT MAX(id) FROM signal_signed_pre_keys WHERE identity = $1", 4 + "describe": { 5 + "columns": [ 6 + { 7 + "ordinal": 0, 8 + "name": "max", 9 + "type_info": "Int4" 10 + } 11 + ], 12 + "parameters": { 13 + "Left": [ 14 + "Text" 15 + ] 16 + }, 17 + "nullable": [ 18 + null 19 + ] 20 + }, 21 + "hash": "f41749b35c081fc9d0881c7e2fc988e7c4d164ab5996f18e9f3a29fe4d183db9" 22 + }
+1226 -103
Cargo.lock
··· 46 46 "cfg-if", 47 47 "cipher", 48 48 "cpufeatures", 49 + "zeroize", 49 50 ] 50 51 51 52 [[package]] ··· 62 63 "subtle", 63 64 ] 64 65 66 + [[package]] 67 + name = "aes-gcm-siv" 68 + version = "0.11.1" 69 + source = "registry+https://github.com/rust-lang/crates.io-index" 70 + checksum = "ae0784134ba9375416d469ec31e7c5f9fa94405049cf08c5ce5b4698be673e0d" 71 + dependencies = [ 72 + "aead", 73 + "aes", 74 + "cipher", 75 + "ctr", 76 + "polyval", 77 + "subtle", 78 + "zeroize", 79 + ] 80 + 65 81 [[package]] 66 82 name = "ahash" 67 83 version = "0.8.12" ··· 181 197 source = "registry+https://github.com/rust-lang/crates.io-index" 182 198 checksum = "03918c3dbd7701a85c6b9887732e2921175f26c350b4563841d0958c21d57e6d" 183 199 200 + [[package]] 201 + name = "argon2" 202 + version = "0.5.3" 203 + source = "registry+https://github.com/rust-lang/crates.io-index" 204 + checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" 205 + dependencies = [ 206 + "base64ct", 207 + "blake2", 208 + "cpufeatures", 209 + "password-hash", 210 + "zeroize", 211 + ] 212 + 184 213 [[package]] 185 214 name = "asn1-rs" 186 215 version = "0.6.2" ··· 230 259 "serde_json", 231 260 ] 232 261 262 + [[package]] 263 + name = "assert_matches" 264 + version = "1.5.0" 265 + source = "registry+https://github.com/rust-lang/crates.io-index" 266 + checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" 267 + 233 268 [[package]] 234 269 name = "astral-tokio-tar" 235 270 version = "0.5.6" ··· 292 327 "syn 2.0.111", 293 328 ] 294 329 330 + [[package]] 331 + name = "async-tungstenite" 332 + version = "0.28.2" 333 + source = "registry+https://github.com/rust-lang/crates.io-index" 334 + checksum = "1c348fb0b6d132c596eca3dcd941df48fb597aafcb07a738ec41c004b087dc99" 335 + dependencies = [ 336 + "atomic-waker", 337 + "futures-core", 338 + "futures-io", 339 + "futures-task", 340 + "futures-util", 341 + "log", 342 + "pin-project-lite", 343 + "tungstenite 0.24.0", 344 + ] 345 + 295 346 [[package]] 296 347 name = "atoi" 297 348 version = "2.0.0" ··· 854 905 source = "registry+https://github.com/rust-lang/crates.io-index" 855 906 checksum = "b5e9430d9a245a77c92176e649af6e275f20839a48389859d1661e9a128d077c" 856 907 dependencies = [ 857 - "const-str", 908 + "const-str 0.4.3", 858 909 "match-lookup", 859 910 ] 860 911 ··· 916 967 "zeroize", 917 968 ] 918 969 970 + [[package]] 971 + name = "bincode" 972 + version = "1.3.3" 973 + source = "registry+https://github.com/rust-lang/crates.io-index" 974 + checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" 975 + dependencies = [ 976 + "serde", 977 + ] 978 + 919 979 [[package]] 920 980 name = "bincode" 921 981 version = "2.0.1" ··· 945 1005 "serde_core", 946 1006 ] 947 1007 1008 + [[package]] 1009 + name = "blake2" 1010 + version = "0.10.6" 1011 + source = "registry+https://github.com/rust-lang/crates.io-index" 1012 + checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" 1013 + dependencies = [ 1014 + "digest", 1015 + ] 1016 + 948 1017 [[package]] 949 1018 name = "block-buffer" 950 1019 version = "0.10.4" ··· 954 1023 "generic-array", 955 1024 ] 956 1025 1026 + [[package]] 1027 + name = "block-padding" 1028 + version = "0.3.3" 1029 + source = "registry+https://github.com/rust-lang/crates.io-index" 1030 + checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" 1031 + dependencies = [ 1032 + "generic-array", 1033 + ] 1034 + 957 1035 [[package]] 958 1036 name = "blowfish" 959 1037 version = "0.9.1" ··· 1017 1095 source = "registry+https://github.com/rust-lang/crates.io-index" 1018 1096 checksum = "85a885520bf6249ab931a764ffdb87b0ceef48e6e7d807cfdb21b751e086e1ad" 1019 1097 dependencies = [ 1020 - "prost", 1021 - "prost-types", 1098 + "prost 0.14.1", 1099 + "prost-types 0.14.1", 1022 1100 "tonic", 1023 1101 "tonic-prost", 1024 1102 "ureq", ··· 1034 1112 "bollard-buildkit-proto", 1035 1113 "bytes", 1036 1114 "chrono", 1037 - "prost", 1115 + "prost 0.14.1", 1038 1116 "serde", 1039 1117 "serde_json", 1040 1118 "serde_repr", ··· 1137 1215 version = "1.11.0" 1138 1216 source = "registry+https://github.com/rust-lang/crates.io-index" 1139 1217 checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" 1218 + dependencies = [ 1219 + "serde", 1220 + ] 1140 1221 1141 1222 [[package]] 1142 1223 name = "bytes-utils" ··· 1148 1229 "either", 1149 1230 ] 1150 1231 1232 + [[package]] 1233 + name = "cbc" 1234 + version = "0.1.2" 1235 + source = "registry+https://github.com/rust-lang/crates.io-index" 1236 + checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" 1237 + dependencies = [ 1238 + "cipher", 1239 + ] 1240 + 1151 1241 [[package]] 1152 1242 name = "cbor4ii" 1153 1243 version = "0.2.14" ··· 1264 1354 dependencies = [ 1265 1355 "crypto-common", 1266 1356 "inout", 1357 + "zeroize", 1267 1358 ] 1268 1359 1269 1360 [[package]] ··· 1411 1502 source = "registry+https://github.com/rust-lang/crates.io-index" 1412 1503 checksum = "2f421161cb492475f1661ddc9815a745a1c894592070661180fdec3d4872e9c3" 1413 1504 1505 + [[package]] 1506 + name = "const-str" 1507 + version = "1.1.0" 1508 + source = "registry+https://github.com/rust-lang/crates.io-index" 1509 + checksum = "18f12cc9948ed9604230cdddc7c86e270f9401ccbe3c2e98a4378c5e7632212f" 1510 + 1414 1511 [[package]] 1415 1512 name = "constant_time_eq" 1416 1513 version = "0.3.1" ··· 1453 1550 source = "registry+https://github.com/rust-lang/crates.io-index" 1454 1551 checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 1455 1552 1553 + [[package]] 1554 + name = "core-models" 1555 + version = "0.0.4" 1556 + source = "registry+https://github.com/rust-lang/crates.io-index" 1557 + checksum = "0940496e5c83c54f3b753d5317daec82e8edac71c33aaa1f666d76f518de2444" 1558 + dependencies = [ 1559 + "hax-lib", 1560 + "pastey", 1561 + "rand 0.9.2", 1562 + ] 1563 + 1456 1564 [[package]] 1457 1565 name = "core2" 1458 1566 version = "0.4.0" ··· 1514 1622 source = "registry+https://github.com/rust-lang/crates.io-index" 1515 1623 checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" 1516 1624 1625 + [[package]] 1626 + name = "crossbeam-deque" 1627 + version = "0.8.6" 1628 + source = "registry+https://github.com/rust-lang/crates.io-index" 1629 + checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" 1630 + dependencies = [ 1631 + "crossbeam-epoch", 1632 + "crossbeam-utils", 1633 + ] 1634 + 1517 1635 [[package]] 1518 1636 name = "crossbeam-epoch" 1519 1637 version = "0.9.18" ··· 1607 1725 [[package]] 1608 1726 name = "curve25519-dalek" 1609 1727 version = "4.1.3" 1610 - source = "registry+https://github.com/rust-lang/crates.io-index" 1611 - checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" 1728 + source = "git+https://github.com/signalapp/curve25519-dalek?tag=signal-curve25519-4.1.3#7c6d34756355a3566a704da84dce7b1c039a6572" 1612 1729 dependencies = [ 1613 1730 "cfg-if", 1614 1731 "cpufeatures", 1615 1732 "curve25519-dalek-derive", 1616 1733 "digest", 1617 1734 "fiat-crypto", 1735 + "rand_core 0.6.4", 1618 1736 "rustc_version", 1737 + "serde", 1619 1738 "subtle", 1620 1739 "zeroize", 1621 1740 ] ··· 1623 1742 [[package]] 1624 1743 name = "curve25519-dalek-derive" 1625 1744 version = "0.1.1" 1626 - source = "registry+https://github.com/rust-lang/crates.io-index" 1627 - checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" 1745 + source = "git+https://github.com/signalapp/curve25519-dalek?tag=signal-curve25519-4.1.3#7c6d34756355a3566a704da84dce7b1c039a6572" 1628 1746 dependencies = [ 1629 1747 "proc-macro2", 1630 1748 "quote", ··· 1769 1887 "serde_core", 1770 1888 ] 1771 1889 1890 + [[package]] 1891 + name = "derive-where" 1892 + version = "1.6.1" 1893 + source = "registry+https://github.com/rust-lang/crates.io-index" 1894 + checksum = "d08b3a0bcc0d079199cd476b2cae8435016ec11d1c0986c6901c5ac223041534" 1895 + dependencies = [ 1896 + "proc-macro2", 1897 + "quote", 1898 + "syn 2.0.111", 1899 + ] 1900 + 1772 1901 [[package]] 1773 1902 name = "derive_arbitrary" 1774 1903 version = "1.4.2" ··· 1786 1915 source = "registry+https://github.com/rust-lang/crates.io-index" 1787 1916 checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" 1788 1917 dependencies = [ 1789 - "derive_more-impl", 1918 + "derive_more-impl 1.0.0", 1919 + ] 1920 + 1921 + [[package]] 1922 + name = "derive_more" 1923 + version = "2.1.1" 1924 + source = "registry+https://github.com/rust-lang/crates.io-index" 1925 + checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" 1926 + dependencies = [ 1927 + "derive_more-impl 2.1.1", 1790 1928 ] 1791 1929 1792 1930 [[package]] ··· 1801 1939 "unicode-xid", 1802 1940 ] 1803 1941 1942 + [[package]] 1943 + name = "derive_more-impl" 1944 + version = "2.1.1" 1945 + source = "registry+https://github.com/rust-lang/crates.io-index" 1946 + checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" 1947 + dependencies = [ 1948 + "proc-macro2", 1949 + "quote", 1950 + "rustc_version", 1951 + "syn 2.0.111", 1952 + "unicode-xid", 1953 + ] 1954 + 1804 1955 [[package]] 1805 1956 name = "diatomic-waker" 1806 1957 version = "0.2.3" ··· 2126 2277 source = "registry+https://github.com/rust-lang/crates.io-index" 2127 2278 checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" 2128 2279 2280 + [[package]] 2281 + name = "fixedbitset" 2282 + version = "0.5.7" 2283 + source = "registry+https://github.com/rust-lang/crates.io-index" 2284 + checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" 2285 + 2129 2286 [[package]] 2130 2287 name = "flate2" 2131 2288 version = "1.1.5" ··· 2160 2317 source = "registry+https://github.com/rust-lang/crates.io-index" 2161 2318 checksum = "1f59e967f3f675997e4a4a6b99d2a75148d59d64c46211b78b4f34ebb951b273" 2162 2319 dependencies = [ 2163 - "bincode", 2320 + "bincode 2.0.1", 2164 2321 "bytes", 2165 2322 "rand 0.9.2", 2166 2323 "serde", ··· 2402 2559 dependencies = [ 2403 2560 "opaque-debug", 2404 2561 "polyval", 2562 + "zeroize", 2405 2563 ] 2406 2564 2407 2565 [[package]] ··· 2572 2730 "hashbrown 0.15.5", 2573 2731 ] 2574 2732 2733 + [[package]] 2734 + name = "hax-lib" 2735 + version = "0.3.5" 2736 + source = "registry+https://github.com/rust-lang/crates.io-index" 2737 + checksum = "74d9ba66d1739c68e0219b2b2238b5c4145f491ebf181b9c6ab561a19352ae86" 2738 + dependencies = [ 2739 + "hax-lib-macros", 2740 + "num-bigint", 2741 + "num-traits", 2742 + ] 2743 + 2744 + [[package]] 2745 + name = "hax-lib-macros" 2746 + version = "0.3.5" 2747 + source = "registry+https://github.com/rust-lang/crates.io-index" 2748 + checksum = "24ba777a231a58d1bce1d68313fa6b6afcc7966adef23d60f45b8a2b9b688bf1" 2749 + dependencies = [ 2750 + "hax-lib-macros-types", 2751 + "proc-macro-error2", 2752 + "proc-macro2", 2753 + "quote", 2754 + "syn 2.0.111", 2755 + ] 2756 + 2757 + [[package]] 2758 + name = "hax-lib-macros-types" 2759 + version = "0.3.5" 2760 + source = "registry+https://github.com/rust-lang/crates.io-index" 2761 + checksum = "867e19177d7425140b417cd27c2e05320e727ee682e98368f88b7194e80ad515" 2762 + dependencies = [ 2763 + "proc-macro2", 2764 + "quote", 2765 + "serde", 2766 + "serde_json", 2767 + "uuid", 2768 + ] 2769 + 2575 2770 [[package]] 2576 2771 name = "heapless" 2577 2772 version = "0.7.17" ··· 2688 2883 "windows-sys 0.61.2", 2689 2884 ] 2690 2885 2886 + [[package]] 2887 + name = "hpke-rs" 2888 + version = "0.5.0" 2889 + source = "registry+https://github.com/rust-lang/crates.io-index" 2890 + checksum = "c8c09b01d75373842d3123a4dd51bad5cb70e95d8b96e50bc20d08877a8d2443" 2891 + dependencies = [ 2892 + "hpke-rs-crypto", 2893 + "libcrux-sha3 0.0.4", 2894 + "log", 2895 + "rand_core 0.9.3", 2896 + "zeroize", 2897 + ] 2898 + 2899 + [[package]] 2900 + name = "hpke-rs-crypto" 2901 + version = "0.4.0" 2902 + source = "registry+https://github.com/rust-lang/crates.io-index" 2903 + checksum = "2dd92b7d7f0deaae59c152e01c01f5280ea92dfac82090e5c025879b32df9193" 2904 + dependencies = [ 2905 + "rand_core 0.9.3", 2906 + ] 2907 + 2691 2908 [[package]] 2692 2909 name = "http" 2693 2910 version = "0.2.12" ··· 3117 3334 source = "registry+https://github.com/rust-lang/crates.io-index" 3118 3335 checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" 3119 3336 dependencies = [ 3337 + "block-padding", 3120 3338 "generic-array", 3121 3339 ] 3122 3340 ··· 3398 3616 checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" 3399 3617 3400 3618 [[package]] 3401 - name = "libm" 3402 - version = "0.2.15" 3619 + name = "libcrux-hacl-rs" 3620 + version = "0.0.4" 3403 3621 source = "registry+https://github.com/rust-lang/crates.io-index" 3404 - checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" 3622 + checksum = "2637dc87d158e1f1b550fd9b226443e84153fded4de69028d897b534d16d22e6" 3623 + dependencies = [ 3624 + "libcrux-macros", 3625 + ] 3405 3626 3406 3627 [[package]] 3407 - name = "libredox" 3408 - version = "0.1.11" 3628 + name = "libcrux-hmac" 3629 + version = "0.0.4" 3409 3630 source = "registry+https://github.com/rust-lang/crates.io-index" 3410 - checksum = "df15f6eac291ed1cf25865b1ee60399f57e7c227e7f51bdbd4c5270396a9ed50" 3631 + checksum = "9f0e8011bfcdb6059127e673ec0e1fc7b2a3705c683ade9d708875ed4c26cd8d" 3411 3632 dependencies = [ 3412 - "bitflags", 3413 - "libc", 3414 - "redox_syscall 0.6.0", 3633 + "libcrux-hacl-rs", 3634 + "libcrux-macros", 3635 + "libcrux-sha2", 3415 3636 ] 3416 3637 3417 3638 [[package]] 3418 - name = "libsqlite3-sys" 3419 - version = "0.30.1" 3639 + name = "libcrux-intrinsics" 3640 + version = "0.0.4" 3420 3641 source = "registry+https://github.com/rust-lang/crates.io-index" 3421 - checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" 3642 + checksum = "bc9ee7ef66569dd7516454fe26de4e401c0c62073929803486b96744594b9632" 3422 3643 dependencies = [ 3423 - "pkg-config", 3424 - "vcpkg", 3644 + "core-models", 3645 + "hax-lib", 3425 3646 ] 3426 3647 3427 3648 [[package]] 3428 - name = "libz-rs-sys" 3429 - version = "0.5.5" 3649 + name = "libcrux-macros" 3650 + version = "0.0.3" 3430 3651 source = "registry+https://github.com/rust-lang/crates.io-index" 3431 - checksum = "c10501e7805cee23da17c7790e59df2870c0d4043ec6d03f67d31e2b53e77415" 3652 + checksum = "ffd6aa2dcd5be681662001b81d493f1569c6d49a32361f470b0c955465cd0338" 3432 3653 dependencies = [ 3433 - "zlib-rs", 3654 + "quote", 3655 + "syn 2.0.111", 3434 3656 ] 3435 3657 3436 3658 [[package]] 3437 - name = "linked-hash-map" 3438 - version = "0.5.6" 3659 + name = "libcrux-ml-kem" 3660 + version = "0.0.5" 3439 3661 source = "registry+https://github.com/rust-lang/crates.io-index" 3440 - checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" 3662 + checksum = "22a36f21056e552438dbe6ce413b6682001795e53bd1f0e2c941d7e231238e5a" 3663 + dependencies = [ 3664 + "hax-lib", 3665 + "libcrux-intrinsics", 3666 + "libcrux-platform 0.0.3", 3667 + "libcrux-secrets", 3668 + "libcrux-sha3 0.0.5", 3669 + "libcrux-traits", 3670 + ] 3441 3671 3442 3672 [[package]] 3443 - name = "linux-raw-sys" 3444 - version = "0.11.0" 3673 + name = "libcrux-platform" 3674 + version = "0.0.2" 3445 3675 source = "registry+https://github.com/rust-lang/crates.io-index" 3446 - checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" 3676 + checksum = "db82d058aa76ea315a3b2092f69dfbd67ddb0e462038a206e1dcd73f058c0778" 3677 + dependencies = [ 3678 + "libc", 3679 + ] 3447 3680 3448 3681 [[package]] 3449 - name = "litemap" 3450 - version = "0.8.1" 3682 + name = "libcrux-platform" 3683 + version = "0.0.3" 3451 3684 source = "registry+https://github.com/rust-lang/crates.io-index" 3452 - checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" 3685 + checksum = "1d9e21d7ed31a92ac539bd69a8c970b183ee883872d2d19ce27036e24cb8ecc4" 3686 + dependencies = [ 3687 + "libc", 3688 + ] 3453 3689 3454 3690 [[package]] 3455 - name = "lock_api" 3456 - version = "0.4.14" 3691 + name = "libcrux-secrets" 3692 + version = "0.0.4" 3457 3693 source = "registry+https://github.com/rust-lang/crates.io-index" 3458 - checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" 3694 + checksum = "6e4dbbf6bc9f2bc0f20dc3bea3e5c99adff3bdccf6d2a40488963da69e2ec307" 3459 3695 dependencies = [ 3460 - "scopeguard", 3696 + "hax-lib", 3461 3697 ] 3462 3698 3463 3699 [[package]] 3464 - name = "log" 3465 - version = "0.4.29" 3700 + name = "libcrux-sha2" 3701 + version = "0.0.4" 3466 3702 source = "registry+https://github.com/rust-lang/crates.io-index" 3467 - checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" 3703 + checksum = "649d9401e6e1954f58531b8eb13b12c800f85bbadc93362871b63a1f8a8d6d32" 3704 + dependencies = [ 3705 + "libcrux-hacl-rs", 3706 + "libcrux-macros", 3707 + "libcrux-traits", 3708 + ] 3468 3709 3469 3710 [[package]] 3470 - name = "loom" 3471 - version = "0.7.2" 3711 + name = "libcrux-sha3" 3712 + version = "0.0.4" 3472 3713 source = "registry+https://github.com/rust-lang/crates.io-index" 3473 - checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" 3714 + checksum = "2400bec764d1c75b8a496d5747cffe32f1fb864a12577f0aca2f55a92021c962" 3474 3715 dependencies = [ 3475 - "cfg-if", 3476 - "generator", 3477 - "scoped-tls", 3478 - "tracing", 3479 - "tracing-subscriber", 3716 + "hax-lib", 3717 + "libcrux-intrinsics", 3718 + "libcrux-platform 0.0.2", 3719 + "libcrux-traits", 3480 3720 ] 3481 3721 3482 3722 [[package]] 3483 - name = "lru" 3484 - version = "0.12.5" 3723 + name = "libcrux-sha3" 3724 + version = "0.0.5" 3485 3725 source = "registry+https://github.com/rust-lang/crates.io-index" 3486 - checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" 3726 + checksum = "18e869fdeb9af62c55c3fcd60ce407552eb282d727550ce986abac94a3474479" 3487 3727 dependencies = [ 3488 - "hashbrown 0.15.5", 3728 + "hax-lib", 3729 + "libcrux-intrinsics", 3730 + "libcrux-platform 0.0.3", 3731 + "libcrux-traits", 3489 3732 ] 3490 3733 3491 3734 [[package]] 3492 - name = "lru-cache" 3493 - version = "0.1.2" 3735 + name = "libcrux-traits" 3736 + version = "0.0.4" 3494 3737 source = "registry+https://github.com/rust-lang/crates.io-index" 3495 - checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" 3738 + checksum = "9adfd58e79d860f6b9e40e35127bfae9e5bd3ade33201d1347459011a2add034" 3496 3739 dependencies = [ 3497 - "linked-hash-map", 3740 + "libcrux-secrets", 3741 + "rand 0.9.2", 3498 3742 ] 3499 3743 3500 3744 [[package]] 3501 - name = "lru-slab" 3502 - version = "0.1.2" 3745 + name = "libm" 3746 + version = "0.2.15" 3503 3747 source = "registry+https://github.com/rust-lang/crates.io-index" 3504 - checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" 3748 + checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" 3505 3749 3506 3750 [[package]] 3507 - name = "match-lookup" 3508 - version = "0.1.1" 3751 + name = "libredox" 3752 + version = "0.1.11" 3509 3753 source = "registry+https://github.com/rust-lang/crates.io-index" 3510 - checksum = "1265724d8cb29dbbc2b0f06fffb8bf1a8c0cf73a78eede9ba73a4a66c52a981e" 3754 + checksum = "df15f6eac291ed1cf25865b1ee60399f57e7c227e7f51bdbd4c5270396a9ed50" 3511 3755 dependencies = [ 3512 - "proc-macro2", 3513 - "quote", 3514 - "syn 1.0.109", 3756 + "bitflags", 3757 + "libc", 3758 + "redox_syscall 0.6.0", 3759 + ] 3760 + 3761 + [[package]] 3762 + name = "libsignal-account-keys" 3763 + version = "0.1.0" 3764 + source = "git+https://github.com/signalapp/libsignal?tag=v0.87.4#38514bdc8acaaffbccd5c96515c68deb2019abe0" 3765 + dependencies = [ 3766 + "argon2", 3767 + "derive_more 2.1.1", 3768 + "displaydoc", 3769 + "hkdf", 3770 + "libsignal-core", 3771 + "partial-default", 3772 + "protobuf", 3773 + "protobuf-codegen", 3774 + "rand 0.9.2", 3775 + "rand_core 0.9.3", 3776 + "serde", 3777 + "sha2", 3778 + "signal-crypto", 3779 + "static_assertions", 3780 + "thiserror 2.0.17", 3781 + "zerocopy", 3782 + ] 3783 + 3784 + [[package]] 3785 + name = "libsignal-core" 3786 + version = "0.1.0" 3787 + source = "git+https://github.com/signalapp/libsignal?tag=v0.87.4#38514bdc8acaaffbccd5c96515c68deb2019abe0" 3788 + dependencies = [ 3789 + "curve25519-dalek", 3790 + "derive_more 2.1.1", 3791 + "displaydoc", 3792 + "log", 3793 + "rand 0.9.2", 3794 + "sha2", 3795 + "subtle", 3796 + "thiserror 2.0.17", 3797 + "uuid", 3798 + "x25519-dalek", 3799 + "zerocopy", 3800 + ] 3801 + 3802 + [[package]] 3803 + name = "libsignal-protocol" 3804 + version = "0.1.0" 3805 + source = "git+https://github.com/signalapp/libsignal?tag=v0.87.4#38514bdc8acaaffbccd5c96515c68deb2019abe0" 3806 + dependencies = [ 3807 + "aes", 3808 + "aes-gcm-siv", 3809 + "assert_matches", 3810 + "async-trait", 3811 + "bitflags", 3812 + "const-str 1.1.0", 3813 + "ctr", 3814 + "data-encoding-macro", 3815 + "derive-where", 3816 + "derive_more 2.1.1", 3817 + "displaydoc", 3818 + "hex", 3819 + "hkdf", 3820 + "hmac", 3821 + "indexmap 2.12.1", 3822 + "itertools", 3823 + "libcrux-ml-kem", 3824 + "libsignal-core", 3825 + "log", 3826 + "prost 0.14.1", 3827 + "prost-build 0.14.1", 3828 + "rand 0.9.2", 3829 + "rayon", 3830 + "serde", 3831 + "sha2", 3832 + "signal-crypto", 3833 + "spqr", 3834 + "subtle", 3835 + "thiserror 2.0.17", 3836 + "uuid", 3837 + "zerocopy", 3838 + ] 3839 + 3840 + [[package]] 3841 + name = "libsignal-service" 3842 + version = "0.1.0" 3843 + source = "git+https://github.com/whisperfish/libsignal-service-rs?rev=3d07d8df33482b2d191c075fdc2b750738a89384#3d07d8df33482b2d191c075fdc2b750738a89384" 3844 + dependencies = [ 3845 + "aes", 3846 + "aes-gcm", 3847 + "async-trait", 3848 + "base64 0.22.1", 3849 + "bincode 1.3.3", 3850 + "bytes", 3851 + "cbc", 3852 + "chrono", 3853 + "ctr", 3854 + "derive_more 2.1.1", 3855 + "futures", 3856 + "hex", 3857 + "hkdf", 3858 + "hmac", 3859 + "libsignal-core", 3860 + "libsignal-protocol", 3861 + "phonenumber", 3862 + "prost 0.13.5", 3863 + "prost-build 0.13.5", 3864 + "rand 0.9.2", 3865 + "rand_core 0.6.4", 3866 + "reqwest", 3867 + "reqwest-websocket", 3868 + "serde", 3869 + "serde_json", 3870 + "sha2", 3871 + "signal-crypto", 3872 + "thiserror 2.0.17", 3873 + "tokio", 3874 + "tracing", 3875 + "tracing-futures", 3876 + "url", 3877 + "usernames", 3878 + "uuid", 3879 + "zkgroup", 3880 + ] 3881 + 3882 + [[package]] 3883 + name = "libsqlite3-sys" 3884 + version = "0.30.1" 3885 + source = "registry+https://github.com/rust-lang/crates.io-index" 3886 + checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" 3887 + dependencies = [ 3888 + "pkg-config", 3889 + "vcpkg", 3890 + ] 3891 + 3892 + [[package]] 3893 + name = "libz-rs-sys" 3894 + version = "0.5.5" 3895 + source = "registry+https://github.com/rust-lang/crates.io-index" 3896 + checksum = "c10501e7805cee23da17c7790e59df2870c0d4043ec6d03f67d31e2b53e77415" 3897 + dependencies = [ 3898 + "zlib-rs", 3899 + ] 3900 + 3901 + [[package]] 3902 + name = "linked-hash-map" 3903 + version = "0.5.6" 3904 + source = "registry+https://github.com/rust-lang/crates.io-index" 3905 + checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" 3906 + 3907 + [[package]] 3908 + name = "linux-raw-sys" 3909 + version = "0.4.15" 3910 + source = "registry+https://github.com/rust-lang/crates.io-index" 3911 + checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" 3912 + 3913 + [[package]] 3914 + name = "linux-raw-sys" 3915 + version = "0.11.0" 3916 + source = "registry+https://github.com/rust-lang/crates.io-index" 3917 + checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" 3918 + 3919 + [[package]] 3920 + name = "litemap" 3921 + version = "0.8.1" 3922 + source = "registry+https://github.com/rust-lang/crates.io-index" 3923 + checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" 3924 + 3925 + [[package]] 3926 + name = "lock_api" 3927 + version = "0.4.14" 3928 + source = "registry+https://github.com/rust-lang/crates.io-index" 3929 + checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" 3930 + dependencies = [ 3931 + "scopeguard", 3932 + ] 3933 + 3934 + [[package]] 3935 + name = "log" 3936 + version = "0.4.29" 3937 + source = "registry+https://github.com/rust-lang/crates.io-index" 3938 + checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" 3939 + 3940 + [[package]] 3941 + name = "loom" 3942 + version = "0.7.2" 3943 + source = "registry+https://github.com/rust-lang/crates.io-index" 3944 + checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" 3945 + dependencies = [ 3946 + "cfg-if", 3947 + "generator", 3948 + "scoped-tls", 3949 + "tracing", 3950 + "tracing-subscriber", 3951 + ] 3952 + 3953 + [[package]] 3954 + name = "lru" 3955 + version = "0.12.5" 3956 + source = "registry+https://github.com/rust-lang/crates.io-index" 3957 + checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" 3958 + dependencies = [ 3959 + "hashbrown 0.15.5", 3960 + ] 3961 + 3962 + [[package]] 3963 + name = "lru-cache" 3964 + version = "0.1.2" 3965 + source = "registry+https://github.com/rust-lang/crates.io-index" 3966 + checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" 3967 + dependencies = [ 3968 + "linked-hash-map", 3969 + ] 3970 + 3971 + [[package]] 3972 + name = "lru-slab" 3973 + version = "0.1.2" 3974 + source = "registry+https://github.com/rust-lang/crates.io-index" 3975 + checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" 3976 + 3977 + [[package]] 3978 + name = "match-lookup" 3979 + version = "0.1.1" 3980 + source = "registry+https://github.com/rust-lang/crates.io-index" 3981 + checksum = "1265724d8cb29dbbc2b0f06fffb8bf1a8c0cf73a78eede9ba73a4a66c52a981e" 3982 + dependencies = [ 3983 + "proc-macro2", 3984 + "quote", 3985 + "syn 1.0.109", 3515 3986 ] 3516 3987 3517 3988 [[package]] ··· 3689 4160 "unsigned-varint 0.8.0", 3690 4161 ] 3691 4162 4163 + [[package]] 4164 + name = "multimap" 4165 + version = "0.10.1" 4166 + source = "registry+https://github.com/rust-lang/crates.io-index" 4167 + checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" 4168 + 3692 4169 [[package]] 3693 4170 name = "n0-future" 3694 4171 version = "0.1.3" ··· 3696 4173 checksum = "7bb0e5d99e681ab3c938842b96fcb41bf8a7bb4bfdb11ccbd653a7e83e06c794" 3697 4174 dependencies = [ 3698 4175 "cfg_aliases", 3699 - "derive_more", 4176 + "derive_more 1.0.0", 3700 4177 "futures-buffered", 3701 4178 "futures-lite", 3702 4179 "futures-util", ··· 3841 4318 "libc", 3842 4319 ] 3843 4320 4321 + [[package]] 4322 + name = "num_enum" 4323 + version = "0.7.6" 4324 + source = "registry+https://github.com/rust-lang/crates.io-index" 4325 + checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" 4326 + dependencies = [ 4327 + "num_enum_derive", 4328 + "rustversion", 4329 + ] 4330 + 4331 + [[package]] 4332 + name = "num_enum_derive" 4333 + version = "0.7.6" 4334 + source = "registry+https://github.com/rust-lang/crates.io-index" 4335 + checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" 4336 + dependencies = [ 4337 + "proc-macro-crate", 4338 + "proc-macro2", 4339 + "quote", 4340 + "syn 2.0.111", 4341 + ] 4342 + 3844 4343 [[package]] 3845 4344 name = "oid-registry" 3846 4345 version = "0.7.1" ··· 3862 4361 source = "registry+https://github.com/rust-lang/crates.io-index" 3863 4362 checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" 3864 4363 4364 + [[package]] 4365 + name = "oncemutex" 4366 + version = "0.1.1" 4367 + source = "registry+https://github.com/rust-lang/crates.io-index" 4368 + checksum = "44d11de466f4a3006fe8a5e7ec84e93b79c70cb992ae0aa0eb631ad2df8abfe2" 4369 + 3865 4370 [[package]] 3866 4371 name = "opaque-debug" 3867 4372 version = "0.3.1" ··· 4014 4519 dependencies = [ 4015 4520 "parse-display-derive", 4016 4521 "regex", 4017 - "regex-syntax", 4522 + "regex-syntax 0.8.8", 4018 4523 ] 4019 4524 4020 4525 [[package]] ··· 4026 4531 "proc-macro2", 4027 4532 "quote", 4028 4533 "regex", 4029 - "regex-syntax", 4534 + "regex-syntax 0.8.8", 4030 4535 "structmeta", 4031 4536 "syn 2.0.111", 4032 4537 ] 4033 4538 4539 + [[package]] 4540 + name = "partial-default" 4541 + version = "0.1.0" 4542 + source = "registry+https://github.com/rust-lang/crates.io-index" 4543 + checksum = "124dc3c21ffb6fb3a0562d129929a8a54998766ef7adc1ba09ddc467d092c14b" 4544 + dependencies = [ 4545 + "partial-default-derive", 4546 + ] 4547 + 4548 + [[package]] 4549 + name = "partial-default-derive" 4550 + version = "0.1.0" 4551 + source = "registry+https://github.com/rust-lang/crates.io-index" 4552 + checksum = "7459127d7a18cb202d418e4b7df1103ffd6d82a106e9b2091c250624c2ace70d" 4553 + dependencies = [ 4554 + "proc-macro2", 4555 + "quote", 4556 + "syn 2.0.111", 4557 + ] 4558 + 4559 + [[package]] 4560 + name = "password-hash" 4561 + version = "0.5.0" 4562 + source = "registry+https://github.com/rust-lang/crates.io-index" 4563 + checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" 4564 + dependencies = [ 4565 + "base64ct", 4566 + "rand_core 0.6.4", 4567 + "subtle", 4568 + ] 4569 + 4034 4570 [[package]] 4035 4571 name = "pastey" 4036 4572 version = "0.1.1" ··· 4062 4598 source = "registry+https://github.com/rust-lang/crates.io-index" 4063 4599 checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" 4064 4600 4601 + [[package]] 4602 + name = "petgraph" 4603 + version = "0.7.1" 4604 + source = "registry+https://github.com/rust-lang/crates.io-index" 4605 + checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" 4606 + dependencies = [ 4607 + "fixedbitset", 4608 + "indexmap 2.12.1", 4609 + ] 4610 + 4611 + [[package]] 4612 + name = "phonenumber" 4613 + version = "0.3.9+9.0.21" 4614 + source = "registry+https://github.com/rust-lang/crates.io-index" 4615 + checksum = "9114f9c1683dd09c5f4fa024c89fdad783eaae21d3d52dd23ddaaffa29ffb168" 4616 + dependencies = [ 4617 + "either", 4618 + "fnv", 4619 + "nom", 4620 + "once_cell", 4621 + "postcard", 4622 + "quick-xml", 4623 + "regex", 4624 + "regex-cache", 4625 + "serde", 4626 + "serde_derive", 4627 + "strum", 4628 + "thiserror 2.0.17", 4629 + ] 4630 + 4065 4631 [[package]] 4066 4632 name = "pin-project" 4067 4633 version = "1.1.10" ··· 4144 4710 "miniz_oxide", 4145 4711 ] 4146 4712 4713 + [[package]] 4714 + name = "poksho" 4715 + version = "0.7.0" 4716 + source = "git+https://github.com/signalapp/libsignal?tag=v0.87.4#38514bdc8acaaffbccd5c96515c68deb2019abe0" 4717 + dependencies = [ 4718 + "curve25519-dalek", 4719 + "hmac", 4720 + "sha2", 4721 + ] 4722 + 4147 4723 [[package]] 4148 4724 name = "polyval" 4149 4725 version = "0.6.2" ··· 4199 4775 "zerocopy", 4200 4776 ] 4201 4777 4778 + [[package]] 4779 + name = "presage" 4780 + version = "0.8.0-dev" 4781 + source = "git+https://github.com/whisperfish/presage?rev=fe3ed54c4844ae51c3a9fa49cf80a7816a31a425#fe3ed54c4844ae51c3a9fa49cf80a7816a31a425" 4782 + dependencies = [ 4783 + "base64 0.22.1", 4784 + "bytes", 4785 + "derive_more 2.1.1", 4786 + "futures", 4787 + "hex", 4788 + "libsignal-service", 4789 + "rand 0.9.2", 4790 + "serde", 4791 + "serde_json", 4792 + "sha2", 4793 + "thiserror 1.0.69", 4794 + "tokio", 4795 + "tracing", 4796 + "url", 4797 + ] 4798 + 4202 4799 [[package]] 4203 4800 name = "prettyplease" 4204 4801 version = "0.2.37" ··· 4218 4815 "elliptic-curve 0.13.8", 4219 4816 ] 4220 4817 4818 + [[package]] 4819 + name = "proc-macro-crate" 4820 + version = "3.5.0" 4821 + source = "registry+https://github.com/rust-lang/crates.io-index" 4822 + checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" 4823 + dependencies = [ 4824 + "toml_edit", 4825 + ] 4826 + 4221 4827 [[package]] 4222 4828 name = "proc-macro-error" 4223 4829 version = "1.0.4" ··· 4242 4848 "version_check", 4243 4849 ] 4244 4850 4851 + [[package]] 4852 + name = "proc-macro-error-attr2" 4853 + version = "2.0.0" 4854 + source = "registry+https://github.com/rust-lang/crates.io-index" 4855 + checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" 4856 + dependencies = [ 4857 + "proc-macro2", 4858 + "quote", 4859 + ] 4860 + 4861 + [[package]] 4862 + name = "proc-macro-error2" 4863 + version = "2.0.1" 4864 + source = "registry+https://github.com/rust-lang/crates.io-index" 4865 + checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" 4866 + dependencies = [ 4867 + "proc-macro-error-attr2", 4868 + "proc-macro2", 4869 + "quote", 4870 + "syn 2.0.111", 4871 + ] 4872 + 4245 4873 [[package]] 4246 4874 name = "proc-macro2" 4247 4875 version = "1.0.103" ··· 4264 4892 "yansi", 4265 4893 ] 4266 4894 4895 + [[package]] 4896 + name = "prost" 4897 + version = "0.13.5" 4898 + source = "registry+https://github.com/rust-lang/crates.io-index" 4899 + checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" 4900 + dependencies = [ 4901 + "bytes", 4902 + "prost-derive 0.13.5", 4903 + ] 4904 + 4267 4905 [[package]] 4268 4906 name = "prost" 4269 4907 version = "0.14.1" ··· 4271 4909 checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d" 4272 4910 dependencies = [ 4273 4911 "bytes", 4274 - "prost-derive", 4912 + "prost-derive 0.14.1", 4913 + ] 4914 + 4915 + [[package]] 4916 + name = "prost-build" 4917 + version = "0.13.5" 4918 + source = "registry+https://github.com/rust-lang/crates.io-index" 4919 + checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" 4920 + dependencies = [ 4921 + "heck 0.4.1", 4922 + "itertools", 4923 + "log", 4924 + "multimap", 4925 + "once_cell", 4926 + "petgraph", 4927 + "prettyplease", 4928 + "prost 0.13.5", 4929 + "prost-types 0.13.5", 4930 + "regex", 4931 + "syn 2.0.111", 4932 + "tempfile", 4933 + ] 4934 + 4935 + [[package]] 4936 + name = "prost-build" 4937 + version = "0.14.1" 4938 + source = "registry+https://github.com/rust-lang/crates.io-index" 4939 + checksum = "ac6c3320f9abac597dcbc668774ef006702672474aad53c6d596b62e487b40b1" 4940 + dependencies = [ 4941 + "heck 0.4.1", 4942 + "itertools", 4943 + "log", 4944 + "multimap", 4945 + "once_cell", 4946 + "petgraph", 4947 + "prettyplease", 4948 + "prost 0.14.1", 4949 + "prost-types 0.14.1", 4950 + "regex", 4951 + "syn 2.0.111", 4952 + "tempfile", 4953 + ] 4954 + 4955 + [[package]] 4956 + name = "prost-derive" 4957 + version = "0.13.5" 4958 + source = "registry+https://github.com/rust-lang/crates.io-index" 4959 + checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" 4960 + dependencies = [ 4961 + "anyhow", 4962 + "itertools", 4963 + "proc-macro2", 4964 + "quote", 4965 + "syn 2.0.111", 4275 4966 ] 4276 4967 4277 4968 [[package]] ··· 4287 4978 "syn 2.0.111", 4288 4979 ] 4289 4980 4981 + [[package]] 4982 + name = "prost-types" 4983 + version = "0.13.5" 4984 + source = "registry+https://github.com/rust-lang/crates.io-index" 4985 + checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" 4986 + dependencies = [ 4987 + "prost 0.13.5", 4988 + ] 4989 + 4290 4990 [[package]] 4291 4991 name = "prost-types" 4292 4992 version = "0.14.1" 4293 4993 source = "registry+https://github.com/rust-lang/crates.io-index" 4294 4994 checksum = "b9b4db3d6da204ed77bb26ba83b6122a73aeb2e87e25fbf7ad2e84c4ccbf8f72" 4295 4995 dependencies = [ 4296 - "prost", 4996 + "prost 0.14.1", 4997 + ] 4998 + 4999 + [[package]] 5000 + name = "protobuf" 5001 + version = "3.7.2" 5002 + source = "registry+https://github.com/rust-lang/crates.io-index" 5003 + checksum = "d65a1d4ddae7d8b5de68153b48f6aa3bba8cb002b243dbdbc55a5afbc98f99f4" 5004 + dependencies = [ 5005 + "once_cell", 5006 + "protobuf-support", 5007 + "thiserror 1.0.69", 5008 + ] 5009 + 5010 + [[package]] 5011 + name = "protobuf-codegen" 5012 + version = "3.7.2" 5013 + source = "registry+https://github.com/rust-lang/crates.io-index" 5014 + checksum = "5d3976825c0014bbd2f3b34f0001876604fe87e0c86cd8fa54251530f1544ace" 5015 + dependencies = [ 5016 + "anyhow", 5017 + "once_cell", 5018 + "protobuf", 5019 + "protobuf-parse", 5020 + "regex", 5021 + "tempfile", 5022 + "thiserror 1.0.69", 5023 + ] 5024 + 5025 + [[package]] 5026 + name = "protobuf-parse" 5027 + version = "3.7.2" 5028 + source = "registry+https://github.com/rust-lang/crates.io-index" 5029 + checksum = "b4aeaa1f2460f1d348eeaeed86aea999ce98c1bded6f089ff8514c9d9dbdc973" 5030 + dependencies = [ 5031 + "anyhow", 5032 + "indexmap 2.12.1", 5033 + "log", 5034 + "protobuf", 5035 + "protobuf-support", 5036 + "tempfile", 5037 + "thiserror 1.0.69", 5038 + "which", 5039 + ] 5040 + 5041 + [[package]] 5042 + name = "protobuf-support" 5043 + version = "3.7.2" 5044 + source = "registry+https://github.com/rust-lang/crates.io-index" 5045 + checksum = "3e36c2f31e0a47f9280fb347ef5e461ffcd2c52dd520d8e216b52f93b0b0d7d6" 5046 + dependencies = [ 5047 + "thiserror 1.0.69", 4297 5048 ] 4298 5049 4299 5050 [[package]] ··· 4343 5094 source = "registry+https://github.com/rust-lang/crates.io-index" 4344 5095 checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" 4345 5096 5097 + [[package]] 5098 + name = "quick-xml" 5099 + version = "0.38.4" 5100 + source = "registry+https://github.com/rust-lang/crates.io-index" 5101 + checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" 5102 + dependencies = [ 5103 + "memchr", 5104 + ] 5105 + 4346 5106 [[package]] 4347 5107 name = "quinn" 4348 5108 version = "0.11.9" ··· 4496 5256 "bitflags", 4497 5257 ] 4498 5258 5259 + [[package]] 5260 + name = "rayon" 5261 + version = "1.11.0" 5262 + source = "registry+https://github.com/rust-lang/crates.io-index" 5263 + checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" 5264 + dependencies = [ 5265 + "either", 5266 + "rayon-core", 5267 + ] 5268 + 5269 + [[package]] 5270 + name = "rayon-core" 5271 + version = "1.13.0" 5272 + source = "registry+https://github.com/rust-lang/crates.io-index" 5273 + checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" 5274 + dependencies = [ 5275 + "crossbeam-deque", 5276 + "crossbeam-utils", 5277 + ] 5278 + 4499 5279 [[package]] 4500 5280 name = "redis" 4501 5281 version = "1.0.1" ··· 4570 5350 "aho-corasick", 4571 5351 "memchr", 4572 5352 "regex-automata", 4573 - "regex-syntax", 5353 + "regex-syntax 0.8.8", 4574 5354 ] 4575 5355 4576 5356 [[package]] ··· 4581 5361 dependencies = [ 4582 5362 "aho-corasick", 4583 5363 "memchr", 4584 - "regex-syntax", 5364 + "regex-syntax 0.8.8", 5365 + ] 5366 + 5367 + [[package]] 5368 + name = "regex-cache" 5369 + version = "0.2.1" 5370 + source = "registry+https://github.com/rust-lang/crates.io-index" 5371 + checksum = "2f7b62d69743b8b94f353b6b7c3deb4c5582828328bcb8d5fedf214373808793" 5372 + dependencies = [ 5373 + "lru-cache", 5374 + "oncemutex", 5375 + "regex", 5376 + "regex-syntax 0.6.29", 4585 5377 ] 4586 5378 4587 5379 [[package]] 4588 5380 name = "regex-lite" 4589 5381 version = "0.1.8" 4590 5382 source = "registry+https://github.com/rust-lang/crates.io-index" 4591 - checksum = "8d942b98df5e658f56f20d592c7f868833fe38115e65c33003d8cd224b0155da" 5383 + checksum = "8d942b98df5e658f56f20d592c7f868833fe38115e65c33003d8cd224b0155da" 5384 + 5385 + [[package]] 5386 + name = "regex-syntax" 5387 + version = "0.6.29" 5388 + source = "registry+https://github.com/rust-lang/crates.io-index" 5389 + checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" 4592 5390 4593 5391 [[package]] 4594 5392 name = "regex-syntax" ··· 4606 5404 "bytes", 4607 5405 "encoding_rs", 4608 5406 "futures-core", 5407 + "futures-util", 4609 5408 "h2 0.4.12", 4610 5409 "http 1.4.0", 4611 5410 "http-body 1.0.1", ··· 4616 5415 "js-sys", 4617 5416 "log", 4618 5417 "mime", 5418 + "mime_guess", 4619 5419 "percent-encoding", 4620 5420 "pin-project-lite", 4621 5421 "quinn", ··· 4627 5427 "sync_wrapper", 4628 5428 "tokio", 4629 5429 "tokio-rustls 0.26.4", 5430 + "tokio-util", 4630 5431 "tower", 4631 5432 "tower-http", 4632 5433 "tower-service", 4633 5434 "url", 4634 5435 "wasm-bindgen", 4635 5436 "wasm-bindgen-futures", 5437 + "wasm-streams", 4636 5438 "web-sys", 4637 5439 "webpki-roots 1.0.4", 4638 5440 ] 4639 5441 5442 + [[package]] 5443 + name = "reqwest-websocket" 5444 + version = "0.4.4" 5445 + source = "registry+https://github.com/rust-lang/crates.io-index" 5446 + checksum = "f477f800f86d8f5c320e19d8b2b1ef0b1e773ea7c75eec6c7f442e7ec3f06d7e" 5447 + dependencies = [ 5448 + "async-tungstenite", 5449 + "futures-util", 5450 + "reqwest", 5451 + "serde", 5452 + "serde_json", 5453 + "thiserror 2.0.17", 5454 + "tokio", 5455 + "tokio-util", 5456 + "tracing", 5457 + "tungstenite 0.24.0", 5458 + "web-sys", 5459 + ] 5460 + 4640 5461 [[package]] 4641 5462 name = "resolv-conf" 4642 5463 version = "0.7.6" ··· 4722 5543 "nom", 4723 5544 ] 4724 5545 5546 + [[package]] 5547 + name = "rustix" 5548 + version = "0.38.44" 5549 + source = "registry+https://github.com/rust-lang/crates.io-index" 5550 + checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" 5551 + dependencies = [ 5552 + "bitflags", 5553 + "errno", 5554 + "libc", 5555 + "linux-raw-sys 0.4.15", 5556 + "windows-sys 0.52.0", 5557 + ] 5558 + 4725 5559 [[package]] 4726 5560 name = "rustix" 4727 5561 version = "1.1.3" ··· 4731 5565 "bitflags", 4732 5566 "errno", 4733 5567 "libc", 4734 - "linux-raw-sys", 5568 + "linux-raw-sys 0.11.0", 4735 5569 "windows-sys 0.61.2", 4736 5570 ] 4737 5571 ··· 5134 5968 "cfg-if", 5135 5969 "cpufeatures", 5136 5970 "digest", 5971 + "sha2-asm", 5972 + ] 5973 + 5974 + [[package]] 5975 + name = "sha2-asm" 5976 + version = "0.6.4" 5977 + source = "registry+https://github.com/rust-lang/crates.io-index" 5978 + checksum = "b845214d6175804686b2bd482bcffe96651bb2d1200742b712003504a2dac1ab" 5979 + dependencies = [ 5980 + "cc", 5137 5981 ] 5138 5982 5139 5983 [[package]] ··· 5151 5995 source = "registry+https://github.com/rust-lang/crates.io-index" 5152 5996 checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 5153 5997 5998 + [[package]] 5999 + name = "signal-crypto" 6000 + version = "0.1.0" 6001 + source = "git+https://github.com/signalapp/libsignal?tag=v0.87.4#38514bdc8acaaffbccd5c96515c68deb2019abe0" 6002 + dependencies = [ 6003 + "aes", 6004 + "cbc", 6005 + "ctr", 6006 + "derive_more 2.1.1", 6007 + "displaydoc", 6008 + "ghash", 6009 + "hkdf", 6010 + "hmac", 6011 + "hpke-rs", 6012 + "hpke-rs-crypto", 6013 + "libsignal-core", 6014 + "rand_chacha 0.9.0", 6015 + "rand_core 0.9.3", 6016 + "sha1", 6017 + "sha2", 6018 + "subtle", 6019 + "thiserror 2.0.17", 6020 + ] 6021 + 5154 6022 [[package]] 5155 6023 name = "signal-hook-registry" 5156 6024 version = "1.4.7" ··· 5249 6117 "windows-sys 0.60.2", 5250 6118 ] 5251 6119 6120 + [[package]] 6121 + name = "sorted-vec" 6122 + version = "0.8.10" 6123 + source = "registry+https://github.com/rust-lang/crates.io-index" 6124 + checksum = "19f58d7b0190c7f12df7e8be6b79767a0836059159811b869d5ab55721fe14d0" 6125 + 5252 6126 [[package]] 5253 6127 name = "spin" 5254 6128 version = "0.9.8" ··· 5293 6167 "der 0.7.10", 5294 6168 ] 5295 6169 6170 + [[package]] 6171 + name = "spqr" 6172 + version = "1.4.0" 6173 + source = "git+https://github.com/signalapp/SparsePostQuantumRatchet.git?tag=v1.4.0#d310c99c57a046549be205b9ce50d80dcbe5f3e4" 6174 + dependencies = [ 6175 + "cpufeatures", 6176 + "curve25519-dalek", 6177 + "displaydoc", 6178 + "hax-lib", 6179 + "hkdf", 6180 + "libcrux-hmac", 6181 + "libcrux-ml-kem", 6182 + "log", 6183 + "num_enum", 6184 + "prost 0.14.1", 6185 + "prost-build 0.14.1", 6186 + "rand 0.9.2", 6187 + "rand_core 0.9.3", 6188 + "sha2", 6189 + "sorted-vec", 6190 + "thiserror 2.0.17", 6191 + ] 6192 + 5296 6193 [[package]] 5297 6194 name = "sqlx" 5298 6195 version = "0.8.6" ··· 5563 6460 "syn 2.0.111", 5564 6461 ] 5565 6462 6463 + [[package]] 6464 + name = "strum" 6465 + version = "0.27.2" 6466 + source = "registry+https://github.com/rust-lang/crates.io-index" 6467 + checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" 6468 + dependencies = [ 6469 + "strum_macros", 6470 + ] 6471 + 6472 + [[package]] 6473 + name = "strum_macros" 6474 + version = "0.27.2" 6475 + source = "registry+https://github.com/rust-lang/crates.io-index" 6476 + checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" 6477 + dependencies = [ 6478 + "heck 0.5.0", 6479 + "proc-macro2", 6480 + "quote", 6481 + "syn 2.0.111", 6482 + ] 6483 + 5566 6484 [[package]] 5567 6485 name = "subtle" 5568 6486 version = "2.6.1" ··· 5632 6550 "libc", 5633 6551 ] 5634 6552 6553 + [[package]] 6554 + name = "tempfile" 6555 + version = "3.25.0" 6556 + source = "registry+https://github.com/rust-lang/crates.io-index" 6557 + checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" 6558 + dependencies = [ 6559 + "fastrand", 6560 + "getrandom 0.3.4", 6561 + "once_cell", 6562 + "rustix 1.1.3", 6563 + "windows-sys 0.52.0", 6564 + ] 6565 + 5635 6566 [[package]] 5636 6567 name = "testcontainers" 5637 6568 version = "0.26.2" ··· 5846 6777 "rustls-pki-types", 5847 6778 "tokio", 5848 6779 "tokio-rustls 0.26.4", 5849 - "tungstenite", 6780 + "tungstenite 0.28.0", 5850 6781 "webpki-roots 0.26.11", 5851 6782 ] 5852 6783 ··· 5858 6789 dependencies = [ 5859 6790 "bytes", 5860 6791 "futures-core", 6792 + "futures-io", 5861 6793 "futures-sink", 5862 6794 "futures-util", 5863 6795 "pin-project-lite", ··· 5873 6805 "indexmap 2.12.1", 5874 6806 "serde_core", 5875 6807 "serde_spanned", 5876 - "toml_datetime", 6808 + "toml_datetime 0.7.5+spec-1.1.0", 5877 6809 "toml_parser", 5878 6810 "toml_writer", 5879 6811 "winnow", ··· 5888 6820 "serde_core", 5889 6821 ] 5890 6822 6823 + [[package]] 6824 + name = "toml_datetime" 6825 + version = "1.0.1+spec-1.1.0" 6826 + source = "registry+https://github.com/rust-lang/crates.io-index" 6827 + checksum = "9b320e741db58cac564e26c607d3cc1fdc4a88fd36c879568c07856ed83ff3e9" 6828 + dependencies = [ 6829 + "serde_core", 6830 + ] 6831 + 6832 + [[package]] 6833 + name = "toml_edit" 6834 + version = "0.25.0+spec-1.1.0" 6835 + source = "registry+https://github.com/rust-lang/crates.io-index" 6836 + checksum = "caee3f6e1c6f2025affe9191e6e6f66ade10b48f36b1a1b3cd92dfe405ffd260" 6837 + dependencies = [ 6838 + "indexmap 2.12.1", 6839 + "toml_datetime 1.0.1+spec-1.1.0", 6840 + "toml_parser", 6841 + "winnow", 6842 + ] 6843 + 5891 6844 [[package]] 5892 6845 name = "toml_parser" 5893 6846 version = "1.0.7+spec-1.1.0" ··· 5939 6892 checksum = "66bd50ad6ce1252d87ef024b3d64fe4c3cf54a86fb9ef4c631fdd0ded7aeaa67" 5940 6893 dependencies = [ 5941 6894 "bytes", 5942 - "prost", 6895 + "prost 0.14.1", 5943 6896 "tonic", 5944 6897 ] 5945 6898 ··· 6052 7005 "valuable", 6053 7006 ] 6054 7007 7008 + [[package]] 7009 + name = "tracing-futures" 7010 + version = "0.2.5" 7011 + source = "registry+https://github.com/rust-lang/crates.io-index" 7012 + checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" 7013 + dependencies = [ 7014 + "pin-project", 7015 + "tracing", 7016 + ] 7017 + 6055 7018 [[package]] 6056 7019 name = "tracing-log" 6057 7020 version = "0.2.0" ··· 6094 7057 6095 7058 [[package]] 6096 7059 name = "tranquil-api" 6097 - version = "0.4.6" 7060 + version = "0.4.7" 6098 7061 dependencies = [ 6099 7062 "anyhow", 6100 7063 "axum", ··· 6142 7105 6143 7106 [[package]] 6144 7107 name = "tranquil-auth" 6145 - version = "0.4.6" 7108 + version = "0.4.7" 6146 7109 dependencies = [ 6147 7110 "anyhow", 6148 7111 "base32", ··· 6165 7128 6166 7129 [[package]] 6167 7130 name = "tranquil-cache" 6168 - version = "0.4.6" 7131 + version = "0.4.7" 6169 7132 dependencies = [ 6170 7133 "async-trait", 6171 7134 "base64 0.22.1", ··· 6179 7142 6180 7143 [[package]] 6181 7144 name = "tranquil-comms" 6182 - version = "0.4.6" 7145 + version = "0.4.7" 6183 7146 dependencies = [ 6184 7147 "async-trait", 6185 7148 "base64 0.22.1", ··· 6194 7157 6195 7158 [[package]] 6196 7159 name = "tranquil-config" 6197 - version = "0.4.6" 7160 + version = "0.4.7" 6198 7161 dependencies = [ 6199 7162 "confique", 6200 7163 "serde", ··· 6202 7165 6203 7166 [[package]] 6204 7167 name = "tranquil-crypto" 6205 - version = "0.4.6" 7168 + version = "0.4.7" 6206 7169 dependencies = [ 6207 7170 "aes-gcm", 6208 7171 "base64 0.22.1", ··· 6218 7181 6219 7182 [[package]] 6220 7183 name = "tranquil-db" 6221 - version = "0.4.6" 7184 + version = "0.4.7" 6222 7185 dependencies = [ 6223 7186 "async-trait", 6224 7187 "chrono", ··· 6235 7198 6236 7199 [[package]] 6237 7200 name = "tranquil-db-traits" 6238 - version = "0.4.6" 7201 + version = "0.4.7" 6239 7202 dependencies = [ 6240 7203 "async-trait", 6241 7204 "base64 0.22.1", ··· 6251 7214 6252 7215 [[package]] 6253 7216 name = "tranquil-infra" 6254 - version = "0.4.6" 7217 + version = "0.4.7" 6255 7218 dependencies = [ 6256 7219 "async-trait", 6257 7220 "bytes", ··· 6262 7225 6263 7226 [[package]] 6264 7227 name = "tranquil-lexicon" 6265 - version = "0.4.6" 7228 + version = "0.4.7" 6266 7229 dependencies = [ 6267 7230 "chrono", 6268 7231 "hickory-resolver", ··· 6280 7243 6281 7244 [[package]] 6282 7245 name = "tranquil-oauth" 6283 - version = "0.4.6" 7246 + version = "0.4.7" 6284 7247 dependencies = [ 6285 7248 "anyhow", 6286 7249 "axum", ··· 6303 7266 6304 7267 [[package]] 6305 7268 name = "tranquil-oauth-server" 6306 - version = "0.4.6" 7269 + version = "0.4.7" 6307 7270 dependencies = [ 6308 7271 "axum", 6309 7272 "base64 0.22.1", ··· 6336 7299 6337 7300 [[package]] 6338 7301 name = "tranquil-pds" 6339 - version = "0.4.6" 7302 + version = "0.4.7" 6340 7303 dependencies = [ 6341 7304 "aes-gcm", 6342 7305 "anyhow", ··· 6424 7387 6425 7388 [[package]] 6426 7389 name = "tranquil-repo" 6427 - version = "0.4.6" 7390 + version = "0.4.7" 6428 7391 dependencies = [ 6429 7392 "bytes", 6430 7393 "cid", ··· 6436 7399 6437 7400 [[package]] 6438 7401 name = "tranquil-ripple" 6439 - version = "0.4.6" 7402 + version = "0.4.7" 6440 7403 dependencies = [ 6441 7404 "async-trait", 6442 7405 "backon", 6443 - "bincode", 7406 + "bincode 2.0.1", 6444 7407 "bytes", 6445 7408 "foca", 6446 7409 "futures", ··· 6461 7424 6462 7425 [[package]] 6463 7426 name = "tranquil-scopes" 6464 - version = "0.4.6" 7427 + version = "0.4.7" 6465 7428 dependencies = [ 6466 7429 "axum", 6467 7430 "futures", ··· 6477 7440 6478 7441 [[package]] 6479 7442 name = "tranquil-server" 6480 - version = "0.4.6" 7443 + version = "0.4.7" 6481 7444 dependencies = [ 6482 7445 "axum", 6483 7446 "clap", ··· 6495 7458 "tranquil-sync", 6496 7459 ] 6497 7460 7461 + [[package]] 7462 + name = "tranquil-signal" 7463 + version = "0.4.7" 7464 + dependencies = [ 7465 + "async-trait", 7466 + "chrono", 7467 + "futures", 7468 + "presage", 7469 + "rand 0.9.2", 7470 + "serde", 7471 + "serde_json", 7472 + "sqlx", 7473 + "thiserror 2.0.17", 7474 + "tokio", 7475 + "tokio-util", 7476 + "tracing", 7477 + "url", 7478 + "uuid", 7479 + ] 7480 + 6498 7481 [[package]] 6499 7482 name = "tranquil-storage" 6500 - version = "0.4.6" 7483 + version = "0.4.7" 6501 7484 dependencies = [ 6502 7485 "async-trait", 6503 7486 "aws-config", ··· 6514 7497 6515 7498 [[package]] 6516 7499 name = "tranquil-sync" 6517 - version = "0.4.6" 7500 + version = "0.4.7" 6518 7501 dependencies = [ 6519 7502 "anyhow", 6520 7503 "axum", ··· 6536 7519 6537 7520 [[package]] 6538 7521 name = "tranquil-types" 6539 - version = "0.4.6" 7522 + version = "0.4.7" 6540 7523 dependencies = [ 6541 7524 "chrono", 6542 7525 "cid", ··· 6553 7536 source = "registry+https://github.com/rust-lang/crates.io-index" 6554 7537 checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 6555 7538 7539 + [[package]] 7540 + name = "tungstenite" 7541 + version = "0.24.0" 7542 + source = "registry+https://github.com/rust-lang/crates.io-index" 7543 + checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" 7544 + dependencies = [ 7545 + "byteorder", 7546 + "bytes", 7547 + "data-encoding", 7548 + "http 1.4.0", 7549 + "httparse", 7550 + "log", 7551 + "rand 0.8.5", 7552 + "sha1", 7553 + "thiserror 1.0.69", 7554 + "utf-8", 7555 + ] 7556 + 6556 7557 [[package]] 6557 7558 name = "tungstenite" 6558 7559 version = "0.28.0" ··· 6709 7710 source = "registry+https://github.com/rust-lang/crates.io-index" 6710 7711 checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" 6711 7712 7713 + [[package]] 7714 + name = "usernames" 7715 + version = "0.1.0" 7716 + source = "git+https://github.com/signalapp/libsignal?tag=v0.87.4#38514bdc8acaaffbccd5c96515c68deb2019abe0" 7717 + dependencies = [ 7718 + "curve25519-dalek", 7719 + "displaydoc", 7720 + "hkdf", 7721 + "hmac", 7722 + "log", 7723 + "poksho", 7724 + "prost 0.14.1", 7725 + "prost-build 0.14.1", 7726 + "rand 0.9.2", 7727 + "sha2", 7728 + "signal-crypto", 7729 + "subtle", 7730 + "thiserror 2.0.17", 7731 + ] 7732 + 6712 7733 [[package]] 6713 7734 name = "utf-8" 6714 7735 version = "0.7.6" ··· 6859 7880 "unicode-ident", 6860 7881 ] 6861 7882 7883 + [[package]] 7884 + name = "wasm-streams" 7885 + version = "0.4.2" 7886 + source = "registry+https://github.com/rust-lang/crates.io-index" 7887 + checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" 7888 + dependencies = [ 7889 + "futures-util", 7890 + "js-sys", 7891 + "wasm-bindgen", 7892 + "wasm-bindgen-futures", 7893 + "web-sys", 7894 + ] 7895 + 6862 7896 [[package]] 6863 7897 name = "web-sys" 6864 7898 version = "0.3.83" ··· 6971 8005 source = "registry+https://github.com/rust-lang/crates.io-index" 6972 8006 checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" 6973 8007 8008 + [[package]] 8009 + name = "which" 8010 + version = "4.4.2" 8011 + source = "registry+https://github.com/rust-lang/crates.io-index" 8012 + checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" 8013 + dependencies = [ 8014 + "either", 8015 + "home", 8016 + "once_cell", 8017 + "rustix 0.38.44", 8018 + ] 8019 + 6974 8020 [[package]] 6975 8021 name = "whoami" 6976 8022 version = "1.6.1" ··· 7306 8352 version = "0.7.14" 7307 8353 source = "registry+https://github.com/rust-lang/crates.io-index" 7308 8354 checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" 8355 + dependencies = [ 8356 + "memchr", 8357 + ] 7309 8358 7310 8359 [[package]] 7311 8360 name = "winreg" ··· 7352 8401 source = "registry+https://github.com/rust-lang/crates.io-index" 7353 8402 checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" 7354 8403 8404 + [[package]] 8405 + name = "x25519-dalek" 8406 + version = "2.0.1" 8407 + source = "registry+https://github.com/rust-lang/crates.io-index" 8408 + checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" 8409 + dependencies = [ 8410 + "curve25519-dalek", 8411 + "rand_core 0.6.4", 8412 + "serde", 8413 + "zeroize", 8414 + ] 8415 + 7355 8416 [[package]] 7356 8417 name = "x509-parser" 7357 8418 version = "0.16.0" ··· 7376 8437 checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" 7377 8438 dependencies = [ 7378 8439 "libc", 7379 - "rustix", 8440 + "rustix 1.1.3", 7380 8441 ] 7381 8442 7382 8443 [[package]] ··· 7466 8527 version = "1.8.2" 7467 8528 source = "registry+https://github.com/rust-lang/crates.io-index" 7468 8529 checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" 8530 + dependencies = [ 8531 + "zeroize_derive", 8532 + ] 8533 + 8534 + [[package]] 8535 + name = "zeroize_derive" 8536 + version = "1.4.3" 8537 + source = "registry+https://github.com/rust-lang/crates.io-index" 8538 + checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" 8539 + dependencies = [ 8540 + "proc-macro2", 8541 + "quote", 8542 + "syn 2.0.111", 8543 + ] 7469 8544 7470 8545 [[package]] 7471 8546 name = "zerotrie" ··· 7514 8589 "zopfli", 7515 8590 ] 7516 8591 8592 + [[package]] 8593 + name = "zkcredential" 8594 + version = "0.1.0" 8595 + source = "git+https://github.com/signalapp/libsignal?tag=v0.87.4#38514bdc8acaaffbccd5c96515c68deb2019abe0" 8596 + dependencies = [ 8597 + "cfg-if", 8598 + "curve25519-dalek", 8599 + "derive-where", 8600 + "displaydoc", 8601 + "partial-default", 8602 + "poksho", 8603 + "rayon", 8604 + "serde", 8605 + "sha2", 8606 + "subtle", 8607 + "thiserror 2.0.17", 8608 + ] 8609 + 8610 + [[package]] 8611 + name = "zkgroup" 8612 + version = "0.9.0" 8613 + source = "git+https://github.com/signalapp/libsignal?tag=v0.87.4#38514bdc8acaaffbccd5c96515c68deb2019abe0" 8614 + dependencies = [ 8615 + "aes", 8616 + "aes-gcm-siv", 8617 + "bincode 1.3.3", 8618 + "const-str 1.1.0", 8619 + "curve25519-dalek", 8620 + "derive-where", 8621 + "derive_more 2.1.1", 8622 + "displaydoc", 8623 + "hex", 8624 + "hkdf", 8625 + "libsignal-account-keys", 8626 + "libsignal-core", 8627 + "partial-default", 8628 + "poksho", 8629 + "rand 0.9.2", 8630 + "rayon", 8631 + "serde", 8632 + "sha2", 8633 + "static_assertions", 8634 + "subtle", 8635 + "thiserror 2.0.17", 8636 + "uuid", 8637 + "zkcredential", 8638 + ] 8639 + 7517 8640 [[package]] 7518 8641 name = "zlib-rs" 7519 8642 version = "0.5.5"
+9 -1
Cargo.toml
··· 21 21 "crates/tranquil-oauth-server", 22 22 "crates/tranquil-api", 23 23 "crates/tranquil-lexicon", 24 + "crates/tranquil-signal", 24 25 ] 25 26 26 27 [workspace.package] 27 - version = "0.4.6" 28 + version = "0.4.7" 28 29 edition = "2024" 29 30 license = "AGPL-3.0-or-later" 30 31 ··· 49 50 tranquil-sync = { path = "crates/tranquil-sync" } 50 51 tranquil-oauth-server = { path = "crates/tranquil-oauth-server" } 51 52 tranquil-api = { path = "crates/tranquil-api" } 53 + tranquil-signal = { path = "crates/tranquil-signal" } 54 + 55 + presage = { git = "https://github.com/whisperfish/presage", rev = "fe3ed54c4844ae51c3a9fa49cf80a7816a31a425", default-features = false } 52 56 53 57 unicode-segmentation = "1" 54 58 ··· 81 85 hmac = "0.12" 82 86 http = "1.4" 83 87 image = { version = "0.25", default-features = false, features = ["jpeg", "png", "gif", "webp"] } 88 + qrcodegen = "1.8" 84 89 infer = "0.19" 85 90 ipld-core = "0.4" 86 91 iroh-car = "0.5" ··· 129 134 testcontainers-modules = { version = "0.14", features = ["postgres"] } 130 135 wiremock = "0.6" 131 136 137 + [patch.crates-io] 138 + curve25519-dalek = { git = "https://github.com/signalapp/curve25519-dalek", tag = "signal-curve25519-4.1.3" } 139 + 132 140 [profile.release] 133 141 lto = "fat" 134 142 strip = true
+23
crates/tranquil-signal/Cargo.toml
··· 1 + [package] 2 + name = "tranquil-signal" 3 + version.workspace = true 4 + edition.workspace = true 5 + license.workspace = true 6 + 7 + [dependencies] 8 + presage = { workspace = true } 9 + async-trait = { workspace = true } 10 + chrono = { workspace = true } 11 + sqlx = { workspace = true } 12 + tracing = { workspace = true } 13 + tokio = { workspace = true } 14 + tokio-util = { workspace = true } 15 + futures = { workspace = true } 16 + serde = { workspace = true } 17 + serde_json = { workspace = true } 18 + url = "2.5" 19 + uuid = { workspace = true } 20 + thiserror = { workspace = true } 21 + 22 + [dev-dependencies] 23 + rand = "0.9"
+1177
crates/tranquil-signal/src/store.rs
··· 1 + use std::ops::RangeBounds; 2 + 3 + use async_trait::async_trait; 4 + use presage::{ 5 + AvatarBytes, 6 + libsignal_service::{ 7 + Profile, 8 + pre_keys::{KyberPreKeyStoreExt, PreKeysStore}, 9 + prelude::{Content, MasterKey, ProfileKey, SessionStoreExt, Uuid}, 10 + protocol::{ 11 + CiphertextMessageType, DeviceId, Direction, GenericSignedPreKey, IdentityChange, 12 + IdentityKey, IdentityKeyPair, IdentityKeyStore, KyberPreKeyId, KyberPreKeyRecord, 13 + KyberPreKeyStore, PreKeyId, PreKeyRecord, PreKeyStore, ProtocolAddress, ProtocolStore, 14 + PublicKey, SenderCertificate, SenderKeyRecord, SenderKeyStore, ServiceId, 15 + SessionRecord, SessionStore, SignalProtocolError, SignedPreKeyId, SignedPreKeyRecord, 16 + SignedPreKeyStore, 17 + }, 18 + push_service::DEFAULT_DEVICE_ID, 19 + zkgroup::GroupMasterKeyBytes, 20 + }, 21 + manager::RegistrationData, 22 + model::{contacts::Contact, groups::Group}, 23 + store::{ContentsStore, StateStore, StickerPack, Store, Thread}, 24 + }; 25 + use sqlx::PgPool; 26 + use tracing::warn; 27 + 28 + #[derive(Debug, Clone)] 29 + pub struct PgSignalStore { 30 + pub db: PgPool, 31 + } 32 + 33 + impl PgSignalStore { 34 + pub fn new(db: PgPool) -> Self { 35 + Self { db } 36 + } 37 + 38 + pub async fn is_linked(&self) -> Result<bool, PgStoreError> { 39 + let row = sqlx::query!("SELECT value FROM signal_kv WHERE key = 'registration'") 40 + .fetch_optional(&self.db) 41 + .await?; 42 + Ok(row.is_some()) 43 + } 44 + 45 + async fn set_identity_key_pair( 46 + &self, 47 + identity: IdentityType, 48 + key_pair: IdentityKeyPair, 49 + ) -> Result<(), PgStoreError> { 50 + let key = identity.identity_key_pair_key(); 51 + let value = key_pair.serialize().to_vec(); 52 + sqlx::query!( 53 + "INSERT INTO signal_kv (key, value) VALUES ($1, $2) 54 + ON CONFLICT (key) DO UPDATE SET value = $2", 55 + key, 56 + &value, 57 + ) 58 + .execute(&self.db) 59 + .await?; 60 + Ok(()) 61 + } 62 + 63 + async fn clear_protocol_tables( 64 + tx: &mut sqlx::Transaction<'_, sqlx::Postgres>, 65 + ) -> Result<(), PgStoreError> { 66 + sqlx::query!("DELETE FROM signal_base_keys_seen") 67 + .execute(&mut **tx) 68 + .await?; 69 + sqlx::query!("DELETE FROM signal_sender_keys") 70 + .execute(&mut **tx) 71 + .await?; 72 + sqlx::query!("DELETE FROM signal_kyber_pre_keys") 73 + .execute(&mut **tx) 74 + .await?; 75 + sqlx::query!("DELETE FROM signal_signed_pre_keys") 76 + .execute(&mut **tx) 77 + .await?; 78 + sqlx::query!("DELETE FROM signal_pre_keys") 79 + .execute(&mut **tx) 80 + .await?; 81 + sqlx::query!("DELETE FROM signal_identities") 82 + .execute(&mut **tx) 83 + .await?; 84 + sqlx::query!("DELETE FROM signal_sessions") 85 + .execute(&mut **tx) 86 + .await?; 87 + Ok(()) 88 + } 89 + 90 + pub async fn clear_all(&self) -> Result<(), PgStoreError> { 91 + let mut tx = self.db.begin().await?; 92 + Self::clear_protocol_tables(&mut tx).await?; 93 + sqlx::query!("DELETE FROM signal_profile_keys") 94 + .execute(&mut *tx) 95 + .await?; 96 + sqlx::query!("DELETE FROM signal_kv") 97 + .execute(&mut *tx) 98 + .await?; 99 + tx.commit().await?; 100 + Ok(()) 101 + } 102 + } 103 + 104 + #[derive(Debug, Clone)] 105 + pub struct PgProtocolStore { 106 + store: PgSignalStore, 107 + identity: IdentityType, 108 + } 109 + 110 + impl PgProtocolStore { 111 + pub(crate) fn new(store: PgSignalStore, identity: IdentityType) -> Self { 112 + Self { store, identity } 113 + } 114 + } 115 + 116 + fn next_id_from_max(max_id: Option<i32>) -> Result<u32, SignalProtocolError> { 117 + match max_id { 118 + None => Ok(1), 119 + Some(id) => { 120 + let current = i32_to_u32(id)?; 121 + current.checked_add(1).ok_or_else(|| { 122 + SignalProtocolError::InvalidState( 123 + "pre key id space exhausted", 124 + format!("max id {current} has no successor"), 125 + ) 126 + }) 127 + } 128 + } 129 + } 130 + 131 + #[derive(Debug, Clone, Copy)] 132 + pub enum IdentityType { 133 + Aci, 134 + Pni, 135 + } 136 + 137 + impl IdentityType { 138 + fn as_str(&self) -> &'static str { 139 + match self { 140 + Self::Aci => "aci", 141 + Self::Pni => "pni", 142 + } 143 + } 144 + 145 + fn identity_key_pair_key(&self) -> &'static str { 146 + match self { 147 + Self::Aci => "identity_keypair_aci", 148 + Self::Pni => "identity_keypair_pni", 149 + } 150 + } 151 + } 152 + 153 + #[derive(Debug, thiserror::Error)] 154 + pub enum PgStoreError { 155 + #[error("sqlx: {0}")] 156 + Sqlx(#[from] sqlx::Error), 157 + #[error("json: {0}")] 158 + Json(#[from] serde_json::Error), 159 + #[error("protocol: {0}")] 160 + Protocol(#[from] SignalProtocolError), 161 + #[error("invalid format")] 162 + InvalidFormat, 163 + } 164 + 165 + impl presage::store::StoreError for PgStoreError {} 166 + 167 + fn u32_to_i32(val: u32) -> Result<i32, SignalProtocolError> { 168 + i32::try_from(val).map_err(|_| { 169 + SignalProtocolError::InvalidState("id overflow", format!("{val} exceeds i32::MAX")) 170 + }) 171 + } 172 + 173 + fn i32_to_u32(val: i32) -> Result<u32, SignalProtocolError> { 174 + u32::try_from(val) 175 + .map_err(|_| SignalProtocolError::InvalidState("negative id", format!("{val} is negative"))) 176 + } 177 + 178 + trait IntoProtocolError<T> { 179 + fn into_protocol_error(self) -> Result<T, SignalProtocolError>; 180 + } 181 + 182 + impl<T> IntoProtocolError<T> for Result<T, sqlx::Error> { 183 + fn into_protocol_error(self) -> Result<T, SignalProtocolError> { 184 + self.map_err(|e| SignalProtocolError::InvalidState("sqlx", e.to_string())) 185 + } 186 + } 187 + 188 + impl<T> IntoProtocolError<T> for Result<T, PgStoreError> { 189 + fn into_protocol_error(self) -> Result<T, SignalProtocolError> { 190 + self.map_err(|e| SignalProtocolError::InvalidState("store", e.to_string())) 191 + } 192 + } 193 + 194 + impl Store for PgSignalStore { 195 + type Error = PgStoreError; 196 + type AciStore = PgProtocolStore; 197 + type PniStore = PgProtocolStore; 198 + 199 + async fn clear(&mut self) -> Result<(), PgStoreError> { 200 + self.clear_all().await 201 + } 202 + 203 + fn aci_protocol_store(&self) -> Self::AciStore { 204 + PgProtocolStore::new(self.clone(), IdentityType::Aci) 205 + } 206 + 207 + fn pni_protocol_store(&self) -> Self::PniStore { 208 + PgProtocolStore::new(self.clone(), IdentityType::Pni) 209 + } 210 + } 211 + 212 + impl StateStore for PgSignalStore { 213 + type StateStoreError = PgStoreError; 214 + 215 + async fn load_registration_data(&self) -> Result<Option<RegistrationData>, PgStoreError> { 216 + sqlx::query_scalar!("SELECT value FROM signal_kv WHERE key = 'registration'") 217 + .fetch_optional(&self.db) 218 + .await? 219 + .map(|value| serde_json::from_slice(&value)) 220 + .transpose() 221 + .map_err(From::from) 222 + } 223 + 224 + async fn save_registration_data( 225 + &mut self, 226 + state: &RegistrationData, 227 + ) -> Result<(), PgStoreError> { 228 + let value = serde_json::to_vec(state)?; 229 + sqlx::query!( 230 + "INSERT INTO signal_kv (key, value) VALUES ('registration', $1) 231 + ON CONFLICT (key) DO UPDATE SET value = $1", 232 + &value, 233 + ) 234 + .execute(&self.db) 235 + .await?; 236 + Ok(()) 237 + } 238 + 239 + async fn is_registered(&self) -> bool { 240 + self.load_registration_data().await.ok().flatten().is_some() 241 + } 242 + 243 + async fn clear_registration(&mut self) -> Result<(), PgStoreError> { 244 + let mut tx = self.db.begin().await?; 245 + sqlx::query!("DELETE FROM signal_kv WHERE key = 'registration'") 246 + .execute(&mut *tx) 247 + .await?; 248 + Self::clear_protocol_tables(&mut tx).await?; 249 + tx.commit().await?; 250 + Ok(()) 251 + } 252 + 253 + async fn set_aci_identity_key_pair( 254 + &self, 255 + key_pair: IdentityKeyPair, 256 + ) -> Result<(), PgStoreError> { 257 + self.set_identity_key_pair(IdentityType::Aci, key_pair) 258 + .await 259 + } 260 + 261 + async fn set_pni_identity_key_pair( 262 + &self, 263 + key_pair: IdentityKeyPair, 264 + ) -> Result<(), PgStoreError> { 265 + self.set_identity_key_pair(IdentityType::Pni, key_pair) 266 + .await 267 + } 268 + 269 + async fn sender_certificate(&self) -> Result<Option<SenderCertificate>, PgStoreError> { 270 + sqlx::query_scalar!("SELECT value FROM signal_kv WHERE key = 'sender_certificate' LIMIT 1") 271 + .fetch_optional(&self.db) 272 + .await? 273 + .map(|value| SenderCertificate::deserialize(&value)) 274 + .transpose() 275 + .map_err(From::from) 276 + } 277 + 278 + async fn save_sender_certificate( 279 + &self, 280 + certificate: &SenderCertificate, 281 + ) -> Result<(), PgStoreError> { 282 + let value = certificate.serialized()?.to_vec(); 283 + sqlx::query!( 284 + "INSERT INTO signal_kv (key, value) VALUES ('sender_certificate', $1) 285 + ON CONFLICT (key) DO UPDATE SET value = $1", 286 + &value, 287 + ) 288 + .execute(&self.db) 289 + .await?; 290 + Ok(()) 291 + } 292 + 293 + async fn fetch_master_key(&self) -> Result<Option<MasterKey>, PgStoreError> { 294 + sqlx::query_scalar!("SELECT value FROM signal_kv WHERE key = 'master_key' LIMIT 1") 295 + .fetch_optional(&self.db) 296 + .await? 297 + .map(|value| MasterKey::from_slice(&value)) 298 + .transpose() 299 + .map_err(|_| PgStoreError::InvalidFormat) 300 + } 301 + 302 + async fn store_master_key(&self, master_key: Option<&MasterKey>) -> Result<(), PgStoreError> { 303 + match master_key { 304 + Some(k) => { 305 + let value = k.inner.to_vec(); 306 + sqlx::query!( 307 + "INSERT INTO signal_kv (key, value) VALUES ('master_key', $1) 308 + ON CONFLICT (key) DO UPDATE SET value = $1", 309 + &value, 310 + ) 311 + .execute(&self.db) 312 + .await?; 313 + } 314 + None => { 315 + sqlx::query!("DELETE FROM signal_kv WHERE key = 'master_key'") 316 + .execute(&self.db) 317 + .await?; 318 + } 319 + } 320 + Ok(()) 321 + } 322 + } 323 + 324 + impl ProtocolStore for PgProtocolStore {} 325 + 326 + #[async_trait(?Send)] 327 + impl SessionStore for PgProtocolStore { 328 + async fn load_session( 329 + &self, 330 + address: &ProtocolAddress, 331 + ) -> Result<Option<SessionRecord>, SignalProtocolError> { 332 + let device_id: i32 = u32_to_i32(u32::from(address.device_id()))?; 333 + let identity = self.identity.as_str(); 334 + let addr = address.name(); 335 + sqlx::query_scalar!( 336 + "SELECT record FROM signal_sessions 337 + WHERE address = $1 AND device_id = $2 AND identity = $3", 338 + addr, 339 + device_id, 340 + identity, 341 + ) 342 + .fetch_optional(&self.store.db) 343 + .await 344 + .into_protocol_error()? 345 + .map(|record| SessionRecord::deserialize(&record)) 346 + .transpose() 347 + } 348 + 349 + async fn store_session( 350 + &mut self, 351 + address: &ProtocolAddress, 352 + record: &SessionRecord, 353 + ) -> Result<(), SignalProtocolError> { 354 + let device_id: i32 = u32_to_i32(u32::from(address.device_id()))?; 355 + let identity = self.identity.as_str(); 356 + let addr = address.name(); 357 + let record = record.serialize()?; 358 + sqlx::query!( 359 + "INSERT INTO signal_sessions (address, device_id, identity, record) 360 + VALUES ($1, $2, $3, $4) 361 + ON CONFLICT (address, device_id, identity) DO UPDATE SET record = $4", 362 + addr, 363 + device_id, 364 + identity, 365 + &record, 366 + ) 367 + .execute(&self.store.db) 368 + .await 369 + .into_protocol_error()?; 370 + Ok(()) 371 + } 372 + } 373 + 374 + #[async_trait(?Send)] 375 + impl SessionStoreExt for PgProtocolStore { 376 + async fn get_sub_device_sessions( 377 + &self, 378 + name: &ServiceId, 379 + ) -> Result<Vec<DeviceId>, SignalProtocolError> { 380 + let address = name.raw_uuid().to_string(); 381 + let default_device: i32 = u32_to_i32(u32::from(*DEFAULT_DEVICE_ID))?; 382 + let identity = self.identity.as_str(); 383 + sqlx::query_scalar!( 384 + "SELECT device_id FROM signal_sessions 385 + WHERE address = $1 AND device_id != $2 AND identity = $3", 386 + &address, 387 + default_device, 388 + identity, 389 + ) 390 + .fetch_all(&self.store.db) 391 + .await 392 + .into_protocol_error()? 393 + .into_iter() 394 + .map(|id| { 395 + let v = i32_to_u32(id)?; 396 + let byte = u8::try_from(v).map_err(|_| { 397 + SignalProtocolError::InvalidState("device id", format!("{id} exceeds u8::MAX")) 398 + })?; 399 + DeviceId::new(byte).map_err(|_| { 400 + SignalProtocolError::InvalidState("device id", format!("invalid device id {id}")) 401 + }) 402 + }) 403 + .collect() 404 + } 405 + 406 + async fn delete_session(&self, address: &ProtocolAddress) -> Result<(), SignalProtocolError> { 407 + let device_id: i32 = u32_to_i32(u32::from(address.device_id()))?; 408 + let identity = self.identity.as_str(); 409 + let addr = address.name(); 410 + sqlx::query!( 411 + "DELETE FROM signal_sessions WHERE address = $1 AND device_id = $2 AND identity = $3", 412 + addr, 413 + device_id, 414 + identity, 415 + ) 416 + .execute(&self.store.db) 417 + .await 418 + .into_protocol_error()?; 419 + Ok(()) 420 + } 421 + 422 + async fn delete_all_sessions(&self, name: &ServiceId) -> Result<usize, SignalProtocolError> { 423 + let address = name.raw_uuid().to_string(); 424 + let identity = self.identity.as_str(); 425 + let res = sqlx::query!( 426 + "DELETE FROM signal_sessions WHERE address = $1 AND identity = $2", 427 + &address, 428 + identity, 429 + ) 430 + .execute(&self.store.db) 431 + .await 432 + .into_protocol_error()?; 433 + Ok(usize::try_from(res.rows_affected()).unwrap_or(usize::MAX)) 434 + } 435 + } 436 + 437 + #[async_trait(?Send)] 438 + impl PreKeyStore for PgProtocolStore { 439 + async fn get_pre_key(&self, prekey_id: PreKeyId) -> Result<PreKeyRecord, SignalProtocolError> { 440 + let id: i32 = u32_to_i32(u32::from(prekey_id))?; 441 + let identity = self.identity.as_str(); 442 + let record = sqlx::query_scalar!( 443 + "SELECT record FROM signal_pre_keys WHERE id = $1 AND identity = $2", 444 + id, 445 + identity, 446 + ) 447 + .fetch_one(&self.store.db) 448 + .await 449 + .into_protocol_error()?; 450 + PreKeyRecord::deserialize(&record) 451 + } 452 + 453 + async fn save_pre_key( 454 + &mut self, 455 + prekey_id: PreKeyId, 456 + record: &PreKeyRecord, 457 + ) -> Result<(), SignalProtocolError> { 458 + let id: i32 = u32_to_i32(u32::from(prekey_id))?; 459 + let identity = self.identity.as_str(); 460 + let record = record.serialize()?; 461 + sqlx::query!( 462 + "INSERT INTO signal_pre_keys (id, identity, record) 463 + VALUES ($1, $2, $3) 464 + ON CONFLICT (id, identity) DO UPDATE SET record = $3", 465 + id, 466 + identity, 467 + &record, 468 + ) 469 + .execute(&self.store.db) 470 + .await 471 + .into_protocol_error()?; 472 + Ok(()) 473 + } 474 + 475 + async fn remove_pre_key(&mut self, prekey_id: PreKeyId) -> Result<(), SignalProtocolError> { 476 + let id: i32 = u32_to_i32(u32::from(prekey_id))?; 477 + let identity = self.identity.as_str(); 478 + sqlx::query!( 479 + "DELETE FROM signal_pre_keys WHERE id = $1 AND identity = $2", 480 + id, 481 + identity, 482 + ) 483 + .execute(&self.store.db) 484 + .await 485 + .into_protocol_error()?; 486 + Ok(()) 487 + } 488 + } 489 + 490 + #[async_trait(?Send)] 491 + impl PreKeysStore for PgProtocolStore { 492 + async fn next_pre_key_id(&self) -> Result<u32, SignalProtocolError> { 493 + let identity = self.identity.as_str(); 494 + let max_id = sqlx::query_scalar!( 495 + "SELECT MAX(id) FROM signal_pre_keys WHERE identity = $1", 496 + identity, 497 + ) 498 + .fetch_one(&self.store.db) 499 + .await 500 + .into_protocol_error()?; 501 + next_id_from_max(max_id) 502 + } 503 + 504 + async fn next_signed_pre_key_id(&self) -> Result<u32, SignalProtocolError> { 505 + let identity = self.identity.as_str(); 506 + let max_id = sqlx::query_scalar!( 507 + "SELECT MAX(id) FROM signal_signed_pre_keys WHERE identity = $1", 508 + identity, 509 + ) 510 + .fetch_one(&self.store.db) 511 + .await 512 + .into_protocol_error()?; 513 + next_id_from_max(max_id) 514 + } 515 + 516 + async fn next_pq_pre_key_id(&self) -> Result<u32, SignalProtocolError> { 517 + let identity = self.identity.as_str(); 518 + let max_id = sqlx::query_scalar!( 519 + "SELECT MAX(id) FROM signal_kyber_pre_keys WHERE identity = $1", 520 + identity, 521 + ) 522 + .fetch_one(&self.store.db) 523 + .await 524 + .into_protocol_error()?; 525 + next_id_from_max(max_id) 526 + } 527 + 528 + async fn signed_pre_keys_count(&self) -> Result<usize, SignalProtocolError> { 529 + let identity = self.identity.as_str(); 530 + let count = sqlx::query_scalar!( 531 + "SELECT COUNT(*) AS \"count!\" FROM signal_signed_pre_keys WHERE identity = $1", 532 + identity, 533 + ) 534 + .fetch_one(&self.store.db) 535 + .await 536 + .into_protocol_error()?; 537 + Ok(usize::try_from(count).unwrap_or(usize::MAX)) 538 + } 539 + 540 + async fn kyber_pre_keys_count(&self, last_resort: bool) -> Result<usize, SignalProtocolError> { 541 + let identity = self.identity.as_str(); 542 + let count = sqlx::query_scalar!( 543 + "SELECT COUNT(*) AS \"count!\" FROM signal_kyber_pre_keys 544 + WHERE identity = $1 AND is_last_resort = $2", 545 + identity, 546 + last_resort, 547 + ) 548 + .fetch_one(&self.store.db) 549 + .await 550 + .into_protocol_error()?; 551 + Ok(usize::try_from(count).unwrap_or(usize::MAX)) 552 + } 553 + 554 + async fn signed_prekey_id(&self) -> Result<Option<SignedPreKeyId>, SignalProtocolError> { 555 + let identity = self.identity.as_str(); 556 + let max_id = sqlx::query_scalar!( 557 + "SELECT MAX(id) FROM signal_signed_pre_keys WHERE identity = $1", 558 + identity, 559 + ) 560 + .fetch_one(&self.store.db) 561 + .await 562 + .into_protocol_error()?; 563 + max_id 564 + .map(|id| i32_to_u32(id).map(SignedPreKeyId::from)) 565 + .transpose() 566 + } 567 + 568 + async fn last_resort_kyber_prekey_id( 569 + &self, 570 + ) -> Result<Option<KyberPreKeyId>, SignalProtocolError> { 571 + let identity = self.identity.as_str(); 572 + let max_id = sqlx::query_scalar!( 573 + "SELECT MAX(id) FROM signal_kyber_pre_keys 574 + WHERE identity = $1 AND is_last_resort = TRUE", 575 + identity, 576 + ) 577 + .fetch_one(&self.store.db) 578 + .await 579 + .into_protocol_error()?; 580 + max_id 581 + .map(|id| i32_to_u32(id).map(KyberPreKeyId::from)) 582 + .transpose() 583 + } 584 + } 585 + 586 + #[async_trait(?Send)] 587 + impl SignedPreKeyStore for PgProtocolStore { 588 + async fn get_signed_pre_key( 589 + &self, 590 + signed_prekey_id: SignedPreKeyId, 591 + ) -> Result<SignedPreKeyRecord, SignalProtocolError> { 592 + let id: i32 = u32_to_i32(u32::from(signed_prekey_id))?; 593 + let identity = self.identity.as_str(); 594 + let bytes = sqlx::query_scalar!( 595 + "SELECT record FROM signal_signed_pre_keys WHERE id = $1 AND identity = $2", 596 + id, 597 + identity, 598 + ) 599 + .fetch_one(&self.store.db) 600 + .await 601 + .into_protocol_error()?; 602 + SignedPreKeyRecord::deserialize(&bytes) 603 + } 604 + 605 + async fn save_signed_pre_key( 606 + &mut self, 607 + signed_prekey_id: SignedPreKeyId, 608 + record: &SignedPreKeyRecord, 609 + ) -> Result<(), SignalProtocolError> { 610 + let id: i32 = u32_to_i32(u32::from(signed_prekey_id))?; 611 + let identity = self.identity.as_str(); 612 + let bytes = record.serialize()?; 613 + sqlx::query!( 614 + "INSERT INTO signal_signed_pre_keys (id, identity, record) 615 + VALUES ($1, $2, $3) 616 + ON CONFLICT (id, identity) DO UPDATE SET record = $3", 617 + id, 618 + identity, 619 + &bytes, 620 + ) 621 + .execute(&self.store.db) 622 + .await 623 + .into_protocol_error()?; 624 + Ok(()) 625 + } 626 + } 627 + 628 + #[async_trait(?Send)] 629 + impl KyberPreKeyStore for PgProtocolStore { 630 + async fn get_kyber_pre_key( 631 + &self, 632 + kyber_prekey_id: KyberPreKeyId, 633 + ) -> Result<KyberPreKeyRecord, SignalProtocolError> { 634 + let id: i32 = u32_to_i32(u32::from(kyber_prekey_id))?; 635 + let identity = self.identity.as_str(); 636 + let bytes = sqlx::query_scalar!( 637 + "SELECT record FROM signal_kyber_pre_keys WHERE id = $1 AND identity = $2", 638 + id, 639 + identity, 640 + ) 641 + .fetch_one(&self.store.db) 642 + .await 643 + .into_protocol_error()?; 644 + KyberPreKeyRecord::deserialize(&bytes) 645 + } 646 + 647 + async fn save_kyber_pre_key( 648 + &mut self, 649 + kyber_prekey_id: KyberPreKeyId, 650 + record: &KyberPreKeyRecord, 651 + ) -> Result<(), SignalProtocolError> { 652 + let id: i32 = u32_to_i32(u32::from(kyber_prekey_id))?; 653 + let identity = self.identity.as_str(); 654 + let record = record.serialize()?; 655 + sqlx::query!( 656 + "INSERT INTO signal_kyber_pre_keys (id, identity, record, is_last_resort) 657 + VALUES ($1, $2, $3, FALSE) 658 + ON CONFLICT (id, identity) DO UPDATE SET record = $3, is_last_resort = FALSE", 659 + id, 660 + identity, 661 + &record, 662 + ) 663 + .execute(&self.store.db) 664 + .await 665 + .into_protocol_error()?; 666 + Ok(()) 667 + } 668 + 669 + async fn mark_kyber_pre_key_used( 670 + &mut self, 671 + kyber_prekey_id: KyberPreKeyId, 672 + ec_prekey_id: SignedPreKeyId, 673 + base_key: &PublicKey, 674 + ) -> Result<(), SignalProtocolError> { 675 + let mut tx = self.store.db.begin().await.into_protocol_error()?; 676 + let kyber_id: i32 = u32_to_i32(u32::from(kyber_prekey_id))?; 677 + let identity = self.identity.as_str(); 678 + 679 + let is_last_resort = sqlx::query_scalar!( 680 + "SELECT is_last_resort FROM signal_kyber_pre_keys WHERE id = $1 AND identity = $2", 681 + kyber_id, 682 + identity, 683 + ) 684 + .fetch_one(&mut *tx) 685 + .await 686 + .into_protocol_error()?; 687 + 688 + if is_last_resort { 689 + let ec_id: i32 = u32_to_i32(u32::from(ec_prekey_id))?; 690 + let base_key_bytes = base_key.serialize().to_vec(); 691 + 692 + let result = sqlx::query!( 693 + "INSERT INTO signal_base_keys_seen 694 + (kyber_pre_key_id, signed_pre_key_id, identity, base_key) 695 + VALUES ($1, $2, $3, $4)", 696 + kyber_id, 697 + ec_id, 698 + identity, 699 + &base_key_bytes, 700 + ) 701 + .execute(&mut *tx) 702 + .await; 703 + 704 + match result { 705 + Err(sqlx::Error::Database(ref e)) if e.is_unique_violation() => { 706 + return Err(SignalProtocolError::InvalidMessage( 707 + CiphertextMessageType::PreKey, 708 + "reused base key", 709 + )); 710 + } 711 + other => { 712 + other.into_protocol_error()?; 713 + } 714 + } 715 + } else { 716 + sqlx::query!( 717 + "DELETE FROM signal_kyber_pre_keys 718 + WHERE id = $1 AND identity = $2 AND is_last_resort = FALSE", 719 + kyber_id, 720 + identity, 721 + ) 722 + .execute(&mut *tx) 723 + .await 724 + .into_protocol_error()?; 725 + } 726 + 727 + tx.commit().await.into_protocol_error()?; 728 + Ok(()) 729 + } 730 + } 731 + 732 + #[async_trait(?Send)] 733 + impl KyberPreKeyStoreExt for PgProtocolStore { 734 + async fn store_last_resort_kyber_pre_key( 735 + &mut self, 736 + kyber_prekey_id: KyberPreKeyId, 737 + record: &KyberPreKeyRecord, 738 + ) -> Result<(), SignalProtocolError> { 739 + let id: i32 = u32_to_i32(u32::from(kyber_prekey_id))?; 740 + let identity = self.identity.as_str(); 741 + let record = record.serialize()?; 742 + sqlx::query!( 743 + "INSERT INTO signal_kyber_pre_keys (id, identity, record, is_last_resort) 744 + VALUES ($1, $2, $3, TRUE) 745 + ON CONFLICT (id, identity) DO UPDATE SET is_last_resort = TRUE, record = $3", 746 + id, 747 + identity, 748 + &record, 749 + ) 750 + .execute(&self.store.db) 751 + .await 752 + .into_protocol_error()?; 753 + Ok(()) 754 + } 755 + 756 + async fn load_last_resort_kyber_pre_keys( 757 + &self, 758 + ) -> Result<Vec<KyberPreKeyRecord>, SignalProtocolError> { 759 + let identity = self.identity.as_str(); 760 + sqlx::query_scalar!( 761 + "SELECT record FROM signal_kyber_pre_keys 762 + WHERE identity = $1 AND is_last_resort = TRUE", 763 + identity, 764 + ) 765 + .fetch_all(&self.store.db) 766 + .await 767 + .into_protocol_error()? 768 + .into_iter() 769 + .map(|record| KyberPreKeyRecord::deserialize(&record)) 770 + .collect() 771 + } 772 + 773 + async fn remove_kyber_pre_key( 774 + &mut self, 775 + kyber_prekey_id: KyberPreKeyId, 776 + ) -> Result<(), SignalProtocolError> { 777 + let id: i32 = u32_to_i32(u32::from(kyber_prekey_id))?; 778 + let identity = self.identity.as_str(); 779 + sqlx::query!( 780 + "DELETE FROM signal_kyber_pre_keys WHERE id = $1 AND identity = $2", 781 + id, 782 + identity, 783 + ) 784 + .execute(&self.store.db) 785 + .await 786 + .into_protocol_error()?; 787 + Ok(()) 788 + } 789 + 790 + async fn mark_all_one_time_kyber_pre_keys_stale_if_necessary( 791 + &mut self, 792 + stale_time: chrono::DateTime<chrono::Utc>, 793 + ) -> Result<(), SignalProtocolError> { 794 + let identity = self.identity.as_str(); 795 + sqlx::query!( 796 + "UPDATE signal_kyber_pre_keys 797 + SET stale_at = $1 798 + WHERE identity = $2 AND is_last_resort = FALSE AND stale_at IS NULL", 799 + stale_time, 800 + identity, 801 + ) 802 + .execute(&self.store.db) 803 + .await 804 + .into_protocol_error()?; 805 + Ok(()) 806 + } 807 + 808 + async fn delete_all_stale_one_time_kyber_pre_keys( 809 + &mut self, 810 + threshold: chrono::DateTime<chrono::Utc>, 811 + min_count: usize, 812 + ) -> Result<(), SignalProtocolError> { 813 + let identity = self.identity.as_str(); 814 + let min_count = i64::try_from(min_count).unwrap_or(i64::MAX); 815 + sqlx::query!( 816 + "WITH total AS ( 817 + SELECT COUNT(*) AS cnt FROM signal_kyber_pre_keys 818 + WHERE identity = $1 AND is_last_resort = FALSE 819 + ) 820 + DELETE FROM signal_kyber_pre_keys 821 + WHERE identity = $1 AND is_last_resort = FALSE 822 + AND stale_at IS NOT NULL AND stale_at < $2 823 + AND (SELECT cnt FROM total) > $3", 824 + identity, 825 + threshold, 826 + min_count, 827 + ) 828 + .execute(&self.store.db) 829 + .await 830 + .into_protocol_error()?; 831 + Ok(()) 832 + } 833 + } 834 + 835 + #[async_trait(?Send)] 836 + impl IdentityKeyStore for PgProtocolStore { 837 + async fn get_identity_key_pair(&self) -> Result<IdentityKeyPair, SignalProtocolError> { 838 + let key = self.identity.identity_key_pair_key(); 839 + let bytes = sqlx::query_scalar!("SELECT value FROM signal_kv WHERE key = $1", key,) 840 + .fetch_one(&self.store.db) 841 + .await 842 + .into_protocol_error()?; 843 + IdentityKeyPair::try_from(&*bytes) 844 + } 845 + 846 + async fn get_local_registration_id(&self) -> Result<u32, SignalProtocolError> { 847 + let data = self 848 + .store 849 + .load_registration_data() 850 + .await 851 + .into_protocol_error()? 852 + .ok_or_else(|| { 853 + SignalProtocolError::InvalidState( 854 + "failed to load registration ID", 855 + "no registration data".into(), 856 + ) 857 + })?; 858 + Ok(data.registration_id) 859 + } 860 + 861 + async fn save_identity( 862 + &mut self, 863 + address: &ProtocolAddress, 864 + identity_key: &IdentityKey, 865 + ) -> Result<IdentityChange, SignalProtocolError> { 866 + let existing = self.get_identity(address).await?; 867 + 868 + let addr = address.name(); 869 + let identity = self.identity.as_str(); 870 + let bytes = identity_key.serialize().to_vec(); 871 + 872 + sqlx::query!( 873 + "INSERT INTO signal_identities (address, identity, record) 874 + VALUES ($1, $2, $3) 875 + ON CONFLICT (address, identity) DO UPDATE SET record = $3", 876 + addr, 877 + identity, 878 + &bytes, 879 + ) 880 + .execute(&self.store.db) 881 + .await 882 + .into_protocol_error()?; 883 + 884 + Ok(match existing { 885 + Some(k) if k == *identity_key => IdentityChange::NewOrUnchanged, 886 + Some(_) => IdentityChange::ReplacedExisting, 887 + None => IdentityChange::NewOrUnchanged, 888 + }) 889 + } 890 + 891 + async fn is_trusted_identity( 892 + &self, 893 + address: &ProtocolAddress, 894 + identity_key: &IdentityKey, 895 + _direction: Direction, 896 + ) -> Result<bool, SignalProtocolError> { 897 + match self.get_identity(address).await? { 898 + Some(trusted_key) if identity_key == &trusted_key => Ok(true), 899 + Some(_) => { 900 + warn!(%address, "trusting changed identity"); 901 + Ok(true) 902 + } 903 + None => { 904 + warn!(%address, "trusting new identity"); 905 + Ok(true) 906 + } 907 + } 908 + } 909 + 910 + async fn get_identity( 911 + &self, 912 + address: &ProtocolAddress, 913 + ) -> Result<Option<IdentityKey>, SignalProtocolError> { 914 + let addr = address.name(); 915 + let identity = self.identity.as_str(); 916 + sqlx::query_scalar!( 917 + "SELECT record FROM signal_identities WHERE address = $1 AND identity = $2", 918 + addr, 919 + identity, 920 + ) 921 + .fetch_optional(&self.store.db) 922 + .await 923 + .into_protocol_error()? 924 + .map(|bytes| IdentityKey::decode(&bytes)) 925 + .transpose() 926 + } 927 + } 928 + 929 + #[async_trait(?Send)] 930 + impl SenderKeyStore for PgProtocolStore { 931 + async fn store_sender_key( 932 + &mut self, 933 + sender: &ProtocolAddress, 934 + distribution_id: Uuid, 935 + record: &SenderKeyRecord, 936 + ) -> Result<(), SignalProtocolError> { 937 + let device_id: i32 = u32_to_i32(u32::from(sender.device_id()))?; 938 + let identity = self.identity.as_str(); 939 + let addr = sender.name(); 940 + let record = record.serialize()?; 941 + sqlx::query!( 942 + "INSERT INTO signal_sender_keys 943 + (address, device_id, identity, distribution_id, record) 944 + VALUES ($1, $2, $3, $4, $5) 945 + ON CONFLICT (address, device_id, identity, distribution_id) DO UPDATE SET record = $5", 946 + addr, 947 + device_id, 948 + identity, 949 + distribution_id, 950 + &record, 951 + ) 952 + .execute(&self.store.db) 953 + .await 954 + .into_protocol_error()?; 955 + Ok(()) 956 + } 957 + 958 + async fn load_sender_key( 959 + &mut self, 960 + sender: &ProtocolAddress, 961 + distribution_id: Uuid, 962 + ) -> Result<Option<SenderKeyRecord>, SignalProtocolError> { 963 + let device_id: i32 = u32_to_i32(u32::from(sender.device_id()))?; 964 + let identity = self.identity.as_str(); 965 + let addr = sender.name(); 966 + sqlx::query_scalar!( 967 + "SELECT record FROM signal_sender_keys 968 + WHERE address = $1 AND device_id = $2 AND identity = $3 AND distribution_id = $4", 969 + addr, 970 + device_id, 971 + identity, 972 + distribution_id, 973 + ) 974 + .fetch_optional(&self.store.db) 975 + .await 976 + .into_protocol_error()? 977 + .map(|record| SenderKeyRecord::deserialize(&record)) 978 + .transpose() 979 + } 980 + } 981 + 982 + type EmptyIter<T> = std::iter::Empty<Result<T, PgStoreError>>; 983 + 984 + impl ContentsStore for PgSignalStore { 985 + type ContentsStoreError = PgStoreError; 986 + type ContactsIter = EmptyIter<Contact>; 987 + type GroupsIter = EmptyIter<(GroupMasterKeyBytes, Group)>; 988 + type MessagesIter = EmptyIter<Content>; 989 + type StickerPacksIter = EmptyIter<StickerPack>; 990 + 991 + async fn clear_profiles(&mut self) -> Result<(), PgStoreError> { 992 + sqlx::query!("DELETE FROM signal_profile_keys") 993 + .execute(&self.db) 994 + .await?; 995 + Ok(()) 996 + } 997 + 998 + async fn clear_contents(&mut self) -> Result<(), PgStoreError> { 999 + Ok(()) 1000 + } 1001 + 1002 + async fn clear_messages(&mut self) -> Result<(), PgStoreError> { 1003 + Ok(()) 1004 + } 1005 + 1006 + async fn clear_thread(&mut self, _thread: &Thread) -> Result<(), PgStoreError> { 1007 + Ok(()) 1008 + } 1009 + 1010 + async fn save_message(&self, _thread: &Thread, _message: Content) -> Result<(), PgStoreError> { 1011 + Ok(()) 1012 + } 1013 + 1014 + async fn delete_message( 1015 + &mut self, 1016 + _thread: &Thread, 1017 + _timestamp: u64, 1018 + ) -> Result<bool, PgStoreError> { 1019 + Ok(false) 1020 + } 1021 + 1022 + async fn message( 1023 + &self, 1024 + _thread: &Thread, 1025 + _timestamp: u64, 1026 + ) -> Result<Option<Content>, PgStoreError> { 1027 + Ok(None) 1028 + } 1029 + 1030 + async fn messages( 1031 + &self, 1032 + _thread: &Thread, 1033 + _range: impl RangeBounds<u64>, 1034 + ) -> Result<Self::MessagesIter, PgStoreError> { 1035 + Ok(std::iter::empty()) 1036 + } 1037 + 1038 + async fn clear_contacts(&mut self) -> Result<(), PgStoreError> { 1039 + Ok(()) 1040 + } 1041 + 1042 + async fn save_contact(&mut self, _contact: &Contact) -> Result<(), PgStoreError> { 1043 + Ok(()) 1044 + } 1045 + 1046 + async fn contacts(&self) -> Result<Self::ContactsIter, PgStoreError> { 1047 + Ok(std::iter::empty()) 1048 + } 1049 + 1050 + async fn contact_by_id(&self, _id: &ServiceId) -> Result<Option<Contact>, PgStoreError> { 1051 + Ok(None) 1052 + } 1053 + 1054 + async fn clear_groups(&mut self) -> Result<(), PgStoreError> { 1055 + Ok(()) 1056 + } 1057 + 1058 + async fn save_group( 1059 + &self, 1060 + _master_key: GroupMasterKeyBytes, 1061 + _group: impl Into<Group>, 1062 + ) -> Result<(), PgStoreError> { 1063 + Ok(()) 1064 + } 1065 + 1066 + async fn groups(&self) -> Result<Self::GroupsIter, PgStoreError> { 1067 + Ok(std::iter::empty()) 1068 + } 1069 + 1070 + async fn group(&self, _master_key: GroupMasterKeyBytes) -> Result<Option<Group>, PgStoreError> { 1071 + Ok(None) 1072 + } 1073 + 1074 + async fn save_group_avatar( 1075 + &self, 1076 + _master_key: GroupMasterKeyBytes, 1077 + _avatar: &AvatarBytes, 1078 + ) -> Result<(), PgStoreError> { 1079 + Ok(()) 1080 + } 1081 + 1082 + async fn group_avatar( 1083 + &self, 1084 + _master_key: GroupMasterKeyBytes, 1085 + ) -> Result<Option<AvatarBytes>, PgStoreError> { 1086 + Ok(None) 1087 + } 1088 + 1089 + async fn upsert_profile_key( 1090 + &mut self, 1091 + uuid: &Uuid, 1092 + key: ProfileKey, 1093 + ) -> Result<bool, PgStoreError> { 1094 + let key_bytes = key.bytes.to_vec(); 1095 + let inserted = sqlx::query_scalar!( 1096 + "INSERT INTO signal_profile_keys (uuid, key) VALUES ($1, $2) 1097 + ON CONFLICT (uuid) DO UPDATE SET key = $2 1098 + RETURNING (xmax = 0) AS \"inserted!\"", 1099 + uuid, 1100 + &key_bytes, 1101 + ) 1102 + .fetch_one(&self.db) 1103 + .await?; 1104 + Ok(inserted) 1105 + } 1106 + 1107 + async fn profile_key( 1108 + &self, 1109 + service_id: &ServiceId, 1110 + ) -> Result<Option<ProfileKey>, PgStoreError> { 1111 + let uuid: Uuid = service_id.raw_uuid(); 1112 + let row = sqlx::query!("SELECT key FROM signal_profile_keys WHERE uuid = $1", uuid,) 1113 + .fetch_optional(&self.db) 1114 + .await?; 1115 + 1116 + Ok(match row { 1117 + Some(r) => match <[u8; 32]>::try_from(r.key.as_slice()) { 1118 + Ok(arr) => Some(ProfileKey { bytes: arr }), 1119 + Err(_) => { 1120 + warn!(%uuid, len = r.key.len(), "corrupted profile key (expected 32 bytes)"); 1121 + None 1122 + } 1123 + }, 1124 + None => None, 1125 + }) 1126 + } 1127 + 1128 + async fn save_profile( 1129 + &mut self, 1130 + _uuid: Uuid, 1131 + _key: ProfileKey, 1132 + _profile: Profile, 1133 + ) -> Result<(), PgStoreError> { 1134 + Ok(()) 1135 + } 1136 + 1137 + async fn profile( 1138 + &self, 1139 + _uuid: Uuid, 1140 + _key: ProfileKey, 1141 + ) -> Result<Option<Profile>, PgStoreError> { 1142 + Ok(None) 1143 + } 1144 + 1145 + async fn save_profile_avatar( 1146 + &mut self, 1147 + _uuid: Uuid, 1148 + _key: ProfileKey, 1149 + _profile: &AvatarBytes, 1150 + ) -> Result<(), PgStoreError> { 1151 + Ok(()) 1152 + } 1153 + 1154 + async fn profile_avatar( 1155 + &self, 1156 + _uuid: Uuid, 1157 + _key: ProfileKey, 1158 + ) -> Result<Option<AvatarBytes>, PgStoreError> { 1159 + Ok(None) 1160 + } 1161 + 1162 + async fn add_sticker_pack(&mut self, _pack: &StickerPack) -> Result<(), PgStoreError> { 1163 + Ok(()) 1164 + } 1165 + 1166 + async fn sticker_pack(&self, _id: &[u8]) -> Result<Option<StickerPack>, PgStoreError> { 1167 + Ok(None) 1168 + } 1169 + 1170 + async fn remove_sticker_pack(&mut self, _id: &[u8]) -> Result<bool, PgStoreError> { 1171 + Ok(false) 1172 + } 1173 + 1174 + async fn sticker_packs(&self) -> Result<Self::StickerPacksIter, PgStoreError> { 1175 + Ok(std::iter::empty()) 1176 + } 1177 + }
+64
migrations/20260321_signal_protocol_tables.sql
··· 1 + CREATE TABLE signal_kv ( 2 + key TEXT PRIMARY KEY, 3 + value BYTEA NOT NULL 4 + ); 5 + 6 + CREATE TABLE signal_sessions ( 7 + address TEXT NOT NULL, 8 + device_id INTEGER NOT NULL CHECK (device_id BETWEEN 0 AND 127), 9 + identity TEXT NOT NULL CHECK (identity IN ('aci', 'pni')), 10 + record BYTEA NOT NULL, 11 + PRIMARY KEY (address, device_id, identity) 12 + ); 13 + 14 + CREATE TABLE signal_identities ( 15 + address TEXT NOT NULL, 16 + identity TEXT NOT NULL CHECK (identity IN ('aci', 'pni')), 17 + record BYTEA NOT NULL, 18 + PRIMARY KEY (address, identity) 19 + ); 20 + 21 + CREATE TABLE signal_pre_keys ( 22 + id INTEGER NOT NULL CHECK (id >= 0), 23 + identity TEXT NOT NULL CHECK (identity IN ('aci', 'pni')), 24 + record BYTEA NOT NULL, 25 + PRIMARY KEY (id, identity) 26 + ); 27 + 28 + CREATE TABLE signal_signed_pre_keys ( 29 + id INTEGER NOT NULL CHECK (id >= 0), 30 + identity TEXT NOT NULL CHECK (identity IN ('aci', 'pni')), 31 + record BYTEA NOT NULL, 32 + PRIMARY KEY (id, identity) 33 + ); 34 + 35 + CREATE TABLE signal_kyber_pre_keys ( 36 + id INTEGER NOT NULL CHECK (id >= 0), 37 + identity TEXT NOT NULL CHECK (identity IN ('aci', 'pni')), 38 + record BYTEA NOT NULL, 39 + is_last_resort BOOLEAN NOT NULL DEFAULT FALSE, 40 + stale_at TIMESTAMPTZ, 41 + PRIMARY KEY (id, identity) 42 + ); 43 + 44 + CREATE TABLE signal_sender_keys ( 45 + address TEXT NOT NULL, 46 + device_id INTEGER NOT NULL CHECK (device_id BETWEEN 0 AND 127), 47 + identity TEXT NOT NULL CHECK (identity IN ('aci', 'pni')), 48 + distribution_id UUID NOT NULL, 49 + record BYTEA NOT NULL, 50 + PRIMARY KEY (address, device_id, identity, distribution_id) 51 + ); 52 + 53 + CREATE TABLE signal_base_keys_seen ( 54 + kyber_pre_key_id INTEGER NOT NULL CHECK (kyber_pre_key_id >= 0), 55 + signed_pre_key_id INTEGER NOT NULL CHECK (signed_pre_key_id >= 0), 56 + identity TEXT NOT NULL CHECK (identity IN ('aci', 'pni')), 57 + base_key BYTEA NOT NULL, 58 + PRIMARY KEY (identity, kyber_pre_key_id, signed_pre_key_id, base_key) 59 + ); 60 + 61 + CREATE TABLE signal_profile_keys ( 62 + uuid UUID PRIMARY KEY, 63 + key BYTEA NOT NULL 64 + );

History

1 round 0 comments
sign up or login to add to the discussion
oyster.cafe submitted #0
1 commit
expand
feat(signal): add postgres-backed signal protocol store
expand 0 comments
pull request successfully merged