diff --git a/.sqlx/query-0295414146e4ddacad638486443fd1036609ab8443390820be8696f708be3812.json b/.sqlx/query-0295414146e4ddacad638486443fd1036609ab8443390820be8696f708be3812.json new file mode 100644 index 0000000..2c83117 --- /dev/null +++ b/.sqlx/query-0295414146e4ddacad638486443fd1036609ab8443390820be8696f708be3812.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM signal_kyber_pre_keys", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "0295414146e4ddacad638486443fd1036609ab8443390820be8696f708be3812" +} diff --git a/.sqlx/query-0a3eaf432e99ef22aa6b3b43978740b085f6416a058ea2da6d639ea1cf276eda.json b/.sqlx/query-0a3eaf432e99ef22aa6b3b43978740b085f6416a058ea2da6d639ea1cf276eda.json new file mode 100644 index 0000000..717d73c --- /dev/null +++ b/.sqlx/query-0a3eaf432e99ef22aa6b3b43978740b085f6416a058ea2da6d639ea1cf276eda.json @@ -0,0 +1,18 @@ +{ + "db_name": "PostgreSQL", + "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", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int4", + "Text", + "Uuid", + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "0a3eaf432e99ef22aa6b3b43978740b085f6416a058ea2da6d639ea1cf276eda" +} diff --git a/.sqlx/query-166ee5a554e3ddc75496616d9fba75a15cc0c072f493f579b881a4f2300f38c8.json b/.sqlx/query-166ee5a554e3ddc75496616d9fba75a15cc0c072f493f579b881a4f2300f38c8.json new file mode 100644 index 0000000..3f30cd9 --- /dev/null +++ b/.sqlx/query-166ee5a554e3ddc75496616d9fba75a15cc0c072f493f579b881a4f2300f38c8.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM signal_kv", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "166ee5a554e3ddc75496616d9fba75a15cc0c072f493f579b881a4f2300f38c8" +} diff --git a/.sqlx/query-1a061c261518573c29aa55c5d8e2181f1728034e723ed0bc836e928b4c69128f.json b/.sqlx/query-1a061c261518573c29aa55c5d8e2181f1728034e723ed0bc836e928b4c69128f.json new file mode 100644 index 0000000..5742f74 --- /dev/null +++ b/.sqlx/query-1a061c261518573c29aa55c5d8e2181f1728034e723ed0bc836e928b4c69128f.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT record FROM signal_signed_pre_keys WHERE id = $1 AND identity = $2", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "record", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int4", + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "1a061c261518573c29aa55c5d8e2181f1728034e723ed0bc836e928b4c69128f" +} diff --git a/.sqlx/query-1aac5ab7dbc29f0d0937767ae174e8b47d236b3cdc973974cec413dc65198d64.json b/.sqlx/query-1aac5ab7dbc29f0d0937767ae174e8b47d236b3cdc973974cec413dc65198d64.json new file mode 100644 index 0000000..532d677 --- /dev/null +++ b/.sqlx/query-1aac5ab7dbc29f0d0937767ae174e8b47d236b3cdc973974cec413dc65198d64.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT record FROM signal_kyber_pre_keys WHERE id = $1 AND identity = $2", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "record", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int4", + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "1aac5ab7dbc29f0d0937767ae174e8b47d236b3cdc973974cec413dc65198d64" +} diff --git a/.sqlx/query-1d4459863eeddea9ccb5ce5c0eaffd39d56a763728ce5b1f76871265e704e241.json b/.sqlx/query-1d4459863eeddea9ccb5ce5c0eaffd39d56a763728ce5b1f76871265e704e241.json new file mode 100644 index 0000000..9e2882c --- /dev/null +++ b/.sqlx/query-1d4459863eeddea9ccb5ce5c0eaffd39d56a763728ce5b1f76871265e704e241.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "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", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int4", + "Text", + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "1d4459863eeddea9ccb5ce5c0eaffd39d56a763728ce5b1f76871265e704e241" +} diff --git a/.sqlx/query-1f464d947e93274cbc974f8a6f31d8a47eb676df857fa83f08ed1937cf8a6d9d.json b/.sqlx/query-1f464d947e93274cbc974f8a6f31d8a47eb676df857fa83f08ed1937cf8a6d9d.json new file mode 100644 index 0000000..79f6064 --- /dev/null +++ b/.sqlx/query-1f464d947e93274cbc974f8a6f31d8a47eb676df857fa83f08ed1937cf8a6d9d.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM signal_sessions WHERE address = $1 AND identity = $2", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [] + }, + "hash": "1f464d947e93274cbc974f8a6f31d8a47eb676df857fa83f08ed1937cf8a6d9d" +} diff --git a/.sqlx/query-222836500a964ee6fd238ddb128691215cd15d2ede9a1a19e7a580e4d6644ce8.json b/.sqlx/query-222836500a964ee6fd238ddb128691215cd15d2ede9a1a19e7a580e4d6644ce8.json new file mode 100644 index 0000000..5ff9a64 --- /dev/null +++ b/.sqlx/query-222836500a964ee6fd238ddb128691215cd15d2ede9a1a19e7a580e4d6644ce8.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM signal_base_keys_seen", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "222836500a964ee6fd238ddb128691215cd15d2ede9a1a19e7a580e4d6644ce8" +} diff --git a/.sqlx/query-252d42bb50ef918fe414d036979daba055dbadd3cd7e1bdcce4526867be79930.json b/.sqlx/query-252d42bb50ef918fe414d036979daba055dbadd3cd7e1bdcce4526867be79930.json new file mode 100644 index 0000000..dda2057 --- /dev/null +++ b/.sqlx/query-252d42bb50ef918fe414d036979daba055dbadd3cd7e1bdcce4526867be79930.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM signal_identities", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "252d42bb50ef918fe414d036979daba055dbadd3cd7e1bdcce4526867be79930" +} diff --git a/.sqlx/query-29c834b7870cdbcdcc2d2c9259a04326e20433237ebe25e33dbd39952ae9f976.json b/.sqlx/query-29c834b7870cdbcdcc2d2c9259a04326e20433237ebe25e33dbd39952ae9f976.json new file mode 100644 index 0000000..77c9761 --- /dev/null +++ b/.sqlx/query-29c834b7870cdbcdcc2d2c9259a04326e20433237ebe25e33dbd39952ae9f976.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO signal_kv (key, value) VALUES ($1, $2)\n ON CONFLICT (key) DO UPDATE SET value = $2", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "29c834b7870cdbcdcc2d2c9259a04326e20433237ebe25e33dbd39952ae9f976" +} diff --git a/.sqlx/query-31edfe22cdd8e5f62322dad01a65165ec9546eaa92c9e372a5a4fce99d938d22.json b/.sqlx/query-31edfe22cdd8e5f62322dad01a65165ec9546eaa92c9e372a5a4fce99d938d22.json new file mode 100644 index 0000000..f2a8632 --- /dev/null +++ b/.sqlx/query-31edfe22cdd8e5f62322dad01a65165ec9546eaa92c9e372a5a4fce99d938d22.json @@ -0,0 +1,17 @@ +{ + "db_name": "PostgreSQL", + "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)", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int4", + "Int4", + "Text", + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "31edfe22cdd8e5f62322dad01a65165ec9546eaa92c9e372a5a4fce99d938d22" +} diff --git a/.sqlx/query-374be0bd97ed927b15929e2f86d88913b2fec45ab67e4805fb9f1e39b422ee7f.json b/.sqlx/query-374be0bd97ed927b15929e2f86d88913b2fec45ab67e4805fb9f1e39b422ee7f.json new file mode 100644 index 0000000..f50530d --- /dev/null +++ b/.sqlx/query-374be0bd97ed927b15929e2f86d88913b2fec45ab67e4805fb9f1e39b422ee7f.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM signal_kv WHERE key = 'registration'", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "374be0bd97ed927b15929e2f86d88913b2fec45ab67e4805fb9f1e39b422ee7f" +} diff --git a/.sqlx/query-3a3eee11be6a9c5fe012d2a634c7ef514fb695ca6a4ba7631d1c5aba87a854a5.json b/.sqlx/query-3a3eee11be6a9c5fe012d2a634c7ef514fb695ca6a4ba7631d1c5aba87a854a5.json new file mode 100644 index 0000000..0518f0f --- /dev/null +++ b/.sqlx/query-3a3eee11be6a9c5fe012d2a634c7ef514fb695ca6a4ba7631d1c5aba87a854a5.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM signal_pre_keys WHERE id = $1 AND identity = $2", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int4", + "Text" + ] + }, + "nullable": [] + }, + "hash": "3a3eee11be6a9c5fe012d2a634c7ef514fb695ca6a4ba7631d1c5aba87a854a5" +} diff --git a/.sqlx/query-4011d789a6b619231f4e2b917753f0b4452f21243e1d95d47dbaa91cac019e64.json b/.sqlx/query-4011d789a6b619231f4e2b917753f0b4452f21243e1d95d47dbaa91cac019e64.json new file mode 100644 index 0000000..6a0f59d --- /dev/null +++ b/.sqlx/query-4011d789a6b619231f4e2b917753f0b4452f21243e1d95d47dbaa91cac019e64.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM signal_sender_keys", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "4011d789a6b619231f4e2b917753f0b4452f21243e1d95d47dbaa91cac019e64" +} diff --git a/.sqlx/query-4316de453ec1d5ba65a1dbee29599287d42bf87517936b3b61958c0675ce8115.json b/.sqlx/query-4316de453ec1d5ba65a1dbee29599287d42bf87517936b3b61958c0675ce8115.json new file mode 100644 index 0000000..79415ad --- /dev/null +++ b/.sqlx/query-4316de453ec1d5ba65a1dbee29599287d42bf87517936b3b61958c0675ce8115.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT value FROM signal_kv WHERE key = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "value", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "4316de453ec1d5ba65a1dbee29599287d42bf87517936b3b61958c0675ce8115" +} diff --git a/.sqlx/query-43583f8246016d15d9875c4d33855317c41ae07af5676228c0533724590ec6ed.json b/.sqlx/query-43583f8246016d15d9875c4d33855317c41ae07af5676228c0533724590ec6ed.json new file mode 100644 index 0000000..fb6e1ec --- /dev/null +++ b/.sqlx/query-43583f8246016d15d9875c4d33855317c41ae07af5676228c0533724590ec6ed.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM signal_sessions", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "43583f8246016d15d9875c4d33855317c41ae07af5676228c0533724590ec6ed" +} diff --git a/.sqlx/query-4bcd896340fc9178e2d97ad572269e8f57561190ec5f94ccfa06ca93f4827e79.json b/.sqlx/query-4bcd896340fc9178e2d97ad572269e8f57561190ec5f94ccfa06ca93f4827e79.json new file mode 100644 index 0000000..db8456e --- /dev/null +++ b/.sqlx/query-4bcd896340fc9178e2d97ad572269e8f57561190ec5f94ccfa06ca93f4827e79.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT record FROM signal_identities WHERE address = $1 AND identity = $2", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "record", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "4bcd896340fc9178e2d97ad572269e8f57561190ec5f94ccfa06ca93f4827e79" +} diff --git a/.sqlx/query-4d22ba21356bdc84ea549799c77cab8c34ca9a5f0815150254b590fd87509eb8.json b/.sqlx/query-4d22ba21356bdc84ea549799c77cab8c34ca9a5f0815150254b590fd87509eb8.json new file mode 100644 index 0000000..4062891 --- /dev/null +++ b/.sqlx/query-4d22ba21356bdc84ea549799c77cab8c34ca9a5f0815150254b590fd87509eb8.json @@ -0,0 +1,17 @@ +{ + "db_name": "PostgreSQL", + "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", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int4", + "Text", + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "4d22ba21356bdc84ea549799c77cab8c34ca9a5f0815150254b590fd87509eb8" +} diff --git a/.sqlx/query-513a0d3b907df1004f2178ebf14fc182f20fc13c5691cbeb7656d428cb6437f9.json b/.sqlx/query-513a0d3b907df1004f2178ebf14fc182f20fc13c5691cbeb7656d428cb6437f9.json new file mode 100644 index 0000000..437f46c --- /dev/null +++ b/.sqlx/query-513a0d3b907df1004f2178ebf14fc182f20fc13c5691cbeb7656d428cb6437f9.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT is_last_resort FROM signal_kyber_pre_keys WHERE id = $1 AND identity = $2", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "is_last_resort", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Int4", + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "513a0d3b907df1004f2178ebf14fc182f20fc13c5691cbeb7656d428cb6437f9" +} diff --git a/.sqlx/query-53814b5db4f051c30573d146007ddc487f4c12c726bb970efe17e325536629e4.json b/.sqlx/query-53814b5db4f051c30573d146007ddc487f4c12c726bb970efe17e325536629e4.json new file mode 100644 index 0000000..c4cbd34 --- /dev/null +++ b/.sqlx/query-53814b5db4f051c30573d146007ddc487f4c12c726bb970efe17e325536629e4.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO signal_kv (key, value) VALUES ('master_key', $1)\n ON CONFLICT (key) DO UPDATE SET value = $1", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "53814b5db4f051c30573d146007ddc487f4c12c726bb970efe17e325536629e4" +} diff --git a/.sqlx/query-5cd556968671fc8ecf57dd7fd40f65e3a168f17bd389ce2cf7ddee27d810cf1d.json b/.sqlx/query-5cd556968671fc8ecf57dd7fd40f65e3a168f17bd389ce2cf7ddee27d810cf1d.json new file mode 100644 index 0000000..3e01361 --- /dev/null +++ b/.sqlx/query-5cd556968671fc8ecf57dd7fd40f65e3a168f17bd389ce2cf7ddee27d810cf1d.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO signal_kv (key, value) VALUES ('sender_certificate', $1)\n ON CONFLICT (key) DO UPDATE SET value = $1", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "5cd556968671fc8ecf57dd7fd40f65e3a168f17bd389ce2cf7ddee27d810cf1d" +} diff --git a/.sqlx/query-62dc57cf7ad007a6458df06619fe7e0bf5ffeba195e55793f6bf6d170e053226.json b/.sqlx/query-62dc57cf7ad007a6458df06619fe7e0bf5ffeba195e55793f6bf6d170e053226.json new file mode 100644 index 0000000..91bd3c0 --- /dev/null +++ b/.sqlx/query-62dc57cf7ad007a6458df06619fe7e0bf5ffeba195e55793f6bf6d170e053226.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO signal_identities (address, identity, record)\n VALUES ($1, $2, $3)\n ON CONFLICT (address, identity) DO UPDATE SET record = $3", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Text", + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "62dc57cf7ad007a6458df06619fe7e0bf5ffeba195e55793f6bf6d170e053226" +} diff --git a/.sqlx/query-63ecf786e52a52d83232f6d4c8d93d5d7065f5dbfd3cd1e259d7990d02da1114.json b/.sqlx/query-63ecf786e52a52d83232f6d4c8d93d5d7065f5dbfd3cd1e259d7990d02da1114.json new file mode 100644 index 0000000..bb96344 --- /dev/null +++ b/.sqlx/query-63ecf786e52a52d83232f6d4c8d93d5d7065f5dbfd3cd1e259d7990d02da1114.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT COUNT(*) AS \"count!\" FROM signal_kyber_pre_keys\n WHERE identity = $1 AND is_last_resort = $2", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count!", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Text", + "Bool" + ] + }, + "nullable": [ + null + ] + }, + "hash": "63ecf786e52a52d83232f6d4c8d93d5d7065f5dbfd3cd1e259d7990d02da1114" +} diff --git a/.sqlx/query-6a91d97ed4f955ce0936eced6318c630f39ebebc52cee584f1b0dacefec984cd.json b/.sqlx/query-6a91d97ed4f955ce0936eced6318c630f39ebebc52cee584f1b0dacefec984cd.json new file mode 100644 index 0000000..88fce27 --- /dev/null +++ b/.sqlx/query-6a91d97ed4f955ce0936eced6318c630f39ebebc52cee584f1b0dacefec984cd.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT record FROM signal_kyber_pre_keys\n WHERE identity = $1 AND is_last_resort = TRUE", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "record", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "6a91d97ed4f955ce0936eced6318c630f39ebebc52cee584f1b0dacefec984cd" +} diff --git a/.sqlx/query-6cb39ddd462ae93fe97d930ce64425ed16271adc4ca066c4d51bb742beffc22b.json b/.sqlx/query-6cb39ddd462ae93fe97d930ce64425ed16271adc4ca066c4d51bb742beffc22b.json new file mode 100644 index 0000000..7cd447d --- /dev/null +++ b/.sqlx/query-6cb39ddd462ae93fe97d930ce64425ed16271adc4ca066c4d51bb742beffc22b.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM signal_kv WHERE key = 'master_key'", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "6cb39ddd462ae93fe97d930ce64425ed16271adc4ca066c4d51bb742beffc22b" +} diff --git a/.sqlx/query-6cbfcd552a7b4eeb6a1e525f2f11e8f432405e3606e3af7d31b9eca32bc28607.json b/.sqlx/query-6cbfcd552a7b4eeb6a1e525f2f11e8f432405e3606e3af7d31b9eca32bc28607.json new file mode 100644 index 0000000..0959d41 --- /dev/null +++ b/.sqlx/query-6cbfcd552a7b4eeb6a1e525f2f11e8f432405e3606e3af7d31b9eca32bc28607.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT record FROM signal_pre_keys WHERE id = $1 AND identity = $2", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "record", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Int4", + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "6cbfcd552a7b4eeb6a1e525f2f11e8f432405e3606e3af7d31b9eca32bc28607" +} diff --git a/.sqlx/query-6f14e2d74ed0c1e0946c62da2a3ddd63344892bdd4022073123604ee17114ce0.json b/.sqlx/query-6f14e2d74ed0c1e0946c62da2a3ddd63344892bdd4022073123604ee17114ce0.json new file mode 100644 index 0000000..f85c518 --- /dev/null +++ b/.sqlx/query-6f14e2d74ed0c1e0946c62da2a3ddd63344892bdd4022073123604ee17114ce0.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO signal_kv (key, value) VALUES ('registration', $1)\n ON CONFLICT (key) DO UPDATE SET value = $1", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "6f14e2d74ed0c1e0946c62da2a3ddd63344892bdd4022073123604ee17114ce0" +} diff --git a/.sqlx/query-811af305fef56437151c1cfe27eaccf6312b8234f1217a81a4d36cd5758fd863.json b/.sqlx/query-811af305fef56437151c1cfe27eaccf6312b8234f1217a81a4d36cd5758fd863.json new file mode 100644 index 0000000..5b88bdc --- /dev/null +++ b/.sqlx/query-811af305fef56437151c1cfe27eaccf6312b8234f1217a81a4d36cd5758fd863.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "INSERT INTO signal_pre_keys (id, identity, record)\n VALUES ($1, $2, $3)\n ON CONFLICT (id, identity) DO UPDATE SET record = $3", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int4", + "Text", + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "811af305fef56437151c1cfe27eaccf6312b8234f1217a81a4d36cd5758fd863" +} diff --git a/.sqlx/query-894169c5a40acade1000869bdde61d09984e17a686c1b487004d79897ecb4e4f.json b/.sqlx/query-894169c5a40acade1000869bdde61d09984e17a686c1b487004d79897ecb4e4f.json new file mode 100644 index 0000000..f542421 --- /dev/null +++ b/.sqlx/query-894169c5a40acade1000869bdde61d09984e17a686c1b487004d79897ecb4e4f.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "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!\"", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "inserted!", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Uuid", + "Bytea" + ] + }, + "nullable": [ + null + ] + }, + "hash": "894169c5a40acade1000869bdde61d09984e17a686c1b487004d79897ecb4e4f" +} diff --git a/.sqlx/query-9da9a790efa51edd6abcb4b0991b307c3ba7f0a929e114a4e0cb2ffb88adfbbb.json b/.sqlx/query-9da9a790efa51edd6abcb4b0991b307c3ba7f0a929e114a4e0cb2ffb88adfbbb.json new file mode 100644 index 0000000..03e4c94 --- /dev/null +++ b/.sqlx/query-9da9a790efa51edd6abcb4b0991b307c3ba7f0a929e114a4e0cb2ffb88adfbbb.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT MAX(id) FROM signal_kyber_pre_keys\n WHERE identity = $1 AND is_last_resort = TRUE", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "max", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "9da9a790efa51edd6abcb4b0991b307c3ba7f0a929e114a4e0cb2ffb88adfbbb" +} diff --git a/.sqlx/query-9fdcff515573446f0b4340bf94421bb8a425cc65304fa8c3fd153945904136f0.json b/.sqlx/query-9fdcff515573446f0b4340bf94421bb8a425cc65304fa8c3fd153945904136f0.json new file mode 100644 index 0000000..b34033b --- /dev/null +++ b/.sqlx/query-9fdcff515573446f0b4340bf94421bb8a425cc65304fa8c3fd153945904136f0.json @@ -0,0 +1,24 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT device_id FROM signal_sessions\n WHERE address = $1 AND device_id != $2 AND identity = $3", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "device_id", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Text", + "Int4", + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "9fdcff515573446f0b4340bf94421bb8a425cc65304fa8c3fd153945904136f0" +} diff --git a/.sqlx/query-a403c2982978159b120d4bfa6d6fdca5808b667e54b0765b5ada047ce6dac9d6.json b/.sqlx/query-a403c2982978159b120d4bfa6d6fdca5808b667e54b0765b5ada047ce6dac9d6.json new file mode 100644 index 0000000..8b1c8f8 --- /dev/null +++ b/.sqlx/query-a403c2982978159b120d4bfa6d6fdca5808b667e54b0765b5ada047ce6dac9d6.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM signal_profile_keys", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "a403c2982978159b120d4bfa6d6fdca5808b667e54b0765b5ada047ce6dac9d6" +} diff --git a/.sqlx/query-adabc98c853ae77678ad6cf1747384706154334cc507eb7542a8b5490f5a1e2a.json b/.sqlx/query-adabc98c853ae77678ad6cf1747384706154334cc507eb7542a8b5490f5a1e2a.json new file mode 100644 index 0000000..8f56def --- /dev/null +++ b/.sqlx/query-adabc98c853ae77678ad6cf1747384706154334cc507eb7542a8b5490f5a1e2a.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "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", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Timestamptz", + "Text" + ] + }, + "nullable": [] + }, + "hash": "adabc98c853ae77678ad6cf1747384706154334cc507eb7542a8b5490f5a1e2a" +} diff --git a/.sqlx/query-b157b94e003376d827b92eab1ff55caa773ed5691e2e555ab1d1f23fc5adcf8e.json b/.sqlx/query-b157b94e003376d827b92eab1ff55caa773ed5691e2e555ab1d1f23fc5adcf8e.json new file mode 100644 index 0000000..9a4541d --- /dev/null +++ b/.sqlx/query-b157b94e003376d827b92eab1ff55caa773ed5691e2e555ab1d1f23fc5adcf8e.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "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", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int4", + "Text", + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "b157b94e003376d827b92eab1ff55caa773ed5691e2e555ab1d1f23fc5adcf8e" +} diff --git a/.sqlx/query-b558892051ad793b4ae38a76d072e4ea440092663bd0d4ed9d48f5074788157a.json b/.sqlx/query-b558892051ad793b4ae38a76d072e4ea440092663bd0d4ed9d48f5074788157a.json new file mode 100644 index 0000000..73ea2ce --- /dev/null +++ b/.sqlx/query-b558892051ad793b4ae38a76d072e4ea440092663bd0d4ed9d48f5074788157a.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT MAX(id) FROM signal_pre_keys WHERE identity = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "max", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "b558892051ad793b4ae38a76d072e4ea440092663bd0d4ed9d48f5074788157a" +} diff --git a/.sqlx/query-b583ea011f17bd703a1dde860d1cc595a18c33dd0e37b575a71fa78f9fddc96f.json b/.sqlx/query-b583ea011f17bd703a1dde860d1cc595a18c33dd0e37b575a71fa78f9fddc96f.json new file mode 100644 index 0000000..324b9f3 --- /dev/null +++ b/.sqlx/query-b583ea011f17bd703a1dde860d1cc595a18c33dd0e37b575a71fa78f9fddc96f.json @@ -0,0 +1,25 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT record FROM signal_sender_keys\n WHERE address = $1 AND device_id = $2 AND identity = $3 AND distribution_id = $4", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "record", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Text", + "Int4", + "Text", + "Uuid" + ] + }, + "nullable": [ + false + ] + }, + "hash": "b583ea011f17bd703a1dde860d1cc595a18c33dd0e37b575a71fa78f9fddc96f" +} diff --git a/.sqlx/query-c08770c1ca1cb553e9067c26dec9a47d40f4cd3e16461cf0edbbb49020695f18.json b/.sqlx/query-c08770c1ca1cb553e9067c26dec9a47d40f4cd3e16461cf0edbbb49020695f18.json new file mode 100644 index 0000000..113915c --- /dev/null +++ b/.sqlx/query-c08770c1ca1cb553e9067c26dec9a47d40f4cd3e16461cf0edbbb49020695f18.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM signal_signed_pre_keys", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "c08770c1ca1cb553e9067c26dec9a47d40f4cd3e16461cf0edbbb49020695f18" +} diff --git a/.sqlx/query-c130944c8791acb05ebf5f7b5b0f82b8c548ea9d516c0e9310fb46ffd3907977.json b/.sqlx/query-c130944c8791acb05ebf5f7b5b0f82b8c548ea9d516c0e9310fb46ffd3907977.json new file mode 100644 index 0000000..6e85422 --- /dev/null +++ b/.sqlx/query-c130944c8791acb05ebf5f7b5b0f82b8c548ea9d516c0e9310fb46ffd3907977.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT value FROM signal_kv WHERE key = 'registration'", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "value", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "c130944c8791acb05ebf5f7b5b0f82b8c548ea9d516c0e9310fb46ffd3907977" +} diff --git a/.sqlx/query-c30d8f2bb8a20154b565a93108d3871289a752fb8d0de35a2164619da2c03aa0.json b/.sqlx/query-c30d8f2bb8a20154b565a93108d3871289a752fb8d0de35a2164619da2c03aa0.json new file mode 100644 index 0000000..cb13226 --- /dev/null +++ b/.sqlx/query-c30d8f2bb8a20154b565a93108d3871289a752fb8d0de35a2164619da2c03aa0.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "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", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Timestamptz", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "c30d8f2bb8a20154b565a93108d3871289a752fb8d0de35a2164619da2c03aa0" +} diff --git a/.sqlx/query-c5310fca925ec4188e761f218e98c11182e5757c40a70a2aa50af0f2896d98e7.json b/.sqlx/query-c5310fca925ec4188e761f218e98c11182e5757c40a70a2aa50af0f2896d98e7.json new file mode 100644 index 0000000..ec25689 --- /dev/null +++ b/.sqlx/query-c5310fca925ec4188e761f218e98c11182e5757c40a70a2aa50af0f2896d98e7.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT COUNT(*) AS \"count!\" FROM signal_signed_pre_keys WHERE identity = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "count!", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "c5310fca925ec4188e761f218e98c11182e5757c40a70a2aa50af0f2896d98e7" +} diff --git a/.sqlx/query-c67709e3fb975148fa86d9fd5ed5e1ef805b2f57a2ce5d955629d598e1ab2b80.json b/.sqlx/query-c67709e3fb975148fa86d9fd5ed5e1ef805b2f57a2ce5d955629d598e1ab2b80.json new file mode 100644 index 0000000..27447ea --- /dev/null +++ b/.sqlx/query-c67709e3fb975148fa86d9fd5ed5e1ef805b2f57a2ce5d955629d598e1ab2b80.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT key FROM signal_profile_keys WHERE uuid = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "key", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Uuid" + ] + }, + "nullable": [ + false + ] + }, + "hash": "c67709e3fb975148fa86d9fd5ed5e1ef805b2f57a2ce5d955629d598e1ab2b80" +} diff --git a/.sqlx/query-c749d53e4e38dd53aa2ac59ba2b15b641ace056515c34ec977bf47d74dfd7072.json b/.sqlx/query-c749d53e4e38dd53aa2ac59ba2b15b641ace056515c34ec977bf47d74dfd7072.json new file mode 100644 index 0000000..da461b2 --- /dev/null +++ b/.sqlx/query-c749d53e4e38dd53aa2ac59ba2b15b641ace056515c34ec977bf47d74dfd7072.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM signal_kyber_pre_keys\n WHERE id = $1 AND identity = $2 AND is_last_resort = FALSE", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int4", + "Text" + ] + }, + "nullable": [] + }, + "hash": "c749d53e4e38dd53aa2ac59ba2b15b641ace056515c34ec977bf47d74dfd7072" +} diff --git a/.sqlx/query-c86da12578b2e53e0bff374121b22244c4663820cbb6edfd8f0b8c9aa583cad2.json b/.sqlx/query-c86da12578b2e53e0bff374121b22244c4663820cbb6edfd8f0b8c9aa583cad2.json new file mode 100644 index 0000000..81d1fee --- /dev/null +++ b/.sqlx/query-c86da12578b2e53e0bff374121b22244c4663820cbb6edfd8f0b8c9aa583cad2.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT value FROM signal_kv WHERE key = 'master_key' LIMIT 1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "value", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "c86da12578b2e53e0bff374121b22244c4663820cbb6edfd8f0b8c9aa583cad2" +} diff --git a/.sqlx/query-dded08cb4fd0fc9bca55b3cf0c8d22f4e279bc8aedb72000f4c4bc093f61c750.json b/.sqlx/query-dded08cb4fd0fc9bca55b3cf0c8d22f4e279bc8aedb72000f4c4bc093f61c750.json new file mode 100644 index 0000000..4ea42fa --- /dev/null +++ b/.sqlx/query-dded08cb4fd0fc9bca55b3cf0c8d22f4e279bc8aedb72000f4c4bc093f61c750.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT value FROM signal_kv WHERE key = 'sender_certificate' LIMIT 1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "value", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false + ] + }, + "hash": "dded08cb4fd0fc9bca55b3cf0c8d22f4e279bc8aedb72000f4c4bc093f61c750" +} diff --git a/.sqlx/query-def40c1cfac196a066d81fb0efa0fa7bdf5f242bd13c8b70e47a512c5e9df5b1.json b/.sqlx/query-def40c1cfac196a066d81fb0efa0fa7bdf5f242bd13c8b70e47a512c5e9df5b1.json new file mode 100644 index 0000000..46a1f66 --- /dev/null +++ b/.sqlx/query-def40c1cfac196a066d81fb0efa0fa7bdf5f242bd13c8b70e47a512c5e9df5b1.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "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", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int4", + "Text", + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "def40c1cfac196a066d81fb0efa0fa7bdf5f242bd13c8b70e47a512c5e9df5b1" +} diff --git a/.sqlx/query-e2ed0b4bfe13a99be85311fcc6e3c2dbdb789b9a44c0122f736ead48f4713a5b.json b/.sqlx/query-e2ed0b4bfe13a99be85311fcc6e3c2dbdb789b9a44c0122f736ead48f4713a5b.json new file mode 100644 index 0000000..141dc38 --- /dev/null +++ b/.sqlx/query-e2ed0b4bfe13a99be85311fcc6e3c2dbdb789b9a44c0122f736ead48f4713a5b.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM signal_pre_keys", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "e2ed0b4bfe13a99be85311fcc6e3c2dbdb789b9a44c0122f736ead48f4713a5b" +} diff --git a/.sqlx/query-eb837730e87ff990c4441d7bdab001d7542d1803702c634a6099365a9740e45a.json b/.sqlx/query-eb837730e87ff990c4441d7bdab001d7542d1803702c634a6099365a9740e45a.json new file mode 100644 index 0000000..2bd25a8 --- /dev/null +++ b/.sqlx/query-eb837730e87ff990c4441d7bdab001d7542d1803702c634a6099365a9740e45a.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM signal_kyber_pre_keys WHERE id = $1 AND identity = $2", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int4", + "Text" + ] + }, + "nullable": [] + }, + "hash": "eb837730e87ff990c4441d7bdab001d7542d1803702c634a6099365a9740e45a" +} diff --git a/.sqlx/query-eea566212ffce269028a8623a12b553c048ef1ea433aa5567e72b2b639f69b0d.json b/.sqlx/query-eea566212ffce269028a8623a12b553c048ef1ea433aa5567e72b2b639f69b0d.json new file mode 100644 index 0000000..eda4316 --- /dev/null +++ b/.sqlx/query-eea566212ffce269028a8623a12b553c048ef1ea433aa5567e72b2b639f69b0d.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT MAX(id) FROM signal_kyber_pre_keys WHERE identity = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "max", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "eea566212ffce269028a8623a12b553c048ef1ea433aa5567e72b2b639f69b0d" +} diff --git a/.sqlx/query-efcf513bba65213ed4b71259a7016ffd7b1b8ff85206416a86beba19323a3be7.json b/.sqlx/query-efcf513bba65213ed4b71259a7016ffd7b1b8ff85206416a86beba19323a3be7.json new file mode 100644 index 0000000..f954173 --- /dev/null +++ b/.sqlx/query-efcf513bba65213ed4b71259a7016ffd7b1b8ff85206416a86beba19323a3be7.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "DELETE FROM signal_sessions WHERE address = $1 AND device_id = $2 AND identity = $3", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int4", + "Text" + ] + }, + "nullable": [] + }, + "hash": "efcf513bba65213ed4b71259a7016ffd7b1b8ff85206416a86beba19323a3be7" +} diff --git a/.sqlx/query-f332e618e59a298573c4b6b6c7a12252b461a6676f2d797c5dae5a0baee016a7.json b/.sqlx/query-f332e618e59a298573c4b6b6c7a12252b461a6676f2d797c5dae5a0baee016a7.json new file mode 100644 index 0000000..9473025 --- /dev/null +++ b/.sqlx/query-f332e618e59a298573c4b6b6c7a12252b461a6676f2d797c5dae5a0baee016a7.json @@ -0,0 +1,24 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT record FROM signal_sessions\n WHERE address = $1 AND device_id = $2 AND identity = $3", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "record", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "Text", + "Int4", + "Text" + ] + }, + "nullable": [ + false + ] + }, + "hash": "f332e618e59a298573c4b6b6c7a12252b461a6676f2d797c5dae5a0baee016a7" +} diff --git a/.sqlx/query-f41749b35c081fc9d0881c7e2fc988e7c4d164ab5996f18e9f3a29fe4d183db9.json b/.sqlx/query-f41749b35c081fc9d0881c7e2fc988e7c4d164ab5996f18e9f3a29fe4d183db9.json new file mode 100644 index 0000000..f4cd2e0 --- /dev/null +++ b/.sqlx/query-f41749b35c081fc9d0881c7e2fc988e7c4d164ab5996f18e9f3a29fe4d183db9.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT MAX(id) FROM signal_signed_pre_keys WHERE identity = $1", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "max", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "f41749b35c081fc9d0881c7e2fc988e7c4d164ab5996f18e9f3a29fe4d183db9" +} diff --git a/Cargo.lock b/Cargo.lock index 508344e..4eab9c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -46,6 +46,7 @@ dependencies = [ "cfg-if", "cipher", "cpufeatures", + "zeroize", ] [[package]] @@ -62,6 +63,21 @@ dependencies = [ "subtle", ] +[[package]] +name = "aes-gcm-siv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae0784134ba9375416d469ec31e7c5f9fa94405049cf08c5ce5b4698be673e0d" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "polyval", + "subtle", + "zeroize", +] + [[package]] name = "ahash" version = "0.8.12" @@ -181,6 +197,19 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03918c3dbd7701a85c6b9887732e2921175f26c350b4563841d0958c21d57e6d" +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures", + "password-hash", + "zeroize", +] + [[package]] name = "asn1-rs" version = "0.6.2" @@ -230,6 +259,12 @@ dependencies = [ "serde_json", ] +[[package]] +name = "assert_matches" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" + [[package]] name = "astral-tokio-tar" version = "0.5.6" @@ -292,6 +327,22 @@ dependencies = [ "syn 2.0.111", ] +[[package]] +name = "async-tungstenite" +version = "0.28.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c348fb0b6d132c596eca3dcd941df48fb597aafcb07a738ec41c004b087dc99" +dependencies = [ + "atomic-waker", + "futures-core", + "futures-io", + "futures-task", + "futures-util", + "log", + "pin-project-lite", + "tungstenite 0.24.0", +] + [[package]] name = "atoi" version = "2.0.0" @@ -854,7 +905,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e9430d9a245a77c92176e649af6e275f20839a48389859d1661e9a128d077c" dependencies = [ - "const-str", + "const-str 0.4.3", "match-lookup", ] @@ -916,6 +967,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bincode" version = "2.0.1" @@ -945,6 +1005,15 @@ dependencies = [ "serde_core", ] +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -954,6 +1023,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-padding" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array", +] + [[package]] name = "blowfish" version = "0.9.1" @@ -1017,8 +1095,8 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85a885520bf6249ab931a764ffdb87b0ceef48e6e7d807cfdb21b751e086e1ad" dependencies = [ - "prost", - "prost-types", + "prost 0.14.1", + "prost-types 0.14.1", "tonic", "tonic-prost", "ureq", @@ -1034,7 +1112,7 @@ dependencies = [ "bollard-buildkit-proto", "bytes", "chrono", - "prost", + "prost 0.14.1", "serde", "serde_json", "serde_repr", @@ -1137,6 +1215,9 @@ name = "bytes" version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +dependencies = [ + "serde", +] [[package]] name = "bytes-utils" @@ -1148,6 +1229,15 @@ dependencies = [ "either", ] +[[package]] +name = "cbc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +dependencies = [ + "cipher", +] + [[package]] name = "cbor4ii" version = "0.2.14" @@ -1264,6 +1354,7 @@ checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ "crypto-common", "inout", + "zeroize", ] [[package]] @@ -1411,6 +1502,12 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f421161cb492475f1661ddc9815a745a1c894592070661180fdec3d4872e9c3" +[[package]] +name = "const-str" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18f12cc9948ed9604230cdddc7c86e270f9401ccbe3c2e98a4378c5e7632212f" + [[package]] name = "constant_time_eq" version = "0.3.1" @@ -1453,6 +1550,17 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "core-models" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0940496e5c83c54f3b753d5317daec82e8edac71c33aaa1f666d76f518de2444" +dependencies = [ + "hax-lib", + "pastey", + "rand 0.9.2", +] + [[package]] name = "core2" version = "0.4.0" @@ -1514,6 +1622,16 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + [[package]] name = "crossbeam-epoch" version = "0.9.18" @@ -1607,15 +1725,16 @@ dependencies = [ [[package]] name = "curve25519-dalek" version = "4.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +source = "git+https://github.com/signalapp/curve25519-dalek?tag=signal-curve25519-4.1.3#7c6d34756355a3566a704da84dce7b1c039a6572" dependencies = [ "cfg-if", "cpufeatures", "curve25519-dalek-derive", "digest", "fiat-crypto", + "rand_core 0.6.4", "rustc_version", + "serde", "subtle", "zeroize", ] @@ -1623,8 +1742,7 @@ dependencies = [ [[package]] name = "curve25519-dalek-derive" version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +source = "git+https://github.com/signalapp/curve25519-dalek?tag=signal-curve25519-4.1.3#7c6d34756355a3566a704da84dce7b1c039a6572" dependencies = [ "proc-macro2", "quote", @@ -1769,6 +1887,17 @@ dependencies = [ "serde_core", ] +[[package]] +name = "derive-where" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d08b3a0bcc0d079199cd476b2cae8435016ec11d1c0986c6901c5ac223041534" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "derive_arbitrary" version = "1.4.2" @@ -1786,7 +1915,16 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" dependencies = [ - "derive_more-impl", + "derive_more-impl 1.0.0", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl 2.1.1", ] [[package]] @@ -1801,6 +1939,19 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.111", + "unicode-xid", +] + [[package]] name = "diatomic-waker" version = "0.2.3" @@ -2126,6 +2277,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + [[package]] name = "flate2" version = "1.1.5" @@ -2160,7 +2317,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f59e967f3f675997e4a4a6b99d2a75148d59d64c46211b78b4f34ebb951b273" dependencies = [ - "bincode", + "bincode 2.0.1", "bytes", "rand 0.9.2", "serde", @@ -2402,6 +2559,7 @@ checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" dependencies = [ "opaque-debug", "polyval", + "zeroize", ] [[package]] @@ -2572,6 +2730,43 @@ dependencies = [ "hashbrown 0.15.5", ] +[[package]] +name = "hax-lib" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d9ba66d1739c68e0219b2b2238b5c4145f491ebf181b9c6ab561a19352ae86" +dependencies = [ + "hax-lib-macros", + "num-bigint", + "num-traits", +] + +[[package]] +name = "hax-lib-macros" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24ba777a231a58d1bce1d68313fa6b6afcc7966adef23d60f45b8a2b9b688bf1" +dependencies = [ + "hax-lib-macros-types", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "hax-lib-macros-types" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "867e19177d7425140b417cd27c2e05320e727ee682e98368f88b7194e80ad515" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "serde_json", + "uuid", +] + [[package]] name = "heapless" version = "0.7.17" @@ -2688,6 +2883,28 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "hpke-rs" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8c09b01d75373842d3123a4dd51bad5cb70e95d8b96e50bc20d08877a8d2443" +dependencies = [ + "hpke-rs-crypto", + "libcrux-sha3 0.0.4", + "log", + "rand_core 0.9.3", + "zeroize", +] + +[[package]] +name = "hpke-rs-crypto" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dd92b7d7f0deaae59c152e01c01f5280ea92dfac82090e5c025879b32df9193" +dependencies = [ + "rand_core 0.9.3", +] + [[package]] name = "http" version = "0.2.12" @@ -3117,6 +3334,7 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ + "block-padding", "generic-array", ] @@ -3397,6 +3615,132 @@ version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" +[[package]] +name = "libcrux-hacl-rs" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2637dc87d158e1f1b550fd9b226443e84153fded4de69028d897b534d16d22e6" +dependencies = [ + "libcrux-macros", +] + +[[package]] +name = "libcrux-hmac" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f0e8011bfcdb6059127e673ec0e1fc7b2a3705c683ade9d708875ed4c26cd8d" +dependencies = [ + "libcrux-hacl-rs", + "libcrux-macros", + "libcrux-sha2", +] + +[[package]] +name = "libcrux-intrinsics" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc9ee7ef66569dd7516454fe26de4e401c0c62073929803486b96744594b9632" +dependencies = [ + "core-models", + "hax-lib", +] + +[[package]] +name = "libcrux-macros" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffd6aa2dcd5be681662001b81d493f1569c6d49a32361f470b0c955465cd0338" +dependencies = [ + "quote", + "syn 2.0.111", +] + +[[package]] +name = "libcrux-ml-kem" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22a36f21056e552438dbe6ce413b6682001795e53bd1f0e2c941d7e231238e5a" +dependencies = [ + "hax-lib", + "libcrux-intrinsics", + "libcrux-platform 0.0.3", + "libcrux-secrets", + "libcrux-sha3 0.0.5", + "libcrux-traits", +] + +[[package]] +name = "libcrux-platform" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db82d058aa76ea315a3b2092f69dfbd67ddb0e462038a206e1dcd73f058c0778" +dependencies = [ + "libc", +] + +[[package]] +name = "libcrux-platform" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d9e21d7ed31a92ac539bd69a8c970b183ee883872d2d19ce27036e24cb8ecc4" +dependencies = [ + "libc", +] + +[[package]] +name = "libcrux-secrets" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4dbbf6bc9f2bc0f20dc3bea3e5c99adff3bdccf6d2a40488963da69e2ec307" +dependencies = [ + "hax-lib", +] + +[[package]] +name = "libcrux-sha2" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "649d9401e6e1954f58531b8eb13b12c800f85bbadc93362871b63a1f8a8d6d32" +dependencies = [ + "libcrux-hacl-rs", + "libcrux-macros", + "libcrux-traits", +] + +[[package]] +name = "libcrux-sha3" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2400bec764d1c75b8a496d5747cffe32f1fb864a12577f0aca2f55a92021c962" +dependencies = [ + "hax-lib", + "libcrux-intrinsics", + "libcrux-platform 0.0.2", + "libcrux-traits", +] + +[[package]] +name = "libcrux-sha3" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18e869fdeb9af62c55c3fcd60ce407552eb282d727550ce986abac94a3474479" +dependencies = [ + "hax-lib", + "libcrux-intrinsics", + "libcrux-platform 0.0.3", + "libcrux-traits", +] + +[[package]] +name = "libcrux-traits" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9adfd58e79d860f6b9e40e35127bfae9e5bd3ade33201d1347459011a2add034" +dependencies = [ + "libcrux-secrets", + "rand 0.9.2", +] + [[package]] name = "libm" version = "0.2.15" @@ -3414,6 +3758,127 @@ dependencies = [ "redox_syscall 0.6.0", ] +[[package]] +name = "libsignal-account-keys" +version = "0.1.0" +source = "git+https://github.com/signalapp/libsignal?tag=v0.87.4#38514bdc8acaaffbccd5c96515c68deb2019abe0" +dependencies = [ + "argon2", + "derive_more 2.1.1", + "displaydoc", + "hkdf", + "libsignal-core", + "partial-default", + "protobuf", + "protobuf-codegen", + "rand 0.9.2", + "rand_core 0.9.3", + "serde", + "sha2", + "signal-crypto", + "static_assertions", + "thiserror 2.0.17", + "zerocopy", +] + +[[package]] +name = "libsignal-core" +version = "0.1.0" +source = "git+https://github.com/signalapp/libsignal?tag=v0.87.4#38514bdc8acaaffbccd5c96515c68deb2019abe0" +dependencies = [ + "curve25519-dalek", + "derive_more 2.1.1", + "displaydoc", + "log", + "rand 0.9.2", + "sha2", + "subtle", + "thiserror 2.0.17", + "uuid", + "x25519-dalek", + "zerocopy", +] + +[[package]] +name = "libsignal-protocol" +version = "0.1.0" +source = "git+https://github.com/signalapp/libsignal?tag=v0.87.4#38514bdc8acaaffbccd5c96515c68deb2019abe0" +dependencies = [ + "aes", + "aes-gcm-siv", + "assert_matches", + "async-trait", + "bitflags", + "const-str 1.1.0", + "ctr", + "data-encoding-macro", + "derive-where", + "derive_more 2.1.1", + "displaydoc", + "hex", + "hkdf", + "hmac", + "indexmap 2.12.1", + "itertools", + "libcrux-ml-kem", + "libsignal-core", + "log", + "prost 0.14.1", + "prost-build 0.14.1", + "rand 0.9.2", + "rayon", + "serde", + "sha2", + "signal-crypto", + "spqr", + "subtle", + "thiserror 2.0.17", + "uuid", + "zerocopy", +] + +[[package]] +name = "libsignal-service" +version = "0.1.0" +source = "git+https://github.com/whisperfish/libsignal-service-rs?rev=3d07d8df33482b2d191c075fdc2b750738a89384#3d07d8df33482b2d191c075fdc2b750738a89384" +dependencies = [ + "aes", + "aes-gcm", + "async-trait", + "base64 0.22.1", + "bincode 1.3.3", + "bytes", + "cbc", + "chrono", + "ctr", + "derive_more 2.1.1", + "futures", + "hex", + "hkdf", + "hmac", + "libsignal-core", + "libsignal-protocol", + "phonenumber", + "prost 0.13.5", + "prost-build 0.13.5", + "rand 0.9.2", + "rand_core 0.6.4", + "reqwest", + "reqwest-websocket", + "serde", + "serde_json", + "sha2", + "signal-crypto", + "thiserror 2.0.17", + "tokio", + "tracing", + "tracing-futures", + "url", + "usernames", + "uuid", + "zkgroup", +] + [[package]] name = "libsqlite3-sys" version = "0.30.1" @@ -3439,6 +3904,12 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + [[package]] name = "linux-raw-sys" version = "0.11.0" @@ -3689,6 +4160,12 @@ dependencies = [ "unsigned-varint 0.8.0", ] +[[package]] +name = "multimap" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" + [[package]] name = "n0-future" version = "0.1.3" @@ -3696,7 +4173,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7bb0e5d99e681ab3c938842b96fcb41bf8a7bb4bfdb11ccbd653a7e83e06c794" dependencies = [ "cfg_aliases", - "derive_more", + "derive_more 1.0.0", "futures-buffered", "futures-lite", "futures-util", @@ -3841,6 +4318,28 @@ dependencies = [ "libc", ] +[[package]] +name = "num_enum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "oid-registry" version = "0.7.1" @@ -3862,6 +4361,12 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[package]] +name = "oncemutex" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d11de466f4a3006fe8a5e7ec84e93b79c70cb992ae0aa0eb631ad2df8abfe2" + [[package]] name = "opaque-debug" version = "0.3.1" @@ -4014,7 +4519,7 @@ checksum = "914a1c2265c98e2446911282c6ac86d8524f495792c38c5bd884f80499c7538a" dependencies = [ "parse-display-derive", "regex", - "regex-syntax", + "regex-syntax 0.8.8", ] [[package]] @@ -4026,11 +4531,42 @@ dependencies = [ "proc-macro2", "quote", "regex", - "regex-syntax", + "regex-syntax 0.8.8", "structmeta", "syn 2.0.111", ] +[[package]] +name = "partial-default" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "124dc3c21ffb6fb3a0562d129929a8a54998766ef7adc1ba09ddc467d092c14b" +dependencies = [ + "partial-default-derive", +] + +[[package]] +name = "partial-default-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7459127d7a18cb202d418e4b7df1103ffd6d82a106e9b2091c250624c2ace70d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "pastey" version = "0.1.1" @@ -4062,6 +4598,36 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "petgraph" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" +dependencies = [ + "fixedbitset", + "indexmap 2.12.1", +] + +[[package]] +name = "phonenumber" +version = "0.3.9+9.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9114f9c1683dd09c5f4fa024c89fdad783eaae21d3d52dd23ddaaffa29ffb168" +dependencies = [ + "either", + "fnv", + "nom", + "once_cell", + "postcard", + "quick-xml", + "regex", + "regex-cache", + "serde", + "serde_derive", + "strum", + "thiserror 2.0.17", +] + [[package]] name = "pin-project" version = "1.1.10" @@ -4144,6 +4710,16 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "poksho" +version = "0.7.0" +source = "git+https://github.com/signalapp/libsignal?tag=v0.87.4#38514bdc8acaaffbccd5c96515c68deb2019abe0" +dependencies = [ + "curve25519-dalek", + "hmac", + "sha2", +] + [[package]] name = "polyval" version = "0.6.2" @@ -4199,6 +4775,27 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "presage" +version = "0.8.0-dev" +source = "git+https://github.com/whisperfish/presage?rev=fe3ed54c4844ae51c3a9fa49cf80a7816a31a425#fe3ed54c4844ae51c3a9fa49cf80a7816a31a425" +dependencies = [ + "base64 0.22.1", + "bytes", + "derive_more 2.1.1", + "futures", + "hex", + "libsignal-service", + "rand 0.9.2", + "serde", + "serde_json", + "sha2", + "thiserror 1.0.69", + "tokio", + "tracing", + "url", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -4218,6 +4815,15 @@ dependencies = [ "elliptic-curve 0.13.8", ] +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -4242,6 +4848,28 @@ dependencies = [ "version_check", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "proc-macro2" version = "1.0.103" @@ -4264,6 +4892,16 @@ dependencies = [ "yansi", ] +[[package]] +name = "prost" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +dependencies = [ + "bytes", + "prost-derive 0.13.5", +] + [[package]] name = "prost" version = "0.14.1" @@ -4271,7 +4909,60 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.14.1", +] + +[[package]] +name = "prost-build" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" +dependencies = [ + "heck 0.4.1", + "itertools", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease", + "prost 0.13.5", + "prost-types 0.13.5", + "regex", + "syn 2.0.111", + "tempfile", +] + +[[package]] +name = "prost-build" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac6c3320f9abac597dcbc668774ef006702672474aad53c6d596b62e487b40b1" +dependencies = [ + "heck 0.4.1", + "itertools", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease", + "prost 0.14.1", + "prost-types 0.14.1", + "regex", + "syn 2.0.111", + "tempfile", +] + +[[package]] +name = "prost-derive" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 2.0.111", ] [[package]] @@ -4287,13 +4978,73 @@ dependencies = [ "syn 2.0.111", ] +[[package]] +name = "prost-types" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" +dependencies = [ + "prost 0.13.5", +] + [[package]] name = "prost-types" version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9b4db3d6da204ed77bb26ba83b6122a73aeb2e87e25fbf7ad2e84c4ccbf8f72" dependencies = [ - "prost", + "prost 0.14.1", +] + +[[package]] +name = "protobuf" +version = "3.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d65a1d4ddae7d8b5de68153b48f6aa3bba8cb002b243dbdbc55a5afbc98f99f4" +dependencies = [ + "once_cell", + "protobuf-support", + "thiserror 1.0.69", +] + +[[package]] +name = "protobuf-codegen" +version = "3.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d3976825c0014bbd2f3b34f0001876604fe87e0c86cd8fa54251530f1544ace" +dependencies = [ + "anyhow", + "once_cell", + "protobuf", + "protobuf-parse", + "regex", + "tempfile", + "thiserror 1.0.69", +] + +[[package]] +name = "protobuf-parse" +version = "3.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4aeaa1f2460f1d348eeaeed86aea999ce98c1bded6f089ff8514c9d9dbdc973" +dependencies = [ + "anyhow", + "indexmap 2.12.1", + "log", + "protobuf", + "protobuf-support", + "tempfile", + "thiserror 1.0.69", + "which", +] + +[[package]] +name = "protobuf-support" +version = "3.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e36c2f31e0a47f9280fb347ef5e461ffcd2c52dd520d8e216b52f93b0b0d7d6" +dependencies = [ + "thiserror 1.0.69", ] [[package]] @@ -4343,6 +5094,15 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" +[[package]] +name = "quick-xml" +version = "0.38.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" +dependencies = [ + "memchr", +] + [[package]] name = "quinn" version = "0.11.9" @@ -4496,6 +5256,26 @@ dependencies = [ "bitflags", ] +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redis" version = "1.0.1" @@ -4570,7 +5350,7 @@ dependencies = [ "aho-corasick", "memchr", "regex-automata", - "regex-syntax", + "regex-syntax 0.8.8", ] [[package]] @@ -4581,7 +5361,19 @@ checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.8.8", +] + +[[package]] +name = "regex-cache" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f7b62d69743b8b94f353b6b7c3deb4c5582828328bcb8d5fedf214373808793" +dependencies = [ + "lru-cache", + "oncemutex", + "regex", + "regex-syntax 0.6.29", ] [[package]] @@ -4590,6 +5382,12 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d942b98df5e658f56f20d592c7f868833fe38115e65c33003d8cd224b0155da" +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.8.8" @@ -4606,6 +5404,7 @@ dependencies = [ "bytes", "encoding_rs", "futures-core", + "futures-util", "h2 0.4.12", "http 1.4.0", "http-body 1.0.1", @@ -4616,6 +5415,7 @@ dependencies = [ "js-sys", "log", "mime", + "mime_guess", "percent-encoding", "pin-project-lite", "quinn", @@ -4627,16 +5427,37 @@ dependencies = [ "sync_wrapper", "tokio", "tokio-rustls 0.26.4", + "tokio-util", "tower", "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", + "wasm-streams", "web-sys", "webpki-roots 1.0.4", ] +[[package]] +name = "reqwest-websocket" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f477f800f86d8f5c320e19d8b2b1ef0b1e773ea7c75eec6c7f442e7ec3f06d7e" +dependencies = [ + "async-tungstenite", + "futures-util", + "reqwest", + "serde", + "serde_json", + "thiserror 2.0.17", + "tokio", + "tokio-util", + "tracing", + "tungstenite 0.24.0", + "web-sys", +] + [[package]] name = "resolv-conf" version = "0.7.6" @@ -4722,6 +5543,19 @@ dependencies = [ "nom", ] +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.52.0", +] + [[package]] name = "rustix" version = "1.1.3" @@ -4731,7 +5565,7 @@ dependencies = [ "bitflags", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.11.0", "windows-sys 0.61.2", ] @@ -5134,6 +5968,16 @@ dependencies = [ "cfg-if", "cpufeatures", "digest", + "sha2-asm", +] + +[[package]] +name = "sha2-asm" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b845214d6175804686b2bd482bcffe96651bb2d1200742b712003504a2dac1ab" +dependencies = [ + "cc", ] [[package]] @@ -5151,6 +5995,30 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signal-crypto" +version = "0.1.0" +source = "git+https://github.com/signalapp/libsignal?tag=v0.87.4#38514bdc8acaaffbccd5c96515c68deb2019abe0" +dependencies = [ + "aes", + "cbc", + "ctr", + "derive_more 2.1.1", + "displaydoc", + "ghash", + "hkdf", + "hmac", + "hpke-rs", + "hpke-rs-crypto", + "libsignal-core", + "rand_chacha 0.9.0", + "rand_core 0.9.3", + "sha1", + "sha2", + "subtle", + "thiserror 2.0.17", +] + [[package]] name = "signal-hook-registry" version = "1.4.7" @@ -5249,6 +6117,12 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "sorted-vec" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f58d7b0190c7f12df7e8be6b79767a0836059159811b869d5ab55721fe14d0" + [[package]] name = "spin" version = "0.9.8" @@ -5293,6 +6167,29 @@ dependencies = [ "der 0.7.10", ] +[[package]] +name = "spqr" +version = "1.4.0" +source = "git+https://github.com/signalapp/SparsePostQuantumRatchet.git?tag=v1.4.0#d310c99c57a046549be205b9ce50d80dcbe5f3e4" +dependencies = [ + "cpufeatures", + "curve25519-dalek", + "displaydoc", + "hax-lib", + "hkdf", + "libcrux-hmac", + "libcrux-ml-kem", + "log", + "num_enum", + "prost 0.14.1", + "prost-build 0.14.1", + "rand 0.9.2", + "rand_core 0.9.3", + "sha2", + "sorted-vec", + "thiserror 2.0.17", +] + [[package]] name = "sqlx" version = "0.8.6" @@ -5563,6 +6460,27 @@ dependencies = [ "syn 2.0.111", ] +[[package]] +name = "strum" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "subtle" version = "2.6.1" @@ -5632,6 +6550,19 @@ dependencies = [ "libc", ] +[[package]] +name = "tempfile" +version = "3.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" +dependencies = [ + "fastrand", + "getrandom 0.3.4", + "once_cell", + "rustix 1.1.3", + "windows-sys 0.52.0", +] + [[package]] name = "testcontainers" version = "0.26.2" @@ -5846,7 +6777,7 @@ dependencies = [ "rustls-pki-types", "tokio", "tokio-rustls 0.26.4", - "tungstenite", + "tungstenite 0.28.0", "webpki-roots 0.26.11", ] @@ -5858,6 +6789,7 @@ checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", + "futures-io", "futures-sink", "futures-util", "pin-project-lite", @@ -5873,7 +6805,7 @@ dependencies = [ "indexmap 2.12.1", "serde_core", "serde_spanned", - "toml_datetime", + "toml_datetime 0.7.5+spec-1.1.0", "toml_parser", "toml_writer", "winnow", @@ -5888,6 +6820,27 @@ dependencies = [ "serde_core", ] +[[package]] +name = "toml_datetime" +version = "1.0.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b320e741db58cac564e26c607d3cc1fdc4a88fd36c879568c07856ed83ff3e9" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.0+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caee3f6e1c6f2025affe9191e6e6f66ade10b48f36b1a1b3cd92dfe405ffd260" +dependencies = [ + "indexmap 2.12.1", + "toml_datetime 1.0.1+spec-1.1.0", + "toml_parser", + "winnow", +] + [[package]] name = "toml_parser" version = "1.0.7+spec-1.1.0" @@ -5939,7 +6892,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66bd50ad6ce1252d87ef024b3d64fe4c3cf54a86fb9ef4c631fdd0ded7aeaa67" dependencies = [ "bytes", - "prost", + "prost 0.14.1", "tonic", ] @@ -6052,6 +7005,16 @@ dependencies = [ "valuable", ] +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + [[package]] name = "tracing-log" version = "0.2.0" @@ -6094,7 +7057,7 @@ dependencies = [ [[package]] name = "tranquil-api" -version = "0.4.6" +version = "0.4.7" dependencies = [ "anyhow", "axum", @@ -6142,7 +7105,7 @@ dependencies = [ [[package]] name = "tranquil-auth" -version = "0.4.6" +version = "0.4.7" dependencies = [ "anyhow", "base32", @@ -6165,7 +7128,7 @@ dependencies = [ [[package]] name = "tranquil-cache" -version = "0.4.6" +version = "0.4.7" dependencies = [ "async-trait", "base64 0.22.1", @@ -6179,7 +7142,7 @@ dependencies = [ [[package]] name = "tranquil-comms" -version = "0.4.6" +version = "0.4.7" dependencies = [ "async-trait", "base64 0.22.1", @@ -6194,7 +7157,7 @@ dependencies = [ [[package]] name = "tranquil-config" -version = "0.4.6" +version = "0.4.7" dependencies = [ "confique", "serde", @@ -6202,7 +7165,7 @@ dependencies = [ [[package]] name = "tranquil-crypto" -version = "0.4.6" +version = "0.4.7" dependencies = [ "aes-gcm", "base64 0.22.1", @@ -6218,7 +7181,7 @@ dependencies = [ [[package]] name = "tranquil-db" -version = "0.4.6" +version = "0.4.7" dependencies = [ "async-trait", "chrono", @@ -6235,7 +7198,7 @@ dependencies = [ [[package]] name = "tranquil-db-traits" -version = "0.4.6" +version = "0.4.7" dependencies = [ "async-trait", "base64 0.22.1", @@ -6251,7 +7214,7 @@ dependencies = [ [[package]] name = "tranquil-infra" -version = "0.4.6" +version = "0.4.7" dependencies = [ "async-trait", "bytes", @@ -6262,7 +7225,7 @@ dependencies = [ [[package]] name = "tranquil-lexicon" -version = "0.4.6" +version = "0.4.7" dependencies = [ "chrono", "hickory-resolver", @@ -6280,7 +7243,7 @@ dependencies = [ [[package]] name = "tranquil-oauth" -version = "0.4.6" +version = "0.4.7" dependencies = [ "anyhow", "axum", @@ -6303,7 +7266,7 @@ dependencies = [ [[package]] name = "tranquil-oauth-server" -version = "0.4.6" +version = "0.4.7" dependencies = [ "axum", "base64 0.22.1", @@ -6336,7 +7299,7 @@ dependencies = [ [[package]] name = "tranquil-pds" -version = "0.4.6" +version = "0.4.7" dependencies = [ "aes-gcm", "anyhow", @@ -6424,7 +7387,7 @@ dependencies = [ [[package]] name = "tranquil-repo" -version = "0.4.6" +version = "0.4.7" dependencies = [ "bytes", "cid", @@ -6436,11 +7399,11 @@ dependencies = [ [[package]] name = "tranquil-ripple" -version = "0.4.6" +version = "0.4.7" dependencies = [ "async-trait", "backon", - "bincode", + "bincode 2.0.1", "bytes", "foca", "futures", @@ -6461,7 +7424,7 @@ dependencies = [ [[package]] name = "tranquil-scopes" -version = "0.4.6" +version = "0.4.7" dependencies = [ "axum", "futures", @@ -6477,7 +7440,7 @@ dependencies = [ [[package]] name = "tranquil-server" -version = "0.4.6" +version = "0.4.7" dependencies = [ "axum", "clap", @@ -6495,9 +7458,29 @@ dependencies = [ "tranquil-sync", ] +[[package]] +name = "tranquil-signal" +version = "0.4.7" +dependencies = [ + "async-trait", + "chrono", + "futures", + "presage", + "rand 0.9.2", + "serde", + "serde_json", + "sqlx", + "thiserror 2.0.17", + "tokio", + "tokio-util", + "tracing", + "url", + "uuid", +] + [[package]] name = "tranquil-storage" -version = "0.4.6" +version = "0.4.7" dependencies = [ "async-trait", "aws-config", @@ -6514,7 +7497,7 @@ dependencies = [ [[package]] name = "tranquil-sync" -version = "0.4.6" +version = "0.4.7" dependencies = [ "anyhow", "axum", @@ -6536,7 +7519,7 @@ dependencies = [ [[package]] name = "tranquil-types" -version = "0.4.6" +version = "0.4.7" dependencies = [ "chrono", "cid", @@ -6553,6 +7536,24 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.4.0", + "httparse", + "log", + "rand 0.8.5", + "sha1", + "thiserror 1.0.69", + "utf-8", +] + [[package]] name = "tungstenite" version = "0.28.0" @@ -6709,6 +7710,26 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" +[[package]] +name = "usernames" +version = "0.1.0" +source = "git+https://github.com/signalapp/libsignal?tag=v0.87.4#38514bdc8acaaffbccd5c96515c68deb2019abe0" +dependencies = [ + "curve25519-dalek", + "displaydoc", + "hkdf", + "hmac", + "log", + "poksho", + "prost 0.14.1", + "prost-build 0.14.1", + "rand 0.9.2", + "sha2", + "signal-crypto", + "subtle", + "thiserror 2.0.17", +] + [[package]] name = "utf-8" version = "0.7.6" @@ -6859,6 +7880,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.83" @@ -6971,6 +8005,18 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix 0.38.44", +] + [[package]] name = "whoami" version = "1.6.1" @@ -7306,6 +8352,9 @@ name = "winnow" version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +dependencies = [ + "memchr", +] [[package]] name = "winreg" @@ -7352,6 +8401,18 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +[[package]] +name = "x25519-dalek" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" +dependencies = [ + "curve25519-dalek", + "rand_core 0.6.4", + "serde", + "zeroize", +] + [[package]] name = "x509-parser" version = "0.16.0" @@ -7376,7 +8437,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" dependencies = [ "libc", - "rustix", + "rustix 1.1.3", ] [[package]] @@ -7466,6 +8527,20 @@ name = "zeroize" version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] [[package]] name = "zerotrie" @@ -7514,6 +8589,54 @@ dependencies = [ "zopfli", ] +[[package]] +name = "zkcredential" +version = "0.1.0" +source = "git+https://github.com/signalapp/libsignal?tag=v0.87.4#38514bdc8acaaffbccd5c96515c68deb2019abe0" +dependencies = [ + "cfg-if", + "curve25519-dalek", + "derive-where", + "displaydoc", + "partial-default", + "poksho", + "rayon", + "serde", + "sha2", + "subtle", + "thiserror 2.0.17", +] + +[[package]] +name = "zkgroup" +version = "0.9.0" +source = "git+https://github.com/signalapp/libsignal?tag=v0.87.4#38514bdc8acaaffbccd5c96515c68deb2019abe0" +dependencies = [ + "aes", + "aes-gcm-siv", + "bincode 1.3.3", + "const-str 1.1.0", + "curve25519-dalek", + "derive-where", + "derive_more 2.1.1", + "displaydoc", + "hex", + "hkdf", + "libsignal-account-keys", + "libsignal-core", + "partial-default", + "poksho", + "rand 0.9.2", + "rayon", + "serde", + "sha2", + "static_assertions", + "subtle", + "thiserror 2.0.17", + "uuid", + "zkcredential", +] + [[package]] name = "zlib-rs" version = "0.5.5" diff --git a/Cargo.toml b/Cargo.toml index 1f6e52f..5ffd39f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,10 +21,11 @@ members = [ "crates/tranquil-oauth-server", "crates/tranquil-api", "crates/tranquil-lexicon", + "crates/tranquil-signal", ] [workspace.package] -version = "0.4.6" +version = "0.4.7" edition = "2024" license = "AGPL-3.0-or-later" @@ -49,6 +50,9 @@ tranquil-server = { path = "crates/tranquil-server" } tranquil-sync = { path = "crates/tranquil-sync" } tranquil-oauth-server = { path = "crates/tranquil-oauth-server" } tranquil-api = { path = "crates/tranquil-api" } +tranquil-signal = { path = "crates/tranquil-signal" } + +presage = { git = "https://github.com/whisperfish/presage", rev = "fe3ed54c4844ae51c3a9fa49cf80a7816a31a425", default-features = false } unicode-segmentation = "1" @@ -81,6 +85,7 @@ hkdf = "0.12" hmac = "0.12" http = "1.4" image = { version = "0.25", default-features = false, features = ["jpeg", "png", "gif", "webp"] } +qrcodegen = "1.8" infer = "0.19" ipld-core = "0.4" iroh-car = "0.5" @@ -129,6 +134,9 @@ testcontainers = "0.26" testcontainers-modules = { version = "0.14", features = ["postgres"] } wiremock = "0.6" +[patch.crates-io] +curve25519-dalek = { git = "https://github.com/signalapp/curve25519-dalek", tag = "signal-curve25519-4.1.3" } + [profile.release] lto = "fat" strip = true diff --git a/crates/tranquil-signal/Cargo.toml b/crates/tranquil-signal/Cargo.toml new file mode 100644 index 0000000..b83246c --- /dev/null +++ b/crates/tranquil-signal/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "tranquil-signal" +version.workspace = true +edition.workspace = true +license.workspace = true + +[dependencies] +presage = { workspace = true } +async-trait = { workspace = true } +chrono = { workspace = true } +sqlx = { workspace = true } +tracing = { workspace = true } +tokio = { workspace = true } +tokio-util = { workspace = true } +futures = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +url = "2.5" +uuid = { workspace = true } +thiserror = { workspace = true } + +[dev-dependencies] +rand = "0.9" diff --git a/crates/tranquil-signal/src/store.rs b/crates/tranquil-signal/src/store.rs new file mode 100644 index 0000000..f36127a --- /dev/null +++ b/crates/tranquil-signal/src/store.rs @@ -0,0 +1,1177 @@ +use std::ops::RangeBounds; + +use async_trait::async_trait; +use presage::{ + AvatarBytes, + libsignal_service::{ + Profile, + pre_keys::{KyberPreKeyStoreExt, PreKeysStore}, + prelude::{Content, MasterKey, ProfileKey, SessionStoreExt, Uuid}, + protocol::{ + CiphertextMessageType, DeviceId, Direction, GenericSignedPreKey, IdentityChange, + IdentityKey, IdentityKeyPair, IdentityKeyStore, KyberPreKeyId, KyberPreKeyRecord, + KyberPreKeyStore, PreKeyId, PreKeyRecord, PreKeyStore, ProtocolAddress, ProtocolStore, + PublicKey, SenderCertificate, SenderKeyRecord, SenderKeyStore, ServiceId, + SessionRecord, SessionStore, SignalProtocolError, SignedPreKeyId, SignedPreKeyRecord, + SignedPreKeyStore, + }, + push_service::DEFAULT_DEVICE_ID, + zkgroup::GroupMasterKeyBytes, + }, + manager::RegistrationData, + model::{contacts::Contact, groups::Group}, + store::{ContentsStore, StateStore, StickerPack, Store, Thread}, +}; +use sqlx::PgPool; +use tracing::warn; + +#[derive(Debug, Clone)] +pub struct PgSignalStore { + pub db: PgPool, +} + +impl PgSignalStore { + pub fn new(db: PgPool) -> Self { + Self { db } + } + + pub async fn is_linked(&self) -> Result { + let row = sqlx::query!("SELECT value FROM signal_kv WHERE key = 'registration'") + .fetch_optional(&self.db) + .await?; + Ok(row.is_some()) + } + + async fn set_identity_key_pair( + &self, + identity: IdentityType, + key_pair: IdentityKeyPair, + ) -> Result<(), PgStoreError> { + let key = identity.identity_key_pair_key(); + let value = key_pair.serialize().to_vec(); + sqlx::query!( + "INSERT INTO signal_kv (key, value) VALUES ($1, $2) + ON CONFLICT (key) DO UPDATE SET value = $2", + key, + &value, + ) + .execute(&self.db) + .await?; + Ok(()) + } + + async fn clear_protocol_tables( + tx: &mut sqlx::Transaction<'_, sqlx::Postgres>, + ) -> Result<(), PgStoreError> { + sqlx::query!("DELETE FROM signal_base_keys_seen") + .execute(&mut **tx) + .await?; + sqlx::query!("DELETE FROM signal_sender_keys") + .execute(&mut **tx) + .await?; + sqlx::query!("DELETE FROM signal_kyber_pre_keys") + .execute(&mut **tx) + .await?; + sqlx::query!("DELETE FROM signal_signed_pre_keys") + .execute(&mut **tx) + .await?; + sqlx::query!("DELETE FROM signal_pre_keys") + .execute(&mut **tx) + .await?; + sqlx::query!("DELETE FROM signal_identities") + .execute(&mut **tx) + .await?; + sqlx::query!("DELETE FROM signal_sessions") + .execute(&mut **tx) + .await?; + Ok(()) + } + + pub async fn clear_all(&self) -> Result<(), PgStoreError> { + let mut tx = self.db.begin().await?; + Self::clear_protocol_tables(&mut tx).await?; + sqlx::query!("DELETE FROM signal_profile_keys") + .execute(&mut *tx) + .await?; + sqlx::query!("DELETE FROM signal_kv") + .execute(&mut *tx) + .await?; + tx.commit().await?; + Ok(()) + } +} + +#[derive(Debug, Clone)] +pub struct PgProtocolStore { + store: PgSignalStore, + identity: IdentityType, +} + +impl PgProtocolStore { + pub(crate) fn new(store: PgSignalStore, identity: IdentityType) -> Self { + Self { store, identity } + } +} + +fn next_id_from_max(max_id: Option) -> Result { + match max_id { + None => Ok(1), + Some(id) => { + let current = i32_to_u32(id)?; + current.checked_add(1).ok_or_else(|| { + SignalProtocolError::InvalidState( + "pre key id space exhausted", + format!("max id {current} has no successor"), + ) + }) + } + } +} + +#[derive(Debug, Clone, Copy)] +pub enum IdentityType { + Aci, + Pni, +} + +impl IdentityType { + fn as_str(&self) -> &'static str { + match self { + Self::Aci => "aci", + Self::Pni => "pni", + } + } + + fn identity_key_pair_key(&self) -> &'static str { + match self { + Self::Aci => "identity_keypair_aci", + Self::Pni => "identity_keypair_pni", + } + } +} + +#[derive(Debug, thiserror::Error)] +pub enum PgStoreError { + #[error("sqlx: {0}")] + Sqlx(#[from] sqlx::Error), + #[error("json: {0}")] + Json(#[from] serde_json::Error), + #[error("protocol: {0}")] + Protocol(#[from] SignalProtocolError), + #[error("invalid format")] + InvalidFormat, +} + +impl presage::store::StoreError for PgStoreError {} + +fn u32_to_i32(val: u32) -> Result { + i32::try_from(val).map_err(|_| { + SignalProtocolError::InvalidState("id overflow", format!("{val} exceeds i32::MAX")) + }) +} + +fn i32_to_u32(val: i32) -> Result { + u32::try_from(val) + .map_err(|_| SignalProtocolError::InvalidState("negative id", format!("{val} is negative"))) +} + +trait IntoProtocolError { + fn into_protocol_error(self) -> Result; +} + +impl IntoProtocolError for Result { + fn into_protocol_error(self) -> Result { + self.map_err(|e| SignalProtocolError::InvalidState("sqlx", e.to_string())) + } +} + +impl IntoProtocolError for Result { + fn into_protocol_error(self) -> Result { + self.map_err(|e| SignalProtocolError::InvalidState("store", e.to_string())) + } +} + +impl Store for PgSignalStore { + type Error = PgStoreError; + type AciStore = PgProtocolStore; + type PniStore = PgProtocolStore; + + async fn clear(&mut self) -> Result<(), PgStoreError> { + self.clear_all().await + } + + fn aci_protocol_store(&self) -> Self::AciStore { + PgProtocolStore::new(self.clone(), IdentityType::Aci) + } + + fn pni_protocol_store(&self) -> Self::PniStore { + PgProtocolStore::new(self.clone(), IdentityType::Pni) + } +} + +impl StateStore for PgSignalStore { + type StateStoreError = PgStoreError; + + async fn load_registration_data(&self) -> Result, PgStoreError> { + sqlx::query_scalar!("SELECT value FROM signal_kv WHERE key = 'registration'") + .fetch_optional(&self.db) + .await? + .map(|value| serde_json::from_slice(&value)) + .transpose() + .map_err(From::from) + } + + async fn save_registration_data( + &mut self, + state: &RegistrationData, + ) -> Result<(), PgStoreError> { + let value = serde_json::to_vec(state)?; + sqlx::query!( + "INSERT INTO signal_kv (key, value) VALUES ('registration', $1) + ON CONFLICT (key) DO UPDATE SET value = $1", + &value, + ) + .execute(&self.db) + .await?; + Ok(()) + } + + async fn is_registered(&self) -> bool { + self.load_registration_data().await.ok().flatten().is_some() + } + + async fn clear_registration(&mut self) -> Result<(), PgStoreError> { + let mut tx = self.db.begin().await?; + sqlx::query!("DELETE FROM signal_kv WHERE key = 'registration'") + .execute(&mut *tx) + .await?; + Self::clear_protocol_tables(&mut tx).await?; + tx.commit().await?; + Ok(()) + } + + async fn set_aci_identity_key_pair( + &self, + key_pair: IdentityKeyPair, + ) -> Result<(), PgStoreError> { + self.set_identity_key_pair(IdentityType::Aci, key_pair) + .await + } + + async fn set_pni_identity_key_pair( + &self, + key_pair: IdentityKeyPair, + ) -> Result<(), PgStoreError> { + self.set_identity_key_pair(IdentityType::Pni, key_pair) + .await + } + + async fn sender_certificate(&self) -> Result, PgStoreError> { + sqlx::query_scalar!("SELECT value FROM signal_kv WHERE key = 'sender_certificate' LIMIT 1") + .fetch_optional(&self.db) + .await? + .map(|value| SenderCertificate::deserialize(&value)) + .transpose() + .map_err(From::from) + } + + async fn save_sender_certificate( + &self, + certificate: &SenderCertificate, + ) -> Result<(), PgStoreError> { + let value = certificate.serialized()?.to_vec(); + sqlx::query!( + "INSERT INTO signal_kv (key, value) VALUES ('sender_certificate', $1) + ON CONFLICT (key) DO UPDATE SET value = $1", + &value, + ) + .execute(&self.db) + .await?; + Ok(()) + } + + async fn fetch_master_key(&self) -> Result, PgStoreError> { + sqlx::query_scalar!("SELECT value FROM signal_kv WHERE key = 'master_key' LIMIT 1") + .fetch_optional(&self.db) + .await? + .map(|value| MasterKey::from_slice(&value)) + .transpose() + .map_err(|_| PgStoreError::InvalidFormat) + } + + async fn store_master_key(&self, master_key: Option<&MasterKey>) -> Result<(), PgStoreError> { + match master_key { + Some(k) => { + let value = k.inner.to_vec(); + sqlx::query!( + "INSERT INTO signal_kv (key, value) VALUES ('master_key', $1) + ON CONFLICT (key) DO UPDATE SET value = $1", + &value, + ) + .execute(&self.db) + .await?; + } + None => { + sqlx::query!("DELETE FROM signal_kv WHERE key = 'master_key'") + .execute(&self.db) + .await?; + } + } + Ok(()) + } +} + +impl ProtocolStore for PgProtocolStore {} + +#[async_trait(?Send)] +impl SessionStore for PgProtocolStore { + async fn load_session( + &self, + address: &ProtocolAddress, + ) -> Result, SignalProtocolError> { + let device_id: i32 = u32_to_i32(u32::from(address.device_id()))?; + let identity = self.identity.as_str(); + let addr = address.name(); + sqlx::query_scalar!( + "SELECT record FROM signal_sessions + WHERE address = $1 AND device_id = $2 AND identity = $3", + addr, + device_id, + identity, + ) + .fetch_optional(&self.store.db) + .await + .into_protocol_error()? + .map(|record| SessionRecord::deserialize(&record)) + .transpose() + } + + async fn store_session( + &mut self, + address: &ProtocolAddress, + record: &SessionRecord, + ) -> Result<(), SignalProtocolError> { + let device_id: i32 = u32_to_i32(u32::from(address.device_id()))?; + let identity = self.identity.as_str(); + let addr = address.name(); + let record = record.serialize()?; + sqlx::query!( + "INSERT INTO signal_sessions (address, device_id, identity, record) + VALUES ($1, $2, $3, $4) + ON CONFLICT (address, device_id, identity) DO UPDATE SET record = $4", + addr, + device_id, + identity, + &record, + ) + .execute(&self.store.db) + .await + .into_protocol_error()?; + Ok(()) + } +} + +#[async_trait(?Send)] +impl SessionStoreExt for PgProtocolStore { + async fn get_sub_device_sessions( + &self, + name: &ServiceId, + ) -> Result, SignalProtocolError> { + let address = name.raw_uuid().to_string(); + let default_device: i32 = u32_to_i32(u32::from(*DEFAULT_DEVICE_ID))?; + let identity = self.identity.as_str(); + sqlx::query_scalar!( + "SELECT device_id FROM signal_sessions + WHERE address = $1 AND device_id != $2 AND identity = $3", + &address, + default_device, + identity, + ) + .fetch_all(&self.store.db) + .await + .into_protocol_error()? + .into_iter() + .map(|id| { + let v = i32_to_u32(id)?; + let byte = u8::try_from(v).map_err(|_| { + SignalProtocolError::InvalidState("device id", format!("{id} exceeds u8::MAX")) + })?; + DeviceId::new(byte).map_err(|_| { + SignalProtocolError::InvalidState("device id", format!("invalid device id {id}")) + }) + }) + .collect() + } + + async fn delete_session(&self, address: &ProtocolAddress) -> Result<(), SignalProtocolError> { + let device_id: i32 = u32_to_i32(u32::from(address.device_id()))?; + let identity = self.identity.as_str(); + let addr = address.name(); + sqlx::query!( + "DELETE FROM signal_sessions WHERE address = $1 AND device_id = $2 AND identity = $3", + addr, + device_id, + identity, + ) + .execute(&self.store.db) + .await + .into_protocol_error()?; + Ok(()) + } + + async fn delete_all_sessions(&self, name: &ServiceId) -> Result { + let address = name.raw_uuid().to_string(); + let identity = self.identity.as_str(); + let res = sqlx::query!( + "DELETE FROM signal_sessions WHERE address = $1 AND identity = $2", + &address, + identity, + ) + .execute(&self.store.db) + .await + .into_protocol_error()?; + Ok(usize::try_from(res.rows_affected()).unwrap_or(usize::MAX)) + } +} + +#[async_trait(?Send)] +impl PreKeyStore for PgProtocolStore { + async fn get_pre_key(&self, prekey_id: PreKeyId) -> Result { + let id: i32 = u32_to_i32(u32::from(prekey_id))?; + let identity = self.identity.as_str(); + let record = sqlx::query_scalar!( + "SELECT record FROM signal_pre_keys WHERE id = $1 AND identity = $2", + id, + identity, + ) + .fetch_one(&self.store.db) + .await + .into_protocol_error()?; + PreKeyRecord::deserialize(&record) + } + + async fn save_pre_key( + &mut self, + prekey_id: PreKeyId, + record: &PreKeyRecord, + ) -> Result<(), SignalProtocolError> { + let id: i32 = u32_to_i32(u32::from(prekey_id))?; + let identity = self.identity.as_str(); + let record = record.serialize()?; + sqlx::query!( + "INSERT INTO signal_pre_keys (id, identity, record) + VALUES ($1, $2, $3) + ON CONFLICT (id, identity) DO UPDATE SET record = $3", + id, + identity, + &record, + ) + .execute(&self.store.db) + .await + .into_protocol_error()?; + Ok(()) + } + + async fn remove_pre_key(&mut self, prekey_id: PreKeyId) -> Result<(), SignalProtocolError> { + let id: i32 = u32_to_i32(u32::from(prekey_id))?; + let identity = self.identity.as_str(); + sqlx::query!( + "DELETE FROM signal_pre_keys WHERE id = $1 AND identity = $2", + id, + identity, + ) + .execute(&self.store.db) + .await + .into_protocol_error()?; + Ok(()) + } +} + +#[async_trait(?Send)] +impl PreKeysStore for PgProtocolStore { + async fn next_pre_key_id(&self) -> Result { + let identity = self.identity.as_str(); + let max_id = sqlx::query_scalar!( + "SELECT MAX(id) FROM signal_pre_keys WHERE identity = $1", + identity, + ) + .fetch_one(&self.store.db) + .await + .into_protocol_error()?; + next_id_from_max(max_id) + } + + async fn next_signed_pre_key_id(&self) -> Result { + let identity = self.identity.as_str(); + let max_id = sqlx::query_scalar!( + "SELECT MAX(id) FROM signal_signed_pre_keys WHERE identity = $1", + identity, + ) + .fetch_one(&self.store.db) + .await + .into_protocol_error()?; + next_id_from_max(max_id) + } + + async fn next_pq_pre_key_id(&self) -> Result { + let identity = self.identity.as_str(); + let max_id = sqlx::query_scalar!( + "SELECT MAX(id) FROM signal_kyber_pre_keys WHERE identity = $1", + identity, + ) + .fetch_one(&self.store.db) + .await + .into_protocol_error()?; + next_id_from_max(max_id) + } + + async fn signed_pre_keys_count(&self) -> Result { + let identity = self.identity.as_str(); + let count = sqlx::query_scalar!( + "SELECT COUNT(*) AS \"count!\" FROM signal_signed_pre_keys WHERE identity = $1", + identity, + ) + .fetch_one(&self.store.db) + .await + .into_protocol_error()?; + Ok(usize::try_from(count).unwrap_or(usize::MAX)) + } + + async fn kyber_pre_keys_count(&self, last_resort: bool) -> Result { + let identity = self.identity.as_str(); + let count = sqlx::query_scalar!( + "SELECT COUNT(*) AS \"count!\" FROM signal_kyber_pre_keys + WHERE identity = $1 AND is_last_resort = $2", + identity, + last_resort, + ) + .fetch_one(&self.store.db) + .await + .into_protocol_error()?; + Ok(usize::try_from(count).unwrap_or(usize::MAX)) + } + + async fn signed_prekey_id(&self) -> Result, SignalProtocolError> { + let identity = self.identity.as_str(); + let max_id = sqlx::query_scalar!( + "SELECT MAX(id) FROM signal_signed_pre_keys WHERE identity = $1", + identity, + ) + .fetch_one(&self.store.db) + .await + .into_protocol_error()?; + max_id + .map(|id| i32_to_u32(id).map(SignedPreKeyId::from)) + .transpose() + } + + async fn last_resort_kyber_prekey_id( + &self, + ) -> Result, SignalProtocolError> { + let identity = self.identity.as_str(); + let max_id = sqlx::query_scalar!( + "SELECT MAX(id) FROM signal_kyber_pre_keys + WHERE identity = $1 AND is_last_resort = TRUE", + identity, + ) + .fetch_one(&self.store.db) + .await + .into_protocol_error()?; + max_id + .map(|id| i32_to_u32(id).map(KyberPreKeyId::from)) + .transpose() + } +} + +#[async_trait(?Send)] +impl SignedPreKeyStore for PgProtocolStore { + async fn get_signed_pre_key( + &self, + signed_prekey_id: SignedPreKeyId, + ) -> Result { + let id: i32 = u32_to_i32(u32::from(signed_prekey_id))?; + let identity = self.identity.as_str(); + let bytes = sqlx::query_scalar!( + "SELECT record FROM signal_signed_pre_keys WHERE id = $1 AND identity = $2", + id, + identity, + ) + .fetch_one(&self.store.db) + .await + .into_protocol_error()?; + SignedPreKeyRecord::deserialize(&bytes) + } + + async fn save_signed_pre_key( + &mut self, + signed_prekey_id: SignedPreKeyId, + record: &SignedPreKeyRecord, + ) -> Result<(), SignalProtocolError> { + let id: i32 = u32_to_i32(u32::from(signed_prekey_id))?; + let identity = self.identity.as_str(); + let bytes = record.serialize()?; + sqlx::query!( + "INSERT INTO signal_signed_pre_keys (id, identity, record) + VALUES ($1, $2, $3) + ON CONFLICT (id, identity) DO UPDATE SET record = $3", + id, + identity, + &bytes, + ) + .execute(&self.store.db) + .await + .into_protocol_error()?; + Ok(()) + } +} + +#[async_trait(?Send)] +impl KyberPreKeyStore for PgProtocolStore { + async fn get_kyber_pre_key( + &self, + kyber_prekey_id: KyberPreKeyId, + ) -> Result { + let id: i32 = u32_to_i32(u32::from(kyber_prekey_id))?; + let identity = self.identity.as_str(); + let bytes = sqlx::query_scalar!( + "SELECT record FROM signal_kyber_pre_keys WHERE id = $1 AND identity = $2", + id, + identity, + ) + .fetch_one(&self.store.db) + .await + .into_protocol_error()?; + KyberPreKeyRecord::deserialize(&bytes) + } + + async fn save_kyber_pre_key( + &mut self, + kyber_prekey_id: KyberPreKeyId, + record: &KyberPreKeyRecord, + ) -> Result<(), SignalProtocolError> { + let id: i32 = u32_to_i32(u32::from(kyber_prekey_id))?; + let identity = self.identity.as_str(); + let record = record.serialize()?; + sqlx::query!( + "INSERT INTO signal_kyber_pre_keys (id, identity, record, is_last_resort) + VALUES ($1, $2, $3, FALSE) + ON CONFLICT (id, identity) DO UPDATE SET record = $3, is_last_resort = FALSE", + id, + identity, + &record, + ) + .execute(&self.store.db) + .await + .into_protocol_error()?; + Ok(()) + } + + async fn mark_kyber_pre_key_used( + &mut self, + kyber_prekey_id: KyberPreKeyId, + ec_prekey_id: SignedPreKeyId, + base_key: &PublicKey, + ) -> Result<(), SignalProtocolError> { + let mut tx = self.store.db.begin().await.into_protocol_error()?; + let kyber_id: i32 = u32_to_i32(u32::from(kyber_prekey_id))?; + let identity = self.identity.as_str(); + + let is_last_resort = sqlx::query_scalar!( + "SELECT is_last_resort FROM signal_kyber_pre_keys WHERE id = $1 AND identity = $2", + kyber_id, + identity, + ) + .fetch_one(&mut *tx) + .await + .into_protocol_error()?; + + if is_last_resort { + let ec_id: i32 = u32_to_i32(u32::from(ec_prekey_id))?; + let base_key_bytes = base_key.serialize().to_vec(); + + let result = sqlx::query!( + "INSERT INTO signal_base_keys_seen + (kyber_pre_key_id, signed_pre_key_id, identity, base_key) + VALUES ($1, $2, $3, $4)", + kyber_id, + ec_id, + identity, + &base_key_bytes, + ) + .execute(&mut *tx) + .await; + + match result { + Err(sqlx::Error::Database(ref e)) if e.is_unique_violation() => { + return Err(SignalProtocolError::InvalidMessage( + CiphertextMessageType::PreKey, + "reused base key", + )); + } + other => { + other.into_protocol_error()?; + } + } + } else { + sqlx::query!( + "DELETE FROM signal_kyber_pre_keys + WHERE id = $1 AND identity = $2 AND is_last_resort = FALSE", + kyber_id, + identity, + ) + .execute(&mut *tx) + .await + .into_protocol_error()?; + } + + tx.commit().await.into_protocol_error()?; + Ok(()) + } +} + +#[async_trait(?Send)] +impl KyberPreKeyStoreExt for PgProtocolStore { + async fn store_last_resort_kyber_pre_key( + &mut self, + kyber_prekey_id: KyberPreKeyId, + record: &KyberPreKeyRecord, + ) -> Result<(), SignalProtocolError> { + let id: i32 = u32_to_i32(u32::from(kyber_prekey_id))?; + let identity = self.identity.as_str(); + let record = record.serialize()?; + sqlx::query!( + "INSERT INTO signal_kyber_pre_keys (id, identity, record, is_last_resort) + VALUES ($1, $2, $3, TRUE) + ON CONFLICT (id, identity) DO UPDATE SET is_last_resort = TRUE, record = $3", + id, + identity, + &record, + ) + .execute(&self.store.db) + .await + .into_protocol_error()?; + Ok(()) + } + + async fn load_last_resort_kyber_pre_keys( + &self, + ) -> Result, SignalProtocolError> { + let identity = self.identity.as_str(); + sqlx::query_scalar!( + "SELECT record FROM signal_kyber_pre_keys + WHERE identity = $1 AND is_last_resort = TRUE", + identity, + ) + .fetch_all(&self.store.db) + .await + .into_protocol_error()? + .into_iter() + .map(|record| KyberPreKeyRecord::deserialize(&record)) + .collect() + } + + async fn remove_kyber_pre_key( + &mut self, + kyber_prekey_id: KyberPreKeyId, + ) -> Result<(), SignalProtocolError> { + let id: i32 = u32_to_i32(u32::from(kyber_prekey_id))?; + let identity = self.identity.as_str(); + sqlx::query!( + "DELETE FROM signal_kyber_pre_keys WHERE id = $1 AND identity = $2", + id, + identity, + ) + .execute(&self.store.db) + .await + .into_protocol_error()?; + Ok(()) + } + + async fn mark_all_one_time_kyber_pre_keys_stale_if_necessary( + &mut self, + stale_time: chrono::DateTime, + ) -> Result<(), SignalProtocolError> { + let identity = self.identity.as_str(); + sqlx::query!( + "UPDATE signal_kyber_pre_keys + SET stale_at = $1 + WHERE identity = $2 AND is_last_resort = FALSE AND stale_at IS NULL", + stale_time, + identity, + ) + .execute(&self.store.db) + .await + .into_protocol_error()?; + Ok(()) + } + + async fn delete_all_stale_one_time_kyber_pre_keys( + &mut self, + threshold: chrono::DateTime, + min_count: usize, + ) -> Result<(), SignalProtocolError> { + let identity = self.identity.as_str(); + let min_count = i64::try_from(min_count).unwrap_or(i64::MAX); + sqlx::query!( + "WITH total AS ( + SELECT COUNT(*) AS cnt FROM signal_kyber_pre_keys + WHERE identity = $1 AND is_last_resort = FALSE + ) + DELETE FROM signal_kyber_pre_keys + WHERE identity = $1 AND is_last_resort = FALSE + AND stale_at IS NOT NULL AND stale_at < $2 + AND (SELECT cnt FROM total) > $3", + identity, + threshold, + min_count, + ) + .execute(&self.store.db) + .await + .into_protocol_error()?; + Ok(()) + } +} + +#[async_trait(?Send)] +impl IdentityKeyStore for PgProtocolStore { + async fn get_identity_key_pair(&self) -> Result { + let key = self.identity.identity_key_pair_key(); + let bytes = sqlx::query_scalar!("SELECT value FROM signal_kv WHERE key = $1", key,) + .fetch_one(&self.store.db) + .await + .into_protocol_error()?; + IdentityKeyPair::try_from(&*bytes) + } + + async fn get_local_registration_id(&self) -> Result { + let data = self + .store + .load_registration_data() + .await + .into_protocol_error()? + .ok_or_else(|| { + SignalProtocolError::InvalidState( + "failed to load registration ID", + "no registration data".into(), + ) + })?; + Ok(data.registration_id) + } + + async fn save_identity( + &mut self, + address: &ProtocolAddress, + identity_key: &IdentityKey, + ) -> Result { + let existing = self.get_identity(address).await?; + + let addr = address.name(); + let identity = self.identity.as_str(); + let bytes = identity_key.serialize().to_vec(); + + sqlx::query!( + "INSERT INTO signal_identities (address, identity, record) + VALUES ($1, $2, $3) + ON CONFLICT (address, identity) DO UPDATE SET record = $3", + addr, + identity, + &bytes, + ) + .execute(&self.store.db) + .await + .into_protocol_error()?; + + Ok(match existing { + Some(k) if k == *identity_key => IdentityChange::NewOrUnchanged, + Some(_) => IdentityChange::ReplacedExisting, + None => IdentityChange::NewOrUnchanged, + }) + } + + async fn is_trusted_identity( + &self, + address: &ProtocolAddress, + identity_key: &IdentityKey, + _direction: Direction, + ) -> Result { + match self.get_identity(address).await? { + Some(trusted_key) if identity_key == &trusted_key => Ok(true), + Some(_) => { + warn!(%address, "trusting changed identity"); + Ok(true) + } + None => { + warn!(%address, "trusting new identity"); + Ok(true) + } + } + } + + async fn get_identity( + &self, + address: &ProtocolAddress, + ) -> Result, SignalProtocolError> { + let addr = address.name(); + let identity = self.identity.as_str(); + sqlx::query_scalar!( + "SELECT record FROM signal_identities WHERE address = $1 AND identity = $2", + addr, + identity, + ) + .fetch_optional(&self.store.db) + .await + .into_protocol_error()? + .map(|bytes| IdentityKey::decode(&bytes)) + .transpose() + } +} + +#[async_trait(?Send)] +impl SenderKeyStore for PgProtocolStore { + async fn store_sender_key( + &mut self, + sender: &ProtocolAddress, + distribution_id: Uuid, + record: &SenderKeyRecord, + ) -> Result<(), SignalProtocolError> { + let device_id: i32 = u32_to_i32(u32::from(sender.device_id()))?; + let identity = self.identity.as_str(); + let addr = sender.name(); + let record = record.serialize()?; + sqlx::query!( + "INSERT INTO signal_sender_keys + (address, device_id, identity, distribution_id, record) + VALUES ($1, $2, $3, $4, $5) + ON CONFLICT (address, device_id, identity, distribution_id) DO UPDATE SET record = $5", + addr, + device_id, + identity, + distribution_id, + &record, + ) + .execute(&self.store.db) + .await + .into_protocol_error()?; + Ok(()) + } + + async fn load_sender_key( + &mut self, + sender: &ProtocolAddress, + distribution_id: Uuid, + ) -> Result, SignalProtocolError> { + let device_id: i32 = u32_to_i32(u32::from(sender.device_id()))?; + let identity = self.identity.as_str(); + let addr = sender.name(); + sqlx::query_scalar!( + "SELECT record FROM signal_sender_keys + WHERE address = $1 AND device_id = $2 AND identity = $3 AND distribution_id = $4", + addr, + device_id, + identity, + distribution_id, + ) + .fetch_optional(&self.store.db) + .await + .into_protocol_error()? + .map(|record| SenderKeyRecord::deserialize(&record)) + .transpose() + } +} + +type EmptyIter = std::iter::Empty>; + +impl ContentsStore for PgSignalStore { + type ContentsStoreError = PgStoreError; + type ContactsIter = EmptyIter; + type GroupsIter = EmptyIter<(GroupMasterKeyBytes, Group)>; + type MessagesIter = EmptyIter; + type StickerPacksIter = EmptyIter; + + async fn clear_profiles(&mut self) -> Result<(), PgStoreError> { + sqlx::query!("DELETE FROM signal_profile_keys") + .execute(&self.db) + .await?; + Ok(()) + } + + async fn clear_contents(&mut self) -> Result<(), PgStoreError> { + Ok(()) + } + + async fn clear_messages(&mut self) -> Result<(), PgStoreError> { + Ok(()) + } + + async fn clear_thread(&mut self, _thread: &Thread) -> Result<(), PgStoreError> { + Ok(()) + } + + async fn save_message(&self, _thread: &Thread, _message: Content) -> Result<(), PgStoreError> { + Ok(()) + } + + async fn delete_message( + &mut self, + _thread: &Thread, + _timestamp: u64, + ) -> Result { + Ok(false) + } + + async fn message( + &self, + _thread: &Thread, + _timestamp: u64, + ) -> Result, PgStoreError> { + Ok(None) + } + + async fn messages( + &self, + _thread: &Thread, + _range: impl RangeBounds, + ) -> Result { + Ok(std::iter::empty()) + } + + async fn clear_contacts(&mut self) -> Result<(), PgStoreError> { + Ok(()) + } + + async fn save_contact(&mut self, _contact: &Contact) -> Result<(), PgStoreError> { + Ok(()) + } + + async fn contacts(&self) -> Result { + Ok(std::iter::empty()) + } + + async fn contact_by_id(&self, _id: &ServiceId) -> Result, PgStoreError> { + Ok(None) + } + + async fn clear_groups(&mut self) -> Result<(), PgStoreError> { + Ok(()) + } + + async fn save_group( + &self, + _master_key: GroupMasterKeyBytes, + _group: impl Into, + ) -> Result<(), PgStoreError> { + Ok(()) + } + + async fn groups(&self) -> Result { + Ok(std::iter::empty()) + } + + async fn group(&self, _master_key: GroupMasterKeyBytes) -> Result, PgStoreError> { + Ok(None) + } + + async fn save_group_avatar( + &self, + _master_key: GroupMasterKeyBytes, + _avatar: &AvatarBytes, + ) -> Result<(), PgStoreError> { + Ok(()) + } + + async fn group_avatar( + &self, + _master_key: GroupMasterKeyBytes, + ) -> Result, PgStoreError> { + Ok(None) + } + + async fn upsert_profile_key( + &mut self, + uuid: &Uuid, + key: ProfileKey, + ) -> Result { + let key_bytes = key.bytes.to_vec(); + let inserted = sqlx::query_scalar!( + "INSERT INTO signal_profile_keys (uuid, key) VALUES ($1, $2) + ON CONFLICT (uuid) DO UPDATE SET key = $2 + RETURNING (xmax = 0) AS \"inserted!\"", + uuid, + &key_bytes, + ) + .fetch_one(&self.db) + .await?; + Ok(inserted) + } + + async fn profile_key( + &self, + service_id: &ServiceId, + ) -> Result, PgStoreError> { + let uuid: Uuid = service_id.raw_uuid(); + let row = sqlx::query!("SELECT key FROM signal_profile_keys WHERE uuid = $1", uuid,) + .fetch_optional(&self.db) + .await?; + + Ok(match row { + Some(r) => match <[u8; 32]>::try_from(r.key.as_slice()) { + Ok(arr) => Some(ProfileKey { bytes: arr }), + Err(_) => { + warn!(%uuid, len = r.key.len(), "corrupted profile key (expected 32 bytes)"); + None + } + }, + None => None, + }) + } + + async fn save_profile( + &mut self, + _uuid: Uuid, + _key: ProfileKey, + _profile: Profile, + ) -> Result<(), PgStoreError> { + Ok(()) + } + + async fn profile( + &self, + _uuid: Uuid, + _key: ProfileKey, + ) -> Result, PgStoreError> { + Ok(None) + } + + async fn save_profile_avatar( + &mut self, + _uuid: Uuid, + _key: ProfileKey, + _profile: &AvatarBytes, + ) -> Result<(), PgStoreError> { + Ok(()) + } + + async fn profile_avatar( + &self, + _uuid: Uuid, + _key: ProfileKey, + ) -> Result, PgStoreError> { + Ok(None) + } + + async fn add_sticker_pack(&mut self, _pack: &StickerPack) -> Result<(), PgStoreError> { + Ok(()) + } + + async fn sticker_pack(&self, _id: &[u8]) -> Result, PgStoreError> { + Ok(None) + } + + async fn remove_sticker_pack(&mut self, _id: &[u8]) -> Result { + Ok(false) + } + + async fn sticker_packs(&self) -> Result { + Ok(std::iter::empty()) + } +} diff --git a/migrations/20260321_signal_protocol_tables.sql b/migrations/20260321_signal_protocol_tables.sql new file mode 100644 index 0000000..c31d659 --- /dev/null +++ b/migrations/20260321_signal_protocol_tables.sql @@ -0,0 +1,64 @@ +CREATE TABLE signal_kv ( + key TEXT PRIMARY KEY, + value BYTEA NOT NULL +); + +CREATE TABLE signal_sessions ( + address TEXT NOT NULL, + device_id INTEGER NOT NULL CHECK (device_id BETWEEN 0 AND 127), + identity TEXT NOT NULL CHECK (identity IN ('aci', 'pni')), + record BYTEA NOT NULL, + PRIMARY KEY (address, device_id, identity) +); + +CREATE TABLE signal_identities ( + address TEXT NOT NULL, + identity TEXT NOT NULL CHECK (identity IN ('aci', 'pni')), + record BYTEA NOT NULL, + PRIMARY KEY (address, identity) +); + +CREATE TABLE signal_pre_keys ( + id INTEGER NOT NULL CHECK (id >= 0), + identity TEXT NOT NULL CHECK (identity IN ('aci', 'pni')), + record BYTEA NOT NULL, + PRIMARY KEY (id, identity) +); + +CREATE TABLE signal_signed_pre_keys ( + id INTEGER NOT NULL CHECK (id >= 0), + identity TEXT NOT NULL CHECK (identity IN ('aci', 'pni')), + record BYTEA NOT NULL, + PRIMARY KEY (id, identity) +); + +CREATE TABLE signal_kyber_pre_keys ( + id INTEGER NOT NULL CHECK (id >= 0), + identity TEXT NOT NULL CHECK (identity IN ('aci', 'pni')), + record BYTEA NOT NULL, + is_last_resort BOOLEAN NOT NULL DEFAULT FALSE, + stale_at TIMESTAMPTZ, + PRIMARY KEY (id, identity) +); + +CREATE TABLE signal_sender_keys ( + address TEXT NOT NULL, + device_id INTEGER NOT NULL CHECK (device_id BETWEEN 0 AND 127), + identity TEXT NOT NULL CHECK (identity IN ('aci', 'pni')), + distribution_id UUID NOT NULL, + record BYTEA NOT NULL, + PRIMARY KEY (address, device_id, identity, distribution_id) +); + +CREATE TABLE signal_base_keys_seen ( + kyber_pre_key_id INTEGER NOT NULL CHECK (kyber_pre_key_id >= 0), + signed_pre_key_id INTEGER NOT NULL CHECK (signed_pre_key_id >= 0), + identity TEXT NOT NULL CHECK (identity IN ('aci', 'pni')), + base_key BYTEA NOT NULL, + PRIMARY KEY (identity, kyber_pre_key_id, signed_pre_key_id, base_key) +); + +CREATE TABLE signal_profile_keys ( + uuid UUID PRIMARY KEY, + key BYTEA NOT NULL +);