diff --git a/.gitignore b/.gitignore index a4c04c4..2f06172 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ tmp/* tmp example example/* +db/* +db # gitginore template for creating Snap packages # website: https://snapcraft.io/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 8930401..9b305c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,17 +4,22 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [9.0.2] - 2021-04-25 +## [9.1.0] - 2021-04-02 + +### Added +- verify optional endpoint + +## [9.0.2] - 2021-03-25 ### Fixed - keys on event -## [9.0.0] - 2021-04-25 +## [9.0.0] - 2021-03-25 ### Removed - removed tenant_name from event - uses users event name -## [8.1.x] - 2021-04-25 +## [8.1.x] - 2021-03-25 ### Added - Adds http basic auth diff --git a/Cargo.lock b/Cargo.lock index d4a62a9..63a4227 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,7 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 - [[package]] name = "aead" version = "0.3.2" @@ -76,9 +74,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.38" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" +checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" [[package]] name = "arrayref" @@ -283,7 +281,7 @@ dependencies = [ "async-io", "async-lock", "async-process", - "crossbeam-utils 0.8.3", + "crossbeam-utils", "futures-channel", "futures-core", "futures-io", @@ -461,7 +459,7 @@ dependencies = [ [[package]] name = "broker" -version = "9.0.2" +version = "9.1.0" dependencies = [ "anyhow", "async-std", @@ -494,9 +492,9 @@ checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" [[package]] name = "byte-pool" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38e98299d518ec351ca016363e0cbfc77059dcd08dfa9700d15e405536097a" +checksum = "f8c7230ddbb427b1094d477d821a99f3f54d36333178eeb806e279bcdcecf0ca" dependencies = [ "crossbeam-queue", "stable_deref_trait", @@ -615,9 +613,9 @@ dependencies = [ [[package]] name = "const_fn" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6" +checksum = "076a6803b0dacd6a88cfe64deba628b01533ff5ef265687e6938280c1afd0a28" [[package]] name = "constant_time_eq" @@ -665,24 +663,12 @@ checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" [[package]] name = "crossbeam-queue" -version = "0.2.3" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" +checksum = "0f6cb3c7f5b8e51bc3ebb73a2327ad4abdbd119dc13223f14f961d2f38486756" dependencies = [ - "cfg-if 0.1.10", - "crossbeam-utils 0.7.2", - "maybe-uninit", -] - -[[package]] -name = "crossbeam-utils" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" -dependencies = [ - "autocfg", - "cfg-if 0.1.10", - "lazy_static", + "cfg-if 1.0.0", + "crossbeam-utils", ] [[package]] @@ -718,9 +704,9 @@ dependencies = [ [[package]] name = "ctor" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8f45d9ad417bcef4817d614a501ab55cdd96a6fdb24f49aab89a54acfd66b19" +checksum = "5e98e2ad1a782e33928b96fc3948e7c355e5af34ba4de7670fe8bac2a3b2006d" dependencies = [ "quote", "syn", @@ -759,27 +745,26 @@ checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" [[package]] name = "der-oid-macro" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd17d13ecf875e704369fdbde242483ac769fc18f6af21e43d5a692a079732fc" +checksum = "a4cccf60bb98c0fca115a581f894aed0e43fa55bf289fdac5599bec440bb4fd6" dependencies = [ "nom 6.1.2", - "num-bigint 0.3.2", + "num-bigint 0.4.0", "num-traits", - "proc-macro-hack", + "syn", ] [[package]] name = "der-parser" -version = "5.0.1" +version = "5.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e6cad1223a7b98b59275a56516ed8c40508d21284a32e404ed3fe2ae9a809a" +checksum = "120842c2385dea19347e2f6e31caa5dced5ba8afdfacaac16c59465fdd1168f2" dependencies = [ "der-oid-macro", "nom 6.1.2", - "num-bigint 0.3.2", + "num-bigint 0.4.0", "num-traits", - "proc-macro-hack", "rusticata-macros", ] @@ -1179,9 +1164,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.49" +version = "0.3.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc15e39392125075f60c95ba416f5381ff6c3a948ff02ab12464715adf56c821" +checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c" dependencies = [ "wasm-bindgen", ] @@ -1242,9 +1227,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.90" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4aede83fc3617411dc6993bc8c70919750c1c257c6ca6a502aed6e0e2394ae" +checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" [[package]] name = "libloading" @@ -1284,12 +1269,6 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" -[[package]] -name = "maybe-uninit" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" - [[package]] name = "memchr" version = "2.3.4" @@ -1298,9 +1277,9 @@ checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" [[package]] name = "nb-connect" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670361df1bc2399ee1ff50406a0d422587dd3bb0da596e1978fe8e05dabddf4f" +checksum = "a19900e7eee95eb2b3c2e26d12a874cc80aaf750e31be6fcbe743ead369fa45d" dependencies = [ "libc", "socket2", @@ -1356,9 +1335,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.3.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d0a3d5e207573f948a9e5376662aa743a2ea13f7c50a554d7af443a73fbfeba" +checksum = "4e0d047c1062aa51e256408c560894e5251f08925980e53cf1aa5bd00eec6512" dependencies = [ "autocfg", "num-integer", @@ -1446,18 +1425,18 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "pin-project" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96fa8ebb90271c4477f144354485b8068bd8f6b78b428b01ba892ca26caf0b63" +checksum = "bc174859768806e91ae575187ada95c91a29e96a98dc5d2cd9a1fed039501ba6" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758669ae3558c6f74bd2a18b41f7ac0b5a195aea6639d6a9b5e5d1ad5ba24c0b" +checksum = "a490329918e856ed1b083f244e3bfe2d8c4f336407e4ea9e1a9f479ff09049e5" dependencies = [ "proc-macro2", "quote", @@ -1484,11 +1463,11 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "polling" -version = "2.0.2" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2a7bc6b2a29e632e45451c941832803a18cce6781db04de8a04696cdca8bde4" +checksum = "4fc12d774e799ee9ebae13f4076ca003b40d18a11ac0f3641e6f899618580b7b" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "libc", "log", "wepoll-sys", @@ -1526,9 +1505,9 @@ checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" dependencies = [ "unicode-xid", ] @@ -1681,9 +1660,9 @@ dependencies = [ [[package]] name = "rmp" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f10b46df14cf1ee1ac7baa4d2fbc2c52c0622a4b82fa8740e37bc452ac0184f" +checksum = "4f55e5fa1446c4d5dd1f5daeed2a4fe193071771a2636274d0d7a3b082aa7ad6" dependencies = [ "byteorder", "num-traits", @@ -1691,9 +1670,9 @@ dependencies = [ [[package]] name = "rmp-serde" -version = "0.15.1" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f74489002493a9984ee753ebd049552a1c82f0740e347ee9fc57c907fb19f83" +checksum = "839395ef53057db96b84c9238ab29e1a13f2e5c8ec9f66bef853ab4197303924" dependencies = [ "byteorder", "rmp", @@ -1725,7 +1704,7 @@ dependencies = [ "base64 0.13.0", "blake2b_simd", "constant_time_eq", - "crossbeam-utils 0.8.3", + "crossbeam-utils", ] [[package]] @@ -1767,9 +1746,9 @@ dependencies = [ [[package]] name = "rustls-acme" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa2fc1ea3fc15c70f7cb9b72d21b6a6057ebff6a251a86aa678c1a6ee8ef0c85" +checksum = "6a1a94edf7334989d29752a3a0d9fdeb4e819f890e466a0505380d406dfc81c1" dependencies = [ "async-h1", "async-rustls", @@ -1828,18 +1807,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.124" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd761ff957cb2a45fbb9ab3da6512de9de55872866160b23c25f1a841e99d29f" +checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.124" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1800f7693e94e186f5e25a28291ae1570da908aff7d97a095dec1e56ff99069b" +checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" dependencies = [ "proc-macro2", "quote", @@ -1962,11 +1941,10 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" [[package]] name = "socket2" -version = "0.3.19" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" +checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2" dependencies = [ - "cfg-if 1.0.0", "libc", "winapi", ] @@ -1985,9 +1963,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "standback" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "decebb311175fdaf1bf8a14583716e93163c566db2ead1c1d608c3e1e4313cb8" +checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" dependencies = [ "version_check", ] @@ -2067,9 +2045,9 @@ checksum = "45f6ee7c7b87caf59549e9fe45d6a69c75c8019e79e212a835c5da0e92f0ba08" [[package]] name = "syn" -version = "1.0.64" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f" +checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87" dependencies = [ "proc-macro2", "quote", @@ -2320,9 +2298,9 @@ dependencies = [ [[package]] name = "vec-arena" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eafc1b9b2dfc6f5529177b62cf806484db55b32dc7c9658a118e11bbeb33061d" +checksum = "34b2f665b594b07095e3ac3f718e13c2197143416fae4c5706cffb7b1af8d7f1" [[package]] name = "vec_map" @@ -2356,9 +2334,9 @@ checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wasm-bindgen" -version = "0.2.72" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fe8f61dba8e5d645a4d8132dc7a0a66861ed5e1045d2c0ed940fab33bac0fbe" +checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9" dependencies = [ "cfg-if 1.0.0", "serde", @@ -2368,9 +2346,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.72" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046ceba58ff062da072c7cb4ba5b22a37f00a302483f7e2a6cdc18fedbdc1fd3" +checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae" dependencies = [ "bumpalo", "lazy_static", @@ -2383,9 +2361,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.22" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73157efb9af26fb564bb59a009afd1c7c334a44db171d280690d0c3faaec3468" +checksum = "81b8b767af23de6ac18bf2168b690bed2902743ddf0fb39252e36f9e2bfc63ea" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -2395,9 +2373,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.72" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9aa01d36cda046f797c57959ff5f3c615c9cc63997a8d545831ec7976819b" +checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2405,9 +2383,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.72" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96eb45c1b2ee33545a813a92dbb53856418bf7eb54ab34f7f7ff1448a5b3735d" +checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c" dependencies = [ "proc-macro2", "quote", @@ -2418,15 +2396,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.72" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7148f4696fb4960a346eaa60bbfb42a1ac4ebba21f750f75fc1375b098d5ffa" +checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489" [[package]] name = "web-sys" -version = "0.3.49" +version = "0.3.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fe19d70f5dacc03f6e46777213facae5ac3801575d56ca6cbd4c93dcd12310" +checksum = "a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be" dependencies = [ "js-sys", "wasm-bindgen", @@ -2444,9 +2422,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.21.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82015b7e0b8bad8185994674a13a93306bea76cf5a16c5a181382fd3a5ec2376" +checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" dependencies = [ "webpki", ] @@ -2508,18 +2486,16 @@ checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" [[package]] name = "x509-parser" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db7999ae290e75ec1d4dc8e9ff9870e48e3542a8f2e9c1e2e07d7ca02b459e10" +checksum = "64abca276c58f8341ddc13fd4bd6ae75993cc669043f5b34813c90f7dff04771" dependencies = [ "base64 0.13.0", "chrono", "data-encoding", - "der-oid-macro", "der-parser", "lazy_static", "nom 6.1.2", - "num-bigint 0.3.2", "oid-registry", "rusticata-macros", "rustversion", diff --git a/Cargo.toml b/Cargo.toml index 5670d0e..075ce34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "broker" -version = "9.0.2" +version = "9.1.0" authors = ["Bevan Hunt "] edition = "2018" license = "MIT" diff --git a/README.md b/README.md index f7cc2d6..c8d95ae 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ Broker follows an insert-only/publish/subscribe paradigm rather than a REST CRUD * Insert event via JSON POST request * Sync latest events on SSE client connection * Auto-provision and renews SSL cert via LetsEncrypt +* Verify endpoint for external services using Broker user system like [portal](https://crates.io/crates/portal) ### How it works @@ -109,6 +110,17 @@ POST /insert will return: `200` or `500` or `400` or `401` +#### Optional - verify user + +```html +GET /verify +``` +- authenticated endpoint (Authorization: Bearer {jwt}) or (Authorization: Basic {username:password}) +- verifies that the user is authenticated on broker - used for external services like [portal](https://crates.io/crates/portal) + +will return: `200` or `500` or `401` + + ### Install ``` cargo install broker ``` diff --git a/src/main.rs b/src/main.rs index 169f14b..729e35f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -268,32 +268,22 @@ async fn jwt_verify(token: String) -> Result>> { Ok(None) } -// insert an event -async fn insert(user_username: String, event_form: EventForm) -> Result { +async fn insert(user: User, event_form: EventForm) -> Result<()> { - let user_value = get_user_by_username(user_username)?; + let timestamp = nippy::get_unix_ntp_time().await?; + let id = uuid::Uuid::new_v4(); - match user_value { - Some(user) => { - let timestamp = nippy::get_unix_ntp_time().await?; - let id = uuid::Uuid::new_v4(); + let event = Event{ + id, + data: event_form.data, + event: event_form.event, + user_id: user.id, + timestamp, + tenant_name: user.tenant_name, + }; - let event = Event{ - id, - data: event_form.data, - event: event_form.event, - user_id: user.id, - timestamp, - tenant_name: user.tenant_name, - }; - - puts_event(event.clone())?; - Ok(true) - }, - None => { - Ok(false) - } - } + puts_event(event.clone())?; + Ok(()) } async fn create_user(mut req: Request<()>) -> tide::Result { @@ -334,8 +324,37 @@ async fn insert_event(mut req: Request<()>) -> tide::Result { Some(jwt) => { let r = req.body_string().await?; let event_form : EventForm = serde_json::from_str(&r)?; - insert(jwt.claims.sub, event_form).await?; - Ok(tide::Response::builder(200).header("content-type", "application/json").build()) + match get_user_by_username(jwt.claims.sub)? { + Some(user) => { + insert(user, event_form).await?; + Ok(tide::Response::builder(200).header("content-type", "application/json").build()) + }, + None => { Ok(tide::Response::builder(401).header("content-type", "application/json").build()) } + } + }, + None => { Ok(tide::Response::builder(401).header("content-type", "application/json").build()) } + } + }, + None => { Ok(tide::Response::builder(401).header("content-type", "application/json").build()) } + } +} + +async fn verify_user(req: Request<()>) -> tide::Result { + let token_value = req.header("authorization"); + match token_value { + Some(token_header) => { + let token = token_header.last().to_string(); + let jwt_value = jwt_verify(token).await?; + match jwt_value { + Some(jwt) => { + match get_user_by_username(jwt.claims.sub)? { + Some(_) => { + Ok(tide::Response::builder(200).header("content-type", "application/json").build()) + }, + None => { + Ok(tide::Response::builder(401).header("content-type", "application/json").build()) + } + } }, None => { Ok(tide::Response::builder(401).header("content-type", "application/json").build()) } } @@ -361,6 +380,7 @@ async fn main() -> tide::Result<()> { app.at("/insert").post(insert_event); app.at("/users").post(create_user); app.at("/login").post(login_user); + app.at("/verify").get(verify_user); app.at("/sse").get(tide::sse::endpoint(|req: Request<()>, sender| async move {