From ad26ee9b1bfa56ba4dee44cf91a58c9a6d51dfa4 Mon Sep 17 00:00:00 2001 From: Arvid Lunnemark Date: Thu, 30 Jun 2022 16:46:04 -0700 Subject: [PATCH] Friends (#107) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🔄 "Real world testing (#35) * fix install script * fix even more install things" Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/0126583ca8d00b53859f3a826d4e86bec495eb74 * 🔄 "add story to public id response " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/6dbadec9e3796489496ea6406cfd07cd012bb9ba * 🔄 "Public identifier (#38) * implement base58 * implement identifier * 🔄 "implement identifier " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/15117f27873a17019c0a71273d41397c93887e19" Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/67a91f0799c820c893f1ad4c6e555d8f4dbcfa20 * 🔄 "Public identifier (#18) * add identifier.proto * implement base58 * implement identifier" Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/f8a52a086f2f56f25192e668251ebb6edcaa5645 * 🔄 "Merge branch 'main' into friends " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/7944dd5364cf8644425b43d130f249caf20a3ed8 * 🔄 "Merge branch 'main' into friends " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/b4b457df06b76da857081570d2fd34af104eb40e * 🔄 " Implement friend acking (#21) * update message.proto with control message * handle control message properly * check for ack of control message" Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/5cdc265e51a4bc6987bac893c672ae93a12159e2 * 🔄 " Implement friend acking (#41) * update message.proto with control message * 🔄 "update message.proto with control message " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/e92e27bc6038b48d0ae07662d5517fcb9a64e303 * handle control message properly * 🔄 "handle control message properly " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/420185b2dcfd004044e309c11e917d9e052890b0 * check for ack of control message * 🔄 "check for ack of control message " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/fd692ae8914992f6c7267e038a771bfed337dd70 * normal message shall not be control message * make compile (almost)" Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/b607bfca1cb164ddc66e6d2f84f81d8b573668b7 * Async friending schema (#108) * rename kx_key * 🔄 "rename kx_key " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/aec1b8bfa2ddff56e40880df74e51daa4d40f131 * rewrite crypto in the new protocol * 🔄 "rewrite crypto in the new protocol " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/fdcafcd688e37cb8ce9eeb043cdbc79f01ac99c9 * 🔄 "rewrite crypto in the new protocol " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/49b488b75599a23fcad6856fa83695e59bd882b5 * DB change complete * 🔄 "DB change complete " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/1b6e9bf260fe74a48b75698ef9e2968f9837476e * 🔄 "redesign daemon schema " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/96073e4732af90201cbbbb29abea6f967523329c * 🔄 "fix typo " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/1b0185f545705ccbe35ab03cb60b99b0a4bc52c6 * 🔄 "add story to sync friend request " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/0485f68cf936901bbfc0a5326dc8dedfc87501e2 * configure server for async requests * 🔄 "configure server for async requests " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/5b360b9d52fbd98ab43ef022480e61289f986b2a * 🔄 "configure server for async requests " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/a0458e2d17ebc0e940a1f42e6448335cefabcdea * 🔄 "add public_id to database " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/da589ea1c5e9792f86656c61ca3a17265d344e1f * 🔄 "check point. Most of the code compiles " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/e5d3588c736c9e854714d4231ced0743886313f2 * 🔄 "checkpoint. All programs build " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/757fe13f5fc1c1b802e361332d58412698bb84b6 * checkpoint: rewriting test files * 🔄 "checkpoint: rewriting test files " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/b60891f2b6998c29a3e9eeb89d54c8ca58e4b64e * 🔄 "merge arvid's friend branch " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/75dbc77d97df5758eae3227d711139e4fbeb965e * 🔄 "Merge remote-tracking branch 'origin/friends' into async_friending_schema " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/b56fda2adfb971289586e2dcd25911810f383fc9 * 🔄 "checkpoint in merging friend " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/1f391d596fc943208bfc48775684cbacd6916aa9 * checkpoint in merging friend * weird bug. debugging * 🔄 "weird bug. debugging " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/7da1032a73ac4c3c983897bc90f671691a312e7f * mystery bug resolve. Do not call set_allocated() * 🔄 "mystery bug resolve. Do not call set_allocated() " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/8b247bdb10f66c4a13cf786163d019fb8e285e66 * 🔄 "checkpoint: another bug " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/2ec90a82947194b18aa34c8af4ff8f5122f84562 * update workspace * 🔄 "add linkstatic " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/38ce866ce79d08d01bd6c9dc9df64eeca0fb00d2 * finally builds correctly * 🔄 "finally builds correctly " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/46ce1bd6ff8b87ff69a52b588a0ed628b0cfe187 * checkpoint: use standard logging * 🔄 "checkpoint: use standard logging " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/a90e0b0d7a5f77a1b02c4b1f5cc733819dad24aa * add friend workinggit ca add * 🔄 "add friend workinggit ca add " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/c64027ef7cdcbf84ca489ed080b0a06982af3305 * 🔄 "Merge branch 'friends' into async_friending_schema" Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/5b23eb9784b95d1397a514dadccb88548fe88535 * 🔄 "Merge remote-tracking branch 'origin/friends' into async_friending_schema " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/45a1a1957a57880eb9d6953ed2f672ff27755436 * merging friends and async_friend_request * 🔄 "add outgoing_friend_request " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/e37a115f68c13dab9b88339c173a8a9a4a17d36a * fix fast test * 🔄 "remove comment from crypto' " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/737c86c35561b5c4b11b798bf829f97f59a8952e * 🔄 "fix bug in crypto " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/65e51dd2a2eeb650896db44a88d6f22939f695aa * fix bug * 🔄 "fix bug " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/294d04b7d6032843e74f37fb34e4df88017c7a7f * 🔄 "fix daemonrpc bug " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/91772523e8975bbe2357610cf132c397b6b75968 * 🔄 "add identifier " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/2a32e5c905ff854a73b87b36543854b49646bce7 * 🔄 "Merge remote-tracking branch 'origin/async_friending_schema' into async_friending_schema " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/3700ab7e01e0dca28e415f332348d5361a5cc21f Co-authored-by: Shengtong Zhang * 🔄 "Async friending schema (#36) * rename kx_key * rewrite crypto in the new protocol * 🔄 "rewrite crypto in the new protocol " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/49b488b75599a23fcad6856fa83695e59bd882b5 * DB change complete * 🔄 "redesign daemon schema " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/96073e4732af90201cbbbb29abea6f967523329c * 🔄 "fix typo " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/1b0185f545705ccbe35ab03cb60b99b0a4bc52c6 * 🔄 "add story to sync friend request " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/0485f68cf936901bbfc0a5326dc8dedfc87501e2 * configure server for async requests * 🔄 "configure server for async requests " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/a0458e2d17ebc0e940a1f42e6448335cefabcdea * add public_id to database * check point. Most of the code compiles * checkpoint. All programs build * checkpoint: rewriting test files * 🔄 "checkpoint: rewriting test files " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/b60891f2b6998c29a3e9eeb89d54c8ca58e4b64e * 🔄 "Merge remote-tracking branch 'origin/friends' into async_friending_schema " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/b56fda2adfb971289586e2dcd25911810f383fc9 * checkpoint in merging friend * weird bug. debugging * mystery bug resolve. Do not call set_allocated() * checkpoint: another bug * update workspace * add linkstatic * finally builds correctly * checkpoint: use standard logging * add friend workinggit ca add * 🔄 "add friend workinggit ca add " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/c64027ef7cdcbf84ca489ed080b0a06982af3305 * 🔄 "Merge remote-tracking branch 'origin/friends' into async_friending_schema " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/45a1a1957a57880eb9d6953ed2f672ff27755436 * add outgoing_friend_request * remove comment from crypto' * fix bug in crypto * fix bug * fix daemonrpc bug * add identifier * correct mistake in key exchange Co-authored-by: Shengtong Zhang " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/4f97e125967591249ecd475f1535198473d1af24 * 🔄 "Async friending schema (#22) * configure server for async requests * checkpoint: rewriting test files * add friend workinggit ca add Co-authored-by: Shengtong Zhang " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/a0a42dccb3ae8142bd3315490ce24150aa1898b7 * 🔄 "remove rust warning " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/0ebd6d32b59808748c17abdbba2a7607c1253ec9 * fix tests * change api * 🔄 "change api " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/293509df2556d9fb1352d6134d35a186d7d89e48 * update protos * 🔄 "update protos " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/b518cc0b6134b5949fc820656a9fbd498cf08b40 * add sync test * 🔄 "add sync test " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/b3c8ddbee9c9b93f9bbe1036d652ccbcd9aec71e * 🔄 "add sync test " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/6f74e5240a7e2456008db8c1eb4a611bbff71db9 * 🔄 "push without compile " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/e0bbbc1f448d3701094bba40b53fce7ab3238b25 * make compile * 🔄 "make compile " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/3469f6b8934c74aca99c5ce013c1a556fc4fb7f9 * 🔄 "some things only if registered " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/b887016e7674440f90b765cfb62bd0afbc8ecef3 * use enums instead of integer constants * 🔄 "use enums instead of integer constants " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/b54435f1fee07f21566983081722168492b4afbc * 🔄 "it builds! " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/d7e9c338cd1509919ffbfa216a5908fdc028fd70 * everything builds * 🔄 "daemon.protoo changes " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/6e6f0b9fa8dd5ddd24dc31cdf940159f11a96372 * 🔄 "daemon.protoo changes " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/785fc95512b692444972318b79dbcb81daaf613d * update daemon-js protos * 🔄 "update daemon-js protos " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/be4c41f8fc897a6a06b084f9a5dbae78ab0127b0 * daemon.proto has been fully sualeh-ified * 🔄 "daemon.proto has been fully sualeh-ified " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/ef1e0143a9fa49702c76ee31263547b6b76bfb26 * add vsls * async partitions and a basic test passes * 🔄 "async partitions and a basic test passes " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/ced8449488ee402c6b26a23d2b521add6b004dfc * 🔄 "async partitions and a basic test passes " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/e32c1b6c4de58ea3c6e650e99fd155d7372d3e64 * some questions about how to handle name of requests * 🔄 "update proto. time for disaster to happen. Gooddddd luck " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/778e942b9f22288e96e2d5bcf9b6b56ecbf439de * 🔄 "update protos. We are good. " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/33e39f7c51c6e99b7ca0eefa9908e436baafe8fd * 🔄 "update protos. We are good. " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/e0d9a9d89175187d08acccc033f4c53d601dad42 * update protos for Invitation Progres * 🔄 "update protos for Invitation Progres " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/32a45d0dd104c1115efdbdc98d0e44ebfd7f3205 * fix tests * 🔄 "fix tests " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/8120b2566ece8a0268d3dcd983962e7d559af83b * replace friend_request -> invitation on server * 🔄 "replace friend_request -> invitation on server " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/7cf56b781c72c6d3c5570031460db4209353cbab * added test for people being in different blocks * 🔄 "added test for people being in different blocks " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/dd95b76d5f392bab80252f0502487001cfa34279 * commit tests * 🔄 "Friends implementation (#42) * merge friends * 🔄 "change to system message " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/4415feb0985123d7031924f7298f9b78b3db058f * make transmitter use the new db types * finish transmitter changes * it builds * 🔄 "it builds " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/209b037166f2d9bc4de62daf80a00ea1f0cde0fd * it builds! * it builds! * outgoing async and sync now done * it builds! * it builds! * it builds! * it builds! * it builds! * it builds! * it builds! * fix warnings * add check_rep * some changes with errors * make build * initial tests passing!!! * 🔄 "initial tests passing!!! " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/cd37145a6c83c0f7d32120fb8d00950d66145c84" Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/3abbdb696665fa5257b417af843182d417f9fe26 * 🔄 "Friends implementation (#23) * change to system message * it builds * initial tests passing!!!" Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/f5f22e7913a3d27d1fdb40166725e5e018b15119 * 🔄 "fix bug! " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/6a547de0ad2c566a49be658795faf489a23d0fa7 * 🔄 "add more check_rep consistency constraints " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/ab0bdf27b600e5d1162262b0a2a9b619a547cbbb * 🔄 "more checkrep! " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/b72388b9735fcb33a8878c93b7b7db01af802a16 * revamp crypto * 🔄 "revamp crypto " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/7a2356d27f43ed3031ca1eb6d3fb44d305dfc9db * 🔄 "revamp crypto " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/a156ca92d10e65b93a1123fb80026788ce987e10 * 🔄 "add even more check_rep " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/999a256d907874c4bd78d5fb7e5681344b7751bc * 🔄 "more checkrep!!! i love checkrep " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/f7bf199a1b8ac1863ea1cee90d8ee9e09bbc82d9 * 🔄 "Merge remote-tracking branch 'origin/friends' into friends " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/86d93a9a4c268236e1abd2f21a8b3961e061ae1c * 🔄 "many more check rep " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/cd61b82dd3202cb4394a283333a97ee1ae673fab * 🔄 "add check_rep comment " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/06a7825f86e164a011eff237cec5ad88e8cbbdbe * 🔄 "update comment " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/f91ae43a21f90ac5bd7675773f7c1868a56e5a1b * 🔄 "even more checkreppp " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/bb9c86ec748ab3bc62517a516b10c9d8eea1d06c * 🔄 "even more checkrep " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/826873c8af58408d1c449e9df02546ba20339c6c * add a few anyhow errors * 🔄 "Merge remote-tracking branch 'origin/friends' into friends " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/dcd6d85942f98918f7a0ca1fee72040a1543a814 * test passes * 🔄 "test passes " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/fcb30e49b4cffacc6263c4017f41cb73bc6fdb25 * empty file deletion * all test passes * 🔄 "all test passes " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/d220c14e6afa67323d30aefccbea927f7690cf64 * fix htps * use fail * 🔄 "use fail " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/2a144b8d651034b0784107367ff6c2ce4c598f40 * fix buiaald * fmt all * 🔄 "fmt all " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/1b03578498d3deeed0f7f6e8301cde27532c5def * assert invitation message * replace control->invitation message * factor out the async invitation db into its own file * cap invitation length at 4KB * enforce arguments are reasonable * tests enforce good arguments! * use c++17 std::map syntax * 🔄 "add license notice " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/fbc5062c0307d5467694e5485181db19261f4d06 * remove todos * remove todos * 🔄 "linting fix " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/9c2cf9bcdce6317f087802d7644082ff67798a3e * fix fmt * 🔄 "add license notices " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/bdccc65754593687caa8dd702c494e688ba68563 * 🔄 "add license notices " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/d3c5e3089d03a991a882c513ca4f89894f17bd88 * 🔄 "more format fixes " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/b7bbdbf168d5c87d8fdc0da5fe583b0fa50cefe6 * 🔄 "more format fixes " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/4e46b688b97df5fcdc2227f08bc74e9cd6332f85 * 🔄 "add asyncinvitation proto and additional check " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/64137a25ef38dfe1b286053da4cc0cd2b61a4e08 * updates * 🔄 "updates " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/df1618c9ded084296859b894cd1188b730968db2 * it compiles * 🔄 "it compiles " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/1907b2b52fb056fae395b87eba203177fe774254 * 🔄 "it compiles " Update anysphere/asphr commit SHA 🔗 https://github.com/anysphere/asphr/commit/c7fcff2549426bb3bd4198faabd9e15592f1ec3b * 🔄 "update comments " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/ae817fba72fb603337369b0df003f0aa009d6e28 * fixes from clang-tidy * 🔄 "comment on tests " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/e13fc2a56c0d1a71e77082f54463e147de29ec1c * remove some nouns * 🔄 "remove some nouns " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/a25df0f2d9e1031de34d6e03a8e62e5b6966921d * remove TODO checks from google * 🔄 "remove TODO checks from google " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/9b011291a5460e601c6359d396b612e811b07571 * 🔄 "use asphr assert " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/e89d54ca97f28bba20081ac825db6f9efd4e91d6 * 🔄 "document base58 with static_assert " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/141e279fc9d7af915396695deb651b756f4c067c * 🔄 "bitcoin base58 test works " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/f09c43c86dba0cc5f245d4dd01216aad14712d9c * 🔄 "comments on major functions, part1 " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/c4b54e6fc20b6e8f97c1418ceaceed0b8aa4bd68 * 🔄 "manual test rename " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/6aae3b9e0154d33045ca9644746cf83fd67c4142 * 🔄 "comments on major functions, part 2 " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/468ce8a82e4065943471aea8b67660472855f1e7 * 🔄 "clean up comment " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/355c910179aeff093127610fbb4a8beed525c75a * 🔄 "don't assert false because another user did the wrong thing " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/189ad75b226ed3caa5cc05ca010abddd1f25e816 * 🔄 "update until chunk handling. Comments Part 3 " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/a182ff79421776fa23236dbf98c7d90c8e04d8f7 * 🔄 "add comment " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/3e618ab23e74029b62f40a9c385775aa5b08a45b * 🔄 "update chunk_to_send docs. Comments part 4 " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/0b3b604b57373b8837ab80cab770ba509801dd38 * 🔄 "update transmitter to remove unused variable " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/9d763ff1bcda71116f7cf06a9f9fbb7c55429aa9 * 🔄 "update some helper docs. " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/4ebe93aa9a590e0ed8d42b2da017e8b6eb41b266 * 🔄 "fix receive_ack " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/3b8fb302f91f6cde7a48536093ace71fb9574778 * 🔄 "dont assert false if bad input " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/620a4654d001172371e8d149dfa2f5f7605a3ad8 * 🔄 "update until invitations. Comments Part 6 " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/f15468f0bb1366a8817dddb1d04bca39ebc81d84 * 🔄 "remove todo " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/ad0309ea31e7fea71569e7d497e5793ab6d3ae31 * 🔄 "fix merge conflict " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/fe5fd40a2cc32a68925ad4766ac8e84e0571ff67 * 🔄 "small reg not big reg " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/1fde7033189d792e8235a43ba9fcc8ce16251ca4 * 🔄 "add comment " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/62d257fa950436a9a76c0cb4b85f8ea75af3df26 * 🔄 "remove backticks " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/95979021ef6929fd9dd0788c01112975c599cab3 * 🔄 "fix lex " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/649faddbc26633510386b962d6e6ad9d045e7b29 * 🔄 "make db.rs compile " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/ff287d85e0a1a2eea672a194dbf33f0cb696dff4 * 🔄 "move comment to docstring " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/a90125e4a47f99f02371f132f35fa28aadb3809d * 🔄 "update comments " Update anysphere/client commit SHA 🔗 https://github.com/anysphere/client/commit/5f0aa35c25b9b8d17dbd06f2e2e755da53db9a27 Co-authored-by: Shengtong Zhang Co-authored-by: Sualeh Asif Co-authored-by: Sualeh Asif --- .bazelrc | 20 +- .trunk/.gitignore | 1 + .trunk/trunk.yaml | 4 +- .vscode/.gitignore | 1 + .vscode/c_cpp_properties.json | 5 +- .vscode/settings.json | 24 +- .vsls.json | 4 + WORKSPACE | 4 +- integration_tests/BUILD | 4 +- integration_tests/README.md | 19 + integration_tests/daemon_setup.hpp | 249 +++++++--- .../daemon_tests/daemon_add_friend_test.cc | 177 +++++--- .../daemon_tests/daemon_config_test.cc | 2 +- .../daemon_tests/daemon_fast_test.cc | 36 +- .../daemon_tests/daemon_friends_test.cc | 11 +- .../daemon_tests/daemon_long_messages_test.cc | 8 +- .../daemon_multiple_messages_test.cc | 4 +- .../daemon_tests/daemon_persistence_test.cc | 10 +- .../daemon_tests/daemon_seen_test.cc | 10 +- .../daemon_tests/daemon_send_messages_test.cc | 11 +- .../invitation_tests/async_request_test.cc | 427 ++++++++++++++++++ .../long_messages_test.cc | 6 +- .../multiple_messages_test.cc | 4 +- .../three_messages_test.cc | 4 +- research/strategy/main.pdf | Bin 391463 -> 391463 bytes research/whitepaper | 2 +- server/src/BUILD | 15 +- server/src/async_invitation_database.cc | 47 ++ server/src/async_invitation_database.hpp | 27 ++ server/src/server_constants.hpp | 13 + server/src/server_rpc.cc | 93 +++- server/src/server_rpc.hpp | 30 +- server/src/server_rpc_test.cc | 115 ++++- 33 files changed, 1177 insertions(+), 210 deletions(-) create mode 100644 .vscode/.gitignore create mode 100644 .vsls.json create mode 100644 integration_tests/README.md create mode 100644 integration_tests/invitation_tests/async_request_test.cc create mode 100644 server/src/async_invitation_database.cc create mode 100644 server/src/async_invitation_database.hpp create mode 100644 server/src/server_constants.hpp diff --git a/.bazelrc b/.bazelrc index befea9b8..b903116c 100644 --- a/.bazelrc +++ b/.bazelrc @@ -29,11 +29,11 @@ build --repo_env=RULES_RUST_TOOLCHAIN_INCLUDE_RUSTC_SRCS=true try-import %workspace%/.user.bazelrc # setting up remote caching -#build --bes_results_url=https://app.buildbuddy.io/invocation/ -#build --bes_backend=grpcs://remote.buildbuddy.io -#build --remote_cache=grpcs://remote.buildbuddy.io -#build --remote_upload_local_results -#build --remote_timeout=3600 +# build --bes_results_url=https://app.buildbuddy.io/invocation/ +# build --bes_backend=grpcs://remote.buildbuddy.io +# build --remote_cache=grpcs://remote.buildbuddy.io +# build --remote_upload_local_results +# build --remote_timeout=3600 # build --experimental_remote_cache_compression # build --experimental_remote_cache_async # build --remote_download_toplevel @@ -68,7 +68,7 @@ build:asan --strip=never build:asan --copt -fsanitize=address build:asan --copt -DADDRESS_SANITIZER build:asan --copt -g -build:asan --copt -O3 +build:asan --copt -O1 build:asan --copt -fno-omit-frame-pointer # we ignore ODR violations because we have two versions of zlib, one from protobuf and one from seal. not good. but issok. build:asan --action_env=ASAN_OPTIONS=detect_odr_violation=0 @@ -80,7 +80,7 @@ build:msan --strip=never build:msan --copt -fsanitize=memory build:msan --copt -DMEMORY_SANITIZER build:msan --copt -g -build:msan --copt -O3 +build:msan --copt -O1 build:msan --copt -fno-omit-frame-pointer build:msan --linkopt -fsanitize=memory @@ -90,10 +90,10 @@ build:ubsan --strip=never build:ubsan --copt -fsanitize=undefined build:ubsan --copt -DUNDEFINED_BEHAVIOR_SANITIZER build:ubsan --copt -g -build:ubsan --copt -O3 +build:ubsan --copt -O1 build:ubsan --copt -fno-omit-frame-pointer build:ubsan --linkopt -fsanitize=undefined -build:ubsan --linkopt -lubsan +# build:ubsan --linkopt -lubsan # All sanitizers! # CC=clang bazel build --config san @@ -101,7 +101,7 @@ build:san --strip=never build:san --copt -fsanitize=address,undefined build:san --copt -DADDRESS_SANITIZER build:san --copt -g -build:san --copt -O3 +build:san --copt -O1 build:san --copt -fno-omit-frame-pointer # we ignore ODR violations because we have two versions of zlib, one from protobuf and one from seal. not good. but issok. build:san --action_env=ASAN_OPTIONS=detect_odr_violation=0 diff --git a/.trunk/.gitignore b/.trunk/.gitignore index 7feb17f2..2caa0951 100644 --- a/.trunk/.gitignore +++ b/.trunk/.gitignore @@ -1 +1,2 @@ *out +logs diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 3de7af69..8171bf30 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -1,6 +1,6 @@ version: 0.1 cli: - version: 0.13.1-beta + version: 0.14.1-beta lint: enabled: - gitleaks@8.8.7 @@ -23,4 +23,4 @@ repo: host: github.com owner: anysphere name: anysphere - trunk_branch: origin/main \ No newline at end of file + trunk_branch: origin/main diff --git a/.vscode/.gitignore b/.vscode/.gitignore new file mode 100644 index 00000000..bf0824e5 --- /dev/null +++ b/.vscode/.gitignore @@ -0,0 +1 @@ +*.log \ No newline at end of file diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index b03b88e6..4241a66d 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -8,11 +8,11 @@ "${workspaceFolder}/bazel-out/**/**", "${workspaceFolder}/bazel-bin/external/**/**", "${workspaceFolder}/bazel-bin/external/asphr/third_party/**/**", + "/opt/homebrew/opt/libpqxx/include", "${workspaceFolder}/bazel-out/darwin_arm64-fastbuild/bin/external/asphr/third_party/seal/copy_seal/seal/include", "${workspaceFolder}/bazel-out/darwin_arm64-fastbuild/bin/external/**/**/**/**", "${workspaceFolder}/client/bazel-out/darwin_arm64-fastbuild/bin/daemon/**/**/**/**", - "/home/gitpod/.cache/bazel/_bazel_gitpod/**", - "/private/var/tmp/_bazel_sualeh/39d7406b82f7235a3fefe5e0e301d280/execroot/__main__/bazel-out/darwin_arm64-fastbuild-ST-368686e6f71f/bin/external/asphr/third_party/libsodium/copy_libsodium_/libsodium_/include" + "/home/gitpod/.cache/bazel/_bazel_gitpod/**" ], "defines": [], "macFrameworkPath": [], @@ -21,7 +21,6 @@ "cppStandard": "c++20", "intelliSenseMode": "${default}", "compilerArgs": [] - // "compileCommands": "${workspaceFolder}/compile_commands.json" } ], "version": 4 diff --git a/.vscode/settings.json b/.vscode/settings.json index 1cf96a35..b90b5d2e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -143,5 +143,27 @@ "bazel-anysphere/**": true }, "rust-analyzer.linkedProjects": ["client/rust-project.json"], - "trunk.inlineDecorators": false + "trunk.inlineDecorators": false, + "editor.tokenColorCustomizations": { + "textMateRules": [ + { + "scope": "googletest.failed", + "settings": { + "foreground": "#f00" + } + }, + { + "scope": "googletest.passed", + "settings": { + "foreground": "#0f0" + } + }, + { + "scope": "googletest.run", + "settings": { + "foreground": "#0f0" + } + } + ] + } } diff --git a/.vsls.json b/.vsls.json new file mode 100644 index 00000000..e471dda0 --- /dev/null +++ b/.vsls.json @@ -0,0 +1,4 @@ +{ + "$schema": "http://json.schemastore.org/vsls", + "gitignore": "none" +} diff --git a/WORKSPACE b/WORKSPACE index b43798aa..72dd9e97 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -7,7 +7,7 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") git_repository( name = "asphr", - commit = "bb5afae8fd4c78b8de4139141fcd1747965f5a31", # autoupdate anysphere/asphr + commit = "c7fcff2549426bb3bd4198faabd9e15592f1ec3b", # autoupdate anysphere/asphr init_submodules = True, remote = "https://github.com/anysphere/asphr.git", ) @@ -39,7 +39,7 @@ setup_asphr("@asphr") git_repository( name = "client", - commit = "66467710d906d9ae2d3ce2df08ab91574f5d0069", # autoupdate anysphere/client + commit = "5f0aa35c25b9b8d17dbd06f2e2e755da53db9a27", # autoupdate anysphere/client init_submodules = True, remote = "https://github.com/anysphere/client.git", ) diff --git a/integration_tests/BUILD b/integration_tests/BUILD index 935fb418..5a7b783c 100644 --- a/integration_tests/BUILD +++ b/integration_tests/BUILD @@ -7,7 +7,7 @@ cc_library( "daemon_setup.hpp", "test_helpers.hpp", ], - linkstatic=True, + linkstatic = True, deps = [ "//server/pir/fast_pir:server_fast_pir_lib", "//server/src:as_server_lib", @@ -19,3 +19,5 @@ cc_library( all_tests_in_folder(folder = "daemon_tests") all_tests_in_folder(folder = "multiple_friends_tests") + +all_tests_in_folder(folder = "invitation_tests") diff --git a/integration_tests/README.md b/integration_tests/README.md new file mode 100644 index 00000000..d07c5cde --- /dev/null +++ b/integration_tests/README.md @@ -0,0 +1,19 @@ +# How to check which tests are in the folder + +``` +bazel query 'tests(//integration_tests/...)' +``` + +# How to run individual tests + +From the root of the project: + +``` +bazelisk test //integration_tests:{folder_name}/{test_name} +``` + +From the integration test folder + +``` +bazelisk test :{folder_name}/{test_name} +``` diff --git a/integration_tests/daemon_setup.hpp b/integration_tests/daemon_setup.hpp index 64981a92..ba530c77 100644 --- a/integration_tests/daemon_setup.hpp +++ b/integration_tests/daemon_setup.hpp @@ -12,15 +12,9 @@ #include "server/src/server_rpc.hpp" #include "test_helpers.hpp" -/** - * TODO: have a multiple rounds test. - * - * - * - **/ - struct FriendTestingInfo { string unique_name; + string display_name; unique_ptr G; unique_ptr rpc; unique_ptr t; @@ -37,6 +31,12 @@ class DaemonRpcTest : public ::testing::Test { protected: DaemonRpcTest() : service_(gen_server_rpc()) {} + //---------------------------------------------------------------------------- + //---------------------------------------------------------------------------- + //|| Registration Helpers || + //---------------------------------------------------------------------------- + //---------------------------------------------------------------------------- + auto generateTempFile() -> string { auto config_file_address = string("TMPTMPTMP_config"); for (auto i = 0; i < 50; i++) { @@ -100,13 +100,136 @@ class DaemonRpcTest : public ::testing::Test { return generate_friends_from_list_of_pairs(db_files, pairs); } - auto generate_friends_from_list_of_pairs(vector db_files, - vector> pairs) - -> vector { + auto connect_friends_both_async(const FriendTestingInfo& friend1, + const FriendTestingInfo& friend2) { + // we use the one-sided async invitation procedure to connect the friends + string friend1_id; + string friend2_id; + int friend1_allocation; + { + // get user 1's id via rpc call + GetMyPublicIDRequest request; + GetMyPublicIDResponse response; + friend1.rpc->GetMyPublicID(nullptr, &request, &response); + friend1_id = response.public_id(); + } + { + // get user 1's registration information + auto friend1_registration = friend1.G->db->get_registration(); + friend1_allocation = friend1_registration.allocation; + } + { + // get user 2's id via rpc call + GetMyPublicIDRequest request; + GetMyPublicIDResponse response; + friend2.rpc->GetMyPublicID(nullptr, &request, &response); + friend2_id = response.public_id(); + } + + ASPHR_LOG_INFO("Registration", friend1_id, friend1_id); + ASPHR_LOG_INFO("Registration", friend2_id, friend2_id); + // User 1 send user 2 a request + { + AddAsyncFriendRequest request; + request.set_unique_name(friend2.unique_name); + request.set_display_name(friend2.unique_name); + request.set_public_id(friend2_id); + request.set_message("INVITATION-MESSAGE"); + AddAsyncFriendResponse response; + auto status = friend1.rpc->AddAsyncFriend(nullptr, &request, &response); + EXPECT_TRUE(status.ok()); + // crash fast if cannot establish friend request + if (!status.ok()) { + FAIL() << "Failed to establish friend request"; + } + } + + friend1.t->send(); + friend2.t->retrieve_async_invitations(friend1_allocation, + friend1_allocation + 1); + // user 2 should have obtained the friend request from user1 + // user 2 now approve the friend request. + { + AcceptAsyncInvitationRequest request; + request.set_unique_name(friend1.unique_name); + request.set_display_name(friend1.unique_name); + request.set_public_id(friend1_id); + AcceptAsyncInvitationResponse response; + auto status = + friend2.rpc->AcceptAsyncInvitation(nullptr, &request, &response); + EXPECT_TRUE(status.ok()); + // crash fast if cannot approve friend request + if (!status.ok()) { + FAIL() << "Failed to approve friend request"; + } + } + ASPHR_LOG_INFO("Friend 2 has accepted the request from friend 1!"); + // check that user 2 has user 1 as a friend + { + GetFriendListRequest request; + GetFriendListResponse response; + friend2.rpc->GetFriendList(nullptr, &request, &response); + int friend_index = -1; + for (int i = 0; i < response.friend_infos_size(); i++) { + if (response.friend_infos(i).unique_name() == friend1.unique_name) { + EXPECT_EQ(friend_index, -1); + friend_index = i; + } + } + EXPECT_EQ(response.friend_infos(friend_index).unique_name(), + friend1.unique_name); + EXPECT_EQ(response.friend_infos(friend_index).display_name(), + friend1.unique_name); + EXPECT_EQ(response.friend_infos(friend_index).public_id(), friend1_id); + EXPECT_EQ(response.friend_infos(friend_index).invitation_progress(), + asphrdaemon::InvitationProgress::Complete); + } + // retrieive system control message + friend2.t->retrieve(); + // ACK the system control message + friend2.t->send(); + // user 1 retrive ACK of system control message + // and promotes user 2 to a friend + friend1.t->retrieve(); + // user 1 should have user 2 as a friend + { + GetFriendListRequest request; + GetFriendListResponse response; + friend1.rpc->GetFriendList(nullptr, &request, &response); + ASPHR_LOG_INFO("Friend 1 has " + + std::to_string(response.friend_infos_size()) + " friends"); + int friend_index = -1; + for (int i = 0; i < response.friend_infos_size(); i++) { + if (response.friend_infos(i).unique_name() == friend2.unique_name) { + EXPECT_EQ(friend_index, -1); + friend_index = i; + } + } + EXPECT_EQ(response.friend_infos(friend_index).unique_name(), + friend2.unique_name); + EXPECT_EQ(response.friend_infos(friend_index).display_name(), + friend2.unique_name); + EXPECT_EQ(response.friend_infos(friend_index).public_id(), friend2_id); + } + // reset transmitter + friend1.t->reset_async_scanner(0); + friend2.t->reset_async_scanner(0); + } + + auto register_people(int n) -> vector { + vector db_files; + for (auto i = 0; i < n; i++) { + db_files.push_back(generateTempFile()); + } + return register_people(db_files); + } + + auto register_people(vector db_files) -> vector { vector friends; for (size_t i = 0; i < db_files.size(); i++) { auto [G, rpc, t] = gen_person(db_files.at(i)); auto name = absl::StrCat("user", i + 1); + auto display_name = absl::StrCat("User ", i + 1); { RegisterUserRequest request; request.set_name(name); @@ -114,53 +237,53 @@ class DaemonRpcTest : public ::testing::Test { RegisterUserResponse response; rpc->RegisterUser(nullptr, &request, &response); } - friends.push_back({name, std::move(G), std::move(rpc), std::move(t)}); + friends.push_back( + {name, display_name, std::move(G), std::move(rpc), std::move(t)}); + } + return friends; + } + // call this method to generate N strangers + auto register_N_people(int N) -> vector { + vector db_files; + for (auto i = 0; i < N; i++) { + db_files.push_back(generateTempFile()); + } + return register_people(db_files); + } + + // Due to the simultaneous read capacity constraint, this method might break + // down for more than three users. + auto generate_friends_from_list_of_pairs(vector db_files, + vector> pairs) + -> vector { + std::map friend_count = {}; + auto friends = register_people(db_files); + for (const auto& f : friends) { + friend_count[f.unique_name] = 0; } for (const auto& p : pairs) { auto& friend1 = friends.at(p.first); + friend_count[friend1.unique_name]++; auto& friend2 = friends.at(p.second); - string user1_key; - string user2_key; - { - GenerateFriendKeyRequest request; - request.set_unique_name(friend2.unique_name); - GenerateFriendKeyResponse response; - auto status = - friend1.rpc->GenerateFriendKey(nullptr, &request, &response); - EXPECT_TRUE(status.ok()); - EXPECT_GT(response.key().size(), 0); - user1_key = response.key(); - } + friend_count[friend2.unique_name]++; + connect_friends_both_async(friend1, friend2); + } - { - GenerateFriendKeyRequest request; - request.set_unique_name(friend1.unique_name); - GenerateFriendKeyResponse response; - auto status = - friend2.rpc->GenerateFriendKey(nullptr, &request, &response); - EXPECT_TRUE(status.ok()); - EXPECT_GT(response.key().size(), 0); - user2_key = response.key(); - } - - { - AddFriendRequest request; - request.set_unique_name(friend2.unique_name); - request.set_key(user2_key); - AddFriendResponse response; - auto status = friend1.rpc->AddFriend(nullptr, &request, &response); - EXPECT_TRUE(status.ok()); - } - - { - AddFriendRequest request; - request.set_unique_name(friend1.unique_name); - request.set_key(user1_key); - AddFriendResponse response; - auto status = friend2.rpc->AddFriend(nullptr, &request, &response); - EXPECT_TRUE(status.ok()); + for (const auto& f : friends) { + if (friend_count.at(f.unique_name) > 2) { + ASPHR_LOG_INFO( + "WARNING: You have created a user with more than 2 friends"); + ASPHR_LOG_INFO( + "WARNING: when a user has more than 2 friends, reading message " + "becomes non-deterministic for that user"); + ASPHR_LOG_INFO("WARNING: please adjust test accordingly"); } } + cout + << "End of Setup: Users successfully connected to each other.\n" + << "=================================================================\n" + << "=================================================================\n" + << endl; return friends; } @@ -178,6 +301,11 @@ class DaemonRpcTest : public ::testing::Test { return {std::move(v.at(0)), std::move(v.at(1))}; } + //---------------------------------------------------------------------------- + //---------------------------------------------------------------------------- + //|| Setup/Teardown Server || + //---------------------------------------------------------------------------- + //---------------------------------------------------------------------------- void SetUp() override { // get a random port number // https://github.com/yegor256/random-tcp-port might be useful sometime in @@ -186,7 +314,8 @@ class DaemonRpcTest : public ::testing::Test { server_address_ << "localhost:" << port; // Setup server grpc::ServerBuilder builder; - cout << "server address: " << server_address_.str() << endl; + ASPHR_LOG_INFO("Server initializing", + "server address: ", server_address_.str()); builder.AddListeningPort(server_address_.str(), grpc::InsecureServerCredentials()); builder.RegisterService(&service_); @@ -198,9 +327,9 @@ class DaemonRpcTest : public ::testing::Test { for (const auto& f : config_file_addresses_) { if (remove(f.c_str()) != 0) { - cerr << "Error deleting file"; + ASPHR_LOG_ERR("Error deleting file"); } else { - cout << "File successfully deleted\n"; + ASPHR_LOG_INFO("File successfully deleted\n"); } } for (const auto& f : temp_dirs_) { @@ -212,6 +341,20 @@ class DaemonRpcTest : public ::testing::Test { } } + //---------------------------------------------------------------------------- + //---------------------------------------------------------------------------- + //|| Utility Functions || + //---------------------------------------------------------------------------- + //---------------------------------------------------------------------------- + auto get_public_id(const FriendTestingInfo& friend_info) -> std::string { + GetMyPublicIDRequest request; + GetMyPublicIDResponse response; + + auto status = friend_info.rpc->GetMyPublicID(nullptr, &request, &response); + EXPECT_TRUE(status.ok()); + return response.public_id(); + } + void ResetStub() { std::shared_ptr channel = grpc::CreateChannel( server_address_.str(), grpc::InsecureChannelCredentials()); diff --git a/integration_tests/daemon_tests/daemon_add_friend_test.cc b/integration_tests/daemon_tests/daemon_add_friend_test.cc index bed6dfa2..30706f6c 100644 --- a/integration_tests/daemon_tests/daemon_add_friend_test.cc +++ b/integration_tests/daemon_tests/daemon_add_friend_test.cc @@ -3,106 +3,147 @@ namespace asphr::testing { namespace { -TEST_F(DaemonRpcTest, AddFriend) { +TEST_F(DaemonRpcTest, AddFriendSync) { ResetStub(); + auto friends = register_people(2); + auto& friend1 = friends.at(0); + auto& friend2 = friends.at(1); - generate_two_friends(); -}; - -TEST_F(DaemonRpcTest, AddFriendAndCheckFriendList) { - ResetStub(); - - // we cannot use generate_two_friends() here, because we want to - // check the friend list in the middle + string user1_story; + string user2_story; + { + // get user 1's id via rpc call + GetMyPublicIDRequest request; + GetMyPublicIDResponse response; + friend1.rpc->GetMyPublicID(nullptr, &request, &response); + user1_story = response.story(); + } + { + // get user 2's id via rpc call + GetMyPublicIDRequest request; + GetMyPublicIDResponse response; + friend2.rpc->GetMyPublicID(nullptr, &request, &response); + user2_story = response.story(); + } + { + AddSyncFriendRequest request; + request.set_unique_name(friend2.unique_name); + request.set_display_name(friend2.display_name); + request.set_story(user2_story); + AddSyncFriendResponse response; + friend1.rpc->AddSyncFriend(nullptr, &request, &response); + } - auto [G1, rpc1, t1] = gen_person(); - auto [G2, rpc2, t2] = gen_person(); + // check that we have an outgoing friend request + { + GetOutgoingSyncInvitationsRequest request; + GetOutgoingSyncInvitationsResponse response; + friend1.rpc->GetOutgoingSyncInvitations(nullptr, &request, &response); + EXPECT_EQ(response.invitations_size(), 1); + EXPECT_EQ(response.invitations(0).unique_name(), friend2.unique_name); + EXPECT_EQ(response.invitations(0).display_name(), friend2.display_name); + EXPECT_EQ(response.invitations(0).story(), user2_story); + } + // friend2 should have no friend request + { + GetOutgoingSyncInvitationsRequest request; + GetOutgoingSyncInvitationsResponse response; + friend2.rpc->GetOutgoingSyncInvitations(nullptr, &request, &response); + EXPECT_EQ(response.invitations_size(), 0); + } + // now make the sync friend request in the other direction { - RegisterUserRequest request; - request.set_name("user1local"); - request.set_beta_key("asphr_magic"); - RegisterUserResponse response; - rpc1->RegisterUser(nullptr, &request, &response); + AddSyncFriendRequest request; + request.set_unique_name(friend1.unique_name); + request.set_display_name(friend1.display_name); + request.set_story(user1_story); + AddSyncFriendResponse response; + friend2.rpc->AddSyncFriend(nullptr, &request, &response); } { - RegisterUserRequest request; - request.set_name("user2local"); - request.set_beta_key("asphr_magic"); - RegisterUserResponse response; - rpc2->RegisterUser(nullptr, &request, &response); + GetOutgoingSyncInvitationsRequest request; + GetOutgoingSyncInvitationsResponse response; + friend2.rpc->GetOutgoingSyncInvitations(nullptr, &request, &response); + EXPECT_EQ(response.invitations_size(), 1); + EXPECT_EQ(response.invitations(0).unique_name(), friend1.unique_name); + EXPECT_EQ(response.invitations(0).display_name(), friend1.display_name); + EXPECT_EQ(response.invitations(0).story(), user1_story); } + { + friend1.t->retrieve(); + friend1.t->send(); + } + // nothing should've happened { GetFriendListRequest request; GetFriendListResponse response; - auto status = rpc1->GetFriendList(nullptr, &request, &response); - EXPECT_TRUE(status.ok()); + friend1.rpc->GetFriendList(nullptr, &request, &response); EXPECT_EQ(response.friend_infos_size(), 0); } - - string user1_key; - string user2_key; - { - GenerateFriendKeyRequest request; - request.set_unique_name("user2"); - GenerateFriendKeyResponse response; - auto status = rpc1->GenerateFriendKey(nullptr, &request, &response); - EXPECT_TRUE(status.ok()); - EXPECT_GT(response.key().size(), 0); - user1_key = response.key(); + GetFriendListRequest request; + GetFriendListResponse response; + friend2.rpc->GetFriendList(nullptr, &request, &response); + EXPECT_EQ(response.friend_infos_size(), 0); } - { - GenerateFriendKeyRequest request; - request.set_unique_name("user1"); - GenerateFriendKeyResponse response; - auto status = rpc2->GenerateFriendKey(nullptr, &request, &response); - EXPECT_TRUE(status.ok()); - EXPECT_GT(response.key().size(), 0); - user2_key = response.key(); + friend2.t->retrieve(); + friend2.t->send(); } - + // now 2 should be friends with 1 { GetFriendListRequest request; GetFriendListResponse response; - auto status = rpc1->GetFriendList(nullptr, &request, &response); - EXPECT_TRUE(status.ok()); + friend1.rpc->GetFriendList(nullptr, &request, &response); + EXPECT_EQ(response.friend_infos_size(), 0); + } + { + GetFriendListRequest request; + GetFriendListResponse response; + friend2.rpc->GetFriendList(nullptr, &request, &response); EXPECT_EQ(response.friend_infos_size(), 1); - EXPECT_EQ(response.friend_infos(0).unique_name(), "user2"); - EXPECT_EQ(response.friend_infos(0).enabled(), false); + EXPECT_EQ(response.friend_infos(0).unique_name(), friend1.unique_name); + EXPECT_EQ(response.friend_infos(0).display_name(), friend1.display_name); + EXPECT_EQ(response.friend_infos(0).public_id(), get_public_id(friend1)); + EXPECT_EQ(response.friend_infos(0).invitation_progress(), + asphrdaemon::InvitationProgress::Complete); } - - cout << "user1_key: " << user1_key << endl; - cout << "user2_key: " << user2_key << endl; - { - AddFriendRequest request; - request.set_unique_name("user2"); - request.set_key(user2_key); - AddFriendResponse response; - auto status = rpc1->AddFriend(nullptr, &request, &response); - EXPECT_TRUE(status.ok()); + friend1.t->retrieve(); + friend1.t->send(); } - + // now 1 should be friends with 2 { - AddFriendRequest request; - request.set_unique_name("user1"); - request.set_key(user1_key); - AddFriendResponse response; - auto status = rpc2->AddFriend(nullptr, &request, &response); - EXPECT_TRUE(status.ok()); + GetFriendListRequest request; + GetFriendListResponse response; + friend1.rpc->GetFriendList(nullptr, &request, &response); + EXPECT_EQ(response.friend_infos_size(), 1); + EXPECT_EQ(response.friend_infos(0).unique_name(), friend2.unique_name); + EXPECT_EQ(response.friend_infos(0).display_name(), friend2.display_name); + EXPECT_EQ(response.friend_infos(0).public_id(), get_public_id(friend2)); + EXPECT_EQ(response.friend_infos(0).invitation_progress(), + asphrdaemon::InvitationProgress::Complete); } +} + +TEST_F(DaemonRpcTest, AddFriendAndCheckFriendList) { + ResetStub(); + // this test is already implemented in the two peron constructor + auto [user1, user2] = generate_two_friends(); { GetFriendListRequest request; GetFriendListResponse response; - auto status = rpc1->GetFriendList(nullptr, &request, &response); - EXPECT_TRUE(status.ok()); + user1.rpc->GetFriendList(nullptr, &request, &response); + EXPECT_EQ(response.friend_infos_size(), 1); + } + { + GetFriendListRequest request; + GetFriendListResponse response; + user2.rpc->GetFriendList(nullptr, &request, &response); EXPECT_EQ(response.friend_infos_size(), 1); - EXPECT_EQ(response.friend_infos(0).unique_name(), "user2"); - EXPECT_EQ(response.friend_infos(0).enabled(), true); } }; diff --git a/integration_tests/daemon_tests/daemon_config_test.cc b/integration_tests/daemon_tests/daemon_config_test.cc index 518a2ad9..c090addd 100644 --- a/integration_tests/daemon_tests/daemon_config_test.cc +++ b/integration_tests/daemon_tests/daemon_config_test.cc @@ -61,7 +61,7 @@ TEST_F(DaemonRpcTest, LoadAndUnloadConfigAndReceive) { GetMessagesResponse response; auto status = rpc2->GetMessages(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - EXPECT_EQ(response.messages_size(), 1); + EXPECT_EQ(response.messages_size(), 2); // +1 for invitation message EXPECT_EQ(response.messages(0).m().unique_name(), "user1"); EXPECT_EQ(response.messages(0).m().message(), "hello from 1 to 2"); } diff --git a/integration_tests/daemon_tests/daemon_fast_test.cc b/integration_tests/daemon_tests/daemon_fast_test.cc index 0d0ccfbe..5909c88f 100644 --- a/integration_tests/daemon_tests/daemon_fast_test.cc +++ b/integration_tests/daemon_tests/daemon_fast_test.cc @@ -120,22 +120,32 @@ TEST_F(DaemonRpcTest, LoadAndUnloadConfigAndReceiveHalfFriend) { rpc2->RegisterUser(nullptr, &request, &response); } + string user1_id; + string user2_id; { - GenerateFriendKeyRequest request; - request.set_unique_name("user2"); - GenerateFriendKeyResponse response; - auto status = rpc1->GenerateFriendKey(nullptr, &request, &response); - EXPECT_TRUE(status.ok()); - EXPECT_GT(response.key().size(), 0); + // get user 1's id via rpc call + GetMyPublicIDRequest request; + GetMyPublicIDResponse response; + rpc1->GetMyPublicID(nullptr, &request, &response); + user1_id = response.public_id(); } - { - GenerateFriendKeyRequest request; - request.set_unique_name("user1"); - GenerateFriendKeyResponse response; - auto status = rpc2->GenerateFriendKey(nullptr, &request, &response); + // get user 2's id via rpc call + GetMyPublicIDRequest request; + GetMyPublicIDResponse response; + rpc2->GetMyPublicID(nullptr, &request, &response); + user2_id = response.public_id(); + } + // send one but not the other + { + AddAsyncFriendRequest request; + request.set_unique_name("user2"); + request.set_display_name("user2 display name"); + request.set_public_id(user2_id); + request.set_message("hello from user 1 to user 2"); + AddAsyncFriendResponse response; + auto status = rpc1->AddAsyncFriend(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - EXPECT_GT(response.key().size(), 0); } } @@ -143,6 +153,8 @@ TEST_F(DaemonRpcTest, LoadAndUnloadConfigAndReceiveHalfFriend) { // re-create config from the file! auto [G, rpc, t] = gen_person(db_file); + // we don't expect anything here. no friends have been made + t->retrieve(); t->send(); diff --git a/integration_tests/daemon_tests/daemon_friends_test.cc b/integration_tests/daemon_tests/daemon_friends_test.cc index cecaf1af..463842bc 100644 --- a/integration_tests/daemon_tests/daemon_friends_test.cc +++ b/integration_tests/daemon_tests/daemon_friends_test.cc @@ -24,7 +24,7 @@ TEST_F(DaemonRpcTest, GetFriendList) { } }; -TEST_F(DaemonRpcTest, GenerateFriendKey) { +TEST_F(DaemonRpcTest, GetMyPublicID) { ResetStub(); auto [G, rpc, t] = gen_person(); @@ -37,12 +37,11 @@ TEST_F(DaemonRpcTest, GenerateFriendKey) { } { - GenerateFriendKeyRequest request; - request.set_unique_name("friend_name"); - GenerateFriendKeyResponse response; - auto status = rpc->GenerateFriendKey(nullptr, &request, &response); + GetMyPublicIDRequest request; + GetMyPublicIDResponse response; + auto status = rpc->GetMyPublicID(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - EXPECT_GT(response.key().size(), 0); + EXPECT_GT(response.public_id().size(), 0); } }; diff --git a/integration_tests/daemon_tests/daemon_long_messages_test.cc b/integration_tests/daemon_tests/daemon_long_messages_test.cc index 5d2b35d4..f8efbbab 100644 --- a/integration_tests/daemon_tests/daemon_long_messages_test.cc +++ b/integration_tests/daemon_tests/daemon_long_messages_test.cc @@ -63,7 +63,7 @@ TEST_F(DaemonRpcTest, SendLongMessage) { GetMessagesResponse response; auto status = friend2.rpc->GetMessages(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - EXPECT_EQ(response.messages_size(), 0); + EXPECT_EQ(response.messages_size(), 1); // +1 for invitation message. } { @@ -95,7 +95,7 @@ TEST_F(DaemonRpcTest, SendLongMessage) { GetMessagesResponse response; auto status = friend2.rpc->GetMessages(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - EXPECT_EQ(response.messages_size(), 1); + EXPECT_EQ(response.messages_size(), 2); // +1 for invitation message. EXPECT_EQ(response.messages(0).m().unique_name(), "user1"); EXPECT_EQ(response.messages(0).m().message(), m1); } @@ -166,7 +166,7 @@ TEST_F(DaemonRpcTest, SendLongMessagePersistence) { GetMessagesResponse response; auto status = friend2.rpc->GetMessages(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - EXPECT_EQ(response.messages_size(), 0); + EXPECT_EQ(response.messages_size(), 1); // +1 for invitation message. } } @@ -203,7 +203,7 @@ TEST_F(DaemonRpcTest, SendLongMessagePersistence) { GetMessagesResponse response; auto status = rpc2->GetMessages(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - EXPECT_EQ(response.messages_size(), 1); + EXPECT_EQ(response.messages_size(), 2); // +1 for invitation message. EXPECT_EQ(response.messages(0).m().unique_name(), "user1"); EXPECT_EQ(response.messages(0).m().message(), m1); } diff --git a/integration_tests/daemon_tests/daemon_multiple_messages_test.cc b/integration_tests/daemon_tests/daemon_multiple_messages_test.cc index 7947c1e6..888df18c 100644 --- a/integration_tests/daemon_tests/daemon_multiple_messages_test.cc +++ b/integration_tests/daemon_tests/daemon_multiple_messages_test.cc @@ -61,7 +61,7 @@ TEST_F(DaemonRpcTest, SendMultipleMessagesInBothDirections) { GetMessagesResponse response; auto status = friend2.rpc->GetMessages(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - EXPECT_EQ(response.messages_size(), 1); + EXPECT_EQ(response.messages_size(), 2); // +1 for invitation message. EXPECT_EQ(response.messages(0).m().unique_name(), "user1"); EXPECT_EQ(response.messages(0).m().message(), "hello from 1 to 2"); } @@ -92,7 +92,7 @@ TEST_F(DaemonRpcTest, SendMultipleMessagesInBothDirections) { GetMessagesResponse response; auto status = friend2.rpc->GetMessages(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - EXPECT_EQ(response.messages_size(), 2); + EXPECT_EQ(response.messages_size(), 3); // +1 for invitation message. EXPECT_EQ(response.messages(0).m().unique_name(), "user1"); cout << "message 1: " << response.messages(0).m().message() << endl; diff --git a/integration_tests/daemon_tests/daemon_persistence_test.cc b/integration_tests/daemon_tests/daemon_persistence_test.cc index b3dce087..414f252e 100644 --- a/integration_tests/daemon_tests/daemon_persistence_test.cc +++ b/integration_tests/daemon_tests/daemon_persistence_test.cc @@ -60,7 +60,7 @@ TEST_F(DaemonRpcTest, MsgstorePersistence) { GetMessagesResponse response; auto status = friend2.rpc->GetMessages(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - EXPECT_EQ(response.messages_size(), 1); + EXPECT_EQ(response.messages_size(), 2); // +1 for invitation message. EXPECT_EQ(response.messages(0).m().unique_name(), "user1"); EXPECT_EQ(response.messages(0).m().message(), "hello from 1 to 2"); } @@ -88,7 +88,7 @@ TEST_F(DaemonRpcTest, MsgstorePersistence) { GetMessagesResponse response; auto status = rpc2->GetMessages(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - EXPECT_EQ(response.messages_size(), 1); + EXPECT_EQ(response.messages_size(), 2); // +1 for invitation message. EXPECT_EQ(response.messages(0).m().unique_name(), "user1"); EXPECT_EQ(response.messages(0).m().message(), "hello from 1 to 2"); } @@ -139,7 +139,7 @@ TEST_F(DaemonRpcTest, OutboxPersistence) { GetMessagesResponse response; auto status = friend2.rpc->GetMessages(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - EXPECT_EQ(response.messages_size(), 0); + EXPECT_EQ(response.messages_size(), 1); // +1 for invitation message. } } @@ -195,7 +195,7 @@ TEST_F(DaemonRpcTest, OutboxPersistence) { GetMessagesResponse response; auto status = rpc2->GetMessages(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - EXPECT_EQ(response.messages_size(), 1); + EXPECT_EQ(response.messages_size(), 2); // +1 for invitation message. EXPECT_EQ(response.messages(0).m().unique_name(), "user1"); EXPECT_EQ(response.messages(0).m().message(), "hello from 1 to 2"); } @@ -241,7 +241,7 @@ TEST_F(DaemonRpcTest, OutboxPersistence) { GetMessagesResponse response; auto status = rpc2->GetMessages(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - EXPECT_EQ(response.messages_size(), 2); + EXPECT_EQ(response.messages_size(), 3); // +1 for invitation message. EXPECT_EQ(response.messages(0).m().unique_name(), "user1"); EXPECT_EQ(response.messages(0).m().message(), "hello from 1 to 2, again!"); diff --git a/integration_tests/daemon_tests/daemon_seen_test.cc b/integration_tests/daemon_tests/daemon_seen_test.cc index 1db9d6fa..dee5d5cb 100644 --- a/integration_tests/daemon_tests/daemon_seen_test.cc +++ b/integration_tests/daemon_tests/daemon_seen_test.cc @@ -51,7 +51,7 @@ TEST_F(DaemonRpcTest, SeenMessage) { GetMessagesResponse response; auto status = friend2.rpc->GetMessages(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - EXPECT_EQ(response.messages_size(), 1); + EXPECT_EQ(response.messages_size(), 2); // +1 for invitation message. EXPECT_EQ(response.messages(0).m().unique_name(), "user1"); EXPECT_EQ(response.messages(0).m().message(), "hello from 1 to 2"); } @@ -81,7 +81,7 @@ TEST_F(DaemonRpcTest, SeenMessage) { GetMessagesResponse response; auto status = friend2.rpc->GetMessages(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - EXPECT_EQ(response.messages_size(), 2); + EXPECT_EQ(response.messages_size(), 3); // +1 for invitation message. EXPECT_EQ(response.messages(0).m().unique_name(), "user1"); EXPECT_EQ(response.messages(0).m().message(), "hello from 1 to 2, again!!!! :0"); @@ -96,7 +96,7 @@ TEST_F(DaemonRpcTest, SeenMessage) { GetMessagesResponse response; auto status = friend2.rpc->GetMessages(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - EXPECT_EQ(response.messages_size(), 2); + EXPECT_EQ(response.messages_size(), 3); // +1 for invitation message. EXPECT_EQ(response.messages(0).m().unique_name(), "user1"); EXPECT_EQ(response.messages(0).m().message(), "hello from 1 to 2, again!!!! :0"); @@ -120,7 +120,7 @@ TEST_F(DaemonRpcTest, SeenMessage) { GetMessagesResponse response; auto status = friend2.rpc->GetMessages(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - EXPECT_EQ(response.messages_size(), 2); + EXPECT_EQ(response.messages_size(), 3); // +1 for invitation message. EXPECT_EQ(response.messages(0).m().unique_name(), "user1"); EXPECT_EQ(response.messages(0).m().message(), "hello from 1 to 2, again!!!! :0"); @@ -134,7 +134,7 @@ TEST_F(DaemonRpcTest, SeenMessage) { GetMessagesResponse response; auto status = friend2.rpc->GetMessages(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - EXPECT_EQ(response.messages_size(), 1); + EXPECT_EQ(response.messages_size(), 2); // +1 for invitation message. EXPECT_EQ(response.messages(0).m().unique_name(), "user1"); EXPECT_EQ(response.messages(0).m().message(), "hello from 1 to 2, again!!!! :0"); diff --git a/integration_tests/daemon_tests/daemon_send_messages_test.cc b/integration_tests/daemon_tests/daemon_send_messages_test.cc index 334ceb15..974ebc20 100644 --- a/integration_tests/daemon_tests/daemon_send_messages_test.cc +++ b/integration_tests/daemon_tests/daemon_send_messages_test.cc @@ -55,7 +55,7 @@ TEST_F(DaemonRpcTest, SendMessage) { GetMessagesResponse response; auto status = friend2.rpc->GetMessages(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - EXPECT_EQ(response.messages_size(), 1); + EXPECT_EQ(response.messages_size(), 2); // +1 for invitation message. EXPECT_EQ(response.messages(0).m().unique_name(), friend1.unique_name); EXPECT_EQ(response.messages(0).m().message(), "hello from 1 to 2"); } @@ -110,9 +110,11 @@ TEST_F(DaemonRpcTest, SendMultipleMessages) { GetMessagesResponse response; auto status = friend2.rpc->GetMessages(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - EXPECT_EQ(response.messages_size(), 1); + EXPECT_EQ(response.messages_size(), 2); // +1 for invitation message. EXPECT_EQ(response.messages(0).m().unique_name(), friend1.unique_name); EXPECT_EQ(response.messages(0).m().message(), "hello from 1 to 2"); + EXPECT_EQ(response.messages(1).m().unique_name(), friend1.unique_name); + EXPECT_EQ(response.messages(1).m().message(), "INVITATION-MESSAGE"); } // 2 has sent the ACK for the first message, so 1 should safely send the next @@ -138,7 +140,7 @@ TEST_F(DaemonRpcTest, SendMultipleMessages) { GetMessagesResponse response; auto status = friend2.rpc->GetMessages(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - EXPECT_EQ(response.messages_size(), 2); + EXPECT_EQ(response.messages_size(), 3); // +1 for invitation message. EXPECT_EQ(response.messages(0).m().unique_name(), friend1.unique_name); cout << "message 1: " << response.messages(0).m().message() << endl; @@ -149,6 +151,9 @@ TEST_F(DaemonRpcTest, SendMultipleMessages) { << TimeUtil::ToString(response.messages(1).delivered_at()) << endl; EXPECT_EQ(response.messages(0).m().message(), "hello from 1 to 2, again!!!! :0"); + + EXPECT_EQ(response.messages(2).m().unique_name(), friend1.unique_name); + EXPECT_EQ(response.messages(2).m().message(), "INVITATION-MESSAGE"); } }; diff --git a/integration_tests/invitation_tests/async_request_test.cc b/integration_tests/invitation_tests/async_request_test.cc new file mode 100644 index 00000000..5a0c1cce --- /dev/null +++ b/integration_tests/invitation_tests/async_request_test.cc @@ -0,0 +1,427 @@ +#include "../daemon_setup.hpp" + +// #define DIRECT_TRANSMISSION 1 + +namespace asphr::testing { +namespace { + +// Test GRPC api AddAsyncFriend +// Test GRPC api GetIncomingAsyncFriendRequests +// Test GRPC api DecideAsyncFriendRequest +// Test GRPC api SendMessage after adding a friend + +// Partitions: +// Number of existing friends: 0, 1 +// Chunk of the database where we find the friend: first, middle, last +// Decision on the friend: accept, reject +// InvitationProgress: Incoming, OutgoingAsync, OutgoingSync, Complete +// Number of simultaneous requests: 1, >1 +// Deleted: false, true + +// Test two people are able to befriend each other +// by sending async requests to each other. +// TEST_F(DaemonRpcTest, AcceptInvitation) { +// ResetStub(); + +// auto&& [friend1, friend2] = generate_two_friends(); +// } + +// Friend1 -> Friend2 +// Partition: Zerofriend basic flow. +// - one existing friends, +// - same chunks, +// - Progress = Incoming (friend2), OutgoingAsync (friend1), Complete (friend1, +// - friend2) +// - Not deleted +TEST_F(DaemonRpcTest, ZeroFriendAccept) { + // Precondition: + // Server is starting new everytime. + // This means that p1, p2 will be allocated at index 0, 1 + // thus allow a request to be delivered with one call to the transmitter + ResetStub(); + + auto peoples = register_N_people(2); + auto& p1 = peoples.at(0); // sender + auto& p2 = peoples.at(1); // receiver + + // get the public id of the users + string p1_id = get_public_id(p1); + string p2_id = get_public_id(p2); + + // sender(p1) initialize a friend request to the receiver(p2) + { + AddAsyncFriendRequest request; + AddAsyncFriendResponse response; + + request.set_unique_name("user2"); + request.set_display_name(p2.unique_name); + request.set_public_id(p2_id); + request.set_message("hello from user 1 to user 2"); + + auto status = p1.rpc->AddAsyncFriend(nullptr, &request, &response); + EXPECT_TRUE(status.ok()); + } + + // check that sender(p1) has receiver marked outgoingasync, + // receiver(p2) has no friend request + { + GetOutgoingAsyncInvitationsRequest request; + GetOutgoingAsyncInvitationsResponse response; + + auto status = + p1.rpc->GetOutgoingAsyncInvitations(nullptr, &request, &response); + EXPECT_TRUE(status.ok()); + EXPECT_EQ(response.invitations_size(), 1); + auto& friend_info = response.invitations(0); + // EXPECT_EQ(friend_info.unique_name(), p2.unique_name); + EXPECT_EQ(friend_info.public_id(), p2_id); + } + { + GetIncomingAsyncInvitationsRequest request; + GetIncomingAsyncInvitationsResponse response; + + auto status = + p2.rpc->GetIncomingAsyncInvitations(nullptr, &request, &response); + EXPECT_TRUE(status.ok()); + EXPECT_EQ(response.invitations_size(), 0); + } + + // start a timer + auto start = std::chrono::high_resolution_clock::now(); + +#ifdef DIRECT_TRANSMISSION + + // send this request + p1.t->transmit_async_friend_request(); + + auto [start_index, end_index] = + p2.t->update_async_invitation_retrieve_index(); + p2.t->retrieve_async_friend_request(start_index, end_index); + +#else + p1.t->send(); + p2.t->retrieve(); +#endif + + // end the timer + auto end = std::chrono::high_resolution_clock::now(); + auto duration = + std::chrono::duration_cast(end - start); + auto duration_str = std::to_string(duration.count()); + cout << "Duration: " << duration_str << " ms" << endl; + ASPHR_LOG_INFO("Time taken to process block:", duration, duration_str); + + // check that receiver(p2) has received the request + { + GetIncomingAsyncInvitationsRequest request; + GetIncomingAsyncInvitationsResponse response; + + auto status = + p2.rpc->GetIncomingAsyncInvitations(nullptr, &request, &response); + EXPECT_TRUE(status.ok()); + EXPECT_EQ(response.invitations_size(), 1); + const auto& friend_info = response.invitations(0); + + EXPECT_EQ(friend_info.public_id(), p1_id); + } + // receiver(p2) approves the request + { + AcceptAsyncInvitationRequest request; + AcceptAsyncInvitationResponse response; + + request.set_unique_name("p1 local"); + request.set_display_name("ABCDEF"); + request.set_public_id(p1_id); + + auto status = p2.rpc->AcceptAsyncInvitation(nullptr, &request, &response); + EXPECT_TRUE(status.ok()); + } + + // verify that p2 has p1 as a friend + { + GetFriendListRequest request; + GetFriendListResponse response; + + auto status = p2.rpc->GetFriendList(nullptr, &request, &response); + EXPECT_TRUE(status.ok()); + EXPECT_EQ(response.friend_infos_size(), 1); + const auto& friend_info = response.friend_infos(0); + + // EXPECT_EQ(friend_info.unique_name(), p1.unique_name); + EXPECT_EQ(friend_info.invitation_progress(), InvitationProgress::Complete); + EXPECT_EQ(friend_info.public_id(), p1_id); + } + + // TODO(stzh1555): check the control message flow. +} + +// Friend1 -> Friend2 +// Partition: Zerofriend basic flow. +// - 1 existing friends, +// - same chunks, +// - Progress = Incoming (friend2), OutgoingAsync (friend1), Complete (friend1, +// - friend2) +// - Not deleted +TEST_F(DaemonRpcTest, OneFriendAccept) { + // Precondition: + // Server is starting new everytime. + // This means that p1, p2 will be allocated at index 0, 1 + // thus allow a request to be delivered with one call to the transmitter + ResetStub(); + + auto peoples = register_N_people(4); + auto& p1 = peoples.at(0); // sender + auto& p2 = peoples.at(1); // receiver + auto& p3 = peoples.at(2); // third party + auto& p4 = peoples.at(3); // fourth party + + // make p1 a friend of p3 + connect_friends_both_async(p1, p3); + // make p2 a friend of p4 + connect_friends_both_async(p2, p4); + + // get the public id of the users + string p1_id = get_public_id(p1); + string p2_id = get_public_id(p2); + + // sender(p1) initialize a friend request to the receiver(p2) + { + AddAsyncFriendRequest request; + AddAsyncFriendResponse response; + + request.set_unique_name("user2"); + request.set_display_name(p2.unique_name); + request.set_public_id(p2_id); + request.set_message("hello from user 1 to user 2"); + + auto status = p1.rpc->AddAsyncFriend(nullptr, &request, &response); + EXPECT_TRUE(status.ok()); + } + + // check that sender(p1) has receiver marked outgoingasync, + // receiver(p2) has no friend request + { + GetOutgoingAsyncInvitationsRequest request; + GetOutgoingAsyncInvitationsResponse response; + + auto status = + p1.rpc->GetOutgoingAsyncInvitations(nullptr, &request, &response); + EXPECT_TRUE(status.ok()); + EXPECT_EQ(response.invitations_size(), 1); + const auto& invitation = response.invitations(0); + + // EXPECT_EQ(friend_info.unique_name(), p2.unique_name); + EXPECT_EQ(invitation.public_id(), p2_id); + } + { + GetIncomingAsyncInvitationsRequest request; + GetIncomingAsyncInvitationsResponse response; + + auto status = + p2.rpc->GetIncomingAsyncInvitations(nullptr, &request, &response); + EXPECT_TRUE(status.ok()); + EXPECT_EQ(response.invitations_size(), 0); + } + + // start a timer + auto start = std::chrono::high_resolution_clock::now(); + +#ifdef DIRECT_TRANSMISSION + + // send this request + p1.t->transmit_async_friend_request(); + + auto [start_index, end_index] = + p2.t->update_async_invitation_retrieve_index(); + p2.t->retrieve_async_friend_request(start_index, end_index); + +#else + p1.t->send(); + p2.t->retrieve(); +#endif + + // end the timer + auto end = std::chrono::high_resolution_clock::now(); + auto duration = + std::chrono::duration_cast(end - start); + auto duration_str = std::to_string(duration.count()); + cout << "Duration: " << duration_str << " ms" << endl; + ASPHR_LOG_INFO("Time taken to process block:", duration, duration_str); + + // check that receiver(p2) has received the request + { + GetIncomingAsyncInvitationsRequest request; + GetIncomingAsyncInvitationsResponse response; + + auto status = + p2.rpc->GetIncomingAsyncInvitations(nullptr, &request, &response); + EXPECT_TRUE(status.ok()); + EXPECT_EQ(response.invitations_size(), 1); + const auto& invitation = response.invitations(0); + + // unique name has not been determined yet. + // nothing to check here? + EXPECT_EQ(invitation.public_id(), p1_id); + } + // receiver(p2) approves the request + { + AcceptAsyncInvitationRequest request; + AcceptAsyncInvitationResponse response; + + request.set_unique_name("p1 local"); + request.set_display_name("lyrica"); + request.set_public_id(p1_id); + + auto status = p2.rpc->AcceptAsyncInvitation(nullptr, &request, &response); + EXPECT_TRUE(status.ok()); + } + + // verify that p2 has p1 as a friend + { + GetFriendListRequest request; + GetFriendListResponse response; + + auto status = p2.rpc->GetFriendList(nullptr, &request, &response); + EXPECT_TRUE(status.ok()); + EXPECT_EQ(response.friend_infos_size(), 2); + // get it with the name + const auto& friend_info = response.friend_infos(1); + + // EXPECT_EQ(friend_info.unique_name(), p1.unique_name); + EXPECT_EQ(friend_info.invitation_progress(), InvitationProgress::Complete); + + // BUG + EXPECT_EQ(friend_info.public_id(), p1_id); + } +} + +// Friend1 -> Friend2 +// Partition: Zerofriend basic flow. +// - 0 existing friends, +// - same chunks, +// - Progress = Incoming (friend2), OutgoingAsync (friend1), Complete (both) +// - Not deleted +TEST_F(DaemonRpcTest, DISABLED_ZeroFriendFarAway) { + // Precondition: + // Server is starting new everytime. + // This means that p1, p2 will be allocated at index 0, 1 + // thus allow a request to be delivered with one call to the transmitter + ResetStub(); + + auto const BLOCK_DISTANCE = 1; + + // Sualeh's guess is that this is the slow part of the test. + const auto peoples = + register_N_people(BLOCK_DISTANCE * ASYNC_FRIEND_REQUEST_BATCH_SIZE + 11); + auto& p1 = peoples.at(0); // sender + // get the last user + auto& p2 = peoples.at(peoples.size() - 2); // receiver + + // get the public id of the users + string p1_id = get_public_id(p1); + string p2_id = get_public_id(p2); + + // sender(p1) initialize a friend request to the receiver(p2) + { + AddAsyncFriendRequest request; + AddAsyncFriendResponse response; + + request.set_unique_name("user2"); + request.set_display_name(p2.unique_name); + request.set_public_id(p2_id); + request.set_message("hello from user 1 to user 2"); + + auto status = p1.rpc->AddAsyncFriend(nullptr, &request, &response); + EXPECT_TRUE(status.ok()); + } + + // check that sender(p1) has receiver marked outgoingasync, + // receiver(p2) has no friend request + { + GetOutgoingAsyncInvitationsRequest request; + GetOutgoingAsyncInvitationsResponse response; + + auto status = + p1.rpc->GetOutgoingAsyncInvitations(nullptr, &request, &response); + EXPECT_TRUE(status.ok()); + EXPECT_EQ(response.invitations_size(), 1); + const auto& friend_info = response.invitations(0); + // EXPECT_EQ(friend_info.unique_name(), p2.unique_name); + EXPECT_EQ(friend_info.public_id(), p2_id); + } + { + GetIncomingAsyncInvitationsRequest request; + GetIncomingAsyncInvitationsResponse response; + + auto status = + p2.rpc->GetIncomingAsyncInvitations(nullptr, &request, &response); + EXPECT_TRUE(status.ok()); + EXPECT_EQ(response.invitations_size(), 0); + } + +#ifdef DIRECT_TRANSMISSION + + // send this request + p1.t->transmit_async_friend_request(); + + for (int i = 0; i < BLOCK_DISTANCE + 1; i++) { + auto [start_index, end_index] = + p2.t->update_async_invitation_retrieve_index(); + p2.t->retrieve_async_friend_request(start_index, end_index); + } + +#else + p1.t->send(); + + for (int i = 0; i < BLOCK_DISTANCE + 1; i++) { + p2.t->retrieve(); + } +#endif + + // check that receiver(p2) has received the request + { + GetIncomingAsyncInvitationsRequest request; + GetIncomingAsyncInvitationsResponse response; + + auto status = + p2.rpc->GetIncomingAsyncInvitations(nullptr, &request, &response); + EXPECT_TRUE(status.ok()); + EXPECT_EQ(response.invitations_size(), 1); + auto& friend_info = response.invitations(0); + + EXPECT_EQ(friend_info.public_id(), p1_id); + } + // receiver(p2) approves the request + { + AcceptAsyncInvitationRequest request; + AcceptAsyncInvitationResponse response; + + request.set_unique_name("p1 local"); + request.set_display_name("ABCDEF"); + request.set_public_id(p1_id); + + auto status = p2.rpc->AcceptAsyncInvitation(nullptr, &request, &response); + EXPECT_TRUE(status.ok()); + } + + // verify that p2 has p1 as a friend + { + GetFriendListRequest request; + GetFriendListResponse response; + + auto status = p2.rpc->GetFriendList(nullptr, &request, &response); + EXPECT_TRUE(status.ok()); + EXPECT_EQ(response.friend_infos_size(), 1); + const auto& friend_info = response.friend_infos(0); + + // EXPECT_EQ(friend_info.unique_name(), p1.unique_name); + EXPECT_EQ(friend_info.invitation_progress(), InvitationProgress::Complete); + EXPECT_EQ(friend_info.public_id(), p1_id); + } +} + +// Possibly important partitions for the future: +// - What if the server returns malicious data? + +} // namespace +} // namespace asphr::testing \ No newline at end of file diff --git a/integration_tests/multiple_friends_tests/long_messages_test.cc b/integration_tests/multiple_friends_tests/long_messages_test.cc index 47e2063c..6d5611be 100644 --- a/integration_tests/multiple_friends_tests/long_messages_test.cc +++ b/integration_tests/multiple_friends_tests/long_messages_test.cc @@ -58,7 +58,7 @@ TEST_F(MultipleFriendsTest, SendLongMessage) { auto status = friends.at(i).rpc->GetMessages(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - EXPECT_EQ(response.messages_size(), 0); + EXPECT_EQ(response.messages_size(), 1); } // second round, one! @@ -76,8 +76,8 @@ TEST_F(MultipleFriendsTest, SendLongMessage) { auto status = friends.at(i).rpc->GetMessages(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - if (response.messages_size() > 0) { - EXPECT_EQ(response.messages_size(), 1); + if (response.messages_size() > 1) { + EXPECT_EQ(response.messages_size(), 2); EXPECT_EQ(response.messages(0).m().unique_name(), friends.at(0).unique_name); EXPECT_EQ(response.messages(0).m().message(), long_message); diff --git a/integration_tests/multiple_friends_tests/multiple_messages_test.cc b/integration_tests/multiple_friends_tests/multiple_messages_test.cc index 7d5041c0..3bf3ea3c 100644 --- a/integration_tests/multiple_friends_tests/multiple_messages_test.cc +++ b/integration_tests/multiple_friends_tests/multiple_messages_test.cc @@ -62,7 +62,7 @@ TEST_F(MultipleFriendsTest, SendMultipleMessages) { GetMessagesResponse response; auto status = friend2.rpc->GetMessages(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - EXPECT_EQ(response.messages_size(), 1); + EXPECT_EQ(response.messages_size(), 2); // +1 for invitation message. EXPECT_EQ(response.messages(0).m().unique_name(), friend1.unique_name); EXPECT_EQ(response.messages(0).m().message(), "hello from 1 to 2"); } @@ -88,7 +88,7 @@ TEST_F(MultipleFriendsTest, SendMultipleMessages) { GetMessagesResponse response; auto status = friend2.rpc->GetMessages(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - EXPECT_EQ(response.messages_size(), 2); + EXPECT_EQ(response.messages_size(), 3); // +1 for invitation message. EXPECT_EQ(response.messages(0).m().unique_name(), friend1.unique_name); EXPECT_EQ(response.messages(0).m().message(), "hello from 1 to 2, again!!!! :0"); diff --git a/integration_tests/multiple_friends_tests/three_messages_test.cc b/integration_tests/multiple_friends_tests/three_messages_test.cc index 30c5660c..0831b41b 100644 --- a/integration_tests/multiple_friends_tests/three_messages_test.cc +++ b/integration_tests/multiple_friends_tests/three_messages_test.cc @@ -52,8 +52,8 @@ TEST_F(MultipleFriendsTest, SendThreeMessages) { auto status = friends.at(i).rpc->GetMessages(nullptr, &request, &response); EXPECT_TRUE(status.ok()); - if (response.messages_size() > 0) { - EXPECT_EQ(response.messages_size(), 1); + if (response.messages_size() > 1) { // +1 for invitation message + EXPECT_EQ(response.messages_size(), 2); // +1 for invitation message EXPECT_EQ(response.messages(0).m().unique_name(), friends.at(0).unique_name); EXPECT_EQ(response.messages(0).m().message(), diff --git a/research/strategy/main.pdf b/research/strategy/main.pdf index bec7754fa957a2d57de99472a08c7da6110f63e4..e5a9e401b1d5452bfd85fdb9e57da8fdd97fffa7 100644 GIT binary patch delta 267 zcmZ4fNqqSy@eO6%jOLrmxqou9{A=WYxw%C2il#}o85&!fnk1Vfr#71ewwnYp0x=U1GXpWpc9TF>wgv3whQ=m_h8EKuKeEceINMV` zvL0t~Ha9Rga5J=Yax^z{GqZ4Uay4+VG%+wVbTo7}FfueSv{SGlq-1;EH`bj@0Ej$G AlK=n! delta 267 zcmZ4fNqqSy@eO6%jJBK0xqou9_}u4zytzd5i better privacy. + return "Not found"; + } + // return the request at requester_id + return invitations.at(requester_index); +} + +string AsyncInvitationDatabase::get_friend_public_key(size_t requester_index) { + // if requester_id does not exist, return + if (invitation_public_key.find(requester_index) == + invitation_public_key.end()) { + return "Not found"; + } + // return the request at requester_id + return invitation_public_key.at(requester_index); +} diff --git a/server/src/async_invitation_database.hpp b/server/src/async_invitation_database.hpp new file mode 100644 index 00000000..931cbeeb --- /dev/null +++ b/server/src/async_invitation_database.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "asphr/asphr.hpp" + +// A simple database with no security +// TODO: storing public key here is meaningless +// but it is required by libsodium. +// If we want to opimize friend_request space, +// we can try to remove this. +class AsyncInvitationDatabase { + public: + AsyncInvitationDatabase() + : invitations({}), invitation_public_key({}) {}; + + void register_user(size_t requester_index, const std::string& public_key); + void set_invitation(size_t requester_index, const std::string& invitation); + + string get_invitation(size_t requester_index); + + string get_friend_public_key(size_t requester_index); + + private: + std::map invitations{}; + // a temporary PKI for the friend request + // users do not actually need to trust this PKI. + std::map invitation_public_key{}; +}; diff --git a/server/src/server_constants.hpp b/server/src/server_constants.hpp new file mode 100644 index 00000000..c46b03df --- /dev/null +++ b/server/src/server_constants.hpp @@ -0,0 +1,13 @@ +// +// Copyright 2022 Anysphere, Inc. +// SPDX-License-Identifier: GPL-3.0-only +// + +#pragma once +#include "asphr/asphr.hpp" + +// Cap invitation length at 4KB to make sure we don't get things that are too +// big +constexpr int MAX_INVITATION_LENGTH = 4096; + +constexpr int MAX_ASYNC_INVITATION_BATCH_SIZE = 2000; \ No newline at end of file diff --git a/server/src/server_rpc.cc b/server/src/server_rpc.cc index c8e426f4..452e0117 100644 --- a/server/src/server_rpc.cc +++ b/server/src/server_rpc.cc @@ -1,6 +1,7 @@ #include "server_rpc.hpp" #include "beta_key_auth.hpp" +#include "server_constants.hpp" using grpc::ServerContext; using grpc::Status; @@ -27,12 +28,17 @@ Status ServerRpc::Register( (void)acks_allocation; assert(allocation == acks_allocation); auto [auth_token, allocation_vec] = account_manager.generate_account( - registerInfo->public_key(), allocation); + registerInfo->invitation_public_key(), allocation); + // todo: register to the friend async request database and "PKI" + // this might needs to be changed if there are multiple allocations + async_invitation_database.register_user( + allocation, registerInfo->invitation_public_key()); for (auto& alloc : allocation_vec) { registerResponse->add_allocation(alloc); } - registerResponse->set_public_key(registerInfo->public_key()); + registerResponse->set_public_key(registerInfo->invitation_public_key()); registerResponse->set_authentication_token(auth_token); + } catch (const AccountManagerException& e) { ASPHR_LOG_ERR("Could not access account maanger.", error, e.what(), rpc_call, "Register"); @@ -176,5 +182,88 @@ Status ServerRpc::ReceiveMessage( receiveMessageResponse->set_pir_answer_acks(std::move(answer_acks_string)); + return Status::OK; +} + +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- +// ||| friend_request ||| +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- +template +Status ServerRpc::AddAsyncInvitation( + ServerContext* context, + const AddAsyncInvitationInfo* addAsyncInvitationInfo, + AddAsyncInvitationResponse* addAsyncInvitationResponse) { + ASPHR_LOG_INFO("AddFriendAsync() called"); + auto index = addAsyncInvitationInfo->index(); + pir_index_t pir_index = index; + try { + if (!account_manager.valid_index_access( + addAsyncInvitationInfo->authentication_token(), pir_index)) { + ASPHR_LOG_ERR("incorrect authentication token"); + return Status(grpc::StatusCode::UNAUTHENTICATED, + "incorrect authentication token"); + } + } catch (const AccountManagerException& e) { + ASPHR_LOG_ERR("AccountManagerException: ", exception, e.what()); + return Status(grpc::StatusCode::UNAVAILABLE, e.what()); + } + + auto invitation = + addAsyncInvitationInfo->invitation(); // this is now a byte array + + if (std::ssize(invitation) > MAX_INVITATION_LENGTH) { + ASPHR_LOG_ERR("invitation too long"); + return Status(grpc::StatusCode::INVALID_ARGUMENT, "invitation too long"); + } + + async_invitation_database.set_invitation(index, std::string(invitation)); + + return Status::OK; +} + +template +Status ServerRpc::GetAsyncInvitations( + ServerContext* context, + const GetAsyncInvitationsInfo* getAsyncInvitationsInfo, + GetAsyncInvitationsResponse* getAsyncInvitationsResponse) { + ASPHR_LOG_INFO("Server rpc: GetAsyncInvitations() called"); + // cast to an int to make sure computation doesn't overflow/underflow + auto start_index = static_cast(getAsyncInvitationsInfo->start_index()); + auto end_index = static_cast(getAsyncInvitationsInfo->end_index()); + + if (start_index < 0) { + ASPHR_LOG_ERR("start_index is negative"); + return Status(grpc::StatusCode::INVALID_ARGUMENT, + "start_index is negative"); + } + + if (end_index - start_index > MAX_ASYNC_INVITATION_BATCH_SIZE) { + ASPHR_LOG_ERR("end_index - start_index too large") + return Status(grpc::StatusCode::INVALID_ARGUMENT, + "Attempt to download too many requests"); + } + + if (start_index > end_index) { + ASPHR_LOG_ERR("start_index > end_index"); + return Status(grpc::StatusCode::INVALID_ARGUMENT, + "start_index > end_index"); + } + + for (auto index = start_index; index < end_index; index++) { + string request = async_invitation_database.get_invitation(index); + string invitation_public_key = + async_invitation_database.get_friend_public_key(index); + // Do we need to return fake friend requests for unregistered + // entries? No we do not, cause the server can potentially do anything in + // our model. We are only exposing which slots are registered by not + // returning fake request, which for now can be easily achieved + // by registering a new account. + getAsyncInvitationsResponse->add_invitations(request); + getAsyncInvitationsResponse->add_invitation_public_key( + invitation_public_key); + } + return Status::OK; } \ No newline at end of file diff --git a/server/src/server_rpc.hpp b/server/src/server_rpc.hpp index 1388b8b7..f6514c71 100644 --- a/server/src/server_rpc.hpp +++ b/server/src/server_rpc.hpp @@ -9,6 +9,7 @@ #include "account_manager.hpp" #include "asphr/asphr.hpp" +#include "async_invitation_database.hpp" #include "schema/server.grpc.pb.h" template @@ -34,18 +35,30 @@ class ServerRpc final : public asphrserver::Server::Service { const asphrserver::ReceiveMessageInfo* receiveMessageInfo, asphrserver::ReceiveMessageResponse* receiveMessageResponse) override; + grpc::Status AddAsyncInvitation( + grpc::ServerContext* context, + const asphrserver::AddAsyncInvitationInfo* addAsyncInvitationInfo, + asphrserver::AddAsyncInvitationResponse* addFriendAsyncResponse) override; + + grpc::Status GetAsyncInvitations( + grpc::ServerContext* context, + const asphrserver::GetAsyncInvitationsInfo* getAsyncInvitationsInfo, + asphrserver::GetAsyncInvitationsResponse* getAsyncInvitationsResponse) + override; + // trunk-ignore(clang-tidy/bugprone-easily-swappable-parameters) - ServerRpc(PIR&& pir_arg, PIR&& pir_acks_arg, AccountManager&& account_manager_arg) + ServerRpc(PIR&& pir_arg, PIR&& pir_acks_arg, + AccountManager&& account_manager_arg) : pir(std::move(pir_arg)), pir_acks(std::move(pir_acks_arg)), account_manager(std::move(account_manager_arg)) { - auto pir_indices = account_manager.get_all_pir_indices(); - if (pir_indices.size() > 0) { - auto max_pir = *std::max_element(pir_indices.begin(), pir_indices.end()); - pir.allocate_to_max(max_pir); - pir_acks.allocate_to_max(max_pir); - } - } + auto pir_indices = account_manager.get_all_pir_indices(); + if (pir_indices.size() > 0) { + auto max_pir = *std::max_element(pir_indices.begin(), pir_indices.end()); + pir.allocate_to_max(max_pir); + pir_acks.allocate_to_max(max_pir); + } + } auto get_seal_slot_count() const { return pir.get_seal_slot_count(); } @@ -57,6 +70,7 @@ class ServerRpc final : public asphrserver::Server::Service { // requirements are slightly different! PIR pir_acks; // stores ACKs for every user AccountManager account_manager; + AsyncInvitationDatabase async_invitation_database; }; #include "server_rpc.cc" \ No newline at end of file diff --git a/server/src/server_rpc_test.cc b/server/src/server_rpc_test.cc index 7d14fc4d..d408697d 100644 --- a/server/src/server_rpc_test.cc +++ b/server/src/server_rpc_test.cc @@ -6,6 +6,7 @@ #include "server/pir/fast_pir/fastpir.hpp" using namespace asphrserver; +using namespace std::string_literals; TEST(ServerRpcTest, Register) { FastPIR pir; @@ -16,7 +17,8 @@ TEST(ServerRpcTest, Register) { { RegisterInfo request; - request.set_public_key("fake_public_key"); + + request.set_invitation_public_key("fake_public_key"); request.set_beta_key("asphr_magic"); RegisterResponse response; auto status = rpc.Register(nullptr, &request, &response); @@ -29,7 +31,6 @@ TEST(ServerRpcTest, Register) { TEST(ServerRpcTest, ExistingAccounts) { AccountManagerInMemory account_manager; - string authentication_token; vector allocation; @@ -41,7 +42,7 @@ TEST(ServerRpcTest, ExistingAccounts) { { RegisterInfo request; - request.set_public_key("fake_public_key"); + request.set_invitation_public_key("fake_public_key"); request.set_beta_key("asphr_magic"); RegisterResponse response; auto status = rpc.Register(nullptr, &request, &response); @@ -56,7 +57,7 @@ TEST(ServerRpcTest, ExistingAccounts) { { RegisterInfo request; - request.set_public_key("fake_public_key2"); + request.set_invitation_public_key("fake_public_key2"); request.set_beta_key("asphr_magic"); RegisterResponse response; auto status = rpc.Register(nullptr, &request, &response); @@ -94,7 +95,7 @@ TEST(ServerRpcTest, ExistingAccounts) { } { RegisterInfo request; - request.set_public_key("fake_public_key3"); + request.set_invitation_public_key("fake_public_key3"); request.set_beta_key("asphr_magic"); RegisterResponse response; auto status = rpc.Register(nullptr, &request, &response); @@ -116,7 +117,7 @@ TEST(ServerRpcTest, SendMessage) { vector allocation; { RegisterInfo request; - request.set_public_key("fake_public_key"); + request.set_invitation_public_key("fake_public_key"); request.set_beta_key("asphr_magic"); RegisterResponse response; auto status = rpc.Register(nullptr, &request, &response); @@ -160,7 +161,7 @@ TEST(ServerRpcTest, SendMessageIncorrectSize) { vector allocation; { RegisterInfo request; - request.set_public_key("fake_public_key"); + request.set_invitation_public_key("fake_public_key"); request.set_beta_key("asphr_magic"); RegisterResponse response; auto status = rpc.Register(nullptr, &request, &response); @@ -204,7 +205,7 @@ TEST(ServerRpcTest, SendMessageIncorrectSize2) { vector allocation; { RegisterInfo request; - request.set_public_key("fake_public_key"); + request.set_invitation_public_key("fake_public_key"); request.set_beta_key("asphr_magic"); RegisterResponse response; auto status = rpc.Register(nullptr, &request, &response); @@ -235,4 +236,100 @@ TEST(ServerRpcTest, SendMessageIncorrectSize2) { auto status = rpc.SendMessage(nullptr, &request, &response); EXPECT_FALSE(status.ok()); } -}; \ No newline at end of file +}; + +TEST(ServerRpcTest, AddGetAsyncInvitationMalformed) { + FastPIR pir; + FastPIR pir_acks; + AccountManagerInMemory account_manager; + auto rpc = ServerRpc( + std::move(pir), std::move(pir_acks), std::move(account_manager)); + + string authentication_token; + vector allocation; + auto public_key = "fake_pub\1\0\1lic_key"s; + { + RegisterInfo request; + request.set_invitation_public_key(public_key); + request.set_beta_key("asphr_magic"); + RegisterResponse response; + auto status = rpc.Register(nullptr, &request, &response); + EXPECT_TRUE(status.ok()); + EXPECT_EQ(response.public_key(), public_key); + EXPECT_GE(response.allocation_size(), 1); + authentication_token = response.authentication_token(); + for (const auto& i : response.allocation()) { + allocation.push_back(i); + } + } + + // good invitation + string invitation_0 = + "fake-invitation-which-is-encrypted-in-the-real-world\0\0-some-random-" + "bytes"s; + { + AddAsyncInvitationInfo request; + request.set_authentication_token(authentication_token); + request.set_index(allocation.at(0)); + request.set_invitation(invitation_0); + AddAsyncInvitationResponse response; + auto status = rpc.AddAsyncInvitation(nullptr, &request, &response); + EXPECT_TRUE(status.ok()); + } + + // too long invitation + { + AddAsyncInvitationInfo request; + request.set_authentication_token(authentication_token); + request.set_index(allocation.at(0)); + auto str = ""s; + for (int i = 0; i < MAX_INVITATION_LENGTH + 1; i++) { + str += "a"; + } + request.set_invitation(str); + AddAsyncInvitationResponse response; + auto status = rpc.AddAsyncInvitation(nullptr, &request, &response); + EXPECT_FALSE(status.ok()); + } + + // honest user + { + GetAsyncInvitationsInfo request; + request.set_start_index(allocation.at(0)); + request.set_end_index(allocation.at(0) + + MAX_ASYNC_INVITATION_BATCH_SIZE / 2); + GetAsyncInvitationsResponse response; + auto status = rpc.GetAsyncInvitations(nullptr, &request, &response); + EXPECT_TRUE(status.ok()); + EXPECT_EQ(response.invitations_size(), MAX_ASYNC_INVITATION_BATCH_SIZE / 2); + EXPECT_EQ(response.invitations(0), invitation_0); + EXPECT_EQ(response.invitation_public_key(0), public_key); + } + + // bad indices + { + GetAsyncInvitationsInfo request; + request.set_start_index(allocation.at(0)); + request.set_end_index(allocation.at(0) + MAX_ASYNC_INVITATION_BATCH_SIZE + + 1); + GetAsyncInvitationsResponse response; + auto status = rpc.GetAsyncInvitations(nullptr, &request, &response); + EXPECT_FALSE(status.ok()); + } + { + GetAsyncInvitationsInfo request; + request.set_start_index(allocation.at(0)); + request.set_end_index(-1); + GetAsyncInvitationsResponse response; + auto status = rpc.GetAsyncInvitations(nullptr, &request, &response); + EXPECT_FALSE(status.ok()); + } + { + GetAsyncInvitationsInfo request; + request.set_start_index(-1); + request.set_end_index(allocation.at(0)); + GetAsyncInvitationsResponse response; + auto status = rpc.GetAsyncInvitations(nullptr, &request, &response); + EXPECT_FALSE(status.ok()); + } +} \ No newline at end of file