From 3a618c4da0a71ca8d4f6674a5796baf3b7607d0c Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Sat, 23 Dec 2023 19:17:47 +0530 Subject: [PATCH 01/45] refactored to rocket --- .vscode/settings.json | 7 + Cargo.lock | 355 ++++++++++++++++--------- Cargo.toml | 2 +- src/main.rs | 40 ++- src/organisation/controller.rs | 4 - src/organisation/mod.rs | 3 - src/organization/controller.rs | 12 + src/organization/mod.rs | 16 ++ src/organization/project/controller.rs | 15 ++ src/organization/project/mod.rs | 8 + src/project/controller.rs | 4 - src/project/mod.rs | 3 - src/routes/mod.rs | 3 - src/routes/v1.rs | 15 -- 14 files changed, 300 insertions(+), 187 deletions(-) create mode 100644 .vscode/settings.json delete mode 100644 src/organisation/controller.rs delete mode 100644 src/organisation/mod.rs create mode 100644 src/organization/controller.rs create mode 100644 src/organization/mod.rs create mode 100644 src/organization/project/controller.rs create mode 100644 src/organization/project/mod.rs delete mode 100644 src/project/controller.rs delete mode 100644 src/project/mod.rs delete mode 100644 src/routes/mod.rs delete mode 100644 src/routes/v1.rs diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..a059b70 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "rust-analyzer.linkedProjects": [ + ".\\Cargo.toml", + ".\\Cargo.toml", + ".\\Cargo.toml" + ] +} diff --git a/Cargo.lock b/Cargo.lock index 35c4777..8ac9e5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,9 +43,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.75" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +checksum = "59d2a3357dde987206219e78ecfbbb6e8dad06cbb65292758d3270e6254f7355" [[package]] name = "arrayvec" @@ -175,9 +175,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.4" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "binascii" @@ -220,9 +220,9 @@ checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" @@ -255,18 +255,17 @@ dependencies = [ "iana-time-zone", "num-traits", "serde", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] name = "colored" -version = "2.0.4" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" dependencies = [ - "is-terminal", "lazy_static", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -283,9 +282,9 @@ dependencies = [ [[package]] name = "cookie" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7efb37c3e1ccb1ff97164ad95ac1606e8ccd35b3fa0a7d99a304c7f4a428cc24" +checksum = "3cd91cf61412820176e137621345ee43b3f4423e589e7ae4e50d601d93e35ef8" dependencies = [ "percent-encoding", "time", @@ -294,9 +293,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -304,24 +303,24 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "cpufeatures" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" dependencies = [ "libc", ] [[package]] name = "crossbeam-channel" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +checksum = "14c3242926edf34aec4ac3a77108ad4854bffaa2e4ddc1824124ce59231302d5" dependencies = [ "cfg-if", "crossbeam-utils", @@ -329,9 +328,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f" dependencies = [ "cfg-if", ] @@ -490,7 +489,7 @@ checksum = "add4f07d43996f76ef320709726a556a9d4f965d9410d8d0271132d2f8293480" dependencies = [ "errno-dragonfly", "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -537,9 +536,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -715,7 +714,7 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", "bytes", "headers-core", "http", @@ -747,11 +746,11 @@ checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "home" -version = "0.5.5" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" dependencies = [ - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -830,9 +829,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http", @@ -856,16 +855,16 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.57" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows", + "windows-core", ] [[package]] @@ -895,7 +894,6 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", - "serde", ] [[package]] @@ -906,6 +904,7 @@ checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" dependencies = [ "equivalent", "hashbrown 0.14.1", + "serde", ] [[package]] @@ -916,9 +915,9 @@ checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" [[package]] name = "ipnet" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "is-terminal" @@ -928,7 +927,7 @@ checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", "rustix", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -948,9 +947,9 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" dependencies = [ "wasm-bindgen", ] @@ -961,9 +960,9 @@ version = "8.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", "pem", - "ring", + "ring 0.16.20", "serde", "serde_json", "simple_asn1", @@ -977,9 +976,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.148" +version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" [[package]] name = "linked-hash-map" @@ -1069,7 +1068,7 @@ dependencies = [ "libc", "log", "wasi", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1125,9 +1124,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", ] @@ -1274,7 +1273,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -1291,7 +1290,7 @@ checksum = "61a386cd715229d399604b50d1361683fe687066f42d56f54be995bc6868f71c" dependencies = [ "inlinable_string", "pear_codegen", - "yansi 1.0.0-rc.1", + "yansi", ] [[package]] @@ -1402,7 +1401,7 @@ dependencies = [ "quote", "syn 2.0.37", "version_check", - "yansi 1.0.0-rc.1", + "yansi", ] [[package]] @@ -1551,11 +1550,11 @@ checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "reqwest" -version = "0.11.22" +version = "0.11.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" +checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", "bytes", "encoding_rs", "futures-core", @@ -1599,11 +1598,25 @@ dependencies = [ "libc", "once_cell", "spin 0.5.2", - "untrusted", + "untrusted 0.7.1", "web-sys", "winapi", ] +[[package]] +name = "ring" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.48.0", +] + [[package]] name = "rmp" version = "0.8.12" @@ -1628,9 +1641,9 @@ dependencies = [ [[package]] name = "rocket" -version = "0.5.0-rc.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58734f7401ae5cfd129685b48f61182331745b357b96f2367f01aebaf1cc9cc9" +checksum = "9e7bb57ccb26670d73b6a47396c83139447b9e7878cab627fdfe9ea8da489150" dependencies = [ "async-stream", "async-trait", @@ -1640,8 +1653,7 @@ dependencies = [ "either", "figment", "futures", - "indexmap 1.9.3", - "is-terminal", + "indexmap 2.0.2", "log", "memchr", "multer", @@ -1661,37 +1673,38 @@ dependencies = [ "tokio-util", "ubyte", "version_check", - "yansi 0.5.1", + "yansi", ] [[package]] name = "rocket_codegen" -version = "0.5.0-rc.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7093353f14228c744982e409259fb54878ba9563d08214f2d880d59ff2fc508b" +checksum = "a2238066abf75f21be6cd7dc1a09d5414a671f4246e384e49fe3f8a4936bd04c" dependencies = [ "devise", "glob", - "indexmap 1.9.3", + "indexmap 2.0.2", "proc-macro2", "quote", "rocket_http", "syn 2.0.37", "unicode-xid", + "version_check", ] [[package]] name = "rocket_http" -version = "0.5.0-rc.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936012c99162a03a67f37f9836d5f938f662e26f2717809761a9ac46432090f4" +checksum = "37a1663694d059fe5f943ea5481363e48050acedd241d46deb2e27f71110389e" dependencies = [ "cookie", "either", "futures", "http", "hyper", - "indexmap 1.9.3", + "indexmap 2.0.2", "log", "memchr", "pear", @@ -1739,45 +1752,45 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "rustls" -version = "0.21.7" +version = "0.21.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ "log", - "ring", + "ring 0.17.7", "rustls-webpki", "sct", ] [[package]] name = "rustls-pemfile" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", ] [[package]] name = "rustls-webpki" -version = "0.101.6" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c7d5dece342910d9ba34d259310cae3e0154b873b35408b787b59bce53d34fe" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring", - "untrusted", + "ring 0.17.7", + "untrusted 0.9.0", ] [[package]] name = "rustrict" -version = "0.7.10" +version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f35794fdc3d71a3ac840726c688e7892e58ed71f407b48a975b9d41fc819e80" +checksum = "6d01a15a234aeba83b80a0bdbfa2f0298ed35e67632769633b25882b8314b567" dependencies = [ "arrayvec", "bitflags 1.3.2", @@ -1816,19 +1829,19 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sct" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring", - "untrusted", + "ring 0.17.7", + "untrusted 0.9.0", ] [[package]] name = "semver" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" dependencies = [ "serde", ] @@ -1919,9 +1932,9 @@ dependencies = [ [[package]] name = "shuttle-common" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc20a4545269e84b4a1fcea3d1ed9791cef0361c37f915770d94e392b0641f2" +checksum = "4062f00c2aec0987ab4e58a2ef9b23b241a6760e9d04f8c02d360652ad174720" dependencies = [ "anyhow", "async-trait", @@ -2104,7 +2117,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2130,9 +2143,9 @@ dependencies = [ [[package]] name = "state" -version = "0.5.3" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbe866e1e51e8260c9eed836a042a5e7f6726bb2b411dffeaa712e19c388f23b" +checksum = "2b8c4a4445d81357df8b1a650d0d0d6fbbbfe99d064aa5e02f3e4022061476d8" dependencies = [ "loom", ] @@ -2230,23 +2243,23 @@ dependencies = [ "fastrand", "redox_syscall", "rustix", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "thiserror" -version = "1.0.49" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" +checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.49" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" +checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" dependencies = [ "proc-macro2", "quote", @@ -2322,7 +2335,7 @@ dependencies = [ "signal-hook-registry", "socket2 0.5.4", "tokio-macros", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2627,9 +2640,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" [[package]] name = "unicode-ident" @@ -2664,6 +2677,12 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.4.1" @@ -2683,9 +2702,9 @@ checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" [[package]] name = "uuid" -version = "1.4.1" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" dependencies = [ "getrandom", "serde", @@ -2720,9 +2739,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2730,9 +2749,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" dependencies = [ "bumpalo", "log", @@ -2745,9 +2764,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" dependencies = [ "cfg-if", "js-sys", @@ -2757,9 +2776,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2767,9 +2786,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", @@ -2780,15 +2799,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" dependencies = [ "js-sys", "wasm-bindgen", @@ -2796,9 +2815,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.25.2" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" +checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" [[package]] name = "winapi" @@ -2828,7 +2847,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets 0.48.5", ] [[package]] @@ -2837,7 +2865,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", ] [[package]] @@ -2846,13 +2883,28 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] @@ -2861,42 +2913,84 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + [[package]] name = "winnow" version = "0.5.15" @@ -2913,17 +3007,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ "cfg-if", - "windows-sys", + "windows-sys 0.48.0", ] -[[package]] -name = "yansi" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" - [[package]] name = "yansi" version = "1.0.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1367295b8f788d371ce2dbc842c7b709c73ee1364d30351dd300ec2203b12377" +dependencies = [ + "is-terminal", +] diff --git a/Cargo.toml b/Cargo.toml index 9e4a2df..5bb4cb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ readme = "README.md" repository = "https://github.com/rustsea/shield/" [dependencies] -rocket = "0.5.0-rc.3" +rocket = "0.5.0" shuttle-rocket = "0.28.0" shuttle-runtime = "0.28.0" tokio = "1.32.0" diff --git a/src/main.rs b/src/main.rs index 0e04cc1..3a4f25d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,31 +1,27 @@ -mod constants; -mod routes; -mod organisation; -mod project; - -use routes::{get_routes, RouteKey}; -use organisation::{index as org_index}; -use project::{index as project_index}; - #[macro_use] extern crate rocket; +mod constants; +mod organization; -#[shuttle_runtime::main] -async fn rocket() -> shuttle_rocket::ShuttleRocket { - let rocket = rocket::build() - .mount("/", routes![index]) - .mount(&get_path(&RouteKey::Organisations), routes![org_index]) - .mount(&get_path(&RouteKey::Projects), routes![project_index]); - - Ok(rocket.into()) -} +use organization::org_routes; #[get("/")] fn index() -> &'static str { - "Hello World! It's your Shield" + "Hi! It's your Shield" } -fn get_path(route: &RouteKey) -> String { - let routes_map = get_routes(); - routes_map.get(route).map(|s|s.to_string()).expect("Route not found") +#[launch] +fn rocket() -> _ { + rocket::build() + .mount("/", routes![index]) + .mount("/organizations", org_routes()) } + +// #[shuttle_runtime::main] +// async fn rocket() -> shuttle_rocket::ShuttleRocket { +// let rocket = rocket::build() +// .mount("/", routes![index]) +// .mount("/organizations", org_routes()); + +// Ok(rocket.into()) +// } diff --git a/src/organisation/controller.rs b/src/organisation/controller.rs deleted file mode 100644 index eff078e..0000000 --- a/src/organisation/controller.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[get("/")] -pub fn index() -> &'static str { - "Hello from Shield, this is Organisations Route" -} \ No newline at end of file diff --git a/src/organisation/mod.rs b/src/organisation/mod.rs deleted file mode 100644 index 9f4d3f8..0000000 --- a/src/organisation/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod controller; - -pub use controller::{index}; diff --git a/src/organization/controller.rs b/src/organization/controller.rs new file mode 100644 index 0000000..f382881 --- /dev/null +++ b/src/organization/controller.rs @@ -0,0 +1,12 @@ +#[get("/")] +pub fn index() -> &'static str { + "Hello from Shield, this is Organizations Route" +} + +#[get("/")] +pub fn organization(organization_id: &str) -> String { + format!( + "Hello from Shield, this is Organizations Route for org_id: {}", + organization_id + ) +} diff --git a/src/organization/mod.rs b/src/organization/mod.rs new file mode 100644 index 0000000..b198427 --- /dev/null +++ b/src/organization/mod.rs @@ -0,0 +1,16 @@ +mod controller; +mod project; + +use controller::{index, organization}; +use project::project_routes; + +use rocket::Route; + +pub fn org_routes() -> Vec { + let mut _org_routes = routes![index, organization]; + let mut _project_routes = project_routes(); + + _org_routes.append(&mut _project_routes); + + _org_routes +} diff --git a/src/organization/project/controller.rs b/src/organization/project/controller.rs new file mode 100644 index 0000000..eabc6fa --- /dev/null +++ b/src/organization/project/controller.rs @@ -0,0 +1,15 @@ +#[get("//projects")] +pub fn projects(organization_id: &str) -> String { + format!( + "Hello from Shield, this is Projects belongs to org_id: {}", + organization_id + ) +} + +#[get("//projects/")] +pub fn project(organization_id: &str, project_id: &str) -> String { + format!( + "Hello from Shield, Project id: {} belongs to org_id: {}", + project_id, organization_id + ) +} diff --git a/src/organization/project/mod.rs b/src/organization/project/mod.rs new file mode 100644 index 0000000..e160749 --- /dev/null +++ b/src/organization/project/mod.rs @@ -0,0 +1,8 @@ +mod controller; + +pub use controller::{project, projects}; +use rocket::Route; + +pub fn project_routes() -> Vec { + routes![projects, project] +} diff --git a/src/project/controller.rs b/src/project/controller.rs deleted file mode 100644 index 87c7f52..0000000 --- a/src/project/controller.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[get("/")] -pub fn index() -> &'static str { - "Hello from Shield, this is Projects Route" -} \ No newline at end of file diff --git a/src/project/mod.rs b/src/project/mod.rs deleted file mode 100644 index 9f4d3f8..0000000 --- a/src/project/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod controller; - -pub use controller::{index}; diff --git a/src/routes/mod.rs b/src/routes/mod.rs deleted file mode 100644 index d1de2fc..0000000 --- a/src/routes/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod v1; - -pub use v1::{get_routes, RouteKey}; \ No newline at end of file diff --git a/src/routes/v1.rs b/src/routes/v1.rs deleted file mode 100644 index 417999a..0000000 --- a/src/routes/v1.rs +++ /dev/null @@ -1,15 +0,0 @@ -use std::collections::HashMap; - -#[derive(Eq, Hash, PartialEq)] -pub enum RouteKey { - Organisations, - Projects -} - -pub fn get_routes() -> HashMap { - let mut routes = HashMap::new(); - routes.insert(RouteKey::Organisations, "/organisations".to_string()); - routes.insert(RouteKey::Projects, "/projects".to_string()); - - routes -} \ No newline at end of file From 975f84a82b2185f2ed9aff944c32cccc90aa0ce0 Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Sat, 23 Dec 2023 19:45:06 +0530 Subject: [PATCH 02/45] dependencies fixation --- Cargo.lock | 1421 ++++++++++++++--------------------- Cargo.toml | 6 +- src/main.rs | 2 +- src/organisation/factory.rs | 10 - 4 files changed, 548 insertions(+), 891 deletions(-) delete mode 100644 src/organisation/factory.rs diff --git a/Cargo.lock b/Cargo.lock index 71775ea..0392610 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,185 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "actix-codec" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8" -dependencies = [ - "bitflags 1.3.2", - "bytes", - "futures-core", - "futures-sink", - "memchr", - "pin-project-lite", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "actix-http" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92ef85799cba03f76e4f7c10f533e66d87c9a7e7055f3391f09000ad8351bc9" -dependencies = [ - "actix-codec", - "actix-rt", - "actix-service", - "actix-utils", - "ahash", - "base64 0.21.4", - "bitflags 2.4.0", - "brotli", - "bytes", - "bytestring", - "derive_more", - "encoding_rs", - "flate2", - "futures-core", - "h2", - "http", - "httparse", - "httpdate", - "itoa", - "language-tags", - "local-channel", - "mime", - "percent-encoding", - "pin-project-lite", - "rand", - "sha1", - "smallvec", - "tokio", - "tokio-util", - "tracing", - "zstd", -] - -[[package]] -name = "actix-macros" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" -dependencies = [ - "quote", - "syn 2.0.38", -] - -[[package]] -name = "actix-router" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66ff4d247d2b160861fa2866457e85706833527840e4133f8f49aa423a38799" -dependencies = [ - "bytestring", - "http", - "regex", - "serde", - "tracing", -] - -[[package]] -name = "actix-rt" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28f32d40287d3f402ae0028a9d54bef51af15c8769492826a69d28f81893151d" -dependencies = [ - "futures-core", - "tokio", -] - -[[package]] -name = "actix-server" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eb13e7eef0423ea6eab0e59f6c72e7cb46d33691ad56a726b3cd07ddec2c2d4" -dependencies = [ - "actix-rt", - "actix-service", - "actix-utils", - "futures-core", - "futures-util", - "mio", - "socket2 0.5.4", - "tokio", - "tracing", -] - -[[package]] -name = "actix-service" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" -dependencies = [ - "futures-core", - "paste", - "pin-project-lite", -] - -[[package]] -name = "actix-utils" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" -dependencies = [ - "local-waker", - "pin-project-lite", -] - -[[package]] -name = "actix-web" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4a5b5e29603ca8c94a77c65cf874718ceb60292c5a5c3e5f4ace041af462b9" -dependencies = [ - "actix-codec", - "actix-http", - "actix-macros", - "actix-router", - "actix-rt", - "actix-server", - "actix-service", - "actix-utils", - "actix-web-codegen", - "ahash", - "bytes", - "bytestring", - "cfg-if", - "cookie", - "derive_more", - "encoding_rs", - "futures-core", - "futures-util", - "itoa", - "language-tags", - "log", - "mime", - "once_cell", - "pin-project-lite", - "regex", - "serde", - "serde_json", - "serde_urlencoded", - "smallvec", - "socket2 0.5.4", - "time", - "url", -] - -[[package]] -name = "actix-web-codegen" -version = "4.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1f50ebbb30eca122b188319a4398b3f7bb4a8cdf50ecfb73bfc6a3c3ce54f5" -dependencies = [ - "actix-router", - "proc-macro2", - "quote", - "syn 2.0.38", -] - [[package]] name = "addr2line" version = "0.21.0" @@ -196,42 +17,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "ahash" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" -dependencies = [ - "cfg-if", - "getrandom", - "once_cell", - "version_check", -] - [[package]] name = "aho-corasick" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] - [[package]] name = "android-tzdata" version = "0.1.1" @@ -278,18 +72,33 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.42", ] [[package]] name = "async-trait" -version = "0.1.73" +version = "0.1.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" +checksum = "fdf6721fb0140e4f897002dd086c06f6c27775df19cfe1fccb21181a48fd2c98" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.42", +] + +[[package]] +name = "atomic" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" + +[[package]] +name = "atomic" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994" +dependencies = [ + "bytemuck", ] [[package]] @@ -320,6 +129,8 @@ dependencies = [ "pin-project-lite", "rustversion", "serde", + "serde_json", + "serde_path_to_error", "sync_wrapper", "tower", "tower-layer", @@ -358,12 +169,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - [[package]] name = "base64" version = "0.21.5" @@ -384,9 +189,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "block-buffer" @@ -397,27 +202,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "brotli" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "516074a47ef4bce09577a3b379392300159ce5b1ba2e501ff1c819950066100f" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", -] - -[[package]] -name = "brotli-decompressor" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da74e2b81409b1b743f8f0c62cc6254afefb8b8e50bbfe3735550f7aeefa3448" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - [[package]] name = "bumpalo" version = "3.14.0" @@ -425,10 +209,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] -name = "byteorder" -version = "1.5.0" +name = "bytemuck" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" [[package]] name = "bytes" @@ -436,22 +220,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" -[[package]] -name = "bytestring" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "238e4886760d98c4f899360c834fa93e62cf7f721ac3c2da375cbdf4b8679aae" -dependencies = [ - "bytes", -] - [[package]] name = "cc" version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ - "jobserver", "libc", ] @@ -491,17 +265,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e959d788268e3bf9d35ace83e81b124190378e4c91c9067524675e33394b8ba" dependencies = [ "crossterm 0.26.1", - "strum", - "strum_macros", + "strum 0.24.1", + "strum_macros 0.24.3", "unicode-width", ] -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - [[package]] name = "cookie" version = "0.18.0" @@ -513,16 +281,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "core-foundation-sys" version = "0.8.6" @@ -538,15 +296,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - [[package]] name = "crossbeam-channel" version = "0.5.9" @@ -588,7 +337,7 @@ version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "crossterm_winapi", "libc", "mio", @@ -618,35 +367,45 @@ dependencies = [ ] [[package]] -name = "dashmap" -version = "5.5.3" +name = "deranged" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc" dependencies = [ - "cfg-if", - "hashbrown 0.14.1", - "lock_api", - "once_cell", - "parking_lot_core", + "powerfmt", ] [[package]] -name = "deranged" -version = "0.3.8" +name = "devise" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" +checksum = "d6eacefd3f541c66fc61433d65e54e0e46e0a029a819a7dbbc7a7b489e8a85f8" +dependencies = [ + "devise_codegen", + "devise_core", +] + +[[package]] +name = "devise_codegen" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8cf4b8dd484ede80fd5c547592c46c3745a617c8af278e2b72bea86b2dfed6" +dependencies = [ + "devise_core", + "quote", +] [[package]] -name = "derive_more" -version = "0.99.17" +name = "devise_core" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "35b50dba0afdca80b187392b24f2499a88c336d5a8493e4b4ccfb608708be56a" dependencies = [ - "convert_case", + "bitflags 2.4.1", "proc-macro2", + "proc-macro2-diagnostics", "quote", - "rustc_version", - "syn 1.0.109", + "syn 2.0.42", ] [[package]] @@ -665,12 +424,6 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" -[[package]] -name = "dunce" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" - [[package]] name = "either" version = "1.9.0" @@ -686,25 +439,40 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" -version = "0.3.4" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add4f07d43996f76ef320709726a556a9d4f965d9410d8d0271132d2f8293480" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "errno-dragonfly", "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] -name = "errno-dragonfly" -version = "0.1.2" +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "figment" +version = "0.10.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "649f3e5d826594057e9a519626304d8da859ea8a0b18ce99500c586b8d45faee" dependencies = [ - "cc", - "libc", + "atomic 0.6.0", + "pear", + "serde", + "toml", + "uncased", + "version_check", ] [[package]] @@ -713,16 +481,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" -[[package]] -name = "flate2" -version = "1.0.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - [[package]] name = "fnv" version = "1.0.7" @@ -740,9 +498,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" dependencies = [ "futures-channel", "futures-core", @@ -754,9 +512,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", "futures-sink", @@ -764,15 +522,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" dependencies = [ "futures-core", "futures-task", @@ -781,38 +539,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.42", ] [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-channel", "futures-core", @@ -826,6 +584,19 @@ dependencies = [ "slab", ] +[[package]] +name = "generator" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" +dependencies = [ + "cc", + "libc", + "log", + "rustversion", + "windows", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -838,26 +609,34 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] name = "gimli" -version = "0.28.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "h2" -version = "0.3.21" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" dependencies = [ "bytes", "fnv", @@ -865,7 +644,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 2.1.0", "slab", "tokio", "tokio-util", @@ -880,9 +659,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.1" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "headers" @@ -890,7 +669,7 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" dependencies = [ - "base64 0.21.5", + "base64", "bytes", "headers-core", "http", @@ -920,20 +699,11 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - [[package]] name = "http" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", @@ -942,9 +712,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", @@ -957,16 +727,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" -[[package]] -name = "http-serde" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f560b665ad9f1572cfcaf034f7fb84338a7ce945216d64a90fd81f046a3caee" -dependencies = [ - "http", - "serde", -] - [[package]] name = "httparse" version = "1.8.0" @@ -981,9 +741,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.27" +version = "0.14.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" dependencies = [ "bytes", "futures-channel", @@ -996,27 +756,13 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.9", + "socket2", "tokio", "tower-service", "tracing", "want", ] -[[package]] -name = "hyper-rustls" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" -dependencies = [ - "futures-util", - "http", - "hyper", - "rustls", - "tokio", - "tokio-rustls", -] - [[package]] name = "hyper-timeout" version = "0.4.1" @@ -1054,9 +800,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1074,12 +820,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown 0.14.1", + "hashbrown 0.14.3", "serde", ] @@ -1089,12 +835,6 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" -[[package]] -name = "ipnet" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" - [[package]] name = "is-terminal" version = "0.4.9" @@ -1116,19 +856,19 @@ dependencies = [ ] [[package]] -name = "itoa" -version = "1.0.9" +name = "itertools" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] [[package]] -name = "jobserver" -version = "0.1.26" +name = "itoa" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" -dependencies = [ - "libc", -] +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "js-sys" @@ -1141,24 +881,19 @@ dependencies = [ [[package]] name = "jsonwebtoken" -version = "8.3.0" +version = "9.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" +checksum = "5c7ea04a7c5c055c175f189b6dc6ba036fd62306b58c66c9f6389036c503a3f4" dependencies = [ - "base64 0.21.5", + "base64", + "js-sys", "pem", - "ring 0.16.20", + "ring", "serde", "serde_json", "simple_asn1", ] -[[package]] -name = "language-tags" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" - [[package]] name = "lazy_static" version = "1.4.0" @@ -1179,32 +914,15 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3852614a3bd9ca9804678ba6be5e3b8ce76dfc902cae004e3e0c44051b6e88db" - -[[package]] -name = "local-channel" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a493488de5f18c8ffcba89eebb8532ffc562dc400490eb65b84893fae0b178" -dependencies = [ - "futures-core", - "futures-sink", - "local-waker", -] - -[[package]] -name = "local-waker" -version = "0.1.3" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e34f76eb3611940e0e7d53a9aaa4e6a3151f69541a282fd0dad5571420c53ff1" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -1216,6 +934,21 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "loom" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "serde", + "serde_json", + "tracing", + "tracing-subscriber", +] + [[package]] name = "matchers" version = "0.1.0" @@ -1254,14 +987,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "log", "wasi", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1278,7 +1011,7 @@ dependencies = [ "log", "memchr", "mime", - "spin 0.9.8", + "spin", "tokio", "tokio-util", "version_check", @@ -1345,94 +1078,93 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opentelemetry" -version = "0.19.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4b8347cc26099d3aeee044065ecc3ae11469796b4d65d065a23a584ed92a6f" +checksum = "1e32339a5dc40459130b3bd269e9892439f55b33e772d2a9d402a789baaf4e8a" dependencies = [ - "opentelemetry_api", - "opentelemetry_sdk", + "futures-core", + "futures-sink", + "indexmap 2.1.0", + "js-sys", + "once_cell", + "pin-project-lite", + "thiserror", + "urlencoding", ] [[package]] name = "opentelemetry-http" -version = "0.8.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a819b71d6530c4297b49b3cae2939ab3a8cc1b9f382826a1bc29dd0ca3864906" +checksum = "7f51189ce8be654f9b5f7e70e49967ed894e84a06fc35c6c042e64ac1fc5399e" dependencies = [ "async-trait", "bytes", "http", - "opentelemetry_api", + "opentelemetry", ] [[package]] name = "opentelemetry-otlp" -version = "0.12.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8af72d59a4484654ea8eb183fea5ae4eb6a41d7ac3e3bae5f4d2a282a3a7d3ca" +checksum = "f24cda83b20ed2433c68241f918d0f6fdec8b1d43b7a9590ab4420c5095ca930" dependencies = [ "async-trait", - "futures", - "futures-util", + "futures-core", "http", "opentelemetry", "opentelemetry-proto", - "prost", + "opentelemetry-semantic-conventions", + "opentelemetry_sdk", + "prost 0.11.9", "thiserror", "tokio", - "tonic", + "tonic 0.9.2", ] [[package]] name = "opentelemetry-proto" -version = "0.2.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "045f8eea8c0fa19f7d48e7bc3128a39c2e5c533d5c61298c548dfefc1064474c" +checksum = "a2e155ce5cc812ea3d1dffbd1539aed653de4bf4882d60e6e04dcf0901d674e1" dependencies = [ - "futures", - "futures-util", "opentelemetry", - "prost", - "tonic", + "opentelemetry_sdk", + "prost 0.11.9", + "tonic 0.9.2", ] [[package]] -name = "opentelemetry_api" -version = "0.19.0" +name = "opentelemetry-semantic-conventions" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed41783a5bf567688eb38372f2b7a8530f5a607a4b49d38dd7573236c23ca7e2" +checksum = "f5774f1ef1f982ef2a447f6ee04ec383981a3ab99c8e77a1a7b30182e65bbc84" dependencies = [ - "fnv", - "futures-channel", - "futures-util", - "indexmap", - "once_cell", - "pin-project-lite", - "thiserror", - "urlencoding", + "opentelemetry", ] [[package]] name = "opentelemetry_sdk" -version = "0.19.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b3a2a91fdbfdd4d212c0dcc2ab540de2c2bcbbd90be17de7a7daf8822d010c1" +checksum = "968ba3f2ca03e90e5187f5e4f46c791ef7f2c163ae87789c8ce5f5ca3b7b7de5" dependencies = [ "async-trait", "crossbeam-channel", - "dashmap", - "fnv", "futures-channel", "futures-executor", "futures-util", + "glob", "once_cell", - "opentelemetry_api", + "opentelemetry", + "ordered-float", "percent-encoding", "rand", "thiserror", @@ -1440,6 +1172,15 @@ dependencies = [ "tokio-stream", ] +[[package]] +name = "ordered-float" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76df7075c7d4d01fdcb46c912dd17fba5b60c78ea480b475f2b6ab6f666584e" +dependencies = [ + "num-traits", +] + [[package]] name = "overload" version = "0.1.1" @@ -1458,9 +1199,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", @@ -1469,17 +1210,11 @@ dependencies = [ "windows-targets 0.48.5", ] -[[package]] -name = "paste" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" - [[package]] name = "pear" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a386cd715229d399604b50d1361683fe687066f42d56f54be995bc6868f71c" +checksum = "4ccca0f6c17acc81df8e242ed473ec144cbf5c98037e69aa6d144780aad103c8" dependencies = [ "inlinable_string", "pear_codegen", @@ -1488,30 +1223,31 @@ dependencies = [ [[package]] name = "pear_codegen" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f0f13dac8069c139e8300a6510e3f4143ecf5259c60b116a9b271b4ca0d54" +checksum = "2e22670e8eb757cff11d6c199ca7b987f352f0346e0be4dd23869ec72cb53c77" dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.37", + "syn 2.0.42", ] [[package]] name = "pem" -version = "1.1.1" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +checksum = "1b8fcc794035347fb64beda2d3b462595dd2753e3f268d89c5aae77e8cf2c310" dependencies = [ - "base64 0.13.1", + "base64", + "serde", ] [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project" @@ -1530,7 +1266,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.42", ] [[package]] @@ -1546,10 +1282,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] -name = "pkg-config" -version = "0.3.27" +name = "powerfmt" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" @@ -1583,9 +1319,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.67" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8" dependencies = [ "unicode-ident", ] @@ -1598,7 +1334,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.42", "version_check", "yansi", ] @@ -1610,7 +1346,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.11.9", +] + +[[package]] +name = "prost" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" +dependencies = [ + "bytes", + "prost-derive 0.12.3", ] [[package]] @@ -1620,19 +1366,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", - "itertools", + "itertools 0.10.5", "proc-macro2", "quote", "syn 1.0.109", ] +[[package]] +name = "prost-derive" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" +dependencies = [ + "anyhow", + "itertools 0.11.0", + "proc-macro2", + "quote", + "syn 2.0.42", +] + [[package]] name = "prost-types" -version = "0.11.9" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" +checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e" dependencies = [ - "prost", + "prost 0.12.3", ] [[package]] @@ -1676,23 +1435,43 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "ref-cast" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53313ec9f12686aeeffb43462c3ac77aa25f590a5f630eb2cde0de59417b29c7" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2566c4bf6845f2c2e83b27043c3f5dfcd5ba8f2937d6c00dc009bfb51a079dc4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.42", +] + [[package]] name = "regex" -version = "1.9.6" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebee201405406dbf528b8b672104ae6d6d63e6d118cb10e4d51abbc7b58044ff" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.9", - "regex-syntax 0.7.5", + "regex-automata 0.4.3", + "regex-syntax 0.8.2", ] [[package]] @@ -1706,13 +1485,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.9" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.5", + "regex-syntax 0.8.2", ] [[package]] @@ -1722,65 +1501,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] -name = "regex-syntax" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" - -[[package]] -name = "reqwest" -version = "0.11.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" -dependencies = [ - "base64 0.21.5", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-rustls", - "ipnet", - "js-sys", - "log", - "mime", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls", - "rustls-pemfile", - "serde", - "serde_json", - "serde_urlencoded", - "system-configuration", - "tokio", - "tokio-rustls", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "webpki-roots", - "winreg", -] - -[[package]] -name = "ring" -version = "0.16.20" +name = "regex-syntax" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin 0.5.2", - "untrusted 0.7.1", - "web-sys", - "winapi", -] +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "ring" @@ -1791,33 +1515,11 @@ dependencies = [ "cc", "getrandom", "libc", - "spin 0.9.8", - "untrusted 0.9.0", + "spin", + "untrusted", "windows-sys 0.48.0", ] -[[package]] -name = "rmp" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9860a6cc38ed1da53456442089b4dfa35e7cedaa326df63017af88385e6b20" -dependencies = [ - "byteorder", - "num-traits", - "paste", -] - -[[package]] -name = "rmp-serde" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bffea85eea980d8a74453e5d02a8d93028f3c34725de143085a844ebe953258a" -dependencies = [ - "byteorder", - "rmp", - "serde", -] - [[package]] name = "rocket" version = "0.5.0" @@ -1832,7 +1534,7 @@ dependencies = [ "either", "figment", "futures", - "indexmap 2.0.2", + "indexmap 2.1.0", "log", "memchr", "multer", @@ -1863,11 +1565,11 @@ checksum = "a2238066abf75f21be6cd7dc1a09d5414a671f4246e384e49fe3f8a4936bd04c" dependencies = [ "devise", "glob", - "indexmap 2.0.2", + "indexmap 2.1.0", "proc-macro2", "quote", "rocket_http", - "syn 2.0.37", + "syn 2.0.42", "unicode-xid", "version_check", ] @@ -1883,7 +1585,7 @@ dependencies = [ "futures", "http", "hyper", - "indexmap 2.0.2", + "indexmap 2.1.0", "log", "memchr", "pear", @@ -1899,16 +1601,6 @@ dependencies = [ "uncased", ] -[[package]] -name = "rust-shield" -version = "0.1.0" -dependencies = [ - "rocket", - "shuttle-rocket", - "shuttle-runtime", - "tokio", -] - [[package]] name = "rustc-demangle" version = "0.1.23" @@ -1921,70 +1613,30 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - [[package]] name = "rustix" -version = "0.38.17" +version = "0.38.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f25469e9ae0f3d0047ca8b93fc56843f38e6774f0914a107ff8b41be8be8e0b7" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "errno", "libc", "linux-raw-sys", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustls" -version = "0.21.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" -dependencies = [ - "log", - "ring 0.17.7", - "rustls-webpki", - "sct", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.5", -] - -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring 0.17.7", - "untrusted 0.9.0", + "windows-sys 0.52.0", ] [[package]] name = "rustrict" -version = "0.7.20" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d01a15a234aeba83b80a0bdbfa2f0298ed35e67632769633b25882b8314b567" +checksum = "cfe3300a40b60e76a856237ad1fe2210da1f40686705a2211688bb5742109a63" dependencies = [ "arrayvec", "bitflags 1.3.2", "doc-comment", "finl_unicode", - "itertools", + "itertools 0.10.5", "lazy_static", "rustc-hash", "strsim", @@ -1999,25 +1651,21 @@ checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] -name = "scopeguard" -version = "1.2.0" +name = "scoped-tls" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] -name = "sct" -version = "0.7.1" +name = "scopeguard" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring 0.17.7", - "untrusted 0.9.0", -] +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" @@ -2030,29 +1678,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.188" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.188" +version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.42", ] [[package]] name = "serde_json" -version = "1.0.107" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", @@ -2060,14 +1708,21 @@ dependencies = [ ] [[package]] -name = "serde_urlencoded" -version = "0.7.1" +name = "serde_path_to_error" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335" dependencies = [ - "form_urlencoded", "itoa", - "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ "serde", ] @@ -2095,40 +1750,29 @@ dependencies = [ name = "shield" version = "0.1.0" dependencies = [ - "actix-web", - "shuttle-actix-web", + "rocket", + "shuttle-rocket", "shuttle-runtime", "tokio", ] -[[package]] -name = "shuttle-actix-web" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "022820e4ab1af63c244b31a4a3a178689bd6843711110bc94bc9e8d2ab6377b3" -dependencies = [ - "actix-web", - "num_cpus", - "shuttle-runtime", -] - [[package]] name = "shuttle-codegen" -version = "0.28.0" +version = "0.34.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ee9844e18c0f10289d3c50de14b3838938a6b3eb7379edb2cf6c03f8fe4526" +checksum = "99f584e6f02d513abb864d5a33fb24531318080385eeac6160a9ccf2988b31bb" dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.42", ] [[package]] name = "shuttle-common" -version = "0.28.1" +version = "0.34.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4062f00c2aec0987ab4e58a2ef9b23b241a6760e9d04f8c02d360652ad174720" +checksum = "d0406c689a1edb0d12bd813d2b245619752ce0ad6122dad35c3f08ffccd2a40c" dependencies = [ "anyhow", "async-trait", @@ -2140,58 +1784,60 @@ dependencies = [ "headers", "http", "http-body", - "http-serde", "hyper", "jsonwebtoken", - "once_cell", "opentelemetry", "opentelemetry-http", "opentelemetry-otlp", + "opentelemetry_sdk", "pin-project", - "reqwest", - "rmp-serde", "rustrict", "semver", "serde", "serde_json", - "strum", + "strum 0.25.0", "thiserror", "tokio", - "tonic", + "tonic 0.10.2", "tower", "tower-http", "tracing", "tracing-opentelemetry", "tracing-subscriber", "ttl_cache", + "url", "uuid", + "zeroize", ] [[package]] name = "shuttle-proto" -version = "0.28.0" +version = "0.34.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5729607532b40dcbc02171014b2743df75353fcbffed2360d85a5710406f1b" +checksum = "aa63942eb5dfbc6370a82611f40254b9af28f323985d3c01be400baf729c1104" dependencies = [ - "anyhow", - "chrono", - "dunce", - "home", - "prost", + "futures-core", + "prost 0.12.3", "prost-types", - "serde_json", "shuttle-common", - "tokio", - "tonic", - "tower", - "tracing", + "tonic 0.10.2", +] + +[[package]] +name = "shuttle-rocket" +version = "0.34.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff89701c3433fd7f1137f69e4820a8e0ed09425c0c50356b4ae50a36d9bd7fba" +dependencies = [ + "rocket", + "shuttle-runtime", ] [[package]] name = "shuttle-runtime" -version = "0.28.0" +version = "0.34.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07ac03e0200ed33e2d1d800b17ea543bf016028ffac601f9280a845bd13206a9" +checksum = "4b8c49e755478841ae03351c3a4e7af99c684ce9757e5ddb0071d1ac42d33937" dependencies = [ "anyhow", "async-trait", @@ -2208,16 +1854,16 @@ dependencies = [ "thiserror", "tokio", "tokio-stream", - "tonic", + "tonic 0.10.2", "tower", "tracing-subscriber", ] [[package]] name = "shuttle-service" -version = "0.28.0" +version = "0.34.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad233e7c899cf075c8a637e0c6535532ffdd36d02d10519868e90038c7a3da40" +checksum = "b1c89dbd86fb79a791587317252daac5aa5026ed6fd73ce9f458acd30245bb13" dependencies = [ "anyhow", "async-trait", @@ -2280,36 +1926,20 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" - -[[package]] -name = "socket2" -version = "0.4.9" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" -dependencies = [ - "libc", - "winapi", -] +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "socket2" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", "windows-sys 0.48.0", ] -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - [[package]] name = "spin" version = "0.9.8" @@ -2351,8 +1981,14 @@ name = "strum" version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" dependencies = [ - "strum_macros", + "strum_macros 0.25.3", ] [[package]] @@ -2368,6 +2004,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.42", +] + [[package]] name = "syn" version = "1.0.109" @@ -2381,9 +2030,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.38" +version = "2.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +checksum = "5b7d0a2c048d661a1a59fcd7355baa232f7ed34e0ee4df2eef3c1c1c0d3852d8" dependencies = [ "proc-macro2", "quote", @@ -2396,32 +2045,11 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "tempfile" -version = "3.8.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", "fastrand", @@ -2447,7 +2075,7 @@ checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.42", ] [[package]] @@ -2462,12 +2090,13 @@ dependencies = [ [[package]] name = "time" -version = "0.3.29" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "426f806f4089c493dcac0d24c29c01e2c38baf8e30f1b716ee37e83d200b18fe" +checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" dependencies = [ "deranged", "itoa", + "powerfmt", "serde", "time-core", "time-macros", @@ -2481,9 +2110,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" dependencies = [ "time-core", ] @@ -2505,9 +2134,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.32.0" +version = "1.35.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" +checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" dependencies = [ "backtrace", "bytes", @@ -2517,7 +2146,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.4", + "socket2", "tokio-macros", "windows-sys 0.48.0", ] @@ -2534,23 +2163,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", -] - -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls", - "tokio", + "syn 2.0.42", ] [[package]] @@ -2566,9 +2185,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", @@ -2578,16 +2197,49 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +dependencies = [ + "indexmap 2.1.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tonic" -version = "0.8.3" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f219fad3b929bef19b1f86fbc0358d35daed8f2cac972037ac0dc10bbb8d5fb" +checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a" dependencies = [ - "async-stream", "async-trait", "axum", - "base64 0.13.1", + "base64", "bytes", "futures-core", "futures-util", @@ -2598,16 +2250,40 @@ dependencies = [ "hyper-timeout", "percent-encoding", "pin-project", - "prost", - "prost-derive", + "prost 0.11.9", + "tokio", + "tokio-stream", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tonic" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d560933a0de61cf715926b9cac824d4c883c2c43142f787595e48280c40a1d0e" +dependencies = [ + "async-stream", + "async-trait", + "axum", + "base64", + "bytes", + "h2", + "http", + "http-body", + "hyper", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost 0.12.3", "tokio", "tokio-stream", - "tokio-util", "tower", "tower-layer", "tower-service", "tracing", - "tracing-futures", ] [[package]] @@ -2618,7 +2294,7 @@ checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ "futures-core", "futures-util", - "indexmap", + "indexmap 1.9.3", "pin-project", "pin-project-lite", "rand", @@ -2636,7 +2312,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.1", "bytes", "futures-core", "futures-util", @@ -2663,11 +2339,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "log", "pin-project-lite", "tracing-attributes", @@ -2676,65 +2351,59 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.42", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", ] -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", -] - [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ - "lazy_static", "log", + "once_cell", "tracing-core", ] [[package]] name = "tracing-opentelemetry" -version = "0.19.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00a39dcf9bfc1742fa4d6215253b33a6e474be78275884c216fc2a06267b3600" +checksum = "c67ac25c5407e7b961fafc6f7e9aa5958fd297aada2d20fa2ae1737357e55596" dependencies = [ + "js-sys", "once_cell", "opentelemetry", + "opentelemetry_sdk", + "smallvec", "tracing", "tracing-core", "tracing-log", "tracing-subscriber", + "web-time", ] [[package]] name = "tracing-subscriber" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", "nu-ansi-term", @@ -2750,9 +2419,9 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "ttl_cache" @@ -2769,6 +2438,25 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "ubyte" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f720def6ce1ee2fc44d40ac9ed6d3a59c361c80a75a7aa8e75bb9baed31cf2ea" +dependencies = [ + "serde", +] + +[[package]] +name = "uncased" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b9bc53168a4be7402ab86c3aad243a84dd7381d09be0eddc81280c1da95ca68" +dependencies = [ + "serde", + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.14" @@ -2806,17 +2494,18 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" name = "untrusted" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -2883,22 +2572,10 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.42", "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "wasm-bindgen-macro" version = "0.2.89" @@ -2917,7 +2594,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.38", + "syn 2.0.42", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2929,21 +2606,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" [[package]] -name = "web-sys" -version = "0.3.66" +name = "web-time" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" +checksum = "57099a701fb3a8043f993e8228dc24229c7b942e2b009a1b962e54489ba1d3bf" dependencies = [ "js-sys", "wasm-bindgen", ] -[[package]] -name = "webpki-roots" -version = "0.25.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" - [[package]] name = "winapi" version = "0.3.9" @@ -3118,28 +2789,24 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.15" +version = "0.5.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" +checksum = "9b5c3db89721d50d0e2a673f5043fc4722f76dcc352d7b1ab8b8288bed4ed2c5" dependencies = [ "memchr", ] [[package]] -name = "winreg" -version = "0.50.0" +name = "yansi" +version = "1.0.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +checksum = "1367295b8f788d371ce2dbc842c7b709c73ee1364d30351dd300ec2203b12377" dependencies = [ - "cfg-if", - "windows-sys 0.48.0", + "is-terminal", ] [[package]] -name = "zstd-safe" -version = "6.0.6" +name = "zeroize" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1367295b8f788d371ce2dbc842c7b709c73ee1364d30351dd300ec2203b12377" -dependencies = [ - "is-terminal", -] +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/Cargo.toml b/Cargo.toml index 597f366..b3558f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,6 @@ edition = "2021" [dependencies] rocket = "0.5.0" -shuttle-rocket = "0.28.0" -shuttle-runtime = "0.28.0" -tokio = "1.26.0" +shuttle-rocket = "0.34.1" +shuttle-runtime = "0.34.1" +tokio = "1.35.0" diff --git a/src/main.rs b/src/main.rs index 3a4f25d..878afca 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ #[macro_use] extern crate rocket; -mod constants; + mod organization; use organization::org_routes; diff --git a/src/organisation/factory.rs b/src/organisation/factory.rs deleted file mode 100644 index 4e810a2..0000000 --- a/src/organisation/factory.rs +++ /dev/null @@ -1,10 +0,0 @@ -use actix_web::{Scope, web}; -use crate::organisation::controller::{index, org_info}; -use crate::project::factory::project_factory; - -pub fn organisation_factory () -> Scope { - web::scope("") - .service(index) - .service(org_info) - .service(web::scope("/{organisation_id}/projects").service(project_factory())) -} \ No newline at end of file From 66adcf66f8c4724410bdae57877f21de39621ddb Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Sat, 23 Dec 2023 19:49:11 +0530 Subject: [PATCH 03/45] conflict resolution --- Cargo.lock | 387 +++++++++------------------------------------------- src/main.rs | 15 -- 2 files changed, 67 insertions(+), 335 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0669826..0392610 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,10 +44,8 @@ dependencies = [ [[package]] name = "anyhow" version = "1.0.76" -version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59d2a3357dde987206219e78ecfbbb6e8dad06cbb65292758d3270e6254f7355" -checksum = "59d2a3357dde987206219e78ecfbbb6e8dad06cbb65292758d3270e6254f7355" [[package]] name = "arrayvec" @@ -178,10 +176,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] -name = "base64" -version = "0.21.4" +name = "binascii" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72" [[package]] name = "bitflags" @@ -211,10 +209,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] -name = "byteorder" -version = "1.4.3" +name = "bytemuck" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" [[package]] name = "bytes" @@ -283,16 +281,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "core-foundation-sys" version = "0.8.6" @@ -464,7 +452,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -681,7 +669,7 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" dependencies = [ - "base64 0.21.4", + "base64", "bytes", "headers-core", "http", @@ -711,15 +699,6 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" -[[package]] -name = "home" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" -dependencies = [ - "windows-sys", -] - [[package]] name = "http" version = "0.2.11" @@ -784,20 +763,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" -dependencies = [ - "futures-util", - "http", - "hyper", - "rustls", - "tokio", - "tokio-rustls", -] - [[package]] name = "hyper-timeout" version = "0.4.1" @@ -855,12 +820,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", - "hashbrown 0.14.1", + "hashbrown 0.14.3", "serde", ] @@ -870,12 +835,6 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" -[[package]] -name = "ipnet" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" - [[package]] name = "is-terminal" version = "0.4.9" @@ -926,9 +885,10 @@ version = "9.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c7ea04a7c5c055c175f189b6dc6ba036fd62306b58c66c9f6389036c503a3f4" dependencies = [ - "base64 0.21.4", + "base64", + "js-sys", "pem", - "ring 0.16.20", + "ring", "serde", "serde_json", "simple_asn1", @@ -1057,26 +1017,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "multer" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2" -dependencies = [ - "bytes", - "encoding_rs", - "futures-util", - "http", - "httparse", - "log", - "memchr", - "mime", - "spin 0.9.8", - "tokio", - "tokio-util", - "version_check", -] - [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -1274,7 +1214,24 @@ dependencies = [ name = "pear" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "4ccca0f6c17acc81df8e242ed473ec144cbf5c98037e69aa6d144780aad103c8" +dependencies = [ + "inlinable_string", + "pear_codegen", + "yansi", +] + +[[package]] +name = "pear_codegen" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e22670e8eb757cff11d6c199ca7b987f352f0346e0be4dd23869ec72cb53c77" +dependencies = [ + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn 2.0.42", +] [[package]] name = "pem" @@ -1369,6 +1326,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.42", + "version_check", + "yansi", +] + [[package]] name = "prost" version = "0.11.9" @@ -1534,47 +1504,7 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" name = "regex-syntax" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" - -[[package]] -name = "reqwest" -version = "0.11.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" -dependencies = [ - "base64 0.21.4", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-rustls", - "ipnet", - "js-sys", - "log", - "mime", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls", - "rustls-pemfile", - "serde", - "serde_json", - "serde_urlencoded", - "system-configuration", - "tokio", - "tokio-rustls", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "webpki-roots", - "winreg", -] +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "ring" @@ -1585,24 +1515,8 @@ dependencies = [ "cc", "getrandom", "libc", - "once_cell", "spin", "untrusted", - "web-sys", - "winapi", -] - -[[package]] -name = "ring" -version = "0.17.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" -dependencies = [ - "cc", - "getrandom", - "libc", - "spin 0.9.8", - "untrusted 0.9.0", "windows-sys 0.48.0", ] @@ -1687,97 +1601,6 @@ dependencies = [ "uncased", ] -[[package]] -name = "rocket" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e7bb57ccb26670d73b6a47396c83139447b9e7878cab627fdfe9ea8da489150" -dependencies = [ - "async-stream", - "async-trait", - "atomic 0.5.3", - "binascii", - "bytes", - "either", - "figment", - "futures", - "indexmap 2.0.2", - "log", - "memchr", - "multer", - "num_cpus", - "parking_lot", - "pin-project-lite", - "rand", - "ref-cast", - "rocket_codegen", - "rocket_http", - "serde", - "state", - "tempfile", - "time", - "tokio", - "tokio-stream", - "tokio-util", - "ubyte", - "version_check", - "yansi", -] - -[[package]] -name = "rocket_codegen" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2238066abf75f21be6cd7dc1a09d5414a671f4246e384e49fe3f8a4936bd04c" -dependencies = [ - "devise", - "glob", - "indexmap 2.0.2", - "proc-macro2", - "quote", - "rocket_http", - "syn 2.0.37", - "unicode-xid", - "version_check", -] - -[[package]] -name = "rocket_http" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a1663694d059fe5f943ea5481363e48050acedd241d46deb2e27f71110389e" -dependencies = [ - "cookie", - "either", - "futures", - "http", - "hyper", - "indexmap 2.0.2", - "log", - "memchr", - "pear", - "percent-encoding", - "pin-project-lite", - "ref-cast", - "serde", - "smallvec", - "stable-pattern", - "state", - "time", - "tokio", - "uncased", -] - -[[package]] -name = "rust-shield" -version = "0.1.0" -dependencies = [ - "rocket", - "shuttle-rocket", - "shuttle-runtime", - "tokio", -] - [[package]] name = "rustc-demangle" version = "0.1.23" @@ -1800,45 +1623,14 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys", -] - -[[package]] -name = "rustls" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" -dependencies = [ - "log", - "ring", - "rustls-webpki", - "sct", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" -dependencies = [ - "base64 0.21.4", -] - -[[package]] -name = "rustls-webpki" -version = "0.101.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c7d5dece342910d9ba34d259310cae3e0154b873b35408b787b59bce53d34fe" -dependencies = [ - "ring", - "untrusted", + "windows-sys 0.52.0", ] [[package]] name = "rustrict" -version = "0.7.10" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f35794fdc3d71a3ac840726c688e7892e58ed71f407b48a975b9d41fc819e80" +checksum = "cfe3300a40b60e76a856237ad1fe2210da1f40686705a2211688bb5742109a63" dependencies = [ "arrayvec", "bitflags 1.3.2", @@ -1875,16 +1667,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "sct" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "semver" version = "1.0.20" @@ -2170,15 +1952,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4564168c00635f88eaed410d5efa8131afa8d8699a612c80c455a0ba05c21045" dependencies = [ - "libc", - "windows-sys", + "memchr", ] [[package]] name = "state" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +checksum = "2b8c4a4445d81357df8b1a650d0d0d6fbbbfe99d064aa5e02f3e4022061476d8" +dependencies = [ + "loom", +] [[package]] name = "strfmt" @@ -2274,19 +2058,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "tempfile" -version = "3.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" -dependencies = [ - "cfg-if", - "fastrand", - "redox_syscall", - "rustix", - "windows-sys 0.48.0", -] - [[package]] name = "thiserror" version = "1.0.51" @@ -2805,18 +2576,6 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "wasm-bindgen-macro" version = "0.2.89" @@ -2847,21 +2606,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" [[package]] -name = "web-sys" -version = "0.3.64" +name = "web-time" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "57099a701fb3a8043f993e8228dc24229c7b942e2b009a1b962e54489ba1d3bf" dependencies = [ "js-sys", "wasm-bindgen", ] -[[package]] -name = "webpki-roots" -version = "0.25.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" - [[package]] name = "winapi" version = "0.3.9" @@ -3035,31 +2788,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] -name = "zstd" -version = "0.12.4" +name = "winnow" +version = "0.5.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" +checksum = "9b5c3db89721d50d0e2a673f5043fc4722f76dcc352d7b1ab8b8288bed4ed2c5" dependencies = [ "memchr", ] [[package]] -name = "zstd-safe" -version = "6.0.6" +name = "yansi" +version = "1.0.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" +checksum = "1367295b8f788d371ce2dbc842c7b709c73ee1364d30351dd300ec2203b12377" dependencies = [ - "libc", - "zstd-sys", + "is-terminal", ] [[package]] -name = "zstd-sys" -version = "2.0.8+zstd.1.5.5" +name = "zeroize" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" -dependencies = [ - "cc", - "libc", - "pkg-config", -] +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/src/main.rs b/src/main.rs index 69e46c5..878afca 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,18 +25,3 @@ fn rocket() -> _ { // Ok(rocket.into()) // } -#[launch] -fn rocket() -> _ { - rocket::build() - .mount("/", routes![index]) - .mount("/organizations", org_routes()) -} - -// #[shuttle_runtime::main] -// async fn rocket() -> shuttle_rocket::ShuttleRocket { -// let rocket = rocket::build() -// .mount("/", routes![index]) -// .mount("/organizations", org_routes()); - -// Ok(rocket.into()) -// } From 620074b706f9736ab9e8414c422fc4337f0e6996 Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Sun, 24 Dec 2023 00:40:44 +0530 Subject: [PATCH 04/45] database setup in-progress --- Cargo.lock | 223 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 4 + Rocket.toml | 2 + 3 files changed, 229 insertions(+) create mode 100644 Rocket.toml diff --git a/Cargo.lock b/Cargo.lock index 0392610..5ee1427 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -214,6 +214,12 @@ version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.5.0" @@ -366,6 +372,40 @@ dependencies = [ "typenum", ] +[[package]] +name = "deadpool" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "421fe0f90f2ab22016f32a9881be5134fdd71c65298917084b0c7477cbc3856e" +dependencies = [ + "async-trait", + "deadpool-runtime", + "num_cpus", + "retain_mut", + "tokio", +] + +[[package]] +name = "deadpool-postgres" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836a24a9d49deefe610b8b60c767a7412e9a931d79a89415cd2d2d71630ca8d7" +dependencies = [ + "deadpool", + "log", + "tokio", + "tokio-postgres", +] + +[[package]] +name = "deadpool-runtime" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63dfa964fe2a66f3fde91fc70b267fe193d822c7e603e2a675a49a7f46ad3f49" +dependencies = [ + "tokio", +] + [[package]] name = "deranged" version = "0.3.10" @@ -416,6 +456,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", + "subtle", ] [[package]] @@ -455,6 +496,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + [[package]] name = "fastrand" version = "2.0.1" @@ -699,6 +746,15 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "http" version = "0.2.11" @@ -964,6 +1020,16 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + [[package]] name = "memchr" version = "2.6.4" @@ -1249,6 +1315,24 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project" version = "1.1.3" @@ -1281,6 +1365,35 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "postgres-protocol" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49b6c5ef183cd3ab4ba005f1ca64c21e8bd97ce4699cfea9e8d9a2c4958ca520" +dependencies = [ + "base64", + "byteorder", + "bytes", + "fallible-iterator", + "hmac", + "md-5", + "memchr", + "rand", + "sha2", + "stringprep", +] + +[[package]] +name = "postgres-types" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d2234cdee9408b523530a9b6d2d6b373d1db34f6a8e51dc03ded1828d7fb67c" +dependencies = [ + "bytes", + "fallible-iterator", + "postgres-protocol", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -1506,6 +1619,12 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "retain_mut" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4389f1d5789befaf6029ebd9f7dac4af7f7e3d61b69d4f30e2ac02b57e7712b0" + [[package]] name = "ring" version = "0.17.7" @@ -1574,6 +1693,29 @@ dependencies = [ "version_check", ] +[[package]] +name = "rocket_db_pools" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0ebde3e24cbe917062b862136fd532d1ace80e0377a2f5fed541fadd764f1e5" +dependencies = [ + "deadpool", + "deadpool-postgres", + "rocket", + "rocket_db_pools_codegen", + "version_check", +] + +[[package]] +name = "rocket_db_pools_codegen" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "184a6f59eed0bf3d1cccb091960a2a1c89efa829b8a41158b269985a9c1bee95" +dependencies = [ + "devise", + "quote", +] + [[package]] name = "rocket_http" version = "0.5.0" @@ -1737,6 +1879,17 @@ dependencies = [ "digest", ] +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -1751,6 +1904,7 @@ name = "shield" version = "0.1.0" dependencies = [ "rocket", + "rocket_db_pools", "shuttle-rocket", "shuttle-runtime", "tokio", @@ -1915,6 +2069,12 @@ dependencies = [ "time", ] +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "slab" version = "0.4.9" @@ -1970,6 +2130,17 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a8348af2d9fc3258c8733b8d9d8db2e56f54b2363a4b5b81585c7875ed65e65" +[[package]] +name = "stringprep" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" +dependencies = [ + "finl_unicode", + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "strsim" version = "0.10.0" @@ -2017,6 +2188,12 @@ dependencies = [ "syn 2.0.42", ] +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + [[package]] name = "syn" version = "1.0.109" @@ -2172,6 +2349,32 @@ dependencies = [ "syn 2.0.42", ] +[[package]] +name = "tokio-postgres" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d340244b32d920260ae7448cb72b6e238bddc3d4f7603394e7dd46ed8e48f5b8" +dependencies = [ + "async-trait", + "byteorder", + "bytes", + "fallible-iterator", + "futures-channel", + "futures-util", + "log", + "parking_lot", + "percent-encoding", + "phf", + "pin-project-lite", + "postgres-protocol", + "postgres-types", + "rand", + "socket2", + "tokio", + "tokio-util", + "whoami", +] + [[package]] name = "tokio-stream" version = "0.1.14" @@ -2605,6 +2808,16 @@ version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" +[[package]] +name = "web-sys" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "web-time" version = "0.2.3" @@ -2615,6 +2828,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "whoami" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index b3558f7..c937528 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,3 +8,7 @@ rocket = "0.5.0" shuttle-rocket = "0.34.1" shuttle-runtime = "0.34.1" tokio = "1.35.0" + +[dependencies.rocket_db_pools] +version = "0.1.0" +features = ["deadpool_postgres"] diff --git a/Rocket.toml b/Rocket.toml new file mode 100644 index 0000000..20017e5 --- /dev/null +++ b/Rocket.toml @@ -0,0 +1,2 @@ +[default.databases.shield_db] +url = "postgresql://postgres:1234@localhost:5432/shield" From 61a0cb1d39d0dcc7761cd2f1a5b7564bfbc2b3da Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Tue, 17 Sep 2024 20:58:42 +0530 Subject: [PATCH 05/45] restored to initial stage --- Cargo.lock | 3028 ------------------------ Cargo.toml | 10 - src/main.rs | 28 +- src/organization/controller.rs | 12 - src/organization/mod.rs | 16 - src/organization/project/controller.rs | 15 - src/organization/project/mod.rs | 8 - src/project/factory.rs | 8 - 8 files changed, 2 insertions(+), 3123 deletions(-) delete mode 100644 src/organization/controller.rs delete mode 100644 src/organization/mod.rs delete mode 100644 src/organization/project/controller.rs delete mode 100644 src/organization/project/mod.rs delete mode 100644 src/project/factory.rs diff --git a/Cargo.lock b/Cargo.lock index 5ee1427..ebd3119 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,3034 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aho-corasick" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" -dependencies = [ - "memchr", -] - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anyhow" -version = "1.0.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59d2a3357dde987206219e78ecfbbb6e8dad06cbb65292758d3270e6254f7355" - -[[package]] -name = "arrayvec" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" - -[[package]] -name = "async-stream" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.42", -] - -[[package]] -name = "async-trait" -version = "0.1.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdf6721fb0140e4f897002dd086c06f6c27775df19cfe1fccb21181a48fd2c98" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.42", -] - -[[package]] -name = "atomic" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" - -[[package]] -name = "atomic" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994" -dependencies = [ - "bytemuck", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "axum" -version = "0.6.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" -dependencies = [ - "async-trait", - "axum-core", - "bitflags 1.3.2", - "bytes", - "futures-util", - "http", - "http-body", - "hyper", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "serde_json", - "serde_path_to_error", - "sync_wrapper", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http", - "http-body", - "mime", - "rustversion", - "tower-layer", - "tower-service", -] - -[[package]] -name = "backtrace" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "base64" -version = "0.21.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" - -[[package]] -name = "binascii" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bumpalo" -version = "3.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" - -[[package]] -name = "bytemuck" -version = "1.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" - -[[package]] -name = "cc" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "num-traits", - "serde", - "windows-targets 0.48.5", -] - -[[package]] -name = "colored" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" -dependencies = [ - "lazy_static", - "windows-sys 0.48.0", -] - -[[package]] -name = "comfy-table" -version = "6.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e959d788268e3bf9d35ace83e81b124190378e4c91c9067524675e33394b8ba" -dependencies = [ - "crossterm 0.26.1", - "strum 0.24.1", - "strum_macros 0.24.3", - "unicode-width", -] - -[[package]] -name = "cookie" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cd91cf61412820176e137621345ee43b3f4423e589e7ae4e50d601d93e35ef8" -dependencies = [ - "percent-encoding", - "time", - "version_check", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" - -[[package]] -name = "cpufeatures" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" -dependencies = [ - "libc", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c3242926edf34aec4ac3a77108ad4854bffaa2e4ddc1824124ce59231302d5" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossterm" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a84cda67535339806297f1b331d6dd6320470d2a0fe65381e79ee9e156dd3d13" -dependencies = [ - "bitflags 1.3.2", - "crossterm_winapi", - "libc", - "mio", - "parking_lot", - "signal-hook", - "signal-hook-mio", - "winapi", -] - -[[package]] -name = "crossterm" -version = "0.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" -dependencies = [ - "bitflags 2.4.1", - "crossterm_winapi", - "libc", - "mio", - "parking_lot", - "signal-hook", - "signal-hook-mio", - "winapi", -] - -[[package]] -name = "crossterm_winapi" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" -dependencies = [ - "winapi", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "deadpool" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "421fe0f90f2ab22016f32a9881be5134fdd71c65298917084b0c7477cbc3856e" -dependencies = [ - "async-trait", - "deadpool-runtime", - "num_cpus", - "retain_mut", - "tokio", -] - -[[package]] -name = "deadpool-postgres" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836a24a9d49deefe610b8b60c767a7412e9a931d79a89415cd2d2d71630ca8d7" -dependencies = [ - "deadpool", - "log", - "tokio", - "tokio-postgres", -] - -[[package]] -name = "deadpool-runtime" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63dfa964fe2a66f3fde91fc70b267fe193d822c7e603e2a675a49a7f46ad3f49" -dependencies = [ - "tokio", -] - -[[package]] -name = "deranged" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc" -dependencies = [ - "powerfmt", -] - -[[package]] -name = "devise" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6eacefd3f541c66fc61433d65e54e0e46e0a029a819a7dbbc7a7b489e8a85f8" -dependencies = [ - "devise_codegen", - "devise_core", -] - -[[package]] -name = "devise_codegen" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8cf4b8dd484ede80fd5c547592c46c3745a617c8af278e2b72bea86b2dfed6" -dependencies = [ - "devise_core", - "quote", -] - -[[package]] -name = "devise_core" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35b50dba0afdca80b187392b24f2499a88c336d5a8493e4b4ccfb608708be56a" -dependencies = [ - "bitflags 2.4.1", - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "syn 2.0.42", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "doc-comment" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" - -[[package]] -name = "either" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" - -[[package]] -name = "encoding_rs" -version = "0.8.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "fallible-iterator" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" - -[[package]] -name = "fastrand" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" - -[[package]] -name = "figment" -version = "0.10.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "649f3e5d826594057e9a519626304d8da859ea8a0b18ce99500c586b8d45faee" -dependencies = [ - "atomic 0.6.0", - "pear", - "serde", - "toml", - "uncased", - "version_check", -] - -[[package]] -name = "finl_unicode" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" - -[[package]] -name = "futures-executor" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" - -[[package]] -name = "futures-macro" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.42", -] - -[[package]] -name = "futures-sink" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" - -[[package]] -name = "futures-task" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" - -[[package]] -name = "futures-util" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generator" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" -dependencies = [ - "cc", - "libc", - "log", - "rustversion", - "windows", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" - -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "h2" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap 2.1.0", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" - -[[package]] -name = "headers" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" -dependencies = [ - "base64", - "bytes", - "headers-core", - "http", - "httpdate", - "mime", - "sha1", -] - -[[package]] -name = "headers-core" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" -dependencies = [ - "http", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hermit-abi" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "http" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "http-range-header" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper-timeout" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" -dependencies = [ - "hyper", - "pin-project-lite", - "tokio", - "tokio-io-timeout", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "idna" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - -[[package]] -name = "indexmap" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" -dependencies = [ - "equivalent", - "hashbrown 0.14.3", - "serde", -] - -[[package]] -name = "inlinable_string" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" - -[[package]] -name = "is-terminal" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" -dependencies = [ - "hermit-abi", - "rustix", - "windows-sys 0.48.0", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" - -[[package]] -name = "js-sys" -version = "0.3.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "jsonwebtoken" -version = "9.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7ea04a7c5c055c175f189b6dc6ba036fd62306b58c66c9f6389036c503a3f4" -dependencies = [ - "base64", - "js-sys", - "pem", - "ring", - "serde", - "serde_json", - "simple_asn1", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.151" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" - -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - -[[package]] -name = "linux-raw-sys" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" - -[[package]] -name = "lock_api" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "loom" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" -dependencies = [ - "cfg-if", - "generator", - "scoped-tls", - "serde", - "serde_json", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] - -[[package]] -name = "matchit" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" - -[[package]] -name = "md-5" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" -dependencies = [ - "cfg-if", - "digest", -] - -[[package]] -name = "memchr" -version = "2.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" -dependencies = [ - "libc", - "log", - "wasi", - "windows-sys 0.48.0", -] - -[[package]] -name = "multer" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2" -dependencies = [ - "bytes", - "encoding_rs", - "futures-util", - "http", - "httparse", - "log", - "memchr", - "mime", - "spin", - "tokio", - "tokio-util", - "version_check", -] - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "num-bigint" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "object" -version = "0.32.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "opentelemetry" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e32339a5dc40459130b3bd269e9892439f55b33e772d2a9d402a789baaf4e8a" -dependencies = [ - "futures-core", - "futures-sink", - "indexmap 2.1.0", - "js-sys", - "once_cell", - "pin-project-lite", - "thiserror", - "urlencoding", -] - -[[package]] -name = "opentelemetry-http" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f51189ce8be654f9b5f7e70e49967ed894e84a06fc35c6c042e64ac1fc5399e" -dependencies = [ - "async-trait", - "bytes", - "http", - "opentelemetry", -] - -[[package]] -name = "opentelemetry-otlp" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f24cda83b20ed2433c68241f918d0f6fdec8b1d43b7a9590ab4420c5095ca930" -dependencies = [ - "async-trait", - "futures-core", - "http", - "opentelemetry", - "opentelemetry-proto", - "opentelemetry-semantic-conventions", - "opentelemetry_sdk", - "prost 0.11.9", - "thiserror", - "tokio", - "tonic 0.9.2", -] - -[[package]] -name = "opentelemetry-proto" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2e155ce5cc812ea3d1dffbd1539aed653de4bf4882d60e6e04dcf0901d674e1" -dependencies = [ - "opentelemetry", - "opentelemetry_sdk", - "prost 0.11.9", - "tonic 0.9.2", -] - -[[package]] -name = "opentelemetry-semantic-conventions" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5774f1ef1f982ef2a447f6ee04ec383981a3ab99c8e77a1a7b30182e65bbc84" -dependencies = [ - "opentelemetry", -] - -[[package]] -name = "opentelemetry_sdk" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "968ba3f2ca03e90e5187f5e4f46c791ef7f2c163ae87789c8ce5f5ca3b7b7de5" -dependencies = [ - "async-trait", - "crossbeam-channel", - "futures-channel", - "futures-executor", - "futures-util", - "glob", - "once_cell", - "opentelemetry", - "ordered-float", - "percent-encoding", - "rand", - "thiserror", - "tokio", - "tokio-stream", -] - -[[package]] -name = "ordered-float" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76df7075c7d4d01fdcb46c912dd17fba5b60c78ea480b475f2b6ab6f666584e" -dependencies = [ - "num-traits", -] - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.48.5", -] - -[[package]] -name = "pear" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ccca0f6c17acc81df8e242ed473ec144cbf5c98037e69aa6d144780aad103c8" -dependencies = [ - "inlinable_string", - "pear_codegen", - "yansi", -] - -[[package]] -name = "pear_codegen" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e22670e8eb757cff11d6c199ca7b987f352f0346e0be4dd23869ec72cb53c77" -dependencies = [ - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "syn 2.0.42", -] - -[[package]] -name = "pem" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8fcc794035347fb64beda2d3b462595dd2753e3f268d89c5aae77e8cf2c310" -dependencies = [ - "base64", - "serde", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "phf" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" -dependencies = [ - "phf_shared", -] - -[[package]] -name = "phf_shared" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pin-project" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.42", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "postgres-protocol" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b6c5ef183cd3ab4ba005f1ca64c21e8bd97ce4699cfea9e8d9a2c4958ca520" -dependencies = [ - "base64", - "byteorder", - "bytes", - "fallible-iterator", - "hmac", - "md-5", - "memchr", - "rand", - "sha2", - "stringprep", -] - -[[package]] -name = "postgres-types" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d2234cdee9408b523530a9b6d2d6b373d1db34f6a8e51dc03ded1828d7fb67c" -dependencies = [ - "bytes", - "fallible-iterator", - "postgres-protocol", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.71" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "proc-macro2-diagnostics" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.42", - "version_check", - "yansi", -] - -[[package]] -name = "prost" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" -dependencies = [ - "bytes", - "prost-derive 0.11.9", -] - -[[package]] -name = "prost" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a" -dependencies = [ - "bytes", - "prost-derive 0.12.3", -] - -[[package]] -name = "prost-derive" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" -dependencies = [ - "anyhow", - "itertools 0.10.5", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "prost-derive" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" -dependencies = [ - "anyhow", - "itertools 0.11.0", - "proc-macro2", - "quote", - "syn 2.0.42", -] - -[[package]] -name = "prost-types" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e" -dependencies = [ - "prost 0.12.3", -] - -[[package]] -name = "quote" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "ref-cast" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53313ec9f12686aeeffb43462c3ac77aa25f590a5f630eb2cde0de59417b29c7" -dependencies = [ - "ref-cast-impl", -] - -[[package]] -name = "ref-cast-impl" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2566c4bf6845f2c2e83b27043c3f5dfcd5ba8f2937d6c00dc009bfb51a079dc4" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.42", -] - -[[package]] -name = "regex" -version = "1.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata 0.4.3", - "regex-syntax 0.8.2", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.8.2", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" - -[[package]] -name = "retain_mut" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4389f1d5789befaf6029ebd9f7dac4af7f7e3d61b69d4f30e2ac02b57e7712b0" - -[[package]] -name = "ring" -version = "0.17.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" -dependencies = [ - "cc", - "getrandom", - "libc", - "spin", - "untrusted", - "windows-sys 0.48.0", -] - -[[package]] -name = "rocket" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e7bb57ccb26670d73b6a47396c83139447b9e7878cab627fdfe9ea8da489150" -dependencies = [ - "async-stream", - "async-trait", - "atomic 0.5.3", - "binascii", - "bytes", - "either", - "figment", - "futures", - "indexmap 2.1.0", - "log", - "memchr", - "multer", - "num_cpus", - "parking_lot", - "pin-project-lite", - "rand", - "ref-cast", - "rocket_codegen", - "rocket_http", - "serde", - "state", - "tempfile", - "time", - "tokio", - "tokio-stream", - "tokio-util", - "ubyte", - "version_check", - "yansi", -] - -[[package]] -name = "rocket_codegen" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2238066abf75f21be6cd7dc1a09d5414a671f4246e384e49fe3f8a4936bd04c" -dependencies = [ - "devise", - "glob", - "indexmap 2.1.0", - "proc-macro2", - "quote", - "rocket_http", - "syn 2.0.42", - "unicode-xid", - "version_check", -] - -[[package]] -name = "rocket_db_pools" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0ebde3e24cbe917062b862136fd532d1ace80e0377a2f5fed541fadd764f1e5" -dependencies = [ - "deadpool", - "deadpool-postgres", - "rocket", - "rocket_db_pools_codegen", - "version_check", -] - -[[package]] -name = "rocket_db_pools_codegen" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "184a6f59eed0bf3d1cccb091960a2a1c89efa829b8a41158b269985a9c1bee95" -dependencies = [ - "devise", - "quote", -] - -[[package]] -name = "rocket_http" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a1663694d059fe5f943ea5481363e48050acedd241d46deb2e27f71110389e" -dependencies = [ - "cookie", - "either", - "futures", - "http", - "hyper", - "indexmap 2.1.0", - "log", - "memchr", - "pear", - "percent-encoding", - "pin-project-lite", - "ref-cast", - "serde", - "smallvec", - "stable-pattern", - "state", - "time", - "tokio", - "uncased", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustix" -version = "0.38.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" -dependencies = [ - "bitflags 2.4.1", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustrict" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe3300a40b60e76a856237ad1fe2210da1f40686705a2211688bb5742109a63" -dependencies = [ - "arrayvec", - "bitflags 1.3.2", - "doc-comment", - "finl_unicode", - "itertools 0.10.5", - "lazy_static", - "rustc-hash", - "strsim", - "unicode-normalization", -] - -[[package]] -name = "rustversion" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" - -[[package]] -name = "ryu" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "semver" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" -dependencies = [ - "serde", -] - -[[package]] -name = "serde" -version = "1.0.193" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.193" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.42", -] - -[[package]] -name = "serde_json" -version = "1.0.108" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_path_to_error" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335" -dependencies = [ - "itoa", - "serde", -] - -[[package]] -name = "serde_spanned" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" -dependencies = [ - "serde", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - [[package]] name = "shield" version = "0.1.0" -dependencies = [ - "rocket", - "rocket_db_pools", - "shuttle-rocket", - "shuttle-runtime", - "tokio", -] - -[[package]] -name = "shuttle-codegen" -version = "0.34.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99f584e6f02d513abb864d5a33fb24531318080385eeac6160a9ccf2988b31bb" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.42", -] - -[[package]] -name = "shuttle-common" -version = "0.34.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0406c689a1edb0d12bd813d2b245619752ce0ad6122dad35c3f08ffccd2a40c" -dependencies = [ - "anyhow", - "async-trait", - "axum", - "bytes", - "chrono", - "comfy-table", - "crossterm 0.27.0", - "headers", - "http", - "http-body", - "hyper", - "jsonwebtoken", - "opentelemetry", - "opentelemetry-http", - "opentelemetry-otlp", - "opentelemetry_sdk", - "pin-project", - "rustrict", - "semver", - "serde", - "serde_json", - "strum 0.25.0", - "thiserror", - "tokio", - "tonic 0.10.2", - "tower", - "tower-http", - "tracing", - "tracing-opentelemetry", - "tracing-subscriber", - "ttl_cache", - "url", - "uuid", - "zeroize", -] - -[[package]] -name = "shuttle-proto" -version = "0.34.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa63942eb5dfbc6370a82611f40254b9af28f323985d3c01be400baf729c1104" -dependencies = [ - "futures-core", - "prost 0.12.3", - "prost-types", - "shuttle-common", - "tonic 0.10.2", -] - -[[package]] -name = "shuttle-rocket" -version = "0.34.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff89701c3433fd7f1137f69e4820a8e0ed09425c0c50356b4ae50a36d9bd7fba" -dependencies = [ - "rocket", - "shuttle-runtime", -] - -[[package]] -name = "shuttle-runtime" -version = "0.34.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8c49e755478841ae03351c3a4e7af99c684ce9757e5ddb0071d1ac42d33937" -dependencies = [ - "anyhow", - "async-trait", - "chrono", - "colored", - "prost-types", - "serde", - "serde_json", - "shuttle-codegen", - "shuttle-common", - "shuttle-proto", - "shuttle-service", - "strfmt", - "thiserror", - "tokio", - "tokio-stream", - "tonic 0.10.2", - "tower", - "tracing-subscriber", -] - -[[package]] -name = "shuttle-service" -version = "0.34.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c89dbd86fb79a791587317252daac5aa5026ed6fd73ce9f458acd30245bb13" -dependencies = [ - "anyhow", - "async-trait", - "serde", - "shuttle-common", - "strfmt", - "thiserror", -] - -[[package]] -name = "signal-hook" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-mio" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" -dependencies = [ - "libc", - "mio", - "signal-hook", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" -dependencies = [ - "libc", -] - -[[package]] -name = "simple_asn1" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" -dependencies = [ - "num-bigint", - "num-traits", - "thiserror", - "time", -] - -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" - -[[package]] -name = "socket2" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" -dependencies = [ - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "stable-pattern" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4564168c00635f88eaed410d5efa8131afa8d8699a612c80c455a0ba05c21045" -dependencies = [ - "memchr", -] - -[[package]] -name = "state" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b8c4a4445d81357df8b1a650d0d0d6fbbbfe99d064aa5e02f3e4022061476d8" -dependencies = [ - "loom", -] - -[[package]] -name = "strfmt" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a8348af2d9fc3258c8733b8d9d8db2e56f54b2363a4b5b81585c7875ed65e65" - -[[package]] -name = "stringprep" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" -dependencies = [ - "finl_unicode", - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "strum" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" - -[[package]] -name = "strum" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" -dependencies = [ - "strum_macros 0.25.3", -] - -[[package]] -name = "strum_macros" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn 1.0.109", -] - -[[package]] -name = "strum_macros" -version = "0.25.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.42", -] - -[[package]] -name = "subtle" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b7d0a2c048d661a1a59fcd7355baa232f7ed34e0ee4df2eef3c1c1c0d3852d8" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "tempfile" -version = "3.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" -dependencies = [ - "cfg-if", - "fastrand", - "redox_syscall", - "rustix", - "windows-sys 0.48.0", -] - -[[package]] -name = "thiserror" -version = "1.0.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.42", -] - -[[package]] -name = "thread_local" -version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "time" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" -dependencies = [ - "deranged", - "itoa", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "time-macros" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" -dependencies = [ - "time-core", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.35.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "num_cpus", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys 0.48.0", -] - -[[package]] -name = "tokio-io-timeout" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" -dependencies = [ - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-macros" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.42", -] - -[[package]] -name = "tokio-postgres" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d340244b32d920260ae7448cb72b6e238bddc3d4f7603394e7dd46ed8e48f5b8" -dependencies = [ - "async-trait", - "byteorder", - "bytes", - "fallible-iterator", - "futures-channel", - "futures-util", - "log", - "parking_lot", - "percent-encoding", - "phf", - "pin-project-lite", - "postgres-protocol", - "postgres-types", - "rand", - "socket2", - "tokio", - "tokio-util", - "whoami", -] - -[[package]] -name = "tokio-stream" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - -[[package]] -name = "toml" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" -dependencies = [ - "indexmap 2.1.0", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - -[[package]] -name = "tonic" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a" -dependencies = [ - "async-trait", - "axum", - "base64", - "bytes", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-timeout", - "percent-encoding", - "pin-project", - "prost 0.11.9", - "tokio", - "tokio-stream", - "tower", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tonic" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d560933a0de61cf715926b9cac824d4c883c2c43142f787595e48280c40a1d0e" -dependencies = [ - "async-stream", - "async-trait", - "axum", - "base64", - "bytes", - "h2", - "http", - "http-body", - "hyper", - "hyper-timeout", - "percent-encoding", - "pin-project", - "prost 0.12.3", - "tokio", - "tokio-stream", - "tower", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "indexmap 1.9.3", - "pin-project", - "pin-project-lite", - "rand", - "slab", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-http" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" -dependencies = [ - "bitflags 2.4.1", - "bytes", - "futures-core", - "futures-util", - "http", - "http-body", - "http-range-header", - "pin-project-lite", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-layer" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.42", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-opentelemetry" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c67ac25c5407e7b961fafc6f7e9aa5958fd297aada2d20fa2ae1737357e55596" -dependencies = [ - "js-sys", - "once_cell", - "opentelemetry", - "opentelemetry_sdk", - "smallvec", - "tracing", - "tracing-core", - "tracing-log", - "tracing-subscriber", - "web-time", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "ttl_cache" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4189890526f0168710b6ee65ceaedf1460c48a14318ceec933cb26baa492096a" -dependencies = [ - "linked-hash-map", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "ubyte" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f720def6ce1ee2fc44d40ac9ed6d3a59c361c80a75a7aa8e75bb9baed31cf2ea" -dependencies = [ - "serde", -] - -[[package]] -name = "uncased" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b9bc53168a4be7402ab86c3aad243a84dd7381d09be0eddc81280c1da95ca68" -dependencies = [ - "serde", - "version_check", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-width" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - -[[package]] -name = "uuid" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" -dependencies = [ - "getrandom", - "serde", -] - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.42", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.42", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" - -[[package]] -name = "web-sys" -version = "0.3.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "web-time" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57099a701fb3a8043f993e8228dc24229c7b942e2b009a1b962e54489ba1d3bf" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "whoami" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" -dependencies = [ - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-core" -version = "0.51.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.0", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" -dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" - -[[package]] -name = "winnow" -version = "0.5.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b5c3db89721d50d0e2a673f5043fc4722f76dcc352d7b1ab8b8288bed4ed2c5" -dependencies = [ - "memchr", -] - -[[package]] -name = "yansi" -version = "1.0.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1367295b8f788d371ce2dbc842c7b709c73ee1364d30351dd300ec2203b12377" -dependencies = [ - "is-terminal", -] - -[[package]] -name = "zeroize" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/Cargo.toml b/Cargo.toml index c937528..4062252 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,13 +2,3 @@ name = "shield" version = "0.1.0" edition = "2021" - -[dependencies] -rocket = "0.5.0" -shuttle-rocket = "0.34.1" -shuttle-runtime = "0.34.1" -tokio = "1.35.0" - -[dependencies.rocket_db_pools] -version = "0.1.0" -features = ["deadpool_postgres"] diff --git a/src/main.rs b/src/main.rs index 878afca..f6320bc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,27 +1,3 @@ -#[macro_use] -extern crate rocket; - -mod organization; - -use organization::org_routes; - -#[get("/")] -fn index() -> &'static str { - "Hi! It's your Shield" +fn main() { + println!("Hello World"); } - -#[launch] -fn rocket() -> _ { - rocket::build() - .mount("/", routes![index]) - .mount("/organizations", org_routes()) -} - -// #[shuttle_runtime::main] -// async fn rocket() -> shuttle_rocket::ShuttleRocket { -// let rocket = rocket::build() -// .mount("/", routes![index]) -// .mount("/organizations", org_routes()); - -// Ok(rocket.into()) -// } diff --git a/src/organization/controller.rs b/src/organization/controller.rs deleted file mode 100644 index f382881..0000000 --- a/src/organization/controller.rs +++ /dev/null @@ -1,12 +0,0 @@ -#[get("/")] -pub fn index() -> &'static str { - "Hello from Shield, this is Organizations Route" -} - -#[get("/")] -pub fn organization(organization_id: &str) -> String { - format!( - "Hello from Shield, this is Organizations Route for org_id: {}", - organization_id - ) -} diff --git a/src/organization/mod.rs b/src/organization/mod.rs deleted file mode 100644 index b198427..0000000 --- a/src/organization/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -mod controller; -mod project; - -use controller::{index, organization}; -use project::project_routes; - -use rocket::Route; - -pub fn org_routes() -> Vec { - let mut _org_routes = routes![index, organization]; - let mut _project_routes = project_routes(); - - _org_routes.append(&mut _project_routes); - - _org_routes -} diff --git a/src/organization/project/controller.rs b/src/organization/project/controller.rs deleted file mode 100644 index eabc6fa..0000000 --- a/src/organization/project/controller.rs +++ /dev/null @@ -1,15 +0,0 @@ -#[get("//projects")] -pub fn projects(organization_id: &str) -> String { - format!( - "Hello from Shield, this is Projects belongs to org_id: {}", - organization_id - ) -} - -#[get("//projects/")] -pub fn project(organization_id: &str, project_id: &str) -> String { - format!( - "Hello from Shield, Project id: {} belongs to org_id: {}", - project_id, organization_id - ) -} diff --git a/src/organization/project/mod.rs b/src/organization/project/mod.rs deleted file mode 100644 index e160749..0000000 --- a/src/organization/project/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -mod controller; - -pub use controller::{project, projects}; -use rocket::Route; - -pub fn project_routes() -> Vec { - routes![projects, project] -} diff --git a/src/project/factory.rs b/src/project/factory.rs deleted file mode 100644 index f062831..0000000 --- a/src/project/factory.rs +++ /dev/null @@ -1,8 +0,0 @@ -use actix_web::{Scope, web}; -use crate::project::controller::{index, project_info}; - -pub fn project_factory () -> Scope { - web::scope("") - .service(index) - .service(project_info) -} \ No newline at end of file From 331cc3e6e770075e826c7b05478861d07f697377 Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Wed, 18 Sep 2024 10:36:06 +0530 Subject: [PATCH 06/45] schema in progress --- .gitignore | 1 + Cargo.lock | 1197 +++++++++++++++++ Cargo.toml | 10 + diesel.toml | 9 + migrations/.keep | 0 .../down.sql | 6 + .../up.sql | 36 + .../down.sql | 35 + .../up.sql | 159 +++ src/main.rs | 3 + src/models/db.rs | 0 src/models/mod.rs | 1 + src/schemas/db.rs | 137 ++ src/schemas/mod.rs | 1 + 14 files changed, 1595 insertions(+) create mode 100644 diesel.toml create mode 100644 migrations/.keep create mode 100644 migrations/00000000000000_diesel_initial_setup/down.sql create mode 100644 migrations/00000000000000_diesel_initial_setup/up.sql create mode 100644 migrations/2024-09-17-162851_initial_shield_db/down.sql create mode 100644 migrations/2024-09-17-162851_initial_shield_db/up.sql create mode 100644 src/models/db.rs create mode 100644 src/models/mod.rs create mode 100644 src/schemas/db.rs create mode 100644 src/schemas/mod.rs diff --git a/.gitignore b/.gitignore index a1a5734..d1b731a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target Secrets*.toml +.env* \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index ebd3119..6d572c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,1203 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "async-trait" +version = "0.1.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "axum" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +dependencies = [ + "async-trait", + "axum-core", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper 1.0.1", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets", +] + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cpufeatures" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "cuid-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d59a706635108a7e8eaae7ec8e6154504fafa4a415ef38690d94fccea051757" + +[[package]] +name = "cuid2" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50e281dc36864ea88fae2ec4e21eb280e8239487acb1ddc59b528b0afa7997bd" +dependencies = [ + "cuid-util", + "getrandom", + "num", + "rand", + "sha3", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "diesel" +version = "2.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "158fe8e2e68695bd615d7e4f3227c0727b151330d3e253b525086c348d055d5e" +dependencies = [ + "bitflags", + "byteorder", + "diesel_derives", + "itoa", + "pq-sys", +] + +[[package]] +name = "diesel_derives" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f2c3de51e2ba6bf2a648285696137aaf0f5f487bcbea93972fe8a364e131a4" +dependencies = [ + "diesel_table_macro_syntax", + "dsl_auto_type", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "diesel_table_macro_syntax" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25" +dependencies = [ + "syn", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "dsl_auto_type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5d9abe6314103864cc2d8901b7ae224e0ab1a103a0a416661b4097b0779b607" +dependencies = [ + "darling", + "either", + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", +] + +[[package]] +name = "hyper-util" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da62f120a8a37763efb0cf8fdf264b884c7b8b9ac8660b900c8661030c00e6ba" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "libc" +version = "0.2.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi", + "libc", + "wasi", + "windows-sys", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "object" +version = "0.36.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "pq-sys" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92c30dd81695321846d4dfe348da67b1752ebb61cd1549d203a7b57e323c435" +dependencies = [ + "vcpkg", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" +dependencies = [ + "bitflags", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" +dependencies = [ + "itoa", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + [[package]] name = "shield" version = "0.1.0" +dependencies = [ + "axum", + "cuid2", + "diesel", + "dotenvy", + "serde", + "serde_json", + "thiserror", + "tokio", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" + +[[package]] +name = "thiserror" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio" +version = "1.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index 4062252..991aae9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,3 +2,13 @@ name = "shield" version = "0.1.0" edition = "2021" + +[dependencies] +axum = "0.7.5" +cuid2 = "0.1.3" +diesel = { version = "2.2.4", features = ["postgres"] } +dotenvy = "0.15.7" +serde = { version = "1.0.210", features = ["derive"] } +serde_json = "1.0.128" +thiserror = "1.0.63" +tokio = { version = "1.40.0", features = ["full"] } diff --git a/diesel.toml b/diesel.toml new file mode 100644 index 0000000..aaef931 --- /dev/null +++ b/diesel.toml @@ -0,0 +1,9 @@ +# For documentation on how to configure this file, +# see https://diesel.rs/guides/configuring-diesel-cli + +[print_schema] +file = "src/schemas/db.rs" +custom_type_derives = ["diesel::query_builder::QueryId", "Clone"] + +[migrations_directory] +dir = "migrations" diff --git a/migrations/.keep b/migrations/.keep new file mode 100644 index 0000000..e69de29 diff --git a/migrations/00000000000000_diesel_initial_setup/down.sql b/migrations/00000000000000_diesel_initial_setup/down.sql new file mode 100644 index 0000000..a9f5260 --- /dev/null +++ b/migrations/00000000000000_diesel_initial_setup/down.sql @@ -0,0 +1,6 @@ +-- This file was automatically created by Diesel to setup helper functions +-- and other internal bookkeeping. This file is safe to edit, any future +-- changes will be added to existing projects as new migrations. + +DROP FUNCTION IF EXISTS diesel_manage_updated_at(_tbl regclass); +DROP FUNCTION IF EXISTS diesel_set_updated_at(); diff --git a/migrations/00000000000000_diesel_initial_setup/up.sql b/migrations/00000000000000_diesel_initial_setup/up.sql new file mode 100644 index 0000000..d68895b --- /dev/null +++ b/migrations/00000000000000_diesel_initial_setup/up.sql @@ -0,0 +1,36 @@ +-- This file was automatically created by Diesel to setup helper functions +-- and other internal bookkeeping. This file is safe to edit, any future +-- changes will be added to existing projects as new migrations. + + + + +-- Sets up a trigger for the given table to automatically set a column called +-- `updated_at` whenever the row is modified (unless `updated_at` was included +-- in the modified columns) +-- +-- # Example +-- +-- ```sql +-- CREATE TABLE users (id SERIAL PRIMARY KEY, updated_at TIMESTAMP NOT NULL DEFAULT NOW()); +-- +-- SELECT diesel_manage_updated_at('users'); +-- ``` +CREATE OR REPLACE FUNCTION diesel_manage_updated_at(_tbl regclass) RETURNS VOID AS $$ +BEGIN + EXECUTE format('CREATE TRIGGER set_updated_at BEFORE UPDATE ON %s + FOR EACH ROW EXECUTE PROCEDURE diesel_set_updated_at()', _tbl); +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION diesel_set_updated_at() RETURNS trigger AS $$ +BEGIN + IF ( + NEW IS DISTINCT FROM OLD AND + NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at + ) THEN + NEW.updated_at := current_timestamp; + END IF; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; diff --git a/migrations/2024-09-17-162851_initial_shield_db/down.sql b/migrations/2024-09-17-162851_initial_shield_db/down.sql new file mode 100644 index 0000000..192a426 --- /dev/null +++ b/migrations/2024-09-17-162851_initial_shield_db/down.sql @@ -0,0 +1,35 @@ +-- Drop the trigger +DROP TRIGGER IF EXISTS maintain_single_default_resource ON resource; + +-- Drop the function +DROP FUNCTION IF EXISTS update_default_resource(); + +-- Drop the resource table +DROP TABLE IF EXISTS resource; + +-- Drop the authenticator table +DROP TABLE IF EXISTS authenticator; + +-- Drop the two_factor_confirmation table +DROP TABLE IF EXISTS two_factor_confirmation; + +-- Drop the two_factor_token table +DROP TABLE IF EXISTS two_factor_token; + +-- Drop the password_reset_token table +DROP TABLE IF EXISTS password_reset_token; + +-- Drop the verification_token table +DROP TABLE IF EXISTS verification_token; + +-- Drop the session table +DROP TABLE IF EXISTS session; + +-- Drop the account table +DROP TABLE IF EXISTS account; + +-- Drop the user table +DROP TABLE IF EXISTS "user"; + +-- Drop the role_type enum +DROP TYPE IF EXISTS role_type; diff --git a/migrations/2024-09-17-162851_initial_shield_db/up.sql b/migrations/2024-09-17-162851_initial_shield_db/up.sql new file mode 100644 index 0000000..28881a5 --- /dev/null +++ b/migrations/2024-09-17-162851_initial_shield_db/up.sql @@ -0,0 +1,159 @@ +-- Create realms table +CREATE TABLE realm ( + id SERIAL PRIMARY KEY, + name TEXT NOT NULL UNIQUE, + slug TEXT NOT NULL UNIQUE, -- TODO: this needs to be auto generated from name. + locked_at TIMESTAMP, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +) + +-- Create clients table +CREATE TABLE client ( + id SERIAL PRIMARY KEY, + name TEXT NOT NULL, + two_factor_enabled_at TIMESTAMP, -- if enabled at client level then it will be mandatory for tenant/user + locked_at TIMESTAMP, + realm_id SERIAL REFERENCES realm(id) on DELETE CASCADE, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX realm_id_name_key ON client (realm_id, name); + +-- Create users table +CREATE TABLE "user" ( + id TEXT PRIMARY KEY, + first_name TEXT NOT NULL, + last_name TEXT, + email TEXT NOT NULL, + email_verified_at TIMESTAMP, + image TEXT, + two_factor_enabled_at TIMESTAMP, -- User can opt-in even in case it is not enabled on client level + password TEXT, + is_temp_password BOOLEAN DEFAULT TRUE, + locked_at TIMESTAMP, + client_id SERIAL REFERENCES client(id) ON DELETE CASCADE, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +-- Create indexes for users table +CREATE UNIQUE INDEX client_id_email_idx ON "user" (client_id, email); +CREATE INDEX client_id_email_locked_at_idx ON "user" (client_id, email, locked_at); + +----------------------------------------------------------------- + +-- Create resources table +CREATE TABLE resource ( + id SERIAL PRIMARY KEY, + client_id SERIAL REFERENCES "client"(id) ON DELETE CASCADE, + user_id TEXT NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, + name TEXT NOT NULL, + value TEXT NOT NULL, + is_default BOOLEAN DEFAULT FALSE, + locked_at TIMESTAMP, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +-- Create index for resources table +CREATE INDEX client_id_user_id_is_default_idx ON resource (client_id, user_id, is_default); +CREATE UNIQUE INDEX client_id_user_id_value_idx ON resource (client_id, user_id, value); + +-- Add constraint to ensure only one default resource per user +ALTER TABLE resource ADD CONSTRAINT unique_default_resource_per_user + EXCLUDE USING btree (user_id WITH =) + WHERE (is_default = true); + +-- Function to update is_default flag +CREATE OR REPLACE FUNCTION update_default_resource() +RETURNS TRIGGER AS $$ +BEGIN + IF NEW.is_default THEN + UPDATE resource + SET is_default = FALSE + WHERE user_id = NEW.user_id AND id != NEW.id; + END IF; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +-- Trigger to maintain single default resource per user +CREATE TRIGGER maintain_single_default_resource +BEFORE INSERT OR UPDATE ON resource +FOR EACH ROW +EXECUTE FUNCTION update_default_resource(); +----------------------------------------------------------------- + +-- Create accounts table +CREATE TABLE account ( + user_id TEXT NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, + type TEXT NOT NULL, + provider TEXT NOT NULL, + provider_account_id TEXT NOT NULL, + refresh_token TEXT, + access_token TEXT, + expires_at INTEGER, + token_type TEXT, + scope TEXT, + id_token TEXT, + session_state TEXT, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (provider, provider_account_id) +); + +-- Create sessions table +CREATE TABLE session ( + session_token TEXT PRIMARY KEY, + user_id TEXT NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, + expires TIMESTAMP NOT NULL, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +-- Create verification_token table +CREATE TABLE verification_token ( + identifier TEXT NOT NULL, + token TEXT NOT NULL, + expires TIMESTAMP NOT NULL, + PRIMARY KEY (identifier, token) +); + +-- Create password_reset_token table +CREATE TABLE password_reset_token ( + identifier TEXT NOT NULL, + token TEXT NOT NULL, + expires TIMESTAMP NOT NULL, + PRIMARY KEY (identifier, token) +); + +-- Create two_factor_token table +CREATE TABLE two_factor_token ( + identifier TEXT NOT NULL, + token TEXT NOT NULL, + expires TIMESTAMP NOT NULL, + PRIMARY KEY (identifier, token) +); + +-- Create two_factor_confirmation table +CREATE TABLE two_factor_confirmation ( + identifier TEXT NOT NULL, + token TEXT NOT NULL, + expires TIMESTAMP NOT NULL, + PRIMARY KEY (identifier, token) +); + +-- Create authenticators table +CREATE TABLE authenticator ( + credential_id TEXT NOT NULL UNIQUE, + user_id TEXT NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, + provider_account_id TEXT NOT NULL, + credential_public_key TEXT NOT NULL, + counter INTEGER NOT NULL, + credential_device_type TEXT NOT NULL, + credential_backed_up BOOLEAN NOT NULL, + transports TEXT, + PRIMARY KEY (user_id, credential_id) +); diff --git a/src/main.rs b/src/main.rs index f6320bc..f142296 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,6 @@ +mod models; +mod schemas; + fn main() { println!("Hello World"); } diff --git a/src/models/db.rs b/src/models/db.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/models/mod.rs b/src/models/mod.rs new file mode 100644 index 0000000..dec1023 --- /dev/null +++ b/src/models/mod.rs @@ -0,0 +1 @@ +pub mod db; diff --git a/src/schemas/db.rs b/src/schemas/db.rs new file mode 100644 index 0000000..dbe054c --- /dev/null +++ b/src/schemas/db.rs @@ -0,0 +1,137 @@ +// @generated automatically by Diesel CLI. + +pub mod sql_types { + #[derive(diesel::query_builder::QueryId, Clone, diesel::sql_types::SqlType)] + #[diesel(postgres_type(name = "role_type"))] + pub struct RoleType; +} + +diesel::table! { + account (provider, provider_account_id) { + user_id -> Text, + #[sql_name = "type"] + type_ -> Text, + provider -> Text, + provider_account_id -> Text, + refresh_token -> Nullable, + access_token -> Nullable, + expires_at -> Nullable, + token_type -> Nullable, + scope -> Nullable, + id_token -> Nullable, + session_state -> Nullable, + created_at -> Timestamp, + updated_at -> Timestamp, + } +} + +diesel::table! { + authenticator (user_id, credential_id) { + credential_id -> Text, + user_id -> Text, + provider_account_id -> Text, + credential_public_key -> Text, + counter -> Int4, + credential_device_type -> Text, + credential_backed_up -> Bool, + transports -> Nullable, + } +} + +diesel::table! { + password_reset_token (identifier, token) { + identifier -> Text, + token -> Text, + expires -> Timestamp, + } +} + +diesel::table! { + resource (id) { + id -> Int4, + user_id -> Text, + name -> Text, + value -> Text, + is_default -> Nullable, + created_at -> Timestamp, + updated_at -> Timestamp, + } +} + +diesel::table! { + session (session_token) { + session_token -> Text, + user_id -> Text, + expires -> Timestamp, + created_at -> Timestamp, + updated_at -> Timestamp, + } +} + +diesel::table! { + two_factor_confirmation (identifier, token) { + identifier -> Text, + token -> Text, + expires -> Timestamp, + } +} + +diesel::table! { + two_factor_token (identifier, token) { + identifier -> Text, + token -> Text, + expires -> Timestamp, + } +} + +diesel::table! { + use diesel::sql_types::*; + use super::sql_types::RoleType; + + user (id) { + id -> Text, + name -> Nullable, + first_name -> Nullable, + last_name -> Nullable, + email -> Text, + email_verified -> Nullable, + image -> Nullable, + is_two_factor_enabled -> Nullable, + password -> Nullable, + is_temp_password -> Nullable, + is_active -> Nullable, + app_user_id -> Text, + role -> RoleType, + society_id -> Nullable, + membership_id -> Nullable, + employee_id -> Nullable, + is_multiple_membership -> Nullable, + created_at -> Timestamp, + updated_at -> Timestamp, + } +} + +diesel::table! { + verification_token (identifier, token) { + identifier -> Text, + token -> Text, + expires -> Timestamp, + } +} + +diesel::joinable!(account -> user (user_id)); +diesel::joinable!(authenticator -> user (user_id)); +diesel::joinable!(resource -> user (user_id)); +diesel::joinable!(session -> user (user_id)); + +diesel::allow_tables_to_appear_in_same_query!( + account, + authenticator, + password_reset_token, + resource, + session, + two_factor_confirmation, + two_factor_token, + user, + verification_token, +); diff --git a/src/schemas/mod.rs b/src/schemas/mod.rs new file mode 100644 index 0000000..dec1023 --- /dev/null +++ b/src/schemas/mod.rs @@ -0,0 +1 @@ +pub mod db; From eae257837bb999cdfc4d94666e47d72f79e02adf Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Wed, 18 Sep 2024 21:07:36 +0530 Subject: [PATCH 07/45] first version of db schema created --- .../down.sql | 35 --- .../up.sql | 159 -------------- .../down.sql | 41 ++++ .../up.sql | 206 ++++++++++++++++++ src/schemas/db.rs | 86 +++++--- 5 files changed, 306 insertions(+), 221 deletions(-) delete mode 100644 migrations/2024-09-17-162851_initial_shield_db/down.sql delete mode 100644 migrations/2024-09-17-162851_initial_shield_db/up.sql create mode 100644 migrations/2024-09-18-153303_db_initialization/down.sql create mode 100644 migrations/2024-09-18-153303_db_initialization/up.sql diff --git a/migrations/2024-09-17-162851_initial_shield_db/down.sql b/migrations/2024-09-17-162851_initial_shield_db/down.sql deleted file mode 100644 index 192a426..0000000 --- a/migrations/2024-09-17-162851_initial_shield_db/down.sql +++ /dev/null @@ -1,35 +0,0 @@ --- Drop the trigger -DROP TRIGGER IF EXISTS maintain_single_default_resource ON resource; - --- Drop the function -DROP FUNCTION IF EXISTS update_default_resource(); - --- Drop the resource table -DROP TABLE IF EXISTS resource; - --- Drop the authenticator table -DROP TABLE IF EXISTS authenticator; - --- Drop the two_factor_confirmation table -DROP TABLE IF EXISTS two_factor_confirmation; - --- Drop the two_factor_token table -DROP TABLE IF EXISTS two_factor_token; - --- Drop the password_reset_token table -DROP TABLE IF EXISTS password_reset_token; - --- Drop the verification_token table -DROP TABLE IF EXISTS verification_token; - --- Drop the session table -DROP TABLE IF EXISTS session; - --- Drop the account table -DROP TABLE IF EXISTS account; - --- Drop the user table -DROP TABLE IF EXISTS "user"; - --- Drop the role_type enum -DROP TYPE IF EXISTS role_type; diff --git a/migrations/2024-09-17-162851_initial_shield_db/up.sql b/migrations/2024-09-17-162851_initial_shield_db/up.sql deleted file mode 100644 index 28881a5..0000000 --- a/migrations/2024-09-17-162851_initial_shield_db/up.sql +++ /dev/null @@ -1,159 +0,0 @@ --- Create realms table -CREATE TABLE realm ( - id SERIAL PRIMARY KEY, - name TEXT NOT NULL UNIQUE, - slug TEXT NOT NULL UNIQUE, -- TODO: this needs to be auto generated from name. - locked_at TIMESTAMP, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP -) - --- Create clients table -CREATE TABLE client ( - id SERIAL PRIMARY KEY, - name TEXT NOT NULL, - two_factor_enabled_at TIMESTAMP, -- if enabled at client level then it will be mandatory for tenant/user - locked_at TIMESTAMP, - realm_id SERIAL REFERENCES realm(id) on DELETE CASCADE, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP -); - -CREATE UNIQUE INDEX realm_id_name_key ON client (realm_id, name); - --- Create users table -CREATE TABLE "user" ( - id TEXT PRIMARY KEY, - first_name TEXT NOT NULL, - last_name TEXT, - email TEXT NOT NULL, - email_verified_at TIMESTAMP, - image TEXT, - two_factor_enabled_at TIMESTAMP, -- User can opt-in even in case it is not enabled on client level - password TEXT, - is_temp_password BOOLEAN DEFAULT TRUE, - locked_at TIMESTAMP, - client_id SERIAL REFERENCES client(id) ON DELETE CASCADE, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP -); - --- Create indexes for users table -CREATE UNIQUE INDEX client_id_email_idx ON "user" (client_id, email); -CREATE INDEX client_id_email_locked_at_idx ON "user" (client_id, email, locked_at); - ------------------------------------------------------------------ - --- Create resources table -CREATE TABLE resource ( - id SERIAL PRIMARY KEY, - client_id SERIAL REFERENCES "client"(id) ON DELETE CASCADE, - user_id TEXT NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, - name TEXT NOT NULL, - value TEXT NOT NULL, - is_default BOOLEAN DEFAULT FALSE, - locked_at TIMESTAMP, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP -); - --- Create index for resources table -CREATE INDEX client_id_user_id_is_default_idx ON resource (client_id, user_id, is_default); -CREATE UNIQUE INDEX client_id_user_id_value_idx ON resource (client_id, user_id, value); - --- Add constraint to ensure only one default resource per user -ALTER TABLE resource ADD CONSTRAINT unique_default_resource_per_user - EXCLUDE USING btree (user_id WITH =) - WHERE (is_default = true); - --- Function to update is_default flag -CREATE OR REPLACE FUNCTION update_default_resource() -RETURNS TRIGGER AS $$ -BEGIN - IF NEW.is_default THEN - UPDATE resource - SET is_default = FALSE - WHERE user_id = NEW.user_id AND id != NEW.id; - END IF; - RETURN NEW; -END; -$$ LANGUAGE plpgsql; - --- Trigger to maintain single default resource per user -CREATE TRIGGER maintain_single_default_resource -BEFORE INSERT OR UPDATE ON resource -FOR EACH ROW -EXECUTE FUNCTION update_default_resource(); ------------------------------------------------------------------ - --- Create accounts table -CREATE TABLE account ( - user_id TEXT NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, - type TEXT NOT NULL, - provider TEXT NOT NULL, - provider_account_id TEXT NOT NULL, - refresh_token TEXT, - access_token TEXT, - expires_at INTEGER, - token_type TEXT, - scope TEXT, - id_token TEXT, - session_state TEXT, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (provider, provider_account_id) -); - --- Create sessions table -CREATE TABLE session ( - session_token TEXT PRIMARY KEY, - user_id TEXT NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, - expires TIMESTAMP NOT NULL, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP -); - --- Create verification_token table -CREATE TABLE verification_token ( - identifier TEXT NOT NULL, - token TEXT NOT NULL, - expires TIMESTAMP NOT NULL, - PRIMARY KEY (identifier, token) -); - --- Create password_reset_token table -CREATE TABLE password_reset_token ( - identifier TEXT NOT NULL, - token TEXT NOT NULL, - expires TIMESTAMP NOT NULL, - PRIMARY KEY (identifier, token) -); - --- Create two_factor_token table -CREATE TABLE two_factor_token ( - identifier TEXT NOT NULL, - token TEXT NOT NULL, - expires TIMESTAMP NOT NULL, - PRIMARY KEY (identifier, token) -); - --- Create two_factor_confirmation table -CREATE TABLE two_factor_confirmation ( - identifier TEXT NOT NULL, - token TEXT NOT NULL, - expires TIMESTAMP NOT NULL, - PRIMARY KEY (identifier, token) -); - --- Create authenticators table -CREATE TABLE authenticator ( - credential_id TEXT NOT NULL UNIQUE, - user_id TEXT NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, - provider_account_id TEXT NOT NULL, - credential_public_key TEXT NOT NULL, - counter INTEGER NOT NULL, - credential_device_type TEXT NOT NULL, - credential_backed_up BOOLEAN NOT NULL, - transports TEXT, - PRIMARY KEY (user_id, credential_id) -); diff --git a/migrations/2024-09-18-153303_db_initialization/down.sql b/migrations/2024-09-18-153303_db_initialization/down.sql new file mode 100644 index 0000000..dcf177a --- /dev/null +++ b/migrations/2024-09-18-153303_db_initialization/down.sql @@ -0,0 +1,41 @@ +-- Drop authenticators table +DROP TABLE IF EXISTS authenticator; + +-- Drop two_factor_confirmation table +DROP TABLE IF EXISTS two_factor_confirmation; + +-- Drop two_factor_token table +DROP TABLE IF EXISTS two_factor_token; + +-- Drop password_reset_token table +DROP TABLE IF EXISTS password_reset_token; + +-- Drop verification_token table +DROP TABLE IF EXISTS verification_token; + +-- Drop sessions table +DROP TABLE IF EXISTS session; + +-- Drop accounts table +DROP TABLE IF EXISTS account; + +-- Drop resources table +DROP TABLE IF EXISTS resource; + +-- Drop resource_groups table +DROP TABLE IF EXISTS resource_group; + +-- Drop users table +DROP TABLE IF EXISTS "user"; + +-- Drop clients table +DROP TABLE IF EXISTS client; + +-- Drop realms table +DROP TABLE IF EXISTS realm; + +-- Drop functions and triggers +DROP TRIGGER IF EXISTS ensure_single_default_resource_group ON resource_group; +DROP FUNCTION IF EXISTS manage_default_resource_group(); +DROP TRIGGER IF EXISTS before_insert_and_update_realm ON realm; +DROP FUNCTION IF EXISTS generate_slug(); \ No newline at end of file diff --git a/migrations/2024-09-18-153303_db_initialization/up.sql b/migrations/2024-09-18-153303_db_initialization/up.sql new file mode 100644 index 0000000..45dfe51 --- /dev/null +++ b/migrations/2024-09-18-153303_db_initialization/up.sql @@ -0,0 +1,206 @@ +-- Create realms table +CREATE TABLE realm ( + id SERIAL PRIMARY KEY, + name TEXT NOT NULL UNIQUE, + slug TEXT NOT NULL UNIQUE, + locked_at TIMESTAMP, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +-- Add trigger for auto-generating slug +CREATE OR REPLACE FUNCTION generate_slug() +RETURNS TRIGGER AS $$ +BEGIN + NEW.slug := LOWER(REGEXP_REPLACE(NEW.name, '[^a-zA-Z0-9]+', '-', 'g')); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER before_insert_and_update_realm +BEFORE INSERT OR UPDATE ON realm +FOR EACH ROW +EXECUTE FUNCTION generate_slug(); + +-- Create clients table +CREATE TABLE client ( + id SERIAL PRIMARY KEY, + name TEXT NOT NULL, + two_factor_enabled_at TIMESTAMP, + locked_at TIMESTAMP, + realm_id INTEGER REFERENCES realm(id) ON DELETE CASCADE, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT chk_locked_at CHECK (locked_at IS NULL OR locked_at <= CURRENT_TIMESTAMP) +); + +CREATE UNIQUE INDEX realm_id_name_key ON client (realm_id, name); +CREATE INDEX idx_client_realm_locked ON client (realm_id, locked_at); + +-- Create users table +CREATE TABLE "user" ( + id SERIAL PRIMARY KEY, + first_name TEXT NOT NULL, + last_name TEXT, + email TEXT NOT NULL, + email_verified_at TIMESTAMP, + image TEXT, + two_factor_enabled_at TIMESTAMP, + password_hash TEXT, + is_temp_password BOOLEAN DEFAULT TRUE, + locked_at TIMESTAMP, + realm_id INTEGER REFERENCES realm(id) ON DELETE CASCADE, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT chk_email_format CHECK (email ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}$'), + CONSTRAINT chk_locked_at CHECK (locked_at IS NULL OR locked_at <= CURRENT_TIMESTAMP), + CONSTRAINT chk_email_verified_at CHECK (email_verified_at IS NULL OR email_verified_at >= created_at AND email_verified_at <= CURRENT_TIMESTAMP) +); + +CREATE UNIQUE INDEX realm_email_idx ON "user" (realm_id, email); +CREATE INDEX realm_email_locked_at_idx ON "user" (realm_id, email, locked_at); +CREATE INDEX idx_user_name ON "user" (realm_id, first_name, last_name); + +----------------------------------------------------------- +-- Create resources_groups table +CREATE TABLE resource_group ( + id SERIAL PRIMARY KEY, + realm_id INTEGER REFERENCES realm(id) ON DELETE CASCADE, + client_id INTEGER REFERENCES client(id) ON DELETE CASCADE, + user_id SERIAL NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, + name TEXT NOT NULL, + description TEXT, + is_default BOOLEAN DEFAULT FALSE, + locked_at TIMESTAMP, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT chk_locked_at CHECK (locked_at IS NULL OR locked_at <= CURRENT_TIMESTAMP) +); + +CREATE UNIQUE INDEX realm_client_user_resource_group_idx ON resource_group (name, client_id, user_id); +CREATE INDEX client_user_default_resource_group_idx ON resource_group (client_id, user_id, is_default) WHERE is_default = true; + +-- Function to manage default resource group +CREATE OR REPLACE FUNCTION manage_default_resource_group() +RETURNS TRIGGER AS $$ +BEGIN + -- If the new row is being set as default + IF NEW.is_default THEN + -- Set all other resource groups for the same user and client to non-default + UPDATE resource_group + SET is_default = FALSE + WHERE user_id = NEW.user_id + AND client_id = NEW.client_id + AND id != NEW.id; + ELSE + -- Check if this was the only default group + IF NOT EXISTS ( + SELECT 1 + FROM resource_group + WHERE user_id = NEW.user_id + AND client_id = NEW.client_id + AND is_default = TRUE + AND id != NEW.id + ) THEN + -- If so, force this group to be default + NEW.is_default := TRUE; + END IF; + END IF; + + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +-- Trigger to execute the function +CREATE TRIGGER ensure_single_default_resource_group +BEFORE INSERT OR UPDATE OF is_default ON resource_group +FOR EACH ROW +EXECUTE FUNCTION manage_default_resource_group(); +----------------------------------------------------------- + +-- Create resources table +CREATE TABLE resource ( + id SERIAL PRIMARY KEY, + group_id INTEGER REFERENCES resource_group(id) ON DELETE CASCADE, + name TEXT NOT NULL, + value TEXT NOT NULL, + description TEXT, + locked_at TIMESTAMP, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT chk_locked_at CHECK (locked_at IS NULL OR locked_at <= CURRENT_TIMESTAMP) +); + +CREATE UNIQUE INDEX resource_group_and_resource_idx ON resource (group_id, name); + +-- Create accounts table +CREATE TABLE account ( + user_id SERIAL NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, + type TEXT NOT NULL, + provider TEXT NOT NULL, + provider_account_id TEXT NOT NULL, + refresh_token TEXT, + access_token TEXT, + expires_at INTEGER, + token_type TEXT, + scope TEXT, + id_token TEXT, + session_state TEXT, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (provider, provider_account_id) +); + +-- Create sessions table +CREATE TABLE session ( + session_token TEXT PRIMARY KEY, + user_id SERIAL NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, + expires TIMESTAMP NOT NULL, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +-- Create verification_token table +CREATE TABLE verification_token ( + identifier TEXT NOT NULL, + token TEXT NOT NULL, + expires TIMESTAMP NOT NULL, + PRIMARY KEY (identifier, token) +); + +-- Create password_reset_token table +CREATE TABLE password_reset_token ( + identifier TEXT NOT NULL, + token TEXT NOT NULL, + expires TIMESTAMP NOT NULL, + PRIMARY KEY (identifier, token) +); + +-- Create two_factor_token table +CREATE TABLE two_factor_token ( + identifier TEXT NOT NULL, + token TEXT NOT NULL, + expires TIMESTAMP NOT NULL, + PRIMARY KEY (identifier, token) +); + +-- Create two_factor_confirmation table +CREATE TABLE two_factor_confirmation ( + identifier TEXT NOT NULL, + token TEXT NOT NULL, + expires TIMESTAMP NOT NULL, + PRIMARY KEY (identifier, token) +); + +-- Create authenticators table +CREATE TABLE authenticator ( + credential_id TEXT NOT NULL UNIQUE, + user_id SERIAL NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, + provider_account_id TEXT NOT NULL, + credential_public_key TEXT NOT NULL, + counter INTEGER NOT NULL, + credential_device_type TEXT NOT NULL, + credential_backed_up BOOLEAN NOT NULL, + transports TEXT, + PRIMARY KEY (user_id, credential_id) +); diff --git a/src/schemas/db.rs b/src/schemas/db.rs index dbe054c..3dae98a 100644 --- a/src/schemas/db.rs +++ b/src/schemas/db.rs @@ -1,14 +1,8 @@ // @generated automatically by Diesel CLI. -pub mod sql_types { - #[derive(diesel::query_builder::QueryId, Clone, diesel::sql_types::SqlType)] - #[diesel(postgres_type(name = "role_type"))] - pub struct RoleType; -} - diesel::table! { account (provider, provider_account_id) { - user_id -> Text, + user_id -> Int4, #[sql_name = "type"] type_ -> Text, provider -> Text, @@ -28,7 +22,7 @@ diesel::table! { diesel::table! { authenticator (user_id, credential_id) { credential_id -> Text, - user_id -> Text, + user_id -> Int4, provider_account_id -> Text, credential_public_key -> Text, counter -> Int4, @@ -38,6 +32,18 @@ diesel::table! { } } +diesel::table! { + client (id) { + id -> Int4, + name -> Text, + two_factor_enabled_at -> Nullable, + locked_at -> Nullable, + realm_id -> Nullable, + created_at -> Timestamp, + updated_at -> Timestamp, + } +} + diesel::table! { password_reset_token (identifier, token) { identifier -> Text, @@ -46,13 +52,40 @@ diesel::table! { } } +diesel::table! { + realm (id) { + id -> Int4, + name -> Text, + slug -> Text, + locked_at -> Nullable, + created_at -> Timestamp, + updated_at -> Timestamp, + } +} + diesel::table! { resource (id) { id -> Int4, - user_id -> Text, + group_id -> Nullable, name -> Text, value -> Text, + description -> Nullable, + locked_at -> Nullable, + created_at -> Timestamp, + updated_at -> Timestamp, + } +} + +diesel::table! { + resource_group (id) { + id -> Int4, + realm_id -> Nullable, + client_id -> Nullable, + user_id -> Int4, + name -> Text, + description -> Nullable, is_default -> Nullable, + locked_at -> Nullable, created_at -> Timestamp, updated_at -> Timestamp, } @@ -61,7 +94,7 @@ diesel::table! { diesel::table! { session (session_token) { session_token -> Text, - user_id -> Text, + user_id -> Int4, expires -> Timestamp, created_at -> Timestamp, updated_at -> Timestamp, @@ -85,27 +118,18 @@ diesel::table! { } diesel::table! { - use diesel::sql_types::*; - use super::sql_types::RoleType; - user (id) { - id -> Text, - name -> Nullable, - first_name -> Nullable, + id -> Int4, + first_name -> Text, last_name -> Nullable, email -> Text, - email_verified -> Nullable, + email_verified_at -> Nullable, image -> Nullable, - is_two_factor_enabled -> Nullable, - password -> Nullable, + two_factor_enabled_at -> Nullable, + password_hash -> Nullable, is_temp_password -> Nullable, - is_active -> Nullable, - app_user_id -> Text, - role -> RoleType, - society_id -> Nullable, - membership_id -> Nullable, - employee_id -> Nullable, - is_multiple_membership -> Nullable, + locked_at -> Nullable, + realm_id -> Nullable, created_at -> Timestamp, updated_at -> Timestamp, } @@ -121,14 +145,22 @@ diesel::table! { diesel::joinable!(account -> user (user_id)); diesel::joinable!(authenticator -> user (user_id)); -diesel::joinable!(resource -> user (user_id)); +diesel::joinable!(client -> realm (realm_id)); +diesel::joinable!(resource -> resource_group (group_id)); +diesel::joinable!(resource_group -> client (client_id)); +diesel::joinable!(resource_group -> realm (realm_id)); +diesel::joinable!(resource_group -> user (user_id)); diesel::joinable!(session -> user (user_id)); +diesel::joinable!(user -> realm (realm_id)); diesel::allow_tables_to_appear_in_same_query!( account, authenticator, + client, password_reset_token, + realm, resource, + resource_group, session, two_factor_confirmation, two_factor_token, From 768d7f2ca82110b35ffea6f35c79bffd067be30c Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Thu, 19 Sep 2024 06:37:13 +0530 Subject: [PATCH 08/45] default resource initialization in-progress --- .rustfmt.toml | 1 + Cargo.lock | 722 ++++++++++++++++++++++++++++++++++++++- Cargo.toml | 10 +- config/default.yml | 13 + config/production.yml | 3 + config/test.yml | 8 + src/app.rs | 36 ++ src/handlers/client.rs | 10 + src/handlers/mod.rs | 2 + src/handlers/realm.rs | 10 + src/main.rs | 34 +- src/models/db.rs | 0 src/models/mod.rs | 2 +- src/models/realm.rs | 23 ++ src/packages/admin.rs | 50 +++ src/packages/db.rs | 21 ++ src/packages/errors.rs | 104 ++++++ src/packages/logger.rs | 15 + src/packages/mod.rs | 6 + src/packages/settings.rs | 77 +++++ src/packages/shutdown.rs | 10 + src/routes/client.rs | 10 + src/routes/health.rs | 19 ++ src/routes/mod.rs | 11 + src/routes/realm.rs | 12 + src/utils/mod.rs | 1 + 26 files changed, 1203 insertions(+), 7 deletions(-) create mode 100644 .rustfmt.toml create mode 100644 config/default.yml create mode 100644 config/production.yml create mode 100644 config/test.yml create mode 100644 src/app.rs create mode 100644 src/handlers/client.rs create mode 100644 src/handlers/mod.rs create mode 100644 src/handlers/realm.rs delete mode 100644 src/models/db.rs create mode 100644 src/models/realm.rs create mode 100644 src/packages/admin.rs create mode 100644 src/packages/db.rs create mode 100644 src/packages/errors.rs create mode 100644 src/packages/logger.rs create mode 100644 src/packages/mod.rs create mode 100644 src/packages/settings.rs create mode 100644 src/packages/shutdown.rs create mode 100644 src/routes/client.rs create mode 100644 src/routes/health.rs create mode 100644 src/routes/mod.rs create mode 100644 src/routes/realm.rs create mode 100644 src/utils/mod.rs diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 0000000..bc30bf4 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1 @@ +max_width = 150 diff --git a/Cargo.lock b/Cargo.lock index 6d572c9..fb288fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,49 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "async-compression" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fec134f64e2bc57411226dfc4e52dec859ddfc7e711fc5e07b612584f000e4aa" +dependencies = [ + "brotli", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", +] + [[package]] name = "async-trait" version = "0.1.82" @@ -104,11 +147,39 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bcrypt" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e65938ed058ef47d92cf8b346cc76ef48984572ade631927e9937b5ffc7662c7" +dependencies = [ + "base64 0.22.1", + "blowfish", + "getrandom", + "subtle", + "zeroize", +] + [[package]] name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +dependencies = [ + "serde", +] [[package]] name = "block-buffer" @@ -119,6 +190,37 @@ dependencies = [ "generic-array", ] +[[package]] +name = "blowfish" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" +dependencies = [ + "byteorder", + "cipher", +] + +[[package]] +name = "brotli" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + [[package]] name = "bumpalo" version = "3.16.0" @@ -137,12 +239,107 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +[[package]] +name = "cc" +version = "1.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" +dependencies = [ + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "config" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7328b20597b53c2454f0b1919720c25c7339051c02b72b7e05409e00b14132be" +dependencies = [ + "async-trait", + "convert_case", + "json5", + "lazy_static", + "nom", + "pathdiff", + "ron", + "rust-ini", + "serde", + "serde_json", + "toml", + "yaml-rust", +] + +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom", + "once_cell", + "tiny-keccak", +] + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "cpufeatures" version = "0.2.14" @@ -152,6 +349,12 @@ dependencies = [ "libc", ] +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-common" version = "0.1.6" @@ -162,6 +365,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "ctrlc" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" +dependencies = [ + "nix", + "windows-sys 0.59.0", +] + [[package]] name = "cuid-util" version = "0.1.1" @@ -224,9 +437,11 @@ checksum = "158fe8e2e68695bd615d7e4f3227c0727b151330d3e253b525086c348d055d5e" dependencies = [ "bitflags", "byteorder", + "chrono", "diesel_derives", "itoa", "pq-sys", + "r2d2", ] [[package]] @@ -261,6 +476,15 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "dlv-list" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" +dependencies = [ + "const-random", +] + [[package]] name = "dotenvy" version = "0.15.7" @@ -287,6 +511,12 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "fnv" version = "1.0.7" @@ -317,6 +547,12 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + [[package]] name = "futures-task" version = "0.3.30" @@ -364,6 +600,18 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "heck" version = "0.5.0" @@ -456,12 +704,54 @@ dependencies = [ "tokio", ] +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "ident_case" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "indexmap" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +dependencies = [ + "equivalent", + "hashbrown 0.14.5", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "itoa" version = "1.0.11" @@ -477,6 +767,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "json5" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" +dependencies = [ + "pest", + "pest_derive", + "serde", +] + [[package]] name = "keccak" version = "0.1.5" @@ -486,12 +787,24 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "lock_api" version = "0.4.12" @@ -526,6 +839,12 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.8.0" @@ -544,7 +863,39 @@ dependencies = [ "hermit-abi", "libc", "wasi", - "windows-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", ] [[package]] @@ -635,6 +986,22 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "ordered-multimap" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ed8acf08e98e744e5384c8bc63ceb0364e68a6854187221c18df61c4797690e" +dependencies = [ + "dlv-list", + "hashbrown 0.13.2", +] + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parking_lot" version = "0.12.3" @@ -658,12 +1025,63 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + [[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pest" +version = "2.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c73c26c01b8c87956cea613c907c9d6ecffd8d18a2a5908e5de0adfaa185cea" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "664d22978e2815783adbdd2c588b455b1bd625299ce36b2a99881ac9627e6d8d" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2d5487022d5d33f4c30d91c22afa240ce2a644e87fe08caad974d4eab6badbe" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0091754bbd0ea592c4deb3a122ce8ecbb0753b738aa82bc055fcc2eccc8d8174" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + [[package]] name = "pin-project" version = "1.1.5" @@ -732,6 +1150,17 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r2d2" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" +dependencies = [ + "log", + "parking_lot", + "scheduled-thread-pool", +] + [[package]] name = "rand" version = "0.8.5" @@ -771,6 +1200,28 @@ dependencies = [ "bitflags", ] +[[package]] +name = "ron" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" +dependencies = [ + "base64 0.21.7", + "bitflags", + "serde", + "serde_derive", +] + +[[package]] +name = "rust-ini" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e2a3bcec1f113553ef1c88aae6c020a369d03d55b58de9869a0908930385091" +dependencies = [ + "cfg-if", + "ordered-multimap", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -789,6 +1240,15 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "scheduled-thread-pool" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" +dependencies = [ + "parking_lot", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -837,6 +1297,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -849,6 +1318,17 @@ dependencies = [ "serde", ] +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha3" version = "0.10.8" @@ -859,20 +1339,43 @@ dependencies = [ "keccak", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shield" version = "0.1.0" dependencies = [ "axum", + "bcrypt", + "chrono", + "config", + "ctrlc", "cuid2", "diesel", "dotenvy", + "once_cell", "serde", "serde_json", "thiserror", "tokio", + "tower-http", + "tracing", + "tracing-subscriber", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -895,7 +1398,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -904,6 +1407,12 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "2.0.77" @@ -947,6 +1456,25 @@ dependencies = [ "syn", ] +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tokio" version = "1.40.0" @@ -962,7 +1490,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -976,6 +1504,53 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-util" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tower" version = "0.4.13" @@ -992,6 +1567,27 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower-http" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" +dependencies = [ + "async-compression", + "bitflags", + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "pin-project-lite", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -1012,9 +1608,21 @@ checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tracing-core" version = "0.1.32" @@ -1022,6 +1630,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", ] [[package]] @@ -1030,12 +1664,30 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + [[package]] name = "unicode-ident" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vcpkg" version = "0.2.15" @@ -1109,6 +1761,37 @@ version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.52.0" @@ -1118,6 +1801,15 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -1182,6 +1874,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winnow" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +dependencies = [ + "memchr", +] + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -1202,3 +1912,9 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/Cargo.toml b/Cargo.toml index 991aae9..46e5f83 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,10 +5,18 @@ edition = "2021" [dependencies] axum = "0.7.5" +bcrypt = "0.15.1" +chrono = { version = "0.4.38", features = ["serde"] } +config = { version = "0.14.0", features = ["yaml"] } +ctrlc = { version = "3.4.5", features = ["termination"] } cuid2 = "0.1.3" -diesel = { version = "2.2.4", features = ["postgres"] } +diesel = { version = "2.2.4", features = ["chrono", "postgres", "r2d2"] } dotenvy = "0.15.7" +once_cell = "1.19.0" serde = { version = "1.0.210", features = ["derive"] } serde_json = "1.0.128" thiserror = "1.0.63" tokio = { version = "1.40.0", features = ["full"] } +tower-http = { version = "0.5.2", features = ["trace", "compression-br", "propagate-header", "sensitive-headers", "cors"] } +tracing = "0.1.40" +tracing-subscriber = "0.3.18" diff --git a/config/default.yml b/config/default.yml new file mode 100644 index 0000000..beeb741 --- /dev/null +++ b/config/default.yml @@ -0,0 +1,13 @@ +environment: development +server: + port: 5556 +database: + uri: "postgres://postgres:1234@localhost:5432/shield" + name: shield +auth: + secret: secret +logger: + level: debug +admin: + username: admin + password: 12345 diff --git a/config/production.yml b/config/production.yml new file mode 100644 index 0000000..6481c03 --- /dev/null +++ b/config/production.yml @@ -0,0 +1,3 @@ +environment: production +logger: + level: info diff --git a/config/test.yml b/config/test.yml new file mode 100644 index 0000000..cfda9a2 --- /dev/null +++ b/config/test.yml @@ -0,0 +1,8 @@ +environment: test +server: + port: 8088 +database: + uri: "postgres://postgres:1234@localhost:5432/shield-test" + name: shield-test +logger: + level: error diff --git a/src/app.rs b/src/app.rs new file mode 100644 index 0000000..e531bc5 --- /dev/null +++ b/src/app.rs @@ -0,0 +1,36 @@ +use std::sync::Arc; + +use axum::{http::header, Router}; +use tower_http::{ + compression::CompressionLayer, cors::CorsLayer, propagate_header::PropagateHeaderLayer, sensitive_headers::SetSensitiveHeadersLayer, trace, +}; + +use crate::{ + packages::{admin, db::get_connection_pool, logger}, + routes, +}; + +pub async fn create_app() -> Router { + logger::setup(); + let state = get_connection_pool(); + admin::setup(&state).await; + + Router::new() + .with_state(Arc::new(state)) + .merge(routes::create_routes()) + .layer( + // High level logging of requests and responses + trace::TraceLayer::new_for_http() + .make_span_with(trace::DefaultMakeSpan::new().include_headers(false)) + .on_request(trace::DefaultOnRequest::new().level(tracing::Level::INFO)) + .on_response(trace::DefaultOnResponse::new().level(tracing::Level::INFO)), + ) + // Mark the `Authorization` request header as sensitive so it doesn't + // show in logs. + .layer(SetSensitiveHeadersLayer::new(std::iter::once(header::AUTHORIZATION))) + // Compress responses + .layer(CompressionLayer::new()) + // Propagate `X-Request-Id`s from requests to responses + .layer(PropagateHeaderLayer::new(header::HeaderName::from_static("x-request-id"))) + .layer(CorsLayer::permissive()) // TODO: Update is later +} diff --git a/src/handlers/client.rs b/src/handlers/client.rs new file mode 100644 index 0000000..8b2715b --- /dev/null +++ b/src/handlers/client.rs @@ -0,0 +1,10 @@ +use axum::extract::Path; + +pub async fn get_clients() -> String { + "Hi from clients".to_owned() +} + +pub async fn get_client(Path((realm, client_id)): Path<(String, String)>) -> String { + println!("This is client Name: {} - {}", &realm, &client_id); + format!("client is - {} - {}", realm, client_id) +} diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs new file mode 100644 index 0000000..2cf4974 --- /dev/null +++ b/src/handlers/mod.rs @@ -0,0 +1,2 @@ +pub mod client; +pub mod realm; diff --git a/src/handlers/realm.rs b/src/handlers/realm.rs new file mode 100644 index 0000000..9f3e265 --- /dev/null +++ b/src/handlers/realm.rs @@ -0,0 +1,10 @@ +use axum::extract::Path; + +pub async fn get_realms() -> String { + "Hi from MASTER REALM".to_owned() +} + +pub async fn get_realm(Path(realm): Path) -> String { + println!("This is realm Name: {}", &realm); + format!("Realm is - {}", realm) +} diff --git a/src/main.rs b/src/main.rs index f142296..9c6d809 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,36 @@ +use std::{net::SocketAddr, sync::Arc}; + +use app::create_app; +use packages::{settings::SETTINGS, shutdown::shutdown_signal_handler}; +use tokio::{net::TcpListener, sync::Notify}; +use tracing::info; + +mod app; +mod handlers; mod models; +mod packages; +mod routes; mod schemas; +mod utils; + +#[tokio::main] +async fn main() -> Result<(), std::io::Error> { + let port = SETTINGS.server.port; + let address = SocketAddr::from(([127, 0, 0, 1], port)); + + let app = create_app().await; + let listener = TcpListener::bind(address).await?; + + info!("Server is listening on {}", &address); + + let shutdown_signal = Arc::new(Notify::new()); + let shutdown_signal_clone = shutdown_signal.clone(); + ctrlc::set_handler(move || { + shutdown_signal_clone.notify_one(); + }) + .expect("Error setting Ctrl+C handler"); -fn main() { - println!("Hello World"); + axum::serve(listener, app) + .with_graceful_shutdown(shutdown_signal_handler(shutdown_signal)) + .await } diff --git a/src/models/db.rs b/src/models/db.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/models/mod.rs b/src/models/mod.rs index dec1023..abc366b 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -1 +1 @@ -pub mod db; +pub mod realm; diff --git a/src/models/realm.rs b/src/models/realm.rs new file mode 100644 index 0000000..59d4610 --- /dev/null +++ b/src/models/realm.rs @@ -0,0 +1,23 @@ +use chrono::NaiveDateTime; +use diesel::prelude::*; +use serde::{Deserialize, Serialize}; + +use crate::schemas::db::realm; + +#[derive(Debug, Queryable, Selectable, Serialize)] +#[diesel(table_name = realm)] +#[diesel(check_for_backend(diesel::pg::Pg))] +pub struct Realm { + pub id: i32, + pub name: String, + pub slug: String, + pub locked_at: Option, + pub created_at: NaiveDateTime, + pub updated_at: NaiveDateTime, +} + +#[derive(Debug, Deserialize, Insertable)] +#[diesel(table_name = realm)] +pub struct NewRealm<'a> { + pub name: &'a str, +} diff --git a/src/packages/admin.rs b/src/packages/admin.rs new file mode 100644 index 0000000..449ced3 --- /dev/null +++ b/src/packages/admin.rs @@ -0,0 +1,50 @@ +use diesel::{ + dsl::insert_into, + r2d2::{ConnectionManager, PooledConnection}, + select, ExpressionMethods, PgConnection, QueryDsl, RunQueryDsl, +}; +use tracing::{debug, info}; + +use crate::{ + models::realm::{NewRealm, Realm}, + packages::errors::Error, + schemas::db::realm::{self, name}, +}; + +use super::db::AppState; + +pub async fn setup(state: &AppState) { + info!("Checking ADMIN availability!"); + + let mut conn = state.pool.get().map_err(Error::db_error).unwrap(); + debug!("Connection initialized"); + let is_master_realm_exists = select(diesel::dsl::exists(realm::dsl::realm.filter(name.eq("Master")))) + .get_result::(&mut conn) + .unwrap(); + debug!("find query ran for master realm"); + + if is_master_realm_exists { + info!("Master realm exists"); + info!("Starting the server..."); + } else { + info!("Master realm does not exist"); + info!("⌛ Initializing the ADMIN..."); + // TODO: 1. Create "Master" realm. + let res = create_master_realm(&mut conn); + // TODO: 2. Create admin using the admin_username and admin_password. If missing then throw error. + + println!("{:#?}", res); + // TODO: 3. Give access of "Master" realm to admin. + } +} + +fn create_master_realm(conn: &mut PooledConnection>) -> Realm { + let new_realm = NewRealm { name: "Master" }; + let res = insert_into(realm::table) + .values(&new_realm) + .get_result(conn) + .map_err(Error::db_error) + .unwrap(); + info!("✅ 1/3 Master realm created"); + return res; +} diff --git a/src/packages/db.rs b/src/packages/db.rs new file mode 100644 index 0000000..422626b --- /dev/null +++ b/src/packages/db.rs @@ -0,0 +1,21 @@ +use diesel::{ + r2d2::{ConnectionManager, Pool}, + PgConnection, +}; + +use super::settings::SETTINGS; + +pub struct AppState { + pub pool: Pool>, +} + +pub fn get_connection_pool() -> AppState { + let url = &SETTINGS.database.uri; + let manager = ConnectionManager::::new(url); + let pool = Pool::builder() + .test_on_check_out(true) + .build(manager) + .expect("Could not build connection pool."); + + AppState { pool } +} diff --git a/src/packages/errors.rs b/src/packages/errors.rs new file mode 100644 index 0000000..bc29973 --- /dev/null +++ b/src/packages/errors.rs @@ -0,0 +1,104 @@ +use axum::http::StatusCode; +use axum::response::{IntoResponse, Response}; +use axum::Json; +use bcrypt::BcryptError; +use serde_json::json; +use tokio::task::JoinError; + +#[derive(thiserror::Error, Debug)] +#[error("...")] +pub enum Error { + #[error("{0}")] + Authenticate(#[from] AuthenticateError), + + #[error("{0}")] + BadRequest(#[from] BadRequest), + + #[error("Database error: {0}")] + DatabaseError(#[from] DatabaseError), + + #[error("{0}")] + NotFound(#[from] NotFound), + + #[error("{0}")] + RunSyncTask(#[from] JoinError), + + #[error("{0}")] + HashPassword(#[from] BcryptError), +} + +impl Error { + fn get_codes(&self) -> (StatusCode, u16) { + match *self { + // 4XX Errors + Error::BadRequest(_) => (StatusCode::BAD_REQUEST, 40002), + Error::NotFound(_) => (StatusCode::NOT_FOUND, 40003), + Error::Authenticate(AuthenticateError::WrongCredentials) => (StatusCode::UNAUTHORIZED, 40004), + Error::Authenticate(AuthenticateError::InvalidToken) => (StatusCode::UNAUTHORIZED, 40005), + Error::Authenticate(AuthenticateError::Locked) => (StatusCode::LOCKED, 40006), + Error::Authenticate(AuthenticateError::EmailNotVerified) => (StatusCode::FORBIDDEN, 40007), + + // 5XX Errors + Error::Authenticate(AuthenticateError::TokenCreation) => (StatusCode::INTERNAL_SERVER_ERROR, 5001), + Error::RunSyncTask(_) => (StatusCode::INTERNAL_SERVER_ERROR, 5005), + Error::HashPassword(_) => (StatusCode::INTERNAL_SERVER_ERROR, 5006), + Error::DatabaseError(_) => (StatusCode::INTERNAL_SERVER_ERROR, 5007), + } + } + + pub fn bad_request() -> Self { + Error::BadRequest(BadRequest {}) + } + + pub fn not_found() -> Self { + Error::NotFound(NotFound {}) + } + + pub fn db_error(_: E) -> Self { + Error::DatabaseError(DatabaseError {}) + } + + pub fn internal_error(err: E) -> (StatusCode, String) + where + E: std::error::Error, + { + (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()) + } +} + +impl IntoResponse for Error { + fn into_response(self) -> Response { + let (status_code, code) = self.get_codes(); + let message = self.to_string(); + let body = Json(json!({ "code": code, "message": message })); + + (status_code, body).into_response() + } +} + +#[derive(thiserror::Error, Debug)] +#[error("...")] +pub enum AuthenticateError { + #[error("Wrong authentication credentials")] + WrongCredentials, + #[error("Failed to create authentication token")] + TokenCreation, + #[error("Invalid authentication credentials")] + InvalidToken, + #[error("Email not verified")] + EmailNotVerified, + #[error("User is locked")] + Locked, +} + +#[derive(thiserror::Error, Debug)] +#[error("Bad Request")] +pub struct BadRequest {} + +#[derive(thiserror::Error, Debug)] +#[error("Not found")] +pub struct NotFound {} + +#[derive(thiserror::Error, Debug)] +#[error("Database error")] +pub struct DatabaseError {} diff --git a/src/packages/logger.rs b/src/packages/logger.rs new file mode 100644 index 0000000..883ec1a --- /dev/null +++ b/src/packages/logger.rs @@ -0,0 +1,15 @@ +use std::env; + +use super::settings::SETTINGS; + +pub fn setup() { + if env::var_os("RUST_LOG").is_none() { + let app_name = env::var("CARGO_PKG_NAME").unwrap(); + let level = SETTINGS.logger.level.as_str(); + let env = format!("{app_name }={level},tower_http={level}"); + + env::set_var("RUST_LOG", env); + } + + tracing_subscriber::fmt::init(); +} diff --git a/src/packages/mod.rs b/src/packages/mod.rs new file mode 100644 index 0000000..c7bf08a --- /dev/null +++ b/src/packages/mod.rs @@ -0,0 +1,6 @@ +pub mod admin; +pub mod db; +pub mod errors; +pub mod logger; +pub mod settings; +pub mod shutdown; diff --git a/src/packages/settings.rs b/src/packages/settings.rs new file mode 100644 index 0000000..c7b3f06 --- /dev/null +++ b/src/packages/settings.rs @@ -0,0 +1,77 @@ +use config::{Config, ConfigError, Environment, File}; +use dotenvy::dotenv; +use once_cell::sync::Lazy; +use serde::Deserialize; +use std::{env, fmt}; + +pub static SETTINGS: Lazy = Lazy::new(|| Settings::new().expect("Failed to setup settings")); + +#[derive(Debug, Clone, Deserialize)] +pub struct Server { + pub port: u16, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct Logger { + pub level: String, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct Database { + pub uri: String, + pub name: String, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct Admin { + pub username: String, + pub password: String, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct Settings { + pub environment: String, + pub server: Server, + pub logger: Logger, + pub database: Database, + pub admin: Admin, +} + +impl Settings { + pub fn new() -> Result { + dotenv().ok(); + let run_mode = env::var("RUN_MODE").unwrap_or_else(|_| "development".into()); + + let mut builder = Config::builder() + .add_source(File::with_name("config/default")) + .add_source(File::with_name(&format!("config/{run_mode}")).required(false)) + .add_source(File::with_name("config/local").required(false)) + .add_source(Environment::default().separator("__")); + + // Some cloud services like Heroku exposes a randomly assigned port in + // the PORT env var and there is no way to change the env var name. + if let Ok(port) = env::var("PORT") { + builder = builder.set_override("server.port", port)?; + } + if let Ok(database_uri) = env::var("DATABASE_URL") { + builder = builder.set_override("database.uri", database_uri)?; + } + if let Ok(admin_username) = env::var("ADMIN_USERNAME") { + builder = builder.set_override("admin.username", admin_username)?; + } + if let Ok(admin_password) = env::var("ADMIN_PASSWORD") { + builder = builder.set_override("admin.password", admin_password)?; + } + + builder + .build()? + // Deserialize (and thus freeze) the entire configuration. + .try_deserialize() + } +} + +impl fmt::Display for Server { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "http://localhost:{}", &self.port) + } +} diff --git a/src/packages/shutdown.rs b/src/packages/shutdown.rs new file mode 100644 index 0000000..2ba8006 --- /dev/null +++ b/src/packages/shutdown.rs @@ -0,0 +1,10 @@ +use std::sync::Arc; + +use tokio::sync::Notify; +use tracing::info; + +pub async fn shutdown_signal_handler(shutdown_signal: Arc) { + shutdown_signal.notified().await; + info!("Handling graceful shutdown"); + info!("Close resources, drain and shutdown event handler... etc"); +} diff --git a/src/routes/client.rs b/src/routes/client.rs new file mode 100644 index 0000000..a369415 --- /dev/null +++ b/src/routes/client.rs @@ -0,0 +1,10 @@ +use axum::{routing::get, Router}; + +use crate::handlers::client::{get_client, get_clients}; + +pub fn create_routes() -> Router { + Router::new().nest( + "/clients", + Router::new().route("/", get(get_clients)).route("/:client_id", get(get_client)), + ) +} diff --git a/src/routes/health.rs b/src/routes/health.rs new file mode 100644 index 0000000..9f2fe3c --- /dev/null +++ b/src/routes/health.rs @@ -0,0 +1,19 @@ +use axum::{routing::get, Json, Router}; +use serde::Serialize; +use tracing::debug; + +use crate::packages::errors::Error; + +pub fn create_routes() -> Router { + Router::new().route("/", get(get_health)) +} + +async fn get_health() -> Result, Error> { + debug!("Returning health"); + Ok(Json(Health { ok: true })) +} + +#[derive(Serialize, Debug)] +struct Health { + ok: bool, +} diff --git a/src/routes/mod.rs b/src/routes/mod.rs new file mode 100644 index 0000000..5e40155 --- /dev/null +++ b/src/routes/mod.rs @@ -0,0 +1,11 @@ +use axum::Router; + +pub mod client; +pub mod health; +pub mod realm; + +pub fn create_routes() -> Router { + Router::new() + .nest("/health", health::create_routes()) + .nest("/realms", realm::create_routes()) +} diff --git a/src/routes/realm.rs b/src/routes/realm.rs new file mode 100644 index 0000000..a51e907 --- /dev/null +++ b/src/routes/realm.rs @@ -0,0 +1,12 @@ +use axum::{routing::get, Router}; + +use crate::handlers::realm::{get_realm, get_realms}; + +use super::client; + +pub fn create_routes() -> Router { + Router::new() + .route("/", get(get_realms)) + .route("/:realm", get(get_realm)) + .merge(client::create_routes()) +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/utils/mod.rs @@ -0,0 +1 @@ + From 59a75cba394c9ff89306c2c581ef3911a85ca74f Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Fri, 20 Sep 2024 00:43:48 +0530 Subject: [PATCH 09/45] diesel replaced with sea-orm and db connection is working --- Cargo.lock | 1572 ++++++++++++++++++++--- Cargo.toml | 3 +- src/app.rs | 17 +- src/database/account.rs | 50 + src/database/authenticator.rs | 42 + src/database/client.rs | 45 + src/database/mod.rs | 16 + src/database/password_reset_token.rs | 18 + src/database/prelude.rs | 14 + src/database/realm.rs | 47 + src/database/resource.rs | 40 + src/database/resource_group.rs | 77 ++ src/database/session.rs | 34 + src/database/two_factor_confirmation.rs | 18 + src/database/two_factor_token.rs | 18 + src/database/user.rs | 79 ++ src/database/verification_token.rs | 18 + src/main.rs | 21 +- src/middleware/logger.rs | 12 + src/middleware/mod.rs | 1 + src/models/mod.rs | 1 - src/models/realm.rs | 23 - src/packages/admin.rs | 61 +- src/packages/db.rs | 24 +- src/packages/mod.rs | 1 - src/packages/shutdown.rs | 10 - src/schemas/db.rs | 169 --- src/schemas/mod.rs | 1 - 28 files changed, 2000 insertions(+), 432 deletions(-) create mode 100644 src/database/account.rs create mode 100644 src/database/authenticator.rs create mode 100644 src/database/client.rs create mode 100644 src/database/mod.rs create mode 100644 src/database/password_reset_token.rs create mode 100644 src/database/prelude.rs create mode 100644 src/database/realm.rs create mode 100644 src/database/resource.rs create mode 100644 src/database/resource_group.rs create mode 100644 src/database/session.rs create mode 100644 src/database/two_factor_confirmation.rs create mode 100644 src/database/two_factor_token.rs create mode 100644 src/database/user.rs create mode 100644 src/database/verification_token.rs create mode 100644 src/middleware/logger.rs create mode 100644 src/middleware/mod.rs delete mode 100644 src/models/mod.rs delete mode 100644 src/models/realm.rs delete mode 100644 src/packages/shutdown.rs delete mode 100644 src/schemas/db.rs delete mode 100644 src/schemas/mod.rs diff --git a/Cargo.lock b/Cargo.lock index fb288fb..ad9bcb3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,36 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aliasable" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" + [[package]] name = "alloc-no-stdlib" version = "2.0.4" @@ -32,6 +62,12 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -47,6 +83,12 @@ dependencies = [ "libc", ] +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "async-compression" version = "0.4.12" @@ -60,6 +102,28 @@ dependencies = [ "tokio", ] +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + [[package]] name = "async-trait" version = "0.1.82" @@ -68,7 +132,16 @@ checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.77", +] + +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", ] [[package]] @@ -144,7 +217,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -159,6 +232,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bcrypt" version = "0.15.1" @@ -172,6 +251,17 @@ dependencies = [ "zeroize", ] +[[package]] +name = "bigdecimal" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "bitflags" version = "2.6.0" @@ -181,6 +271,18 @@ dependencies = [ "serde", ] +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -200,6 +302,30 @@ dependencies = [ "cipher", ] +[[package]] +name = "borsh" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" +dependencies = [ + "borsh-derive", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.77", + "syn_derive", +] + [[package]] name = "brotli" version = "6.0.0" @@ -227,6 +353,28 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "byteorder" version = "1.5.0" @@ -272,7 +420,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -305,6 +453,12 @@ dependencies = [ "yaml-rust", ] +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "const-random" version = "0.1.18" @@ -349,6 +503,36 @@ dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "crossbeam-queue" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + [[package]] name = "crunchy" version = "0.2.2" @@ -365,16 +549,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "ctrlc" -version = "3.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" -dependencies = [ - "nix", - "windows-sys 0.59.0", -] - [[package]] name = "cuid-util" version = "0.1.1" @@ -395,127 +569,143 @@ dependencies = [ ] [[package]] -name = "darling" -version = "0.20.10" +name = "der" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ - "darling_core", - "darling_macro", + "const-oid", + "pem-rfc7468", + "zeroize", ] [[package]] -name = "darling_core" -version = "0.20.10" +name = "deranged" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn", + "powerfmt", + "serde", ] [[package]] -name = "darling_macro" -version = "0.20.10" +name = "digest" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "darling_core", - "quote", - "syn", + "block-buffer", + "const-oid", + "crypto-common", + "subtle", ] [[package]] -name = "diesel" -version = "2.2.4" +name = "dlv-list" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "158fe8e2e68695bd615d7e4f3227c0727b151330d3e253b525086c348d055d5e" +checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" dependencies = [ - "bitflags", - "byteorder", - "chrono", - "diesel_derives", - "itoa", - "pq-sys", - "r2d2", + "const-random", ] [[package]] -name = "diesel_derives" -version = "2.2.3" +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "educe" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f2c3de51e2ba6bf2a648285696137aaf0f5f487bcbea93972fe8a364e131a4" +checksum = "e4bd92664bf78c4d3dba9b7cdafce6fa15b13ed3ed16175218196942e99168a8" dependencies = [ - "diesel_table_macro_syntax", - "dsl_auto_type", + "enum-ordinalize", "proc-macro2", "quote", - "syn", + "syn 2.0.77", ] [[package]] -name = "diesel_table_macro_syntax" -version = "0.2.0" +name = "either" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" dependencies = [ - "syn", + "serde", ] [[package]] -name = "digest" -version = "0.10.7" +name = "enum-ordinalize" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" dependencies = [ - "block-buffer", - "crypto-common", + "enum-ordinalize-derive", ] [[package]] -name = "dlv-list" -version = "0.5.2" +name = "enum-ordinalize-derive" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" +checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" dependencies = [ - "const-random", + "proc-macro2", + "quote", + "syn 2.0.77", ] [[package]] -name = "dotenvy" -version = "0.15.7" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] -name = "dsl_auto_type" -version = "0.1.2" +name = "errno" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5d9abe6314103864cc2d8901b7ae224e0ab1a103a0a416661b4097b0779b607" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ - "darling", - "either", - "heck", - "proc-macro2", - "quote", - "syn", + "libc", + "windows-sys 0.52.0", ] [[package]] -name = "either" -version = "1.13.0" +name = "etcetera" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] [[package]] -name = "equivalent" -version = "1.0.1" +name = "event-listener" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "fastrand" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" + +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "futures-core", + "futures-sink", + "spin", +] [[package]] name = "fnv" @@ -532,6 +722,26 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.30" @@ -539,6 +749,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -547,6 +758,34 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + [[package]] name = "futures-sink" version = "0.3.30" @@ -565,10 +804,15 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ + "futures-channel", "futures-core", + "futures-io", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", + "slab", ] [[package]] @@ -600,6 +844,15 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] + [[package]] name = "hashbrown" version = "0.13.2" @@ -611,12 +864,28 @@ name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash 0.8.11", + "allocator-api2", +] + +[[package]] +name = "hashlink" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +dependencies = [ + "hashbrown 0.14.5", +] [[package]] name = "heck" -version = "0.5.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +dependencies = [ + "unicode-segmentation", +] [[package]] name = "hermit-abi" @@ -624,6 +893,39 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "http" version = "1.1.0" @@ -728,10 +1030,14 @@ dependencies = [ ] [[package]] -name = "ident_case" -version = "1.0.1" +name = "idna" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] [[package]] name = "indexmap" @@ -743,6 +1049,17 @@ dependencies = [ "hashbrown 0.14.5", ] +[[package]] +name = "inherent" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0122b7114117e64a63ac49f752a5ca4624d534c7b1c7de796ac196381cd2d947" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + [[package]] name = "inout" version = "0.1.3" @@ -792,6 +1109,9 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] [[package]] name = "libc" @@ -799,12 +1119,35 @@ version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libsqlite3-sys" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linked-hash-map" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + [[package]] name = "lock_api" version = "0.4.12" @@ -827,6 +1170,16 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + [[package]] name = "memchr" version = "2.7.4" @@ -866,18 +1219,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "nix" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" -dependencies = [ - "bitflags", - "cfg-if", - "cfg_aliases", - "libc", -] - [[package]] name = "nom" version = "7.1.3" @@ -922,6 +1263,23 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + [[package]] name = "num-complex" version = "0.4.6" @@ -931,6 +1289,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-integer" version = "0.1.46" @@ -969,6 +1333,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -986,6 +1351,15 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "ordered-float" +version = "3.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1e1c390732d15f1d48471625cd92d154e66db2c56645e29a9cd26f4699f72dc" +dependencies = [ + "num-traits", +] + [[package]] name = "ordered-multimap" version = "0.6.0" @@ -996,6 +1370,30 @@ dependencies = [ "hashbrown 0.13.2", ] +[[package]] +name = "ouroboros" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2ba07320d39dfea882faa70554b4bd342a5f273ed59ba7c1c6b4c840492c954" +dependencies = [ + "aliasable", + "ouroboros_macro", + "static_assertions", +] + +[[package]] +name = "ouroboros_macro" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec4c6225c69b4ca778c0aea097321a64c421cf4577b331c61b229267edabb6f8" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.77", +] + [[package]] name = "overload" version = "0.1.1" @@ -1022,15 +1420,30 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.52.6", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pathdiff" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -1068,7 +1481,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn", + "syn 2.0.77", ] [[package]] @@ -1099,7 +1512,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.77", ] [[package]] @@ -1114,6 +1527,39 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.20" @@ -1124,12 +1570,36 @@ dependencies = [ ] [[package]] -name = "pq-sys" -version = "0.6.2" +name = "proc-macro-crate" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92c30dd81695321846d4dfe348da67b1752ebb61cd1549d203a7b57e323c435" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "vcpkg", + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", ] [[package]] @@ -1141,6 +1611,26 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "quote" version = "1.0.37" @@ -1151,15 +1641,10 @@ dependencies = [ ] [[package]] -name = "r2d2" -version = "0.8.10" +name = "radium" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" -dependencies = [ - "log", - "parking_lot", - "scheduled-thread-pool", -] +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "rand" @@ -1200,6 +1685,59 @@ dependencies = [ "bitflags", ] +[[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rkyv" +version = "0.7.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "ron" version = "0.8.1" @@ -1212,6 +1750,26 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "rsa" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "spki", + "subtle", + "zeroize", +] + [[package]] name = "rust-ini" version = "0.19.0" @@ -1222,12 +1780,71 @@ dependencies = [ "ordered-multimap", ] +[[package]] +name = "rust_decimal" +version = "1.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555" +dependencies = [ + "arrayvec", + "borsh", + "bytes", + "num-traits", + "rand", + "rkyv", + "serde", + "serde_json", +] + [[package]] name = "rustc-demangle" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustix" +version = "0.38.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "ring", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.17" @@ -1240,15 +1857,6 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" -[[package]] -name = "scheduled-thread-pool" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" -dependencies = [ - "parking_lot", -] - [[package]] name = "scopeguard" version = "1.2.0" @@ -1256,32 +1864,136 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "serde" -version = "1.0.210" +name = "sct" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "serde_derive", + "ring", + "untrusted", ] [[package]] -name = "serde_derive" -version = "1.0.210" +name = "sea-bae" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "3bd3534a9978d0aa7edd2808dc1f8f31c4d0ecd31ddf71d997b3c98e9f3c9114" dependencies = [ + "heck", + "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 2.0.77", ] [[package]] -name = "serde_json" -version = "1.0.128" +name = "sea-orm" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "ea1fee0cf8528dbe6eda29d5798afc522a63b75e44c5b15721e6e64af9c7cc4b" dependencies = [ - "itoa", + "async-stream", + "async-trait", + "bigdecimal", + "chrono", + "futures", + "log", + "ouroboros", + "rust_decimal", + "sea-orm-macros", + "sea-query", + "sea-query-binder", + "serde", + "serde_json", + "sqlx", + "strum", + "thiserror", + "time", + "tracing", + "url", + "uuid", +] + +[[package]] +name = "sea-orm-macros" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8737b566799ed0444f278d13c300c4c6f1a91782f60ff5825a591852d5502030" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "sea-bae", + "syn 2.0.77", + "unicode-ident", +] + +[[package]] +name = "sea-query" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e5073b2cfed767511a57d18115f3b3d8bcb5690bf8c89518caec6cb22c0cd74" +dependencies = [ + "bigdecimal", + "chrono", + "educe", + "inherent", + "ordered-float", + "rust_decimal", + "serde_json", + "time", + "uuid", +] + +[[package]] +name = "sea-query-binder" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "754965d4aee6145bec25d0898e5c931e6c22859789ce62fd85a42a15ed5a8ce3" +dependencies = [ + "bigdecimal", + "chrono", + "rust_decimal", + "sea-query", + "serde_json", + "sqlx", + "time", + "uuid", +] + +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "serde" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "serde_json" +version = "1.0.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +dependencies = [ + "itoa", "memchr", "ryu", "serde", @@ -1318,6 +2030,17 @@ dependencies = [ "serde", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha2" version = "0.10.8" @@ -1356,11 +2079,10 @@ dependencies = [ "bcrypt", "chrono", "config", - "ctrlc", "cuid2", - "diesel", "dotenvy", "once_cell", + "sea-orm", "serde", "serde_json", "thiserror", @@ -1385,6 +2107,31 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "simdutf8" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + [[package]] name = "smallvec" version = "1.13.2" @@ -1402,10 +2149,272 @@ dependencies = [ ] [[package]] -name = "strsim" -version = "0.11.1" +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sqlformat" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" +dependencies = [ + "nom", + "unicode_categories", +] + +[[package]] +name = "sqlx" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6" +dependencies = [ + "ahash 0.8.11", + "atoi", + "bigdecimal", + "byteorder", + "bytes", + "chrono", + "crc", + "crossbeam-queue", + "either", + "event-listener", + "futures-channel", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashlink", + "hex", + "indexmap", + "log", + "memchr", + "once_cell", + "paste", + "percent-encoding", + "rust_decimal", + "rustls", + "rustls-pemfile", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlformat", + "thiserror", + "time", + "tokio", + "tokio-stream", + "tracing", + "url", + "uuid", + "webpki-roots", +] + +[[package]] +name = "sqlx-macros" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea40e2345eb2faa9e1e5e326db8c34711317d2b5e08d0d5741619048a803127" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 1.0.109", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8" +dependencies = [ + "dotenvy", + "either", + "heck", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn 1.0.109", + "tempfile", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" +dependencies = [ + "atoi", + "base64 0.21.7", + "bigdecimal", + "bitflags", + "byteorder", + "bytes", + "chrono", + "crc", + "digest", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "percent-encoding", + "rand", + "rsa", + "rust_decimal", + "serde", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "time", + "tracing", + "uuid", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" +dependencies = [ + "atoi", + "base64 0.21.7", + "bigdecimal", + "bitflags", + "byteorder", + "chrono", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "itoa", + "log", + "md-5", + "memchr", + "num-bigint", + "once_cell", + "rand", + "rust_decimal", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "time", + "tracing", + "uuid", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa" +dependencies = [ + "atoi", + "chrono", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "sqlx-core", + "time", + "tracing", + "url", + "urlencoding", + "uuid", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" [[package]] name = "subtle" @@ -1413,6 +2422,17 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.77" @@ -1424,6 +2444,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.77", +] + [[package]] name = "sync_wrapper" version = "0.1.2" @@ -1436,6 +2468,25 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + [[package]] name = "thiserror" version = "1.0.63" @@ -1453,7 +2504,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.77", ] [[package]] @@ -1466,6 +2517,37 @@ dependencies = [ "once_cell", ] +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tiny-keccak" version = "2.0.2" @@ -1475,6 +2557,21 @@ dependencies = [ "crunchy", ] +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" version = "1.40.0" @@ -1501,7 +2598,18 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.77", +] + +[[package]] +name = "tokio-stream" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", ] [[package]] @@ -1620,7 +2728,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.77", ] [[package]] @@ -1670,18 +2778,77 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + [[package]] name = "unicode-ident" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +[[package]] +name = "unicode-normalization" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ea75f83c0137a9b98608359a5f1af8144876eb67bcb1ce837368e906a9f524" + [[package]] name = "unicode-segmentation" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "uuid" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +dependencies = [ + "serde", +] + [[package]] name = "valuable" version = "0.1.0" @@ -1706,6 +2873,12 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + [[package]] name = "wasm-bindgen" version = "0.2.93" @@ -1728,7 +2901,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.77", "wasm-bindgen-shared", ] @@ -1750,7 +2923,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.77", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1761,6 +2934,22 @@ version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "whoami" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" +dependencies = [ + "redox_syscall", + "wasite", +] + [[package]] name = "winapi" version = "0.3.9" @@ -1789,7 +2978,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", ] [[package]] @@ -1798,7 +2996,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -1807,7 +3005,22 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -1816,28 +3029,46 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -1850,24 +3081,48 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -1883,6 +3138,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "yaml-rust" version = "0.4.5" @@ -1910,7 +3174,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.77", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 46e5f83..379a8ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,11 +8,10 @@ axum = "0.7.5" bcrypt = "0.15.1" chrono = { version = "0.4.38", features = ["serde"] } config = { version = "0.14.0", features = ["yaml"] } -ctrlc = { version = "3.4.5", features = ["termination"] } cuid2 = "0.1.3" -diesel = { version = "2.2.4", features = ["chrono", "postgres", "r2d2"] } dotenvy = "0.15.7" once_cell = "1.19.0" +sea-orm = { version = "1.0.1", features = ["macros", "runtime-tokio-rustls", "sqlx-postgres"] } serde = { version = "1.0.210", features = ["derive"] } serde_json = "1.0.128" thiserror = "1.0.63" diff --git a/src/app.rs b/src/app.rs index e531bc5..842f9f5 100644 --- a/src/app.rs +++ b/src/app.rs @@ -2,29 +2,24 @@ use std::sync::Arc; use axum::{http::header, Router}; use tower_http::{ - compression::CompressionLayer, cors::CorsLayer, propagate_header::PropagateHeaderLayer, sensitive_headers::SetSensitiveHeadersLayer, trace, + compression::CompressionLayer, cors::CorsLayer, propagate_header::PropagateHeaderLayer, sensitive_headers::SetSensitiveHeadersLayer, }; use crate::{ - packages::{admin, db::get_connection_pool, logger}, + middleware::logger::logger, + packages::{admin, db::get_db_connection_pool, logger}, routes, }; pub async fn create_app() -> Router { logger::setup(); - let state = get_connection_pool(); - admin::setup(&state).await; + let state = get_db_connection_pool().await.unwrap(); + admin::setup(&state).await; Router::new() .with_state(Arc::new(state)) .merge(routes::create_routes()) - .layer( - // High level logging of requests and responses - trace::TraceLayer::new_for_http() - .make_span_with(trace::DefaultMakeSpan::new().include_headers(false)) - .on_request(trace::DefaultOnRequest::new().level(tracing::Level::INFO)) - .on_response(trace::DefaultOnResponse::new().level(tracing::Level::INFO)), - ) + .layer(logger()) // Mark the `Authorization` request header as sensitive so it doesn't // show in logs. .layer(SetSensitiveHeadersLayer::new(std::iter::once(header::AUTHORIZATION))) diff --git a/src/database/account.rs b/src/database/account.rs new file mode 100644 index 0000000..5b6fb6c --- /dev/null +++ b/src/database/account.rs @@ -0,0 +1,50 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "account")] +pub struct Model { + pub user_id: i32, + #[sea_orm(column_type = "Text")] + pub r#type: String, + #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] + pub provider: String, + #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] + pub provider_account_id: String, + #[sea_orm(column_type = "Text", nullable)] + pub refresh_token: Option, + #[sea_orm(column_type = "Text", nullable)] + pub access_token: Option, + pub expires_at: Option, + #[sea_orm(column_type = "Text", nullable)] + pub token_type: Option, + #[sea_orm(column_type = "Text", nullable)] + pub scope: Option, + #[sea_orm(column_type = "Text", nullable)] + pub id_token: Option, + #[sea_orm(column_type = "Text", nullable)] + pub session_state: Option, + pub created_at: DateTime, + pub updated_at: DateTime, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::user::Entity", + from = "Column::UserId", + to = "super::user::Column::Id", + on_update = "NoAction", + on_delete = "Cascade" + )] + User, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::User.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/database/authenticator.rs b/src/database/authenticator.rs new file mode 100644 index 0000000..ac124c5 --- /dev/null +++ b/src/database/authenticator.rs @@ -0,0 +1,42 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "authenticator")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false, column_type = "Text", unique)] + pub credential_id: String, + #[sea_orm(primary_key)] + pub user_id: i32, + #[sea_orm(column_type = "Text")] + pub provider_account_id: String, + #[sea_orm(column_type = "Text")] + pub credential_public_key: String, + pub counter: i32, + #[sea_orm(column_type = "Text")] + pub credential_device_type: String, + pub credential_backed_up: bool, + #[sea_orm(column_type = "Text", nullable)] + pub transports: Option, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::user::Entity", + from = "Column::UserId", + to = "super::user::Column::Id", + on_update = "NoAction", + on_delete = "Cascade" + )] + User, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::User.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/database/client.rs b/src/database/client.rs new file mode 100644 index 0000000..926b09e --- /dev/null +++ b/src/database/client.rs @@ -0,0 +1,45 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "client")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + #[sea_orm(column_type = "Text")] + pub name: String, + pub two_factor_enabled_at: Option, + pub locked_at: Option, + pub realm_id: Option, + pub created_at: DateTime, + pub updated_at: DateTime, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::realm::Entity", + from = "Column::RealmId", + to = "super::realm::Column::Id", + on_update = "NoAction", + on_delete = "Cascade" + )] + Realm, + #[sea_orm(has_many = "super::resource_group::Entity")] + ResourceGroup, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Realm.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::ResourceGroup.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/database/mod.rs b/src/database/mod.rs new file mode 100644 index 0000000..bd81ac0 --- /dev/null +++ b/src/database/mod.rs @@ -0,0 +1,16 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 + +pub mod prelude; + +pub mod account; +pub mod authenticator; +pub mod client; +pub mod password_reset_token; +pub mod realm; +pub mod resource; +pub mod resource_group; +pub mod session; +pub mod two_factor_confirmation; +pub mod two_factor_token; +pub mod user; +pub mod verification_token; diff --git a/src/database/password_reset_token.rs b/src/database/password_reset_token.rs new file mode 100644 index 0000000..1a449a1 --- /dev/null +++ b/src/database/password_reset_token.rs @@ -0,0 +1,18 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "password_reset_token")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] + pub identifier: String, + #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] + pub token: String, + pub expires: DateTime, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/database/prelude.rs b/src/database/prelude.rs new file mode 100644 index 0000000..8c6dbd4 --- /dev/null +++ b/src/database/prelude.rs @@ -0,0 +1,14 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 + +pub use super::account::Entity as Account; +pub use super::authenticator::Entity as Authenticator; +pub use super::client::Entity as Client; +pub use super::password_reset_token::Entity as PasswordResetToken; +pub use super::realm::Entity as Realm; +pub use super::resource::Entity as Resource; +pub use super::resource_group::Entity as ResourceGroup; +pub use super::session::Entity as Session; +pub use super::two_factor_confirmation::Entity as TwoFactorConfirmation; +pub use super::two_factor_token::Entity as TwoFactorToken; +pub use super::user::Entity as User; +pub use super::verification_token::Entity as VerificationToken; diff --git a/src/database/realm.rs b/src/database/realm.rs new file mode 100644 index 0000000..91eeae1 --- /dev/null +++ b/src/database/realm.rs @@ -0,0 +1,47 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "realm")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + #[sea_orm(column_type = "Text", unique)] + pub name: String, + #[sea_orm(column_type = "Text", unique)] + pub slug: String, + pub locked_at: Option, + pub created_at: DateTime, + pub updated_at: DateTime, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm(has_many = "super::client::Entity")] + Client, + #[sea_orm(has_many = "super::resource_group::Entity")] + ResourceGroup, + #[sea_orm(has_many = "super::user::Entity")] + User, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Client.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::ResourceGroup.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::User.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/database/resource.rs b/src/database/resource.rs new file mode 100644 index 0000000..eb708ac --- /dev/null +++ b/src/database/resource.rs @@ -0,0 +1,40 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "resource")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub group_id: Option, + #[sea_orm(column_type = "Text")] + pub name: String, + #[sea_orm(column_type = "Text")] + pub value: String, + #[sea_orm(column_type = "Text", nullable)] + pub description: Option, + pub locked_at: Option, + pub created_at: DateTime, + pub updated_at: DateTime, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::resource_group::Entity", + from = "Column::GroupId", + to = "super::resource_group::Column::Id", + on_update = "NoAction", + on_delete = "Cascade" + )] + ResourceGroup, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::ResourceGroup.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/database/resource_group.rs b/src/database/resource_group.rs new file mode 100644 index 0000000..e7db636 --- /dev/null +++ b/src/database/resource_group.rs @@ -0,0 +1,77 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "resource_group")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + pub realm_id: Option, + pub client_id: Option, + pub user_id: i32, + #[sea_orm(column_type = "Text")] + pub name: String, + #[sea_orm(column_type = "Text", nullable)] + pub description: Option, + pub is_default: Option, + pub locked_at: Option, + pub created_at: DateTime, + pub updated_at: DateTime, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::client::Entity", + from = "Column::ClientId", + to = "super::client::Column::Id", + on_update = "NoAction", + on_delete = "Cascade" + )] + Client, + #[sea_orm( + belongs_to = "super::realm::Entity", + from = "Column::RealmId", + to = "super::realm::Column::Id", + on_update = "NoAction", + on_delete = "Cascade" + )] + Realm, + #[sea_orm(has_many = "super::resource::Entity")] + Resource, + #[sea_orm( + belongs_to = "super::user::Entity", + from = "Column::UserId", + to = "super::user::Column::Id", + on_update = "NoAction", + on_delete = "Cascade" + )] + User, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Client.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Realm.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Resource.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::User.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/database/session.rs b/src/database/session.rs new file mode 100644 index 0000000..65f6f5b --- /dev/null +++ b/src/database/session.rs @@ -0,0 +1,34 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "session")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] + pub session_token: String, + pub user_id: i32, + pub expires: DateTime, + pub created_at: DateTime, + pub updated_at: DateTime, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::user::Entity", + from = "Column::UserId", + to = "super::user::Column::Id", + on_update = "NoAction", + on_delete = "Cascade" + )] + User, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::User.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/database/two_factor_confirmation.rs b/src/database/two_factor_confirmation.rs new file mode 100644 index 0000000..ffe62d2 --- /dev/null +++ b/src/database/two_factor_confirmation.rs @@ -0,0 +1,18 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "two_factor_confirmation")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] + pub identifier: String, + #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] + pub token: String, + pub expires: DateTime, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/database/two_factor_token.rs b/src/database/two_factor_token.rs new file mode 100644 index 0000000..f95666b --- /dev/null +++ b/src/database/two_factor_token.rs @@ -0,0 +1,18 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "two_factor_token")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] + pub identifier: String, + #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] + pub token: String, + pub expires: DateTime, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/database/user.rs b/src/database/user.rs new file mode 100644 index 0000000..7b27e24 --- /dev/null +++ b/src/database/user.rs @@ -0,0 +1,79 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "user")] +pub struct Model { + #[sea_orm(primary_key)] + pub id: i32, + #[sea_orm(column_type = "Text")] + pub first_name: String, + #[sea_orm(column_type = "Text", nullable)] + pub last_name: Option, + #[sea_orm(column_type = "Text")] + pub email: String, + pub email_verified_at: Option, + #[sea_orm(column_type = "Text", nullable)] + pub image: Option, + pub two_factor_enabled_at: Option, + #[sea_orm(column_type = "Text", nullable)] + pub password_hash: Option, + pub is_temp_password: Option, + pub locked_at: Option, + pub realm_id: Option, + pub created_at: DateTime, + pub updated_at: DateTime, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm(has_many = "super::account::Entity")] + Account, + #[sea_orm(has_many = "super::authenticator::Entity")] + Authenticator, + #[sea_orm( + belongs_to = "super::realm::Entity", + from = "Column::RealmId", + to = "super::realm::Column::Id", + on_update = "NoAction", + on_delete = "Cascade" + )] + Realm, + #[sea_orm(has_many = "super::resource_group::Entity")] + ResourceGroup, + #[sea_orm(has_many = "super::session::Entity")] + Session, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Account.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Authenticator.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Realm.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::ResourceGroup.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Session.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/database/verification_token.rs b/src/database/verification_token.rs new file mode 100644 index 0000000..8e2627f --- /dev/null +++ b/src/database/verification_token.rs @@ -0,0 +1,18 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "verification_token")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] + pub identifier: String, + #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] + pub token: String, + pub expires: DateTime, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/main.rs b/src/main.rs index 9c6d809..6113e4e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,16 @@ -use std::{net::SocketAddr, sync::Arc}; +use std::net::SocketAddr; use app::create_app; -use packages::{settings::SETTINGS, shutdown::shutdown_signal_handler}; -use tokio::{net::TcpListener, sync::Notify}; +use packages::settings::SETTINGS; +use tokio::net::TcpListener; use tracing::info; mod app; +mod database; mod handlers; -mod models; +mod middleware; mod packages; mod routes; -mod schemas; mod utils; #[tokio::main] @@ -23,14 +23,5 @@ async fn main() -> Result<(), std::io::Error> { info!("Server is listening on {}", &address); - let shutdown_signal = Arc::new(Notify::new()); - let shutdown_signal_clone = shutdown_signal.clone(); - ctrlc::set_handler(move || { - shutdown_signal_clone.notify_one(); - }) - .expect("Error setting Ctrl+C handler"); - - axum::serve(listener, app) - .with_graceful_shutdown(shutdown_signal_handler(shutdown_signal)) - .await + axum::serve(listener, app).await } diff --git a/src/middleware/logger.rs b/src/middleware/logger.rs new file mode 100644 index 0000000..414b617 --- /dev/null +++ b/src/middleware/logger.rs @@ -0,0 +1,12 @@ +use tower_http::{ + classify::{ServerErrorsAsFailures, SharedClassifier}, + trace::{DefaultMakeSpan, DefaultOnRequest, DefaultOnResponse, TraceLayer}, +}; + +pub fn logger() -> TraceLayer> { + // High level logging of requests and responses + TraceLayer::new_for_http() + .make_span_with(DefaultMakeSpan::new().include_headers(false)) + .on_request(DefaultOnRequest::new().level(tracing::Level::INFO)) + .on_response(DefaultOnResponse::new().level(tracing::Level::INFO)) +} diff --git a/src/middleware/mod.rs b/src/middleware/mod.rs new file mode 100644 index 0000000..d991728 --- /dev/null +++ b/src/middleware/mod.rs @@ -0,0 +1 @@ +pub mod logger; diff --git a/src/models/mod.rs b/src/models/mod.rs deleted file mode 100644 index abc366b..0000000 --- a/src/models/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod realm; diff --git a/src/models/realm.rs b/src/models/realm.rs deleted file mode 100644 index 59d4610..0000000 --- a/src/models/realm.rs +++ /dev/null @@ -1,23 +0,0 @@ -use chrono::NaiveDateTime; -use diesel::prelude::*; -use serde::{Deserialize, Serialize}; - -use crate::schemas::db::realm; - -#[derive(Debug, Queryable, Selectable, Serialize)] -#[diesel(table_name = realm)] -#[diesel(check_for_backend(diesel::pg::Pg))] -pub struct Realm { - pub id: i32, - pub name: String, - pub slug: String, - pub locked_at: Option, - pub created_at: NaiveDateTime, - pub updated_at: NaiveDateTime, -} - -#[derive(Debug, Deserialize, Insertable)] -#[diesel(table_name = realm)] -pub struct NewRealm<'a> { - pub name: &'a str, -} diff --git a/src/packages/admin.rs b/src/packages/admin.rs index 449ced3..a8ec63f 100644 --- a/src/packages/admin.rs +++ b/src/packages/admin.rs @@ -1,50 +1,47 @@ -use diesel::{ - dsl::insert_into, - r2d2::{ConnectionManager, PooledConnection}, - select, ExpressionMethods, PgConnection, QueryDsl, RunQueryDsl, -}; -use tracing::{debug, info}; +use sea_orm::{ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait, QueryFilter, Set}; +use tracing::info; -use crate::{ - models::realm::{NewRealm, Realm}, - packages::errors::Error, - schemas::db::realm::{self, name}, +use crate::database::{ + prelude::*, + realm::{self, ActiveModel}, }; use super::db::AppState; -pub async fn setup(state: &AppState) { +pub async fn setup(state: &AppState) -> Result<(), Box> { info!("Checking ADMIN availability!"); + let is_master_realm_exists = Realm::find().filter(realm::Column::Name.eq("Master")).one(&state.db).await?; - let mut conn = state.pool.get().map_err(Error::db_error).unwrap(); - debug!("Connection initialized"); - let is_master_realm_exists = select(diesel::dsl::exists(realm::dsl::realm.filter(name.eq("Master")))) - .get_result::(&mut conn) - .unwrap(); - debug!("find query ran for master realm"); - - if is_master_realm_exists { + if is_master_realm_exists.is_some() { info!("Master realm exists"); info!("Starting the server..."); } else { info!("Master realm does not exist"); info!("⌛ Initializing the ADMIN..."); - // TODO: 1. Create "Master" realm. - let res = create_master_realm(&mut conn); - // TODO: 2. Create admin using the admin_username and admin_password. If missing then throw error. - println!("{:#?}", res); - // TODO: 3. Give access of "Master" realm to admin. + // Step 1: Create "Master" realm. + let master_realm = create_master_realm(&state.db).await?; + info!("Master realm created: {:#?}", master_realm); + + // Step 2: Create admin user (implement logic here). + // Example: create_admin(&state.db, admin_username, admin_password).await?; + + // Step 3: Give admin access to "Master" realm. + // Example: grant_access_to_admin(&state.db, master_realm.id, admin_user.id).await?; + + info!("Admin initialization complete."); } + + Ok(()) } -fn create_master_realm(conn: &mut PooledConnection>) -> Realm { - let new_realm = NewRealm { name: "Master" }; - let res = insert_into(realm::table) - .values(&new_realm) - .get_result(conn) - .map_err(Error::db_error) - .unwrap(); +async fn create_master_realm(conn: &DatabaseConnection) -> Result> { + let new_realm = ActiveModel { + name: Set("Master".to_owned()), + ..Default::default() + }; + let inserted_realm = new_realm.insert(conn).await?; info!("✅ 1/3 Master realm created"); - return res; + + Ok(inserted_realm) } diff --git a/src/packages/db.rs b/src/packages/db.rs index 422626b..36ddb63 100644 --- a/src/packages/db.rs +++ b/src/packages/db.rs @@ -1,21 +1,19 @@ -use diesel::{ - r2d2::{ConnectionManager, Pool}, - PgConnection, -}; +use std::time::Duration; + +use sea_orm::{ConnectOptions, Database, DatabaseConnection, DbErr}; use super::settings::SETTINGS; pub struct AppState { - pub pool: Pool>, + pub db: DatabaseConnection, } -pub fn get_connection_pool() -> AppState { - let url = &SETTINGS.database.uri; - let manager = ConnectionManager::::new(url); - let pool = Pool::builder() - .test_on_check_out(true) - .build(manager) - .expect("Could not build connection pool."); +pub async fn get_db_connection_pool() -> Result { + let uri = &SETTINGS.database.uri; + let mut opts = ConnectOptions::new(uri); + opts.max_connections(20).connect_timeout(Duration::from_secs(5)); + + let db = Database::connect(opts).await?; - AppState { pool } + Ok(AppState { db }) } diff --git a/src/packages/mod.rs b/src/packages/mod.rs index c7bf08a..1f4be0f 100644 --- a/src/packages/mod.rs +++ b/src/packages/mod.rs @@ -3,4 +3,3 @@ pub mod db; pub mod errors; pub mod logger; pub mod settings; -pub mod shutdown; diff --git a/src/packages/shutdown.rs b/src/packages/shutdown.rs deleted file mode 100644 index 2ba8006..0000000 --- a/src/packages/shutdown.rs +++ /dev/null @@ -1,10 +0,0 @@ -use std::sync::Arc; - -use tokio::sync::Notify; -use tracing::info; - -pub async fn shutdown_signal_handler(shutdown_signal: Arc) { - shutdown_signal.notified().await; - info!("Handling graceful shutdown"); - info!("Close resources, drain and shutdown event handler... etc"); -} diff --git a/src/schemas/db.rs b/src/schemas/db.rs deleted file mode 100644 index 3dae98a..0000000 --- a/src/schemas/db.rs +++ /dev/null @@ -1,169 +0,0 @@ -// @generated automatically by Diesel CLI. - -diesel::table! { - account (provider, provider_account_id) { - user_id -> Int4, - #[sql_name = "type"] - type_ -> Text, - provider -> Text, - provider_account_id -> Text, - refresh_token -> Nullable, - access_token -> Nullable, - expires_at -> Nullable, - token_type -> Nullable, - scope -> Nullable, - id_token -> Nullable, - session_state -> Nullable, - created_at -> Timestamp, - updated_at -> Timestamp, - } -} - -diesel::table! { - authenticator (user_id, credential_id) { - credential_id -> Text, - user_id -> Int4, - provider_account_id -> Text, - credential_public_key -> Text, - counter -> Int4, - credential_device_type -> Text, - credential_backed_up -> Bool, - transports -> Nullable, - } -} - -diesel::table! { - client (id) { - id -> Int4, - name -> Text, - two_factor_enabled_at -> Nullable, - locked_at -> Nullable, - realm_id -> Nullable, - created_at -> Timestamp, - updated_at -> Timestamp, - } -} - -diesel::table! { - password_reset_token (identifier, token) { - identifier -> Text, - token -> Text, - expires -> Timestamp, - } -} - -diesel::table! { - realm (id) { - id -> Int4, - name -> Text, - slug -> Text, - locked_at -> Nullable, - created_at -> Timestamp, - updated_at -> Timestamp, - } -} - -diesel::table! { - resource (id) { - id -> Int4, - group_id -> Nullable, - name -> Text, - value -> Text, - description -> Nullable, - locked_at -> Nullable, - created_at -> Timestamp, - updated_at -> Timestamp, - } -} - -diesel::table! { - resource_group (id) { - id -> Int4, - realm_id -> Nullable, - client_id -> Nullable, - user_id -> Int4, - name -> Text, - description -> Nullable, - is_default -> Nullable, - locked_at -> Nullable, - created_at -> Timestamp, - updated_at -> Timestamp, - } -} - -diesel::table! { - session (session_token) { - session_token -> Text, - user_id -> Int4, - expires -> Timestamp, - created_at -> Timestamp, - updated_at -> Timestamp, - } -} - -diesel::table! { - two_factor_confirmation (identifier, token) { - identifier -> Text, - token -> Text, - expires -> Timestamp, - } -} - -diesel::table! { - two_factor_token (identifier, token) { - identifier -> Text, - token -> Text, - expires -> Timestamp, - } -} - -diesel::table! { - user (id) { - id -> Int4, - first_name -> Text, - last_name -> Nullable, - email -> Text, - email_verified_at -> Nullable, - image -> Nullable, - two_factor_enabled_at -> Nullable, - password_hash -> Nullable, - is_temp_password -> Nullable, - locked_at -> Nullable, - realm_id -> Nullable, - created_at -> Timestamp, - updated_at -> Timestamp, - } -} - -diesel::table! { - verification_token (identifier, token) { - identifier -> Text, - token -> Text, - expires -> Timestamp, - } -} - -diesel::joinable!(account -> user (user_id)); -diesel::joinable!(authenticator -> user (user_id)); -diesel::joinable!(client -> realm (realm_id)); -diesel::joinable!(resource -> resource_group (group_id)); -diesel::joinable!(resource_group -> client (client_id)); -diesel::joinable!(resource_group -> realm (realm_id)); -diesel::joinable!(resource_group -> user (user_id)); -diesel::joinable!(session -> user (user_id)); -diesel::joinable!(user -> realm (realm_id)); - -diesel::allow_tables_to_appear_in_same_query!( - account, - authenticator, - client, - password_reset_token, - realm, - resource, - resource_group, - session, - two_factor_confirmation, - two_factor_token, - user, - verification_token, -); diff --git a/src/schemas/mod.rs b/src/schemas/mod.rs deleted file mode 100644 index dec1023..0000000 --- a/src/schemas/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod db; From 650ad96d975bc4c3232a47592955b069d7ad9e3b Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Fri, 20 Sep 2024 01:11:32 +0530 Subject: [PATCH 10/45] route structure created till get user by id --- src/app.rs | 2 +- src/handlers/client.rs | 4 ++-- src/handlers/mod.rs | 1 + src/handlers/user.rs | 10 ++++++++++ src/routes/client.rs | 5 +---- src/routes/mod.rs | 1 + src/routes/realm.rs | 13 ++++++++----- src/routes/user.rs | 7 +++++++ 8 files changed, 31 insertions(+), 12 deletions(-) create mode 100644 src/handlers/user.rs create mode 100644 src/routes/user.rs diff --git a/src/app.rs b/src/app.rs index 842f9f5..fb3acdb 100644 --- a/src/app.rs +++ b/src/app.rs @@ -15,7 +15,7 @@ pub async fn create_app() -> Router { logger::setup(); let state = get_db_connection_pool().await.unwrap(); - admin::setup(&state).await; + admin::setup(&state).await.expect("Failed to setup admin account"); Router::new() .with_state(Arc::new(state)) .merge(routes::create_routes()) diff --git a/src/handlers/client.rs b/src/handlers/client.rs index 8b2715b..1386095 100644 --- a/src/handlers/client.rs +++ b/src/handlers/client.rs @@ -1,7 +1,7 @@ use axum::extract::Path; -pub async fn get_clients() -> String { - "Hi from clients".to_owned() +pub async fn get_clients(Path(realm): Path) -> String { + format!("Hi from clients of {realm}") } pub async fn get_client(Path((realm, client_id)): Path<(String, String)>) -> String { diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs index 2cf4974..febc0a5 100644 --- a/src/handlers/mod.rs +++ b/src/handlers/mod.rs @@ -1,2 +1,3 @@ pub mod client; pub mod realm; +pub mod user; diff --git a/src/handlers/user.rs b/src/handlers/user.rs new file mode 100644 index 0000000..c46c9fc --- /dev/null +++ b/src/handlers/user.rs @@ -0,0 +1,10 @@ +use axum::extract::Path; + +pub async fn get_users(Path(realm): Path) -> String { + format!("Hi from users of {realm}") +} + +pub async fn get_user(Path((realm, user_id)): Path<(String, String)>) -> String { + println!("This is user Name: {} - {}", &realm, &user_id); + format!("user is - {} - {}", realm, user_id) +} diff --git a/src/routes/client.rs b/src/routes/client.rs index a369415..08de525 100644 --- a/src/routes/client.rs +++ b/src/routes/client.rs @@ -3,8 +3,5 @@ use axum::{routing::get, Router}; use crate::handlers::client::{get_client, get_clients}; pub fn create_routes() -> Router { - Router::new().nest( - "/clients", - Router::new().route("/", get(get_clients)).route("/:client_id", get(get_client)), - ) + Router::new().route("/", get(get_clients)).route("/:client_id", get(get_client)) } diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 5e40155..2746178 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -3,6 +3,7 @@ use axum::Router; pub mod client; pub mod health; pub mod realm; +pub mod user; pub fn create_routes() -> Router { Router::new() diff --git a/src/routes/realm.rs b/src/routes/realm.rs index a51e907..dd96ca6 100644 --- a/src/routes/realm.rs +++ b/src/routes/realm.rs @@ -2,11 +2,14 @@ use axum::{routing::get, Router}; use crate::handlers::realm::{get_realm, get_realms}; -use super::client; +use super::{client, user}; pub fn create_routes() -> Router { - Router::new() - .route("/", get(get_realms)) - .route("/:realm", get(get_realm)) - .merge(client::create_routes()) + Router::new().route("/", get(get_realms)).nest( + "/:realm", + Router::new() + .route("/", get(get_realm)) + .nest("/clients", client::create_routes()) + .nest("/users", user::create_routes()), + ) } diff --git a/src/routes/user.rs b/src/routes/user.rs new file mode 100644 index 0000000..47a3808 --- /dev/null +++ b/src/routes/user.rs @@ -0,0 +1,7 @@ +use axum::{routing::get, Router}; + +use crate::handlers::user::{get_user, get_users}; + +pub fn create_routes() -> Router { + Router::new().route("/", get(get_users)).route("/:user_id", get(get_user)) +} From 729dedd1f5acfb8f40c86b18b5a62b36be77686f Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Fri, 20 Sep 2024 13:16:34 +0530 Subject: [PATCH 11/45] primary key changed from serial to uuid_v7 --- .../down.sql | 1 + .../up.sql | 48 +++++++++++++------ src/database/account.rs | 2 +- src/database/authenticator.rs | 4 +- src/database/client.rs | 6 +-- src/database/realm.rs | 4 +- src/database/resource.rs | 6 +-- src/database/resource_group.rs | 10 ++-- src/database/session.rs | 2 +- src/database/user.rs | 6 +-- src/packages/admin.rs | 2 + 11 files changed, 57 insertions(+), 34 deletions(-) diff --git a/migrations/2024-09-18-153303_db_initialization/down.sql b/migrations/2024-09-18-153303_db_initialization/down.sql index dcf177a..6f15169 100644 --- a/migrations/2024-09-18-153303_db_initialization/down.sql +++ b/migrations/2024-09-18-153303_db_initialization/down.sql @@ -35,6 +35,7 @@ DROP TABLE IF EXISTS client; DROP TABLE IF EXISTS realm; -- Drop functions and triggers +DROP FUNCTION IF EXISTS uuid_generate_v7(); DROP TRIGGER IF EXISTS ensure_single_default_resource_group ON resource_group; DROP FUNCTION IF EXISTS manage_default_resource_group(); DROP TRIGGER IF EXISTS before_insert_and_update_realm ON realm; diff --git a/migrations/2024-09-18-153303_db_initialization/up.sql b/migrations/2024-09-18-153303_db_initialization/up.sql index 45dfe51..02766d3 100644 --- a/migrations/2024-09-18-153303_db_initialization/up.sql +++ b/migrations/2024-09-18-153303_db_initialization/up.sql @@ -1,6 +1,26 @@ +CREATE OR REPLACE FUNCTION uuid_generate_v7 () RETURNS uuid AS $$ +BEGIN + -- use random v4 uuid as starting point (which has the same variant we need) + -- then overlay timestamp + -- then set version 7 by flipping the 2 and 1 bit in the version 4 string + return encode( + set_bit( + set_bit( + overlay(uuid_send(gen_random_uuid()) + placing substring(int8send(floor(extract(epoch from clock_timestamp()) * 1000)::bigint) from 3) + from 1 for 6 + ), + 52, 1 + ), + 53, 1 + ), + 'hex')::uuid; +END +$$ LANGUAGE plpgsql volatile; + -- Create realms table CREATE TABLE realm ( - id SERIAL PRIMARY KEY, + id UUID PRIMARY KEY DEFAULT uuid_generate_v7(), name TEXT NOT NULL UNIQUE, slug TEXT NOT NULL UNIQUE, locked_at TIMESTAMP, @@ -24,11 +44,11 @@ EXECUTE FUNCTION generate_slug(); -- Create clients table CREATE TABLE client ( - id SERIAL PRIMARY KEY, + id UUID PRIMARY KEY DEFAULT uuid_generate_v7(), name TEXT NOT NULL, two_factor_enabled_at TIMESTAMP, locked_at TIMESTAMP, - realm_id INTEGER REFERENCES realm(id) ON DELETE CASCADE, + realm_id UUID NOT NULL REFERENCES realm(id) ON DELETE CASCADE, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT chk_locked_at CHECK (locked_at IS NULL OR locked_at <= CURRENT_TIMESTAMP) @@ -39,7 +59,7 @@ CREATE INDEX idx_client_realm_locked ON client (realm_id, locked_at); -- Create users table CREATE TABLE "user" ( - id SERIAL PRIMARY KEY, + id UUID PRIMARY KEY DEFAULT uuid_generate_v7(), first_name TEXT NOT NULL, last_name TEXT, email TEXT NOT NULL, @@ -49,7 +69,7 @@ CREATE TABLE "user" ( password_hash TEXT, is_temp_password BOOLEAN DEFAULT TRUE, locked_at TIMESTAMP, - realm_id INTEGER REFERENCES realm(id) ON DELETE CASCADE, + realm_id UUID NOT NULL REFERENCES realm(id) ON DELETE CASCADE, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT chk_email_format CHECK (email ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}$'), @@ -64,10 +84,10 @@ CREATE INDEX idx_user_name ON "user" (realm_id, first_name, last_name); ----------------------------------------------------------- -- Create resources_groups table CREATE TABLE resource_group ( - id SERIAL PRIMARY KEY, - realm_id INTEGER REFERENCES realm(id) ON DELETE CASCADE, - client_id INTEGER REFERENCES client(id) ON DELETE CASCADE, - user_id SERIAL NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, + id UUID PRIMARY KEY DEFAULT uuid_generate_v7(), + realm_id UUID NOT NULL REFERENCES realm(id) ON DELETE CASCADE, + client_id UUID NOT NULL REFERENCES client(id) ON DELETE CASCADE, + user_id UUID NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, name TEXT NOT NULL, description TEXT, is_default BOOLEAN DEFAULT FALSE, @@ -120,8 +140,8 @@ EXECUTE FUNCTION manage_default_resource_group(); -- Create resources table CREATE TABLE resource ( - id SERIAL PRIMARY KEY, - group_id INTEGER REFERENCES resource_group(id) ON DELETE CASCADE, + id UUID PRIMARY KEY DEFAULT uuid_generate_v7(), + group_id UUID NOT NULL REFERENCES resource_group(id) ON DELETE CASCADE, name TEXT NOT NULL, value TEXT NOT NULL, description TEXT, @@ -135,7 +155,7 @@ CREATE UNIQUE INDEX resource_group_and_resource_idx ON resource (group_id, name) -- Create accounts table CREATE TABLE account ( - user_id SERIAL NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, + user_id UUID NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, type TEXT NOT NULL, provider TEXT NOT NULL, provider_account_id TEXT NOT NULL, @@ -154,7 +174,7 @@ CREATE TABLE account ( -- Create sessions table CREATE TABLE session ( session_token TEXT PRIMARY KEY, - user_id SERIAL NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, + user_id UUID NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, expires TIMESTAMP NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP @@ -195,7 +215,7 @@ CREATE TABLE two_factor_confirmation ( -- Create authenticators table CREATE TABLE authenticator ( credential_id TEXT NOT NULL UNIQUE, - user_id SERIAL NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, + user_id UUID NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, provider_account_id TEXT NOT NULL, credential_public_key TEXT NOT NULL, counter INTEGER NOT NULL, diff --git a/src/database/account.rs b/src/database/account.rs index 5b6fb6c..4a37839 100644 --- a/src/database/account.rs +++ b/src/database/account.rs @@ -5,7 +5,7 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "account")] pub struct Model { - pub user_id: i32, + pub user_id: Uuid, #[sea_orm(column_type = "Text")] pub r#type: String, #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] diff --git a/src/database/authenticator.rs b/src/database/authenticator.rs index ac124c5..1e07385 100644 --- a/src/database/authenticator.rs +++ b/src/database/authenticator.rs @@ -7,8 +7,8 @@ use sea_orm::entity::prelude::*; pub struct Model { #[sea_orm(primary_key, auto_increment = false, column_type = "Text", unique)] pub credential_id: String, - #[sea_orm(primary_key)] - pub user_id: i32, + #[sea_orm(primary_key, auto_increment = false)] + pub user_id: Uuid, #[sea_orm(column_type = "Text")] pub provider_account_id: String, #[sea_orm(column_type = "Text")] diff --git a/src/database/client.rs b/src/database/client.rs index 926b09e..b6b4050 100644 --- a/src/database/client.rs +++ b/src/database/client.rs @@ -5,13 +5,13 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "client")] pub struct Model { - #[sea_orm(primary_key)] - pub id: i32, + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, #[sea_orm(column_type = "Text")] pub name: String, pub two_factor_enabled_at: Option, pub locked_at: Option, - pub realm_id: Option, + pub realm_id: Uuid, pub created_at: DateTime, pub updated_at: DateTime, } diff --git a/src/database/realm.rs b/src/database/realm.rs index 91eeae1..1f2a5e9 100644 --- a/src/database/realm.rs +++ b/src/database/realm.rs @@ -5,8 +5,8 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "realm")] pub struct Model { - #[sea_orm(primary_key)] - pub id: i32, + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, #[sea_orm(column_type = "Text", unique)] pub name: String, #[sea_orm(column_type = "Text", unique)] diff --git a/src/database/resource.rs b/src/database/resource.rs index eb708ac..08285a8 100644 --- a/src/database/resource.rs +++ b/src/database/resource.rs @@ -5,9 +5,9 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "resource")] pub struct Model { - #[sea_orm(primary_key)] - pub id: i32, - pub group_id: Option, + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, + pub group_id: Uuid, #[sea_orm(column_type = "Text")] pub name: String, #[sea_orm(column_type = "Text")] diff --git a/src/database/resource_group.rs b/src/database/resource_group.rs index e7db636..d5a5b63 100644 --- a/src/database/resource_group.rs +++ b/src/database/resource_group.rs @@ -5,11 +5,11 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "resource_group")] pub struct Model { - #[sea_orm(primary_key)] - pub id: i32, - pub realm_id: Option, - pub client_id: Option, - pub user_id: i32, + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, + pub realm_id: Uuid, + pub client_id: Uuid, + pub user_id: Uuid, #[sea_orm(column_type = "Text")] pub name: String, #[sea_orm(column_type = "Text", nullable)] diff --git a/src/database/session.rs b/src/database/session.rs index 65f6f5b..2f2b088 100644 --- a/src/database/session.rs +++ b/src/database/session.rs @@ -7,7 +7,7 @@ use sea_orm::entity::prelude::*; pub struct Model { #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] pub session_token: String, - pub user_id: i32, + pub user_id: Uuid, pub expires: DateTime, pub created_at: DateTime, pub updated_at: DateTime, diff --git a/src/database/user.rs b/src/database/user.rs index 7b27e24..774071b 100644 --- a/src/database/user.rs +++ b/src/database/user.rs @@ -5,8 +5,8 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "user")] pub struct Model { - #[sea_orm(primary_key)] - pub id: i32, + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, #[sea_orm(column_type = "Text")] pub first_name: String, #[sea_orm(column_type = "Text", nullable)] @@ -21,7 +21,7 @@ pub struct Model { pub password_hash: Option, pub is_temp_password: Option, pub locked_at: Option, - pub realm_id: Option, + pub realm_id: Uuid, pub created_at: DateTime, pub updated_at: DateTime, } diff --git a/src/packages/admin.rs b/src/packages/admin.rs index a8ec63f..1c5b4e2 100644 --- a/src/packages/admin.rs +++ b/src/packages/admin.rs @@ -45,3 +45,5 @@ async fn create_master_realm(conn: &DatabaseConnection) -> Result Date: Fri, 20 Sep 2024 15:26:28 +0530 Subject: [PATCH 12/45] db initialization steps added --- config/default.yml | 2 +- src/packages/admin.rs | 116 ++++++++++++++++++++++++++++++--------- src/packages/errors.rs | 18 ++++-- src/packages/settings.rs | 6 +- src/utils/hash.rs | 13 +++++ src/utils/mod.rs | 2 +- 6 files changed, 123 insertions(+), 34 deletions(-) create mode 100644 src/utils/hash.rs diff --git a/config/default.yml b/config/default.yml index beeb741..147d6d0 100644 --- a/config/default.yml +++ b/config/default.yml @@ -9,5 +9,5 @@ auth: logger: level: debug admin: - username: admin + email: admin@admin.com password: 12345 diff --git a/src/packages/admin.rs b/src/packages/admin.rs index 1c5b4e2..66cad5c 100644 --- a/src/packages/admin.rs +++ b/src/packages/admin.rs @@ -1,49 +1,115 @@ -use sea_orm::{ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait, QueryFilter, Set}; +use sea_orm::{prelude::Uuid, ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait, QueryFilter, Set}; use tracing::info; -use crate::database::{ - prelude::*, - realm::{self, ActiveModel}, +use crate::{ + database::{ + client, + prelude::{Realm, User}, + realm, resource, resource_group, user, + }, + packages::settings::SETTINGS, + utils::hash::generate_password_hash, }; -use super::db::AppState; +use super::{db::AppState, errors::Error}; -pub async fn setup(state: &AppState) -> Result<(), Box> { +pub async fn setup(state: &AppState) -> Result<(), Error> { info!("Checking ADMIN availability!"); - let is_master_realm_exists = Realm::find().filter(realm::Column::Name.eq("Master")).one(&state.db).await?; + let is_admin_user_exists = User::find().filter(user::Column::Email.eq(&SETTINGS.admin.email)).one(&state.db).await?; - if is_master_realm_exists.is_some() { - info!("Master realm exists"); + if is_admin_user_exists.is_some() { + info!("DB has been already initialized!"); info!("Starting the server..."); } else { - info!("Master realm does not exist"); - info!("⌛ Initializing the ADMIN..."); - - // Step 1: Create "Master" realm. - let master_realm = create_master_realm(&state.db).await?; - info!("Master realm created: {:#?}", master_realm); - - // Step 2: Create admin user (implement logic here). - // Example: create_admin(&state.db, admin_username, admin_password).await?; - - // Step 3: Give admin access to "Master" realm. - // Example: grant_access_to_admin(&state.db, master_realm.id, admin_user.id).await?; + info!("DB has not been initialized!"); + info!("⌛ Initializing the DB..."); + initialize_db(&state.db).await?; info!("Admin initialization complete."); } Ok(()) } -async fn create_master_realm(conn: &DatabaseConnection) -> Result> { - let new_realm = ActiveModel { +async fn initialize_db(conn: &DatabaseConnection) -> Result<(), Error> { + let realm = create_master_realm(conn).await?; + let result = (|| async { + let client = create_default_client(conn, realm.id).await?; + let user = create_admin_user(conn, realm.id).await?; + assign_resource_to_admin(conn, realm.id, client.id, user.id).await?; + Ok(()) + })() + .await; + + if result.is_err() { + Realm::delete_by_id(realm.id).exec(conn).await?; + Err(result.unwrap_err()) + } else { + Ok(()) + } +} + +async fn create_master_realm(conn: &DatabaseConnection) -> Result { + let new_realm = realm::ActiveModel { name: Set("Master".to_owned()), ..Default::default() }; let inserted_realm = new_realm.insert(conn).await?; - info!("✅ 1/3 Master realm created"); + info!("✅ 1/5: Master realm created"); Ok(inserted_realm) } -// async fn create_default_client(conn: &DatabaseConnection, realm_id: uu) +async fn create_default_client(conn: &DatabaseConnection, realm_id: Uuid) -> Result { + let new_client = client::ActiveModel { + name: Set("client".to_owned()), + realm_id: Set(realm_id), + ..Default::default() + }; + let inserted_client = new_client.insert(conn).await?; + info!("✅ 2/5: Default client created"); + + Ok(inserted_client) +} + +async fn create_admin_user(conn: &DatabaseConnection, realm_id: Uuid) -> Result { + let pw_hash = generate_password_hash(&SETTINGS.admin.password).await?; + let new_user = user::ActiveModel { + email: Set(SETTINGS.admin.email.to_owned()), + password_hash: Set(Some(pw_hash)), + realm_id: Set(realm_id), + first_name: Set(SETTINGS.admin.email.to_owned()), + is_temp_password: Set(Some(false)), + ..Default::default() + }; + let inserted_user = new_user.insert(conn).await?; + info!("✅ 3/5: Admin user created"); + + Ok(inserted_user) +} + +async fn assign_resource_to_admin(conn: &DatabaseConnection, realm_id: Uuid, client_id: Uuid, user_id: Uuid) -> Result { + let new_resource_group = resource_group::ActiveModel { + client_id: Set(client_id), + realm_id: Set(realm_id), + user_id: Set(user_id), + name: Set("default_resource_group".to_owned()), + description: Set(Some( + "This resource group has been created at the time of system initialization.".to_owned(), + )), + ..Default::default() + }; + let inserted_resource_group = new_resource_group.insert(conn).await?; + info!("✅ 4/5: Default resource group created"); + + let new_resource = resource::ActiveModel { + group_id: Set(inserted_resource_group.id), + name: Set("role".to_owned()), + value: Set("admin".to_owned()), + description: Set(Some("This role has been created at the time of initialization.".to_owned())), + ..Default::default() + }; + let inserted_resource = new_resource.insert(conn).await?; + info!("✅ 5/5: Default resource created"); + Ok(inserted_resource) +} diff --git a/src/packages/errors.rs b/src/packages/errors.rs index bc29973..f38a537 100644 --- a/src/packages/errors.rs +++ b/src/packages/errors.rs @@ -2,6 +2,7 @@ use axum::http::StatusCode; use axum::response::{IntoResponse, Response}; use axum::Json; use bcrypt::BcryptError; +use sea_orm::DbErr; use serde_json::json; use tokio::task::JoinError; @@ -54,8 +55,11 @@ impl Error { Error::NotFound(NotFound {}) } - pub fn db_error(_: E) -> Self { - Error::DatabaseError(DatabaseError {}) + pub fn db_error(err: E) -> Self + where + E: std::error::Error + Send + Sync + 'static, + { + Error::DatabaseError(DatabaseError(Box::new(err))) } pub fn internal_error(err: E) -> (StatusCode, String) @@ -100,5 +104,11 @@ pub struct BadRequest {} pub struct NotFound {} #[derive(thiserror::Error, Debug)] -#[error("Database error")] -pub struct DatabaseError {} +#[error("Database error: {0}")] +pub struct DatabaseError(#[from] Box); + +impl From for Error { + fn from(err: DbErr) -> Self { + Error::DatabaseError(DatabaseError(Box::new(err))) + } +} diff --git a/src/packages/settings.rs b/src/packages/settings.rs index c7b3f06..43d8f53 100644 --- a/src/packages/settings.rs +++ b/src/packages/settings.rs @@ -24,7 +24,7 @@ pub struct Database { #[derive(Debug, Clone, Deserialize)] pub struct Admin { - pub username: String, + pub email: String, pub password: String, } @@ -56,8 +56,8 @@ impl Settings { if let Ok(database_uri) = env::var("DATABASE_URL") { builder = builder.set_override("database.uri", database_uri)?; } - if let Ok(admin_username) = env::var("ADMIN_USERNAME") { - builder = builder.set_override("admin.username", admin_username)?; + if let Ok(admin_email) = env::var("ADMIN_USERNAME") { + builder = builder.set_override("admin.email", admin_email)?; } if let Ok(admin_password) = env::var("ADMIN_PASSWORD") { builder = builder.set_override("admin.password", admin_password)?; diff --git a/src/utils/hash.rs b/src/utils/hash.rs new file mode 100644 index 0000000..345e1ed --- /dev/null +++ b/src/utils/hash.rs @@ -0,0 +1,13 @@ +use crate::packages::errors::Error; +use tokio::task; + +pub async fn generate_password_hash

(password: P) -> Result +where + P: AsRef + Send + 'static, +{ + let cost = 4; + task::spawn_blocking(move || bcrypt::hash(password.as_ref(), cost)) + .await + .map_err(Error::RunSyncTask)? + .map_err(Error::HashPassword) +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 8b13789..ec5d33c 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1 +1 @@ - +pub mod hash; From 6daee5f80204912f6c3930031af4392eea758ae7 Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Fri, 20 Sep 2024 16:12:03 +0530 Subject: [PATCH 13/45] token user in progress --- Cargo.lock | 38 +++++++++++ Cargo.toml | 1 + .../up.sql | 4 +- src/database/user.rs | 2 + src/packages/mod.rs | 1 + src/packages/token.rs | 65 +++++++++++++++++++ 6 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 src/packages/token.rs diff --git a/Cargo.lock b/Cargo.lock index ad9bcb3..148725e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1095,6 +1095,21 @@ dependencies = [ "serde", ] +[[package]] +name = "jsonwebtoken" +version = "9.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f" +dependencies = [ + "base64 0.21.7", + "js-sys", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + [[package]] name = "keccak" version = "0.1.5" @@ -1435,6 +1450,16 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +[[package]] +name = "pem" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +dependencies = [ + "base64 0.22.1", + "serde", +] + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -2081,6 +2106,7 @@ dependencies = [ "config", "cuid2", "dotenvy", + "jsonwebtoken", "once_cell", "sea-orm", "serde", @@ -2123,6 +2149,18 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time", +] + [[package]] name = "slab" version = "0.4.9" diff --git a/Cargo.toml b/Cargo.toml index 379a8ef..7b71eca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ chrono = { version = "0.4.38", features = ["serde"] } config = { version = "0.14.0", features = ["yaml"] } cuid2 = "0.1.3" dotenvy = "0.15.7" +jsonwebtoken = "9.3.0" once_cell = "1.19.0" sea-orm = { version = "1.0.1", features = ["macros", "runtime-tokio-rustls", "sqlx-postgres"] } serde = { version = "1.0.210", features = ["derive"] } diff --git a/migrations/2024-09-18-153303_db_initialization/up.sql b/migrations/2024-09-18-153303_db_initialization/up.sql index 02766d3..9dd6a2e 100644 --- a/migrations/2024-09-18-153303_db_initialization/up.sql +++ b/migrations/2024-09-18-153303_db_initialization/up.sql @@ -64,6 +64,7 @@ CREATE TABLE "user" ( last_name TEXT, email TEXT NOT NULL, email_verified_at TIMESTAMP, + phone TEXT, image TEXT, two_factor_enabled_at TIMESTAMP, password_hash TEXT, @@ -74,7 +75,8 @@ CREATE TABLE "user" ( updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT chk_email_format CHECK (email ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}$'), CONSTRAINT chk_locked_at CHECK (locked_at IS NULL OR locked_at <= CURRENT_TIMESTAMP), - CONSTRAINT chk_email_verified_at CHECK (email_verified_at IS NULL OR email_verified_at >= created_at AND email_verified_at <= CURRENT_TIMESTAMP) + CONSTRAINT chk_email_verified_at CHECK (email_verified_at IS NULL OR email_verified_at >= created_at AND email_verified_at <= CURRENT_TIMESTAMP), + CONSTRAINT chk_phone_format CHECK (phone ~ '^\+?[0-9]{10,14}$') ); CREATE UNIQUE INDEX realm_email_idx ON "user" (realm_id, email); diff --git a/src/database/user.rs b/src/database/user.rs index 774071b..07c5574 100644 --- a/src/database/user.rs +++ b/src/database/user.rs @@ -15,6 +15,8 @@ pub struct Model { pub email: String, pub email_verified_at: Option, #[sea_orm(column_type = "Text", nullable)] + pub phone: Option, + #[sea_orm(column_type = "Text", nullable)] pub image: Option, pub two_factor_enabled_at: Option, #[sea_orm(column_type = "Text", nullable)] diff --git a/src/packages/mod.rs b/src/packages/mod.rs index 1f4be0f..899094b 100644 --- a/src/packages/mod.rs +++ b/src/packages/mod.rs @@ -3,3 +3,4 @@ pub mod db; pub mod errors; pub mod logger; pub mod settings; +// pub mod token; diff --git a/src/packages/token.rs b/src/packages/token.rs new file mode 100644 index 0000000..3bf7cc1 --- /dev/null +++ b/src/packages/token.rs @@ -0,0 +1,65 @@ +use jsonwebtoken::{errors::Error, Algorithm, DecodingKey, EncodingKey, Header, TokenData, Validation}; +use once_cell::sync::Lazy; +use sea_orm::prelude::Uuid; +use serde::{Deserialize, Serialize}; + +type TokenResult = Result, Error>; + +static VALIDATION: Lazy = Lazy::new(Validation::default); +static HEADER: Lazy

= Lazy::new(|| Header::new(Algorithm::RS512)); + +#[derive(Debug, Serialize, Deserialize)] +pub struct TokenUser { + pub id: Uuid, + #[serde(rename = "firstName")] + pub first_name: String, + #[serde(rename = "lastName")] + pub last_name: String, + pub email: String, + pub phone: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub resource: Option, +} + +impl From for TokenUser { + fn from(user: User) -> Self { + Self { + id: user.id.unwrap(), + first_name: user.first_name.clone(), + last_name: user.last_name.clone(), + email: user.email.clone(), + phone: user.phone.clone(), + resource: user.find_active_resource().cloned(), + } + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Claims { + pub exp: usize, // Expiration time (as UTC timestamp). validate_exp defaults to true in validation + pub iat: usize, // Issued at (as UTC timestamp) + pub user: TokenUser, +} + +impl Claims { + pub fn new(user: User) -> Self { + Self { + exp: (chrono::Local::now() + chrono::Duration::days(30)).timestamp() as usize, + iat: chrono::Local::now().timestamp() as usize, + user: TokenUser::from(user), + } + } +} + +pub fn create(user: User, secret: &str) -> Result { + let encoding_key = EncodingKey::from_secret(secret.as_ref()); + let claims = Claims::new(user); + + jsonwebtoken::encode(&HEADER, &claims, &encoding_key) +} + +pub fn decode(token: &str, secret: &str) -> TokenResult { + let decoding_key = DecodingKey::from_secret(secret.as_ref()); + + jsonwebtoken::decode::(token, &decoding_key, &VALIDATION) +} From a6e48651d27c801c4a7a0a4a32cec7977d825e69 Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Fri, 20 Sep 2024 17:43:10 +0530 Subject: [PATCH 14/45] token user removed for time being --- src/packages/mod.rs | 1 - src/packages/token.rs | 65 ------------------------------------------- 2 files changed, 66 deletions(-) delete mode 100644 src/packages/token.rs diff --git a/src/packages/mod.rs b/src/packages/mod.rs index 899094b..1f4be0f 100644 --- a/src/packages/mod.rs +++ b/src/packages/mod.rs @@ -3,4 +3,3 @@ pub mod db; pub mod errors; pub mod logger; pub mod settings; -// pub mod token; diff --git a/src/packages/token.rs b/src/packages/token.rs deleted file mode 100644 index 3bf7cc1..0000000 --- a/src/packages/token.rs +++ /dev/null @@ -1,65 +0,0 @@ -use jsonwebtoken::{errors::Error, Algorithm, DecodingKey, EncodingKey, Header, TokenData, Validation}; -use once_cell::sync::Lazy; -use sea_orm::prelude::Uuid; -use serde::{Deserialize, Serialize}; - -type TokenResult = Result, Error>; - -static VALIDATION: Lazy = Lazy::new(Validation::default); -static HEADER: Lazy
= Lazy::new(|| Header::new(Algorithm::RS512)); - -#[derive(Debug, Serialize, Deserialize)] -pub struct TokenUser { - pub id: Uuid, - #[serde(rename = "firstName")] - pub first_name: String, - #[serde(rename = "lastName")] - pub last_name: String, - pub email: String, - pub phone: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub resource: Option, -} - -impl From for TokenUser { - fn from(user: User) -> Self { - Self { - id: user.id.unwrap(), - first_name: user.first_name.clone(), - last_name: user.last_name.clone(), - email: user.email.clone(), - phone: user.phone.clone(), - resource: user.find_active_resource().cloned(), - } - } -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct Claims { - pub exp: usize, // Expiration time (as UTC timestamp). validate_exp defaults to true in validation - pub iat: usize, // Issued at (as UTC timestamp) - pub user: TokenUser, -} - -impl Claims { - pub fn new(user: User) -> Self { - Self { - exp: (chrono::Local::now() + chrono::Duration::days(30)).timestamp() as usize, - iat: chrono::Local::now().timestamp() as usize, - user: TokenUser::from(user), - } - } -} - -pub fn create(user: User, secret: &str) -> Result { - let encoding_key = EncodingKey::from_secret(secret.as_ref()); - let claims = Claims::new(user); - - jsonwebtoken::encode(&HEADER, &claims, &encoding_key) -} - -pub fn decode(token: &str, secret: &str) -> TokenResult { - let decoding_key = DecodingKey::from_secret(secret.as_ref()); - - jsonwebtoken::decode::(token, &decoding_key, &VALIDATION) -} From e017557053a358f60386832e719e462dcf6a5806 Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Thu, 26 Sep 2024 09:22:39 +0530 Subject: [PATCH 15/45] fix: login route structure corrected and able to make db calls --- Cargo.lock | 42 ++++++++++----- Cargo.toml | 18 +++++-- config/default.yml | 4 +- src/app.rs | 7 +-- src/handlers/auth.rs | 111 +++++++++++++++++++++++++++++++++++++++ src/handlers/mod.rs | 1 + src/main.rs | 1 + src/models/mod.rs | 1 + src/models/user.rs | 10 ++++ src/packages/db.rs | 1 + src/packages/mod.rs | 1 + src/packages/settings.rs | 6 +++ src/packages/token.rs | 111 +++++++++++++++++++++++++++++++++++++++ src/routes/auth.rs | 10 ++++ src/routes/client.rs | 7 ++- src/routes/mod.rs | 1 + 16 files changed, 309 insertions(+), 23 deletions(-) create mode 100644 src/handlers/auth.rs create mode 100644 src/models/mod.rs create mode 100644 src/models/user.rs create mode 100644 src/packages/token.rs create mode 100644 src/routes/auth.rs diff --git a/Cargo.lock b/Cargo.lock index 148725e..c761a62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -152,9 +152,9 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "axum" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +checksum = "8f43644eed690f5374f1af436ecd6aea01cd201f6fbdf0178adaf6907afb2cec" dependencies = [ "async-trait", "axum-core", @@ -178,7 +178,7 @@ dependencies = [ "serde_urlencoded", "sync_wrapper 1.0.1", "tokio", - "tower", + "tower 0.5.1", "tower-layer", "tower-service", "tracing", @@ -186,9 +186,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +checksum = "5e6b8ba012a258d63c9adfa28b9ddcf66149da6f986c5b5452e629d5ee64bf00" dependencies = [ "async-trait", "bytes", @@ -199,7 +199,7 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper 0.1.2", + "sync_wrapper 1.0.1", "tower-layer", "tower-service", "tracing", @@ -1004,6 +1004,8 @@ dependencies = [ "hyper", "pin-project-lite", "tokio", + "tower 0.4.13", + "tower-service", ] [[package]] @@ -2527,18 +2529,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", @@ -2710,14 +2712,29 @@ dependencies = [ "tokio", "tower-layer", "tower-service", +] + +[[package]] +name = "tower" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tokio", + "tower-layer", + "tower-service", "tracing", ] [[package]] name = "tower-http" -version = "0.5.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" +checksum = "8437150ab6bbc8c5f0f519e3d5ed4aa883a83dd4cdd3d1b21f9482936046cb97" dependencies = [ "async-compression", "bitflags", @@ -2725,7 +2742,6 @@ dependencies = [ "futures-core", "http", "http-body", - "http-body-util", "pin-project-lite", "tokio", "tokio-util", diff --git a/Cargo.toml b/Cargo.toml index 7b71eca..14ea73b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -axum = "0.7.5" +axum = "0.7.6" bcrypt = "0.15.1" chrono = { version = "0.4.38", features = ["serde"] } config = { version = "0.14.0", features = ["yaml"] } @@ -12,11 +12,21 @@ cuid2 = "0.1.3" dotenvy = "0.15.7" jsonwebtoken = "9.3.0" once_cell = "1.19.0" -sea-orm = { version = "1.0.1", features = ["macros", "runtime-tokio-rustls", "sqlx-postgres"] } +sea-orm = { version = "1.0.1", features = [ + "macros", + "runtime-tokio-rustls", + "sqlx-postgres", +] } serde = { version = "1.0.210", features = ["derive"] } serde_json = "1.0.128" -thiserror = "1.0.63" +thiserror = "1.0.64" tokio = { version = "1.40.0", features = ["full"] } -tower-http = { version = "0.5.2", features = ["trace", "compression-br", "propagate-header", "sensitive-headers", "cors"] } +tower-http = { version = "0.6.1", features = [ + "trace", + "compression-br", + "propagate-header", + "sensitive-headers", + "cors", +] } tracing = "0.1.40" tracing-subscriber = "0.3.18" diff --git a/config/default.yml b/config/default.yml index 147d6d0..c796897 100644 --- a/config/default.yml +++ b/config/default.yml @@ -4,8 +4,8 @@ server: database: uri: "postgres://postgres:1234@localhost:5432/shield" name: shield -auth: - secret: secret +secrets: + signing_key: secret logger: level: debug admin: diff --git a/src/app.rs b/src/app.rs index fb3acdb..b83d71b 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use axum::{http::header, Router}; +use axum::{http::header, Extension, Router}; use tower_http::{ compression::CompressionLayer, cors::CorsLayer, propagate_header::PropagateHeaderLayer, sensitive_headers::SetSensitiveHeadersLayer, }; @@ -13,11 +13,11 @@ use crate::{ pub async fn create_app() -> Router { logger::setup(); - let state = get_db_connection_pool().await.unwrap(); + // let state = get_db_connection_pool().await.unwrap(); + let state = Arc::new(get_db_connection_pool().await.unwrap()); admin::setup(&state).await.expect("Failed to setup admin account"); Router::new() - .with_state(Arc::new(state)) .merge(routes::create_routes()) .layer(logger()) // Mark the `Authorization` request header as sensitive so it doesn't @@ -28,4 +28,5 @@ pub async fn create_app() -> Router { // Propagate `X-Request-Id`s from requests to responses .layer(PropagateHeaderLayer::new(header::HeaderName::from_static("x-request-id"))) .layer(CorsLayer::permissive()) // TODO: Update is later + .layer(Extension(state)) } diff --git a/src/handlers/auth.rs b/src/handlers/auth.rs new file mode 100644 index 0000000..bced0ae --- /dev/null +++ b/src/handlers/auth.rs @@ -0,0 +1,111 @@ +use std::sync::Arc; + +use crate::{ + database::{ + client, + prelude::{Client, Resource, ResourceGroup, User}, + resource, resource_group, user, + }, + packages::{ + db::AppState, + errors::{AuthenticateError, Error}, + settings::SETTINGS, + token::{create, Claims, TokenUser}, + }, +}; +use axum::{extract::Path, Extension, Json}; +use sea_orm::{prelude::Uuid, ColumnTrait, EntityTrait, QueryFilter}; +use serde::{Deserialize, Serialize}; +use tracing::debug; + +#[derive(Deserialize)] +pub struct Credentials { + email: String, + password: String, +} + +#[derive(Serialize)] +pub struct LoginResponse { + access_token: String, +} + +pub async fn login( + Extension(state): Extension>, + Path((realm, client_id)): Path<(String, Uuid)>, + Json(payload): Json, +) -> Result, Error> { + debug!("🚀 Login request received!"); + debug!("Realm: {:?}, Client ID: {:?}", realm, client_id); + let user = User::find().filter(user::Column::Email.eq(payload.email)).one(&state.db).await.unwrap(); + + if user.is_none() { + debug!("No user found"); + return Err(Error::not_found()); + } + + let user = user.unwrap(); + if !user.verify_password(&payload.password) { + debug!("Wrong password"); + return Err(Error::Authenticate(AuthenticateError::WrongCredentials)); + } + if user.locked_at.is_some() { + debug!("User is locked"); + return Err(Error::Authenticate(AuthenticateError::Locked)); + } + + let client = Client::find_by_id(client_id).one(&state.db).await.unwrap(); + if client.is_none() { + debug!("No client found"); + return Err(Error::not_found()); + } + + let client = client.unwrap(); + if client.locked_at.is_some() { + debug!("Client is locked"); + return Err(Error::Authenticate(AuthenticateError::Locked)); + } + + let resource_group = ResourceGroup::find() + .filter(resource_group::Column::RealmId.eq(client.realm_id)) + .filter(resource_group::Column::ClientId.eq(client_id)) + .filter(resource_group::Column::UserId.eq(user.id)) + .one(&state.db) + .await + .unwrap(); + + if resource_group.is_none() { + debug!("No resource group found"); + return Err(Error::not_found()); + } + let resource_group = resource_group.unwrap(); + if resource_group.locked_at.is_some() { + debug!("Resource group is locked"); + return Err(Error::Authenticate(AuthenticateError::Locked)); + } + + let resources = Resource::find() + .filter(resource::Column::GroupId.eq(resource_group.id)) + .filter(resource::Column::LockedAt.is_null()) + .all(&state.db) + .await + .unwrap(); + if resources.is_empty() { + debug!("No resources found"); + return Err(Error::Authenticate(AuthenticateError::Locked)); + } + + println!("Resource group: {:#?}, Resources: {:#?}", &resource_group, &resources); + let access_token = create(user, client, resource_group, resources, &SETTINGS.secrets.signing_key).unwrap(); + Ok(Json(LoginResponse { access_token })) +} + +pub async fn register(Extension(state): Extension>) { + debug!("🚀 Register request received!"); + + todo!(); +} + +pub async fn verify() { + debug!("🚀 Verify request received!"); + todo!(); +} diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs index febc0a5..4f4b8ab 100644 --- a/src/handlers/mod.rs +++ b/src/handlers/mod.rs @@ -1,3 +1,4 @@ +pub mod auth; pub mod client; pub mod realm; pub mod user; diff --git a/src/main.rs b/src/main.rs index 6113e4e..a902c54 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ mod app; mod database; mod handlers; mod middleware; +mod models; mod packages; mod routes; mod utils; diff --git a/src/models/mod.rs b/src/models/mod.rs new file mode 100644 index 0000000..22d12a3 --- /dev/null +++ b/src/models/mod.rs @@ -0,0 +1 @@ +pub mod user; diff --git a/src/models/user.rs b/src/models/user.rs new file mode 100644 index 0000000..dcc1387 --- /dev/null +++ b/src/models/user.rs @@ -0,0 +1,10 @@ +use crate::database::user::Model; + +impl Model { + pub fn verify_password(&self, password: &str) -> bool { + match self.password_hash { + Some(ref hash) => bcrypt::verify(password, hash).unwrap_or(false), + None => false, + } + } +} diff --git a/src/packages/db.rs b/src/packages/db.rs index 36ddb63..600d4b5 100644 --- a/src/packages/db.rs +++ b/src/packages/db.rs @@ -4,6 +4,7 @@ use sea_orm::{ConnectOptions, Database, DatabaseConnection, DbErr}; use super::settings::SETTINGS; +#[derive(Clone)] pub struct AppState { pub db: DatabaseConnection, } diff --git a/src/packages/mod.rs b/src/packages/mod.rs index 1f4be0f..a61b728 100644 --- a/src/packages/mod.rs +++ b/src/packages/mod.rs @@ -3,3 +3,4 @@ pub mod db; pub mod errors; pub mod logger; pub mod settings; +pub mod token; diff --git a/src/packages/settings.rs b/src/packages/settings.rs index 43d8f53..a8afd20 100644 --- a/src/packages/settings.rs +++ b/src/packages/settings.rs @@ -28,6 +28,11 @@ pub struct Admin { pub password: String, } +#[derive(Debug, Clone, Deserialize)] +pub struct Secrets { + pub signing_key: String, +} + #[derive(Debug, Clone, Deserialize)] pub struct Settings { pub environment: String, @@ -35,6 +40,7 @@ pub struct Settings { pub logger: Logger, pub database: Database, pub admin: Admin, + pub secrets: Secrets, } impl Settings { diff --git a/src/packages/token.rs b/src/packages/token.rs new file mode 100644 index 0000000..0f6ceee --- /dev/null +++ b/src/packages/token.rs @@ -0,0 +1,111 @@ +use jsonwebtoken::{errors::Error, DecodingKey, EncodingKey, Header, TokenData, Validation}; +use once_cell::sync::Lazy; +use sea_orm::prelude::Uuid; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +use crate::database::{ + client::Model as ClientModel, resource::Model as ResourceModel, resource_group::Model as ResourceGroupModel, user::Model as UserModel, +}; + +type TokenResult = Result, Error>; + +static VALIDATION: Lazy = Lazy::new(Validation::default); +static HEADER: Lazy
= Lazy::new(Header::default); + +#[derive(Debug, Serialize, Deserialize)] +pub struct Resource { + pub client_id: Uuid, + pub client_name: String, + pub group_name: String, + pub identifiers: HashMap, +} + +impl Resource { + fn from(client: ClientModel, resource_group: ResourceGroupModel, resources: Vec) -> Self { + let mut identifiers = HashMap::new(); + for resource in resources { + identifiers.insert(resource.name, resource.value); + } + + Self { + client_id: client.id, + client_name: client.name, + group_name: resource_group.name, + identifiers, + } + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct TokenUser { + pub sub: Uuid, + #[serde(rename = "firstName")] + pub first_name: String, + #[serde(rename = "lastName")] + pub last_name: String, + pub email: String, + pub phone: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub resource: Option, +} + +impl TokenUser { + fn from(user: UserModel, client: ClientModel, resource_group: ResourceGroupModel, resources: Vec) -> Self { + Self { + sub: user.id, + first_name: user.first_name.clone(), + last_name: user.last_name.unwrap_or_else(|| "".into()), + email: user.email.clone(), + phone: user.phone.unwrap_or_else(|| "".into()), + resource: Some(Resource::from(client, resource_group, resources)), + } + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Claims { + pub exp: usize, // Expiration time (as UTC timestamp). validate_exp defaults to true in validation + pub iat: usize, // Issued at (as UTC timestamp) + pub sub: Uuid, + pub first_name: String, + pub last_name: String, + pub email: String, + pub phone: String, + pub resource: Option, +} + +impl Claims { + pub fn new(user: UserModel, client: ClientModel, resource_group: ResourceGroupModel, resources: Vec) -> Self { + let user = TokenUser::from(user, client, resource_group, resources); + Self { + exp: (chrono::Local::now() + chrono::Duration::days(30)).timestamp() as usize, + iat: chrono::Local::now().timestamp() as usize, + sub: user.sub, + first_name: user.first_name, + last_name: user.last_name, + email: user.email, + phone: user.phone, + resource: user.resource, + } + } +} + +pub fn create( + user: UserModel, + client: ClientModel, + resource_group: ResourceGroupModel, + resources: Vec, + secret: &str, +) -> Result { + let encoding_key = EncodingKey::from_secret(secret.as_ref()); + let claims = Claims::new(user, client, resource_group, resources); + + jsonwebtoken::encode(&HEADER, &claims, &encoding_key) +} + +pub fn decode(token: &str, secret: &str) -> TokenResult { + let decoding_key = DecodingKey::from_secret(secret.as_ref()); + + jsonwebtoken::decode::(token, &decoding_key, &VALIDATION) +} diff --git a/src/routes/auth.rs b/src/routes/auth.rs new file mode 100644 index 0000000..87c44ed --- /dev/null +++ b/src/routes/auth.rs @@ -0,0 +1,10 @@ +use axum::{routing::post, Router}; + +use crate::handlers::auth::{login, register, verify}; + +pub fn create_routes() -> Router { + Router::new() + .route("/login", post(login)) + .route("/register", post(register)) + .route("/verify", post(verify)) +} diff --git a/src/routes/client.rs b/src/routes/client.rs index 08de525..d0bbc59 100644 --- a/src/routes/client.rs +++ b/src/routes/client.rs @@ -2,6 +2,11 @@ use axum::{routing::get, Router}; use crate::handlers::client::{get_client, get_clients}; +use super::auth; + pub fn create_routes() -> Router { - Router::new().route("/", get(get_clients)).route("/:client_id", get(get_client)) + Router::new().route("/", get(get_clients)).nest( + "/:client_id", + Router::new().route("/", get(get_client)).nest("/auth", auth::create_routes()), + ) } diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 2746178..4e9616b 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -1,5 +1,6 @@ use axum::Router; +pub mod auth; pub mod client; pub mod health; pub mod realm; From 1e7e97d8edd98e03f85f9a128980865e8b86e8b7 Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Thu, 26 Sep 2024 12:02:16 +0530 Subject: [PATCH 16/45] fix: user table schema updated now need to update the database models and logic --- .../up.sql | 26 +++- src/handlers/auth.rs | 121 +++++++++++++----- src/handlers/client.rs | 11 +- src/handlers/realm.rs | 7 +- src/handlers/user.rs | 11 +- src/routes/realm.rs | 2 +- 6 files changed, 132 insertions(+), 46 deletions(-) diff --git a/migrations/2024-09-18-153303_db_initialization/up.sql b/migrations/2024-09-18-153303_db_initialization/up.sql index 9dd6a2e..39edd1d 100644 --- a/migrations/2024-09-18-153303_db_initialization/up.sql +++ b/migrations/2024-09-18-153303_db_initialization/up.sql @@ -71,17 +71,37 @@ CREATE TABLE "user" ( is_temp_password BOOLEAN DEFAULT TRUE, locked_at TIMESTAMP, realm_id UUID NOT NULL REFERENCES realm(id) ON DELETE CASCADE, + realm_locked_at TIMESTAMP, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT chk_email_format CHECK (email ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}$'), CONSTRAINT chk_locked_at CHECK (locked_at IS NULL OR locked_at <= CURRENT_TIMESTAMP), CONSTRAINT chk_email_verified_at CHECK (email_verified_at IS NULL OR email_verified_at >= created_at AND email_verified_at <= CURRENT_TIMESTAMP), - CONSTRAINT chk_phone_format CHECK (phone ~ '^\+?[0-9]{10,14}$') + CONSTRAINT chk_phone_format CHECK (phone ~ '^\+?[0-9]{10,14}$'), + CONSTRAINT chk_realm_locked_at CHECK (realm_locked_at IS NULL OR realm_locked_at <= CURRENT_TIMESTAMP) ); CREATE UNIQUE INDEX realm_email_idx ON "user" (realm_id, email); -CREATE INDEX realm_email_locked_at_idx ON "user" (realm_id, email, locked_at); +CREATE INDEX realm_email_locked_at_idx ON "user" (realm_id, email, locked_at) WHERE locked_at IS NULL; CREATE INDEX idx_user_name ON "user" (realm_id, first_name, last_name); +CREATE INDEX idx_user_realm_locked_at ON "user" (realm_id, realm_locked_at) WHERE realm_locked_at IS NULL; + +-- Trigger to update realm_locked_at +CREATE OR REPLACE FUNCTION update_user_realm_locked_at() +RETURNS TRIGGER AS $$ +BEGIN + UPDATE "user" + SET realm_locked_at = NEW.locked_at + WHERE realm_id = NEW.id; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trigger_update_user_realm_locked_at +AFTER UPDATE OF locked_at ON realm +FOR EACH ROW +WHEN (OLD.locked_at IS DISTINCT FROM NEW.locked_at) +EXECUTE FUNCTION update_user_realm_locked_at(); ----------------------------------------------------------- -- Create resources_groups table @@ -94,6 +114,7 @@ CREATE TABLE resource_group ( description TEXT, is_default BOOLEAN DEFAULT FALSE, locked_at TIMESTAMP, + client_locked_at TIMESTAMP REFERENCES client(locked_at) ON UPDATE CASCADE, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT chk_locked_at CHECK (locked_at IS NULL OR locked_at <= CURRENT_TIMESTAMP) @@ -148,6 +169,7 @@ CREATE TABLE resource ( value TEXT NOT NULL, description TEXT, locked_at TIMESTAMP, + resource_locked_at TIMESTAMP REFERENCES resource_group(locked_at) ON UPDATE CASCADE, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT chk_locked_at CHECK (locked_at IS NULL OR locked_at <= CURRENT_TIMESTAMP) diff --git a/src/handlers/auth.rs b/src/handlers/auth.rs index bced0ae..753d2c4 100644 --- a/src/handlers/auth.rs +++ b/src/handlers/auth.rs @@ -31,19 +31,25 @@ pub struct LoginResponse { pub async fn login( Extension(state): Extension>, - Path((realm, client_id)): Path<(String, Uuid)>, + Path((realm_id, client_id)): Path<(Uuid, Uuid)>, Json(payload): Json, ) -> Result, Error> { debug!("🚀 Login request received!"); - debug!("Realm: {:?}, Client ID: {:?}", realm, client_id); - let user = User::find().filter(user::Column::Email.eq(payload.email)).one(&state.db).await.unwrap(); + let user_with_resource_groups = User::find() + .filter(user::Column::Email.eq(payload.email)) + .find_with_related(ResourceGroup) + .filter(resource_group::Column::RealmId.eq(realm_id)) + .filter(resource_group::Column::ClientId.eq(client_id)) + .all(&state.db) + .await?; - if user.is_none() { - debug!("No user found"); + if user_with_resource_groups.is_empty() { + debug!("No matching data found"); return Err(Error::not_found()); } - let user = user.unwrap(); + let (user, resource_groups) = &user_with_resource_groups[0]; + if !user.verify_password(&payload.password) { debug!("Wrong password"); return Err(Error::Authenticate(AuthenticateError::WrongCredentials)); @@ -53,50 +59,105 @@ pub async fn login( return Err(Error::Authenticate(AuthenticateError::Locked)); } - let client = Client::find_by_id(client_id).one(&state.db).await.unwrap(); - if client.is_none() { - debug!("No client found"); + if resource_groups.is_empty() { + debug!("No matching resource group found"); return Err(Error::not_found()); } - let client = client.unwrap(); - if client.locked_at.is_some() { - debug!("Client is locked"); + let resource_group = &resource_groups[0]; + if resource_group.locked_at.is_some() { + debug!("Resource group is locked"); return Err(Error::Authenticate(AuthenticateError::Locked)); } - let resource_group = ResourceGroup::find() - .filter(resource_group::Column::RealmId.eq(client.realm_id)) - .filter(resource_group::Column::ClientId.eq(client_id)) - .filter(resource_group::Column::UserId.eq(user.id)) - .one(&state.db) - .await - .unwrap(); + // Fetch client separately + let client = Client::find_by_id(client_id).one(&state.db).await?.ok_or_else(|| { + debug!("No client found"); + Error::not_found() + })?; - if resource_group.is_none() { - debug!("No resource group found"); - return Err(Error::not_found()); - } - let resource_group = resource_group.unwrap(); - if resource_group.locked_at.is_some() { - debug!("Resource group is locked"); + if client.locked_at.is_some() { + debug!("Client is locked"); return Err(Error::Authenticate(AuthenticateError::Locked)); } + // Fetch resources let resources = Resource::find() .filter(resource::Column::GroupId.eq(resource_group.id)) .filter(resource::Column::LockedAt.is_null()) .all(&state.db) - .await - .unwrap(); + .await?; + if resources.is_empty() { debug!("No resources found"); return Err(Error::Authenticate(AuthenticateError::Locked)); } - println!("Resource group: {:#?}, Resources: {:#?}", &resource_group, &resources); - let access_token = create(user, client, resource_group, resources, &SETTINGS.secrets.signing_key).unwrap(); + println!("Resource group: {:#?}, Resources: {:#?}", resource_group, &resources); + let access_token = create(user.clone(), client, resource_group.clone(), resources, &SETTINGS.secrets.signing_key).unwrap(); Ok(Json(LoginResponse { access_token })) + + // let user = User::find().filter(user::Column::Email.eq(payload.email)).one(&state.db).await.unwrap(); + + // if user.is_none() { + // debug!("No user found"); + // return Err(Error::not_found()); + // } + + // let user = user.unwrap(); + // if !user.verify_password(&payload.password) { + // debug!("Wrong password"); + // return Err(Error::Authenticate(AuthenticateError::WrongCredentials)); + // } + // if user.locked_at.is_some() { + // debug!("User is locked"); + // return Err(Error::Authenticate(AuthenticateError::Locked)); + // } + + // // let client = Client::find_by_id(client_id).one(&state.db).await.unwrap(); + // if client.is_none() { + // debug!("No client found"); + // return Err(Error::not_found()); + // } + + // let client = client.unwrap(); + // if client.locked_at.is_some() { + // debug!("Client is locked"); + // return Err(Error::Authenticate(AuthenticateError::Locked)); + // } + + // let resource_group = ResourceGroup::find() + // .filter(resource_group::Column::RealmId.eq(client.realm_id)) + // .filter(resource_group::Column::ClientId.eq(client_id)) + // .filter(resource_group::Column::UserId.eq(user.id)) + // .one(&state.db) + // .await + // .unwrap(); + + // if resource_group.is_none() { + // debug!("No resource group found"); + // return Err(Error::not_found()); + // } + // let resource_group = resource_group.unwrap(); + // if resource_group.locked_at.is_some() { + // debug!("Resource group is locked"); + // return Err(Error::Authenticate(AuthenticateError::Locked)); + // } + + // let resources = Resource::find() + // .filter(resource::Column::GroupId.eq(resource_group.id)) + // .filter(resource::Column::LockedAt.is_null()) + // .all(&state.db) + // .await + // .unwrap(); + // if resources.is_empty() { + // debug!("No resources found"); + // return Err(Error::Authenticate(AuthenticateError::Locked)); + // } + + // println!("Resource group: {:#?}, Resources: {:#?}", &resource_group, &resources); + // let access_token = create(user, client, resource_group, resources, &SETTINGS.secrets.signing_key).unwrap(); + // Ok(Json(LoginResponse { access_token })) } pub async fn register(Extension(state): Extension>) { diff --git a/src/handlers/client.rs b/src/handlers/client.rs index 1386095..98b2de5 100644 --- a/src/handlers/client.rs +++ b/src/handlers/client.rs @@ -1,10 +1,11 @@ use axum::extract::Path; +use sea_orm::prelude::Uuid; -pub async fn get_clients(Path(realm): Path) -> String { - format!("Hi from clients of {realm}") +pub async fn get_clients(Path(realm_id): Path) -> String { + format!("Hi from clients of {realm_id}") } -pub async fn get_client(Path((realm, client_id)): Path<(String, String)>) -> String { - println!("This is client Name: {} - {}", &realm, &client_id); - format!("client is - {} - {}", realm, client_id) +pub async fn get_client(Path((realm_id, client_id)): Path<(Uuid, Uuid)>) -> String { + println!("This is client Name: {} - {}", &realm_id, &client_id); + format!("client is - {} - {}", realm_id, client_id) } diff --git a/src/handlers/realm.rs b/src/handlers/realm.rs index 9f3e265..eec7826 100644 --- a/src/handlers/realm.rs +++ b/src/handlers/realm.rs @@ -1,10 +1,11 @@ use axum::extract::Path; +use sea_orm::prelude::Uuid; pub async fn get_realms() -> String { "Hi from MASTER REALM".to_owned() } -pub async fn get_realm(Path(realm): Path) -> String { - println!("This is realm Name: {}", &realm); - format!("Realm is - {}", realm) +pub async fn get_realm(Path(realm_id): Path) -> String { + println!("This is realm Name: {}", &realm_id); + format!("Realm is - {}", realm_id) } diff --git a/src/handlers/user.rs b/src/handlers/user.rs index c46c9fc..68ae880 100644 --- a/src/handlers/user.rs +++ b/src/handlers/user.rs @@ -1,10 +1,11 @@ use axum::extract::Path; +use sea_orm::prelude::Uuid; -pub async fn get_users(Path(realm): Path) -> String { - format!("Hi from users of {realm}") +pub async fn get_users(Path(realm_id): Path) -> String { + format!("Hi from users of {realm_id}") } -pub async fn get_user(Path((realm, user_id)): Path<(String, String)>) -> String { - println!("This is user Name: {} - {}", &realm, &user_id); - format!("user is - {} - {}", realm, user_id) +pub async fn get_user(Path((realm_id, user_id)): Path<(Uuid, Uuid)>) -> String { + println!("This is user Name: {} - {}", &realm_id, &user_id); + format!("user is - {} - {}", realm_id, user_id) } diff --git a/src/routes/realm.rs b/src/routes/realm.rs index dd96ca6..2a6047a 100644 --- a/src/routes/realm.rs +++ b/src/routes/realm.rs @@ -6,7 +6,7 @@ use super::{client, user}; pub fn create_routes() -> Router { Router::new().route("/", get(get_realms)).nest( - "/:realm", + "/:realm_id", Router::new() .route("/", get(get_realm)) .nest("/clients", client::create_routes()) From 3dc18da9af9c3ecb25e2b629101aed1fc44cb130 Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Thu, 26 Sep 2024 18:59:02 +0530 Subject: [PATCH 17/45] fix: few denormalization applied on tables --- migrations/.keep | 0 .../down.sql | 6 --- .../up.sql | 36 -------------- .../down.sql | 49 +++++++------------ .../up.sql | 46 +++++++++++++++-- src/database/resource_group.rs | 1 + src/database/user.rs | 1 + 7 files changed, 61 insertions(+), 78 deletions(-) delete mode 100644 migrations/.keep delete mode 100644 migrations/00000000000000_diesel_initial_setup/down.sql delete mode 100644 migrations/00000000000000_diesel_initial_setup/up.sql rename migrations/{2024-09-18-153303_db_initialization => }/down.sql (54%) rename migrations/{2024-09-18-153303_db_initialization => }/up.sql (84%) diff --git a/migrations/.keep b/migrations/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/migrations/00000000000000_diesel_initial_setup/down.sql b/migrations/00000000000000_diesel_initial_setup/down.sql deleted file mode 100644 index a9f5260..0000000 --- a/migrations/00000000000000_diesel_initial_setup/down.sql +++ /dev/null @@ -1,6 +0,0 @@ --- This file was automatically created by Diesel to setup helper functions --- and other internal bookkeeping. This file is safe to edit, any future --- changes will be added to existing projects as new migrations. - -DROP FUNCTION IF EXISTS diesel_manage_updated_at(_tbl regclass); -DROP FUNCTION IF EXISTS diesel_set_updated_at(); diff --git a/migrations/00000000000000_diesel_initial_setup/up.sql b/migrations/00000000000000_diesel_initial_setup/up.sql deleted file mode 100644 index d68895b..0000000 --- a/migrations/00000000000000_diesel_initial_setup/up.sql +++ /dev/null @@ -1,36 +0,0 @@ --- This file was automatically created by Diesel to setup helper functions --- and other internal bookkeeping. This file is safe to edit, any future --- changes will be added to existing projects as new migrations. - - - - --- Sets up a trigger for the given table to automatically set a column called --- `updated_at` whenever the row is modified (unless `updated_at` was included --- in the modified columns) --- --- # Example --- --- ```sql --- CREATE TABLE users (id SERIAL PRIMARY KEY, updated_at TIMESTAMP NOT NULL DEFAULT NOW()); --- --- SELECT diesel_manage_updated_at('users'); --- ``` -CREATE OR REPLACE FUNCTION diesel_manage_updated_at(_tbl regclass) RETURNS VOID AS $$ -BEGIN - EXECUTE format('CREATE TRIGGER set_updated_at BEFORE UPDATE ON %s - FOR EACH ROW EXECUTE PROCEDURE diesel_set_updated_at()', _tbl); -END; -$$ LANGUAGE plpgsql; - -CREATE OR REPLACE FUNCTION diesel_set_updated_at() RETURNS trigger AS $$ -BEGIN - IF ( - NEW IS DISTINCT FROM OLD AND - NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at - ) THEN - NEW.updated_at := current_timestamp; - END IF; - RETURN NEW; -END; -$$ LANGUAGE plpgsql; diff --git a/migrations/2024-09-18-153303_db_initialization/down.sql b/migrations/down.sql similarity index 54% rename from migrations/2024-09-18-153303_db_initialization/down.sql rename to migrations/down.sql index 6f15169..c1ceaf8 100644 --- a/migrations/2024-09-18-153303_db_initialization/down.sql +++ b/migrations/down.sql @@ -1,42 +1,29 @@ --- Drop authenticators table -DROP TABLE IF EXISTS authenticator; +-- down.sql +-- Drop triggers first +DROP TRIGGER IF EXISTS trigger_update_user_realm_locked_at ON realm; +DROP TRIGGER IF EXISTS ensure_single_default_resource_group ON resource_group; +DROP TRIGGER IF EXISTS trigger_update_resource_group_client_locked_at ON client; +DROP TRIGGER IF EXISTS before_insert_and_update_realm ON realm; +DROP TRIGGER IF EXISTS trigger_update_resource_locked_at ON resource_group; --- Drop two_factor_confirmation table -DROP TABLE IF EXISTS two_factor_confirmation; +-- Drop functions +DROP FUNCTION IF EXISTS update_user_realm_locked_at(); +DROP FUNCTION IF EXISTS manage_default_resource_group(); +DROP FUNCTION IF EXISTS update_resource_group_client_locked_at(); +DROP FUNCTION IF EXISTS generate_slug(); +DROP FUNCTION IF EXISTS uuid_generate_v7(); +DROP FUNCTION IF EXISTS update_resource_locked_at(); --- Drop two_factor_token table +-- Drop tables +DROP TABLE IF EXISTS authenticator; +DROP TABLE IF EXISTS two_factor_confirmation; DROP TABLE IF EXISTS two_factor_token; - --- Drop password_reset_token table DROP TABLE IF EXISTS password_reset_token; - --- Drop verification_token table DROP TABLE IF EXISTS verification_token; - --- Drop sessions table DROP TABLE IF EXISTS session; - --- Drop accounts table DROP TABLE IF EXISTS account; - --- Drop resources table DROP TABLE IF EXISTS resource; - --- Drop resource_groups table DROP TABLE IF EXISTS resource_group; - --- Drop users table DROP TABLE IF EXISTS "user"; - --- Drop clients table DROP TABLE IF EXISTS client; - --- Drop realms table -DROP TABLE IF EXISTS realm; - --- Drop functions and triggers -DROP FUNCTION IF EXISTS uuid_generate_v7(); -DROP TRIGGER IF EXISTS ensure_single_default_resource_group ON resource_group; -DROP FUNCTION IF EXISTS manage_default_resource_group(); -DROP TRIGGER IF EXISTS before_insert_and_update_realm ON realm; -DROP FUNCTION IF EXISTS generate_slug(); \ No newline at end of file +DROP TABLE IF EXISTS realm; \ No newline at end of file diff --git a/migrations/2024-09-18-153303_db_initialization/up.sql b/migrations/up.sql similarity index 84% rename from migrations/2024-09-18-153303_db_initialization/up.sql rename to migrations/up.sql index 39edd1d..29451b3 100644 --- a/migrations/2024-09-18-153303_db_initialization/up.sql +++ b/migrations/up.sql @@ -114,14 +114,34 @@ CREATE TABLE resource_group ( description TEXT, is_default BOOLEAN DEFAULT FALSE, locked_at TIMESTAMP, - client_locked_at TIMESTAMP REFERENCES client(locked_at) ON UPDATE CASCADE, + client_locked_at TIMESTAMP, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - CONSTRAINT chk_locked_at CHECK (locked_at IS NULL OR locked_at <= CURRENT_TIMESTAMP) + CONSTRAINT chk_locked_at CHECK (locked_at IS NULL OR locked_at <= CURRENT_TIMESTAMP), + CONSTRAINT chk_client_locked_at CHECK (client_locked_at IS NULL OR client_locked_at <= CURRENT_TIMESTAMP) ); -CREATE UNIQUE INDEX realm_client_user_resource_group_idx ON resource_group (name, client_id, user_id); -CREATE INDEX client_user_default_resource_group_idx ON resource_group (client_id, user_id, is_default) WHERE is_default = true; +CREATE UNIQUE INDEX realm_client_user_resource_group_idx ON resource_group (realm_id, client_id, user_id, name); +CREATE INDEX client_user_default_resource_group_idx ON resource_group (client_id, user_id) WHERE is_default = true; +CREATE INDEX idx_resource_group_client_locked_at ON resource_group (client_id, client_locked_at) WHERE client_locked_at IS NULL; +CREATE UNIQUE INDEX idx_single_default_resource_group ON resource_group (client_id, user_id) WHERE is_default = true; + +-- Trigger to update client_locked_at +CREATE OR REPLACE FUNCTION update_resource_group_client_locked_at() +RETURNS TRIGGER AS $$ +BEGIN + UPDATE resource_group + SET client_locked_at = NEW.locked_at + WHERE client_id = NEW.id; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trigger_update_resource_group_client_locked_at +AFTER UPDATE OF locked_at ON client +FOR EACH ROW +WHEN (OLD.locked_at IS DISTINCT FROM NEW.locked_at) +EXECUTE FUNCTION update_resource_group_client_locked_at(); -- Function to manage default resource group CREATE OR REPLACE FUNCTION manage_default_resource_group() @@ -169,7 +189,6 @@ CREATE TABLE resource ( value TEXT NOT NULL, description TEXT, locked_at TIMESTAMP, - resource_locked_at TIMESTAMP REFERENCES resource_group(locked_at) ON UPDATE CASCADE, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT chk_locked_at CHECK (locked_at IS NULL OR locked_at <= CURRENT_TIMESTAMP) @@ -177,6 +196,23 @@ CREATE TABLE resource ( CREATE UNIQUE INDEX resource_group_and_resource_idx ON resource (group_id, name); +-- Add a trigger to update resource.locked_at when resource_group.locked_at changes +CREATE OR REPLACE FUNCTION update_resource_locked_at() +RETURNS TRIGGER AS $$ +BEGIN + UPDATE resource + SET locked_at = NEW.locked_at + WHERE group_id = NEW.id; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trigger_update_resource_locked_at +AFTER UPDATE OF locked_at ON resource_group +FOR EACH ROW +WHEN (OLD.locked_at IS DISTINCT FROM NEW.locked_at) +EXECUTE FUNCTION update_resource_locked_at(); + -- Create accounts table CREATE TABLE account ( user_id UUID NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, diff --git a/src/database/resource_group.rs b/src/database/resource_group.rs index d5a5b63..57f4dab 100644 --- a/src/database/resource_group.rs +++ b/src/database/resource_group.rs @@ -16,6 +16,7 @@ pub struct Model { pub description: Option, pub is_default: Option, pub locked_at: Option, + pub client_locked_at: Option, pub created_at: DateTime, pub updated_at: DateTime, } diff --git a/src/database/user.rs b/src/database/user.rs index 07c5574..c00597c 100644 --- a/src/database/user.rs +++ b/src/database/user.rs @@ -24,6 +24,7 @@ pub struct Model { pub is_temp_password: Option, pub locked_at: Option, pub realm_id: Uuid, + pub realm_locked_at: Option, pub created_at: DateTime, pub updated_at: DateTime, } From bbe3b10d81915ccf005c20276f40f6efd3c4f085 Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Thu, 26 Sep 2024 21:22:35 +0530 Subject: [PATCH 18/45] fix: ready for next function --- migrations/down.sql | 6 --- migrations/up.sql | 70 +++------------------------- src/database/resource_group.rs | 1 - src/database/user.rs | 1 - src/handlers/auth.rs | 84 ++++------------------------------ 5 files changed, 16 insertions(+), 146 deletions(-) diff --git a/migrations/down.sql b/migrations/down.sql index c1ceaf8..e17e256 100644 --- a/migrations/down.sql +++ b/migrations/down.sql @@ -1,18 +1,12 @@ -- down.sql -- Drop triggers first -DROP TRIGGER IF EXISTS trigger_update_user_realm_locked_at ON realm; DROP TRIGGER IF EXISTS ensure_single_default_resource_group ON resource_group; -DROP TRIGGER IF EXISTS trigger_update_resource_group_client_locked_at ON client; DROP TRIGGER IF EXISTS before_insert_and_update_realm ON realm; -DROP TRIGGER IF EXISTS trigger_update_resource_locked_at ON resource_group; -- Drop functions -DROP FUNCTION IF EXISTS update_user_realm_locked_at(); DROP FUNCTION IF EXISTS manage_default_resource_group(); -DROP FUNCTION IF EXISTS update_resource_group_client_locked_at(); DROP FUNCTION IF EXISTS generate_slug(); DROP FUNCTION IF EXISTS uuid_generate_v7(); -DROP FUNCTION IF EXISTS update_resource_locked_at(); -- Drop tables DROP TABLE IF EXISTS authenticator; diff --git a/migrations/up.sql b/migrations/up.sql index 29451b3..136d381 100644 --- a/migrations/up.sql +++ b/migrations/up.sql @@ -71,37 +71,17 @@ CREATE TABLE "user" ( is_temp_password BOOLEAN DEFAULT TRUE, locked_at TIMESTAMP, realm_id UUID NOT NULL REFERENCES realm(id) ON DELETE CASCADE, - realm_locked_at TIMESTAMP, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT chk_email_format CHECK (email ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}$'), CONSTRAINT chk_locked_at CHECK (locked_at IS NULL OR locked_at <= CURRENT_TIMESTAMP), CONSTRAINT chk_email_verified_at CHECK (email_verified_at IS NULL OR email_verified_at >= created_at AND email_verified_at <= CURRENT_TIMESTAMP), - CONSTRAINT chk_phone_format CHECK (phone ~ '^\+?[0-9]{10,14}$'), - CONSTRAINT chk_realm_locked_at CHECK (realm_locked_at IS NULL OR realm_locked_at <= CURRENT_TIMESTAMP) + CONSTRAINT chk_phone_format CHECK (phone ~ '^\+?[0-9]{10,14}$') ); CREATE UNIQUE INDEX realm_email_idx ON "user" (realm_id, email); -CREATE INDEX realm_email_locked_at_idx ON "user" (realm_id, email, locked_at) WHERE locked_at IS NULL; +CREATE INDEX realm_email_locked_at_idx ON "user" (realm_id, email, locked_at); CREATE INDEX idx_user_name ON "user" (realm_id, first_name, last_name); -CREATE INDEX idx_user_realm_locked_at ON "user" (realm_id, realm_locked_at) WHERE realm_locked_at IS NULL; - --- Trigger to update realm_locked_at -CREATE OR REPLACE FUNCTION update_user_realm_locked_at() -RETURNS TRIGGER AS $$ -BEGIN - UPDATE "user" - SET realm_locked_at = NEW.locked_at - WHERE realm_id = NEW.id; - RETURN NEW; -END; -$$ LANGUAGE plpgsql; - -CREATE TRIGGER trigger_update_user_realm_locked_at -AFTER UPDATE OF locked_at ON realm -FOR EACH ROW -WHEN (OLD.locked_at IS DISTINCT FROM NEW.locked_at) -EXECUTE FUNCTION update_user_realm_locked_at(); ----------------------------------------------------------- -- Create resources_groups table @@ -114,34 +94,13 @@ CREATE TABLE resource_group ( description TEXT, is_default BOOLEAN DEFAULT FALSE, locked_at TIMESTAMP, - client_locked_at TIMESTAMP, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - CONSTRAINT chk_locked_at CHECK (locked_at IS NULL OR locked_at <= CURRENT_TIMESTAMP), - CONSTRAINT chk_client_locked_at CHECK (client_locked_at IS NULL OR client_locked_at <= CURRENT_TIMESTAMP) + CONSTRAINT chk_locked_at CHECK (locked_at IS NULL OR locked_at <= CURRENT_TIMESTAMP) ); -CREATE UNIQUE INDEX realm_client_user_resource_group_idx ON resource_group (realm_id, client_id, user_id, name); -CREATE INDEX client_user_default_resource_group_idx ON resource_group (client_id, user_id) WHERE is_default = true; -CREATE INDEX idx_resource_group_client_locked_at ON resource_group (client_id, client_locked_at) WHERE client_locked_at IS NULL; -CREATE UNIQUE INDEX idx_single_default_resource_group ON resource_group (client_id, user_id) WHERE is_default = true; - --- Trigger to update client_locked_at -CREATE OR REPLACE FUNCTION update_resource_group_client_locked_at() -RETURNS TRIGGER AS $$ -BEGIN - UPDATE resource_group - SET client_locked_at = NEW.locked_at - WHERE client_id = NEW.id; - RETURN NEW; -END; -$$ LANGUAGE plpgsql; - -CREATE TRIGGER trigger_update_resource_group_client_locked_at -AFTER UPDATE OF locked_at ON client -FOR EACH ROW -WHEN (OLD.locked_at IS DISTINCT FROM NEW.locked_at) -EXECUTE FUNCTION update_resource_group_client_locked_at(); +CREATE UNIQUE INDEX realm_client_user_resource_group_idx ON resource_group (name, client_id, user_id); +CREATE INDEX client_user_default_resource_group_idx ON resource_group (client_id, user_id, is_default) WHERE is_default = true; -- Function to manage default resource group CREATE OR REPLACE FUNCTION manage_default_resource_group() @@ -196,23 +155,6 @@ CREATE TABLE resource ( CREATE UNIQUE INDEX resource_group_and_resource_idx ON resource (group_id, name); --- Add a trigger to update resource.locked_at when resource_group.locked_at changes -CREATE OR REPLACE FUNCTION update_resource_locked_at() -RETURNS TRIGGER AS $$ -BEGIN - UPDATE resource - SET locked_at = NEW.locked_at - WHERE group_id = NEW.id; - RETURN NEW; -END; -$$ LANGUAGE plpgsql; - -CREATE TRIGGER trigger_update_resource_locked_at -AFTER UPDATE OF locked_at ON resource_group -FOR EACH ROW -WHEN (OLD.locked_at IS DISTINCT FROM NEW.locked_at) -EXECUTE FUNCTION update_resource_locked_at(); - -- Create accounts table CREATE TABLE account ( user_id UUID NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, @@ -283,4 +225,4 @@ CREATE TABLE authenticator ( credential_backed_up BOOLEAN NOT NULL, transports TEXT, PRIMARY KEY (user_id, credential_id) -); +); \ No newline at end of file diff --git a/src/database/resource_group.rs b/src/database/resource_group.rs index 57f4dab..d5a5b63 100644 --- a/src/database/resource_group.rs +++ b/src/database/resource_group.rs @@ -16,7 +16,6 @@ pub struct Model { pub description: Option, pub is_default: Option, pub locked_at: Option, - pub client_locked_at: Option, pub created_at: DateTime, pub updated_at: DateTime, } diff --git a/src/database/user.rs b/src/database/user.rs index c00597c..07c5574 100644 --- a/src/database/user.rs +++ b/src/database/user.rs @@ -24,7 +24,6 @@ pub struct Model { pub is_temp_password: Option, pub locked_at: Option, pub realm_id: Uuid, - pub realm_locked_at: Option, pub created_at: DateTime, pub updated_at: DateTime, } diff --git a/src/handlers/auth.rs b/src/handlers/auth.rs index 753d2c4..60ef47a 100644 --- a/src/handlers/auth.rs +++ b/src/handlers/auth.rs @@ -14,7 +14,7 @@ use crate::{ }, }; use axum::{extract::Path, Extension, Json}; -use sea_orm::{prelude::Uuid, ColumnTrait, EntityTrait, QueryFilter}; +use sea_orm::{prelude::Uuid, ColumnTrait, EntityTrait, QueryFilter, QuerySelect, RelationTrait}; use serde::{Deserialize, Serialize}; use tracing::debug; @@ -37,19 +37,18 @@ pub async fn login( debug!("🚀 Login request received!"); let user_with_resource_groups = User::find() .filter(user::Column::Email.eq(payload.email)) - .find_with_related(ResourceGroup) + .find_also_related(ResourceGroup) .filter(resource_group::Column::RealmId.eq(realm_id)) .filter(resource_group::Column::ClientId.eq(client_id)) - .all(&state.db) + .one(&state.db) .await?; - if user_with_resource_groups.is_empty() { + if user_with_resource_groups.is_none() { debug!("No matching data found"); return Err(Error::not_found()); } - let (user, resource_groups) = &user_with_resource_groups[0]; - + let (user, resource_groups) = user_with_resource_groups.unwrap(); if !user.verify_password(&payload.password) { debug!("Wrong password"); return Err(Error::Authenticate(AuthenticateError::WrongCredentials)); @@ -59,13 +58,13 @@ pub async fn login( return Err(Error::Authenticate(AuthenticateError::Locked)); } - if resource_groups.is_empty() { + if resource_groups.is_none() { debug!("No matching resource group found"); return Err(Error::not_found()); } - let resource_group = &resource_groups[0]; - if resource_group.locked_at.is_some() { + let resource_groups = resource_groups.unwrap(); + if resource_groups.locked_at.is_some() { debug!("Resource group is locked"); return Err(Error::Authenticate(AuthenticateError::Locked)); } @@ -83,7 +82,7 @@ pub async fn login( // Fetch resources let resources = Resource::find() - .filter(resource::Column::GroupId.eq(resource_group.id)) + .filter(resource::Column::GroupId.eq(resource_groups.id)) .filter(resource::Column::LockedAt.is_null()) .all(&state.db) .await?; @@ -93,71 +92,8 @@ pub async fn login( return Err(Error::Authenticate(AuthenticateError::Locked)); } - println!("Resource group: {:#?}, Resources: {:#?}", resource_group, &resources); - let access_token = create(user.clone(), client, resource_group.clone(), resources, &SETTINGS.secrets.signing_key).unwrap(); + let access_token = create(user.clone(), client, resource_groups, resources, &SETTINGS.secrets.signing_key).unwrap(); Ok(Json(LoginResponse { access_token })) - - // let user = User::find().filter(user::Column::Email.eq(payload.email)).one(&state.db).await.unwrap(); - - // if user.is_none() { - // debug!("No user found"); - // return Err(Error::not_found()); - // } - - // let user = user.unwrap(); - // if !user.verify_password(&payload.password) { - // debug!("Wrong password"); - // return Err(Error::Authenticate(AuthenticateError::WrongCredentials)); - // } - // if user.locked_at.is_some() { - // debug!("User is locked"); - // return Err(Error::Authenticate(AuthenticateError::Locked)); - // } - - // // let client = Client::find_by_id(client_id).one(&state.db).await.unwrap(); - // if client.is_none() { - // debug!("No client found"); - // return Err(Error::not_found()); - // } - - // let client = client.unwrap(); - // if client.locked_at.is_some() { - // debug!("Client is locked"); - // return Err(Error::Authenticate(AuthenticateError::Locked)); - // } - - // let resource_group = ResourceGroup::find() - // .filter(resource_group::Column::RealmId.eq(client.realm_id)) - // .filter(resource_group::Column::ClientId.eq(client_id)) - // .filter(resource_group::Column::UserId.eq(user.id)) - // .one(&state.db) - // .await - // .unwrap(); - - // if resource_group.is_none() { - // debug!("No resource group found"); - // return Err(Error::not_found()); - // } - // let resource_group = resource_group.unwrap(); - // if resource_group.locked_at.is_some() { - // debug!("Resource group is locked"); - // return Err(Error::Authenticate(AuthenticateError::Locked)); - // } - - // let resources = Resource::find() - // .filter(resource::Column::GroupId.eq(resource_group.id)) - // .filter(resource::Column::LockedAt.is_null()) - // .all(&state.db) - // .await - // .unwrap(); - // if resources.is_empty() { - // debug!("No resources found"); - // return Err(Error::Authenticate(AuthenticateError::Locked)); - // } - - // println!("Resource group: {:#?}, Resources: {:#?}", &resource_group, &resources); - // let access_token = create(user, client, resource_group, resources, &SETTINGS.secrets.signing_key).unwrap(); - // Ok(Json(LoginResponse { access_token })) } pub async fn register(Extension(state): Extension>) { From a3bf094ad8c3ed26b1eaa64f9357dedeaccdcf22 Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Thu, 26 Sep 2024 22:57:18 +0530 Subject: [PATCH 19/45] fix: default creds gettting written to file --- .gitignore | 3 ++- src/handlers/auth.rs | 5 ++--- src/packages/admin.rs | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index d1b731a..2a560bf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target Secrets*.toml -.env* \ No newline at end of file +.env* +logs \ No newline at end of file diff --git a/src/handlers/auth.rs b/src/handlers/auth.rs index 60ef47a..b9a7207 100644 --- a/src/handlers/auth.rs +++ b/src/handlers/auth.rs @@ -2,7 +2,6 @@ use std::sync::Arc; use crate::{ database::{ - client, prelude::{Client, Resource, ResourceGroup, User}, resource, resource_group, user, }, @@ -10,11 +9,11 @@ use crate::{ db::AppState, errors::{AuthenticateError, Error}, settings::SETTINGS, - token::{create, Claims, TokenUser}, + token::create, }, }; use axum::{extract::Path, Extension, Json}; -use sea_orm::{prelude::Uuid, ColumnTrait, EntityTrait, QueryFilter, QuerySelect, RelationTrait}; +use sea_orm::{prelude::Uuid, ColumnTrait, EntityTrait, QueryFilter}; use serde::{Deserialize, Serialize}; use tracing::debug; diff --git a/src/packages/admin.rs b/src/packages/admin.rs index 66cad5c..f4b5fb4 100644 --- a/src/packages/admin.rs +++ b/src/packages/admin.rs @@ -1,3 +1,9 @@ +use std::{ + fs::{create_dir_all, File}, + io::Write, + path::Path, +}; + use sea_orm::{prelude::Uuid, ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait, QueryFilter, Set}; use tracing::info; @@ -13,6 +19,13 @@ use crate::{ use super::{db::AppState, errors::Error}; +#[allow(dead_code)] +#[derive(Debug)] +pub struct DefaultCred { + realm_id: Uuid, + client_id: Uuid, +} + pub async fn setup(state: &AppState) -> Result<(), Error> { info!("Checking ADMIN availability!"); let is_admin_user_exists = User::find().filter(user::Column::Email.eq(&SETTINGS.admin.email)).one(&state.db).await?; @@ -37,6 +50,25 @@ async fn initialize_db(conn: &DatabaseConnection) -> Result<(), Error> { let client = create_default_client(conn, realm.id).await?; let user = create_admin_user(conn, realm.id).await?; assign_resource_to_admin(conn, realm.id, client.id, user.id).await?; + let default_cred = DefaultCred { + realm_id: realm.id, + client_id: client.id, + }; + info!("🗝️ Please note these credentials!"); + println!("{:?}", default_cred); + + let file_path = "./logs/default_cred.txt"; // Use relative path for better portability + let path = Path::new(file_path); + if let Some(parent_dir) = path.parent() { + create_dir_all(parent_dir).expect("Failed to create directory"); + } else { + panic!("Invalid file path"); + } + let mut file = File::create(file_path).expect("Failed to create file"); + let content = format!("{:#?}", default_cred); + file.write_all(content.as_bytes()).expect("Failed to write to file"); + + info!("📝 However above credentials have been '/logs/default_cred.txt' file."); Ok(()) })() .await; From 0f500eb147b9166aa578e5db57b135dba5bfa616 Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Fri, 27 Sep 2024 12:37:49 +0530 Subject: [PATCH 20/45] fix: default resource updated and get realms function is in progress --- Cargo.lock | 48 +++++++++++++++++++++++++++++ Cargo.toml | 1 + src/database/realm.rs | 3 +- src/handlers/auth.rs | 8 +++-- src/handlers/realm.rs | 50 +++++++++++++++++++++++++++---- src/models/mod.rs | 1 + src/models/realm.rs | 1 + src/packages/admin.rs | 9 ++++++ src/packages/errors.rs | 3 ++ src/packages/token.rs | 11 +++++++ src/utils/authenticate_request.rs | 32 ++++++++++++++++++++ src/utils/mod.rs | 1 + 12 files changed, 158 insertions(+), 10 deletions(-) create mode 100644 src/models/realm.rs create mode 100644 src/utils/authenticate_request.rs diff --git a/Cargo.lock b/Cargo.lock index c761a62..bd99b2b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -205,6 +205,29 @@ dependencies = [ "tracing", ] +[[package]] +name = "axum-extra" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73c3220b188aea709cf1b6c5f9b01c3bd936bb08bd2b5184a12b35ac8131b1f9" +dependencies = [ + "axum", + "axum-core", + "bytes", + "futures-util", + "headers", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "serde", + "tower 0.5.1", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "backtrace" version = "0.3.74" @@ -878,6 +901,30 @@ dependencies = [ "hashbrown 0.14.5", ] +[[package]] +name = "headers" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" +dependencies = [ + "base64 0.21.7", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha1", +] + +[[package]] +name = "headers-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" +dependencies = [ + "http", +] + [[package]] name = "heck" version = "0.4.1" @@ -2103,6 +2150,7 @@ name = "shield" version = "0.1.0" dependencies = [ "axum", + "axum-extra", "bcrypt", "chrono", "config", diff --git a/Cargo.toml b/Cargo.toml index 14ea73b..b1c7a87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] axum = "0.7.6" +axum-extra = { version = "0.9.4", features = ["typed-header"] } bcrypt = "0.15.1" chrono = { version = "0.4.38", features = ["serde"] } config = { version = "0.14.0", features = ["yaml"] } diff --git a/src/database/realm.rs b/src/database/realm.rs index 1f2a5e9..9569f00 100644 --- a/src/database/realm.rs +++ b/src/database/realm.rs @@ -1,8 +1,9 @@ //! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Deserialize, Serialize)] #[sea_orm(table_name = "realm")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] diff --git a/src/handlers/auth.rs b/src/handlers/auth.rs index b9a7207..40a029f 100644 --- a/src/handlers/auth.rs +++ b/src/handlers/auth.rs @@ -9,7 +9,7 @@ use crate::{ db::AppState, errors::{AuthenticateError, Error}, settings::SETTINGS, - token::create, + token::{create, TokenUser}, }, }; use axum::{extract::Path, Extension, Json}; @@ -95,10 +95,12 @@ pub async fn login( Ok(Json(LoginResponse { access_token })) } -pub async fn register(Extension(state): Extension>) { +pub async fn register(user: TokenUser, Extension(state): Extension>) -> Result, Error> { debug!("🚀 Register request received!"); - todo!(); + Ok(Json(LoginResponse { + access_token: format!("Bearer {:#?}", user), + })) } pub async fn verify() { diff --git a/src/handlers/realm.rs b/src/handlers/realm.rs index eec7826..c5651c1 100644 --- a/src/handlers/realm.rs +++ b/src/handlers/realm.rs @@ -1,11 +1,49 @@ -use axum::extract::Path; -use sea_orm::prelude::Uuid; +use std::sync::Arc; -pub async fn get_realms() -> String { +use axum::{extract::Path, Extension, Json}; +use sea_orm::{prelude::Uuid, EntityTrait}; + +use crate::{ + database::{prelude::Realm, realm::Model}, + packages::{ + db::AppState, + errors::{AuthenticateError, Error}, + token::TokenUser, + }, +}; + +pub async fn get_realm() -> String { "Hi from MASTER REALM".to_owned() } -pub async fn get_realm(Path(realm_id): Path) -> String { - println!("This is realm Name: {}", &realm_id); - format!("Realm is - {}", realm_id) +pub async fn get_realms(user: TokenUser, Extension(state): Extension>) -> Result>, Error> { + let resource = match user.resource { + Some(resource) => resource, + None => return Err(Error::Authenticate(AuthenticateError::NoResource)), + }; + let is_admin = resource.identifiers.get("role"); + if is_admin.is_none() { + return Err(Error::Authenticate(AuthenticateError::NoResource)); + } + let is_admin = is_admin.unwrap() == "admin"; + + if !is_admin { + return Err(Error::Authenticate(AuthenticateError::NoResource)); + } + + // let realm = match realm { + // Some(realm) => realm, + // None => return Err(Error::Authenticate(AuthenticateError::NoResource)), + // }; + + // if realm.locked_at.is_some() { + // return Err(Error::Authenticate(AuthenticateError::Locked)); + // } + + // if realm.slug != "master" { + // return Err(Error::Authenticate(AuthenticateError::NoResource)); + // } + + let realms = Realm::find().all(&state.db).await?; + Ok(Json(realms)) } diff --git a/src/models/mod.rs b/src/models/mod.rs index 22d12a3..f4f68f1 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -1 +1,2 @@ +pub mod realm; pub mod user; diff --git a/src/models/realm.rs b/src/models/realm.rs new file mode 100644 index 0000000..5187d04 --- /dev/null +++ b/src/models/realm.rs @@ -0,0 +1 @@ +use crate::database::realm::Model; diff --git a/src/packages/admin.rs b/src/packages/admin.rs index f4b5fb4..bde5982 100644 --- a/src/packages/admin.rs +++ b/src/packages/admin.rs @@ -142,6 +142,15 @@ async fn assign_resource_to_admin(conn: &DatabaseConnection, realm_id: Uuid, cli ..Default::default() }; let inserted_resource = new_resource.insert(conn).await?; + + let new_resource_2 = resource::ActiveModel { + group_id: Set(inserted_resource_group.id), + name: Set("realm".to_owned()), + value: Set("master".to_owned()), + description: Set(Some("This role has been created at the time of initialization.".to_owned())), + ..Default::default() + }; + let _inserted_resource_2 = new_resource_2.insert(conn).await?; info!("✅ 5/5: Default resource created"); Ok(inserted_resource) } diff --git a/src/packages/errors.rs b/src/packages/errors.rs index f38a537..4a52834 100644 --- a/src/packages/errors.rs +++ b/src/packages/errors.rs @@ -38,6 +38,7 @@ impl Error { Error::Authenticate(AuthenticateError::InvalidToken) => (StatusCode::UNAUTHORIZED, 40005), Error::Authenticate(AuthenticateError::Locked) => (StatusCode::LOCKED, 40006), Error::Authenticate(AuthenticateError::EmailNotVerified) => (StatusCode::FORBIDDEN, 40007), + Error::Authenticate(AuthenticateError::NoResource) => (StatusCode::FORBIDDEN, 40008), // 5XX Errors Error::Authenticate(AuthenticateError::TokenCreation) => (StatusCode::INTERNAL_SERVER_ERROR, 5001), @@ -89,6 +90,8 @@ pub enum AuthenticateError { TokenCreation, #[error("Invalid authentication credentials")] InvalidToken, + #[error("Inappropriate resource access")] + NoResource, #[error("Email not verified")] EmailNotVerified, #[error("User is locked")] diff --git a/src/packages/token.rs b/src/packages/token.rs index 0f6ceee..93d2b67 100644 --- a/src/packages/token.rs +++ b/src/packages/token.rs @@ -61,6 +61,17 @@ impl TokenUser { resource: Some(Resource::from(client, resource_group, resources)), } } + + pub fn from_claim(claims: Claims) -> Self { + Self { + sub: claims.sub, + first_name: claims.first_name, + last_name: claims.last_name, + email: claims.email, + phone: claims.phone, + resource: claims.resource, + } + } } #[derive(Debug, Serialize, Deserialize)] diff --git a/src/utils/authenticate_request.rs b/src/utils/authenticate_request.rs new file mode 100644 index 0000000..6d19210 --- /dev/null +++ b/src/utils/authenticate_request.rs @@ -0,0 +1,32 @@ +use crate::packages::errors::AuthenticateError; +use crate::packages::errors::Error; +use crate::packages::settings::SETTINGS; +use crate::packages::token; +use crate::packages::token::TokenUser; + +use axum::{async_trait, extract::FromRequestParts, http::request::Parts, RequestPartsExt}; + +use axum_extra::{ + headers::{authorization::Bearer, Authorization}, + TypedHeader, +}; + +#[async_trait] +impl FromRequestParts for TokenUser +where + S: Send + Sync, +{ + type Rejection = Error; + + async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result { + let TypedHeader(Authorization(bearer)) = parts + .extract::>>() + .await + .map_err(|_| AuthenticateError::InvalidToken)?; + + let secret = &SETTINGS.secrets.signing_key; + let token_data = token::decode(bearer.token(), secret).map_err(|_| AuthenticateError::InvalidToken)?; + + Ok(TokenUser::from_claim(token_data.claims)) + } +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index ec5d33c..dc1bed0 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1 +1,2 @@ +pub mod authenticate_request; pub mod hash; From 7f1be0f1645f2793428cc1d1234786fc2f48f8a8 Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Fri, 27 Sep 2024 23:22:32 +0530 Subject: [PATCH 21/45] fix: realm and client get method implemented --- src/database/client.rs | 3 +- src/handlers/client.rs | 92 ++++++++++++++++++++++++++++++++++++++---- src/handlers/realm.rs | 71 +++++++++++++++++++++++--------- src/models/mod.rs | 1 - src/models/realm.rs | 1 - src/packages/errors.rs | 3 ++ 6 files changed, 141 insertions(+), 30 deletions(-) delete mode 100644 src/models/realm.rs diff --git a/src/database/client.rs b/src/database/client.rs index b6b4050..c320782 100644 --- a/src/database/client.rs +++ b/src/database/client.rs @@ -1,8 +1,9 @@ //! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Deserialize, Serialize)] #[sea_orm(table_name = "client")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] diff --git a/src/handlers/client.rs b/src/handlers/client.rs index 98b2de5..ba39eae 100644 --- a/src/handlers/client.rs +++ b/src/handlers/client.rs @@ -1,11 +1,89 @@ -use axum::extract::Path; -use sea_orm::prelude::Uuid; +use std::sync::Arc; -pub async fn get_clients(Path(realm_id): Path) -> String { - format!("Hi from clients of {realm_id}") +use crate::{ + database::{client, prelude::Client}, + packages::{ + db::AppState, + errors::{AuthenticateError, Error}, + token::TokenUser, + }, +}; +use axum::{extract::Path, Extension, Json}; +use sea_orm::{prelude::Uuid, ColumnTrait, EntityTrait, QueryFilter}; + +pub async fn get_clients( + user: TokenUser, + Extension(state): Extension>, + Path(realm_id): Path, +) -> Result>, Error> { + let resource = match user.resource { + Some(resource) => resource, + None => return Err(Error::Authenticate(AuthenticateError::NoResource)), + }; + let role = resource.identifiers.get("role"); + let realm = resource.identifiers.get("realm"); + if role.is_none() && realm.is_none() { + return Err(Error::Authenticate(AuthenticateError::NoResource)); + } + + if role.unwrap() == "admin" && realm.unwrap() == "master" { + let clients = Client::find().filter(client::Column::RealmId.eq(realm_id)).all(&state.db).await?; + Ok(Json(clients)) + } else { + if role.unwrap() == "admin" { + let clients = Client::find().filter(client::Column::RealmId.eq(realm_id)).all(&state.db).await?; + let client = clients.iter().find(|&client| client.id == resource.client_id); + match client { + Some(_) => return Ok(Json(clients)), + None => return Err(Error::Authenticate(AuthenticateError::NoResource)), + }; + } else { + Err(Error::Authenticate(AuthenticateError::NoResource)) + } + } } -pub async fn get_client(Path((realm_id, client_id)): Path<(Uuid, Uuid)>) -> String { - println!("This is client Name: {} - {}", &realm_id, &client_id); - format!("client is - {} - {}", realm_id, client_id) +pub async fn get_client( + user: TokenUser, + Extension(state): Extension>, + Path((realm_id, client_id)): Path<(Uuid, Uuid)>, +) -> Result, Error> { + let resource = match user.resource { + Some(resource) => resource, + None => return Err(Error::Authenticate(AuthenticateError::NoResource)), + }; + let role = resource.identifiers.get("role"); + let realm = resource.identifiers.get("realm"); + if role.is_none() && realm.is_none() { + return Err(Error::Authenticate(AuthenticateError::NoResource)); + } + + if role.unwrap() == "admin" && realm.unwrap() == "master" { + let client = Client::find_by_id(client_id).one(&state.db).await?; + match client { + Some(client) => Ok(Json(client)), + None => return Err(Error::Authenticate(AuthenticateError::NoResource)), + } + } else { + if role.unwrap() == "admin" { + let client = Client::find_by_id(client_id) + .filter(client::Column::RealmId.eq(realm_id)) + .one(&state.db) + .await?; + match client { + Some(client) => return Ok(Json(client)), + None => return Err(Error::Authenticate(AuthenticateError::NoResource)), + }; + } else { + if resource.client_id == client_id { + let client = Client::find_by_id(client_id).one(&state.db).await?; + match client { + Some(client) => return Ok(Json(client)), + None => return Err(Error::Authenticate(AuthenticateError::NoResource)), + }; + } else { + return Err(Error::Authenticate(AuthenticateError::ActionForbidden)); + } + } + } } diff --git a/src/handlers/realm.rs b/src/handlers/realm.rs index c5651c1..3725733 100644 --- a/src/handlers/realm.rs +++ b/src/handlers/realm.rs @@ -12,38 +12,69 @@ use crate::{ }, }; -pub async fn get_realm() -> String { - "Hi from MASTER REALM".to_owned() -} - pub async fn get_realms(user: TokenUser, Extension(state): Extension>) -> Result>, Error> { let resource = match user.resource { Some(resource) => resource, None => return Err(Error::Authenticate(AuthenticateError::NoResource)), }; - let is_admin = resource.identifiers.get("role"); - if is_admin.is_none() { + let role = resource.identifiers.get("role"); + let realm = resource.identifiers.get("realm"); + if role.is_none() { return Err(Error::Authenticate(AuthenticateError::NoResource)); } - let is_admin = is_admin.unwrap() == "admin"; - - if !is_admin { + if realm.is_none() { return Err(Error::Authenticate(AuthenticateError::NoResource)); } - // let realm = match realm { - // Some(realm) => realm, - // None => return Err(Error::Authenticate(AuthenticateError::NoResource)), - // }; + let is_admin = role.unwrap() == "admin"; + let is_master_realm = realm.unwrap() == "master"; - // if realm.locked_at.is_some() { - // return Err(Error::Authenticate(AuthenticateError::Locked)); - // } - - // if realm.slug != "master" { - // return Err(Error::Authenticate(AuthenticateError::NoResource)); - // } + if !is_admin || !is_master_realm { + return Err(Error::Authenticate(AuthenticateError::NoResource)); + } let realms = Realm::find().all(&state.db).await?; Ok(Json(realms)) } + +pub async fn get_realm(user: TokenUser, Extension(state): Extension>, Path(realm_id): Path) -> Result, Error> { + let resource = match user.resource { + Some(resource) => resource, + None => return Err(Error::Authenticate(AuthenticateError::NoResource)), + }; + let role = resource.identifiers.get("role"); + let realm = resource.identifiers.get("realm"); + if role.is_none() { + return Err(Error::Authenticate(AuthenticateError::NoResource)); + } + if realm.is_none() { + return Err(Error::Authenticate(AuthenticateError::NoResource)); + } + + let is_admin = role.unwrap() == "admin"; + let is_master_realm = realm.unwrap() == "master"; + + if is_admin && is_master_realm { + let fetched_realm = Realm::find().one(&state.db).await?; + match fetched_realm { + Some(fetched_realm) => Ok(Json(fetched_realm)), + None => { + return Err(Error::Authenticate(AuthenticateError::NoResource)); + } + } + } else { + let fetched_realm = Realm::find_by_id(realm_id).one(&state.db).await?; + match fetched_realm { + Some(fetched_realm) => { + if fetched_realm.slug == *realm.unwrap() { + return Ok(Json(fetched_realm)); + } else { + return Err(Error::Authenticate(AuthenticateError::NoResource)); + } + } + None => { + return Err(Error::Authenticate(AuthenticateError::NoResource)); + } + } + } +} diff --git a/src/models/mod.rs b/src/models/mod.rs index f4f68f1..22d12a3 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -1,2 +1 @@ -pub mod realm; pub mod user; diff --git a/src/models/realm.rs b/src/models/realm.rs deleted file mode 100644 index 5187d04..0000000 --- a/src/models/realm.rs +++ /dev/null @@ -1 +0,0 @@ -use crate::database::realm::Model; diff --git a/src/packages/errors.rs b/src/packages/errors.rs index 4a52834..5e51f4f 100644 --- a/src/packages/errors.rs +++ b/src/packages/errors.rs @@ -39,6 +39,7 @@ impl Error { Error::Authenticate(AuthenticateError::Locked) => (StatusCode::LOCKED, 40006), Error::Authenticate(AuthenticateError::EmailNotVerified) => (StatusCode::FORBIDDEN, 40007), Error::Authenticate(AuthenticateError::NoResource) => (StatusCode::FORBIDDEN, 40008), + Error::Authenticate(AuthenticateError::ActionForbidden) => (StatusCode::FORBIDDEN, 40009), // 5XX Errors Error::Authenticate(AuthenticateError::TokenCreation) => (StatusCode::INTERNAL_SERVER_ERROR, 5001), @@ -94,6 +95,8 @@ pub enum AuthenticateError { NoResource, #[error("Email not verified")] EmailNotVerified, + #[error("Action forbidden")] + ActionForbidden, #[error("User is locked")] Locked, } From 42757b9eea18de8f755e3664105d9bf8f5e1d883 Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Sat, 28 Sep 2024 12:21:56 +0530 Subject: [PATCH 22/45] fix: realm crud implemented --- src/handlers/client.rs | 32 ++---- src/handlers/realm.rs | 151 +++++++++++++++++++------- src/packages/admin.rs | 10 +- src/packages/errors.rs | 137 ++++++++++++++++++++--- src/routes/realm.rs | 6 +- src/utils/default_resource_checker.rs | 16 +++ src/utils/helpers/default_cred.rs | 45 ++++++++ src/utils/helpers/mod.rs | 1 + src/utils/mod.rs | 3 + src/utils/role_checker.rs | 27 +++++ 10 files changed, 334 insertions(+), 94 deletions(-) create mode 100644 src/utils/default_resource_checker.rs create mode 100644 src/utils/helpers/default_cred.rs create mode 100644 src/utils/helpers/mod.rs create mode 100644 src/utils/role_checker.rs diff --git a/src/handlers/client.rs b/src/handlers/client.rs index ba39eae..3b8da5b 100644 --- a/src/handlers/client.rs +++ b/src/handlers/client.rs @@ -7,6 +7,7 @@ use crate::{ errors::{AuthenticateError, Error}, token::TokenUser, }, + utils::role_checker::{is_master_realm_admin, is_realm_admin}, }; use axum::{extract::Path, Extension, Json}; use sea_orm::{prelude::Uuid, ColumnTrait, EntityTrait, QueryFilter}; @@ -16,21 +17,12 @@ pub async fn get_clients( Extension(state): Extension>, Path(realm_id): Path, ) -> Result>, Error> { - let resource = match user.resource { - Some(resource) => resource, - None => return Err(Error::Authenticate(AuthenticateError::NoResource)), - }; - let role = resource.identifiers.get("role"); - let realm = resource.identifiers.get("realm"); - if role.is_none() && realm.is_none() { - return Err(Error::Authenticate(AuthenticateError::NoResource)); - } - - if role.unwrap() == "admin" && realm.unwrap() == "master" { + if is_master_realm_admin(&user) { let clients = Client::find().filter(client::Column::RealmId.eq(realm_id)).all(&state.db).await?; Ok(Json(clients)) } else { - if role.unwrap() == "admin" { + if is_realm_admin(&user) { + let resource = user.resource.unwrap(); let clients = Client::find().filter(client::Column::RealmId.eq(realm_id)).all(&state.db).await?; let client = clients.iter().find(|&client| client.id == resource.client_id); match client { @@ -48,24 +40,14 @@ pub async fn get_client( Extension(state): Extension>, Path((realm_id, client_id)): Path<(Uuid, Uuid)>, ) -> Result, Error> { - let resource = match user.resource { - Some(resource) => resource, - None => return Err(Error::Authenticate(AuthenticateError::NoResource)), - }; - let role = resource.identifiers.get("role"); - let realm = resource.identifiers.get("realm"); - if role.is_none() && realm.is_none() { - return Err(Error::Authenticate(AuthenticateError::NoResource)); - } - - if role.unwrap() == "admin" && realm.unwrap() == "master" { + if is_master_realm_admin(&user) { let client = Client::find_by_id(client_id).one(&state.db).await?; match client { Some(client) => Ok(Json(client)), None => return Err(Error::Authenticate(AuthenticateError::NoResource)), } } else { - if role.unwrap() == "admin" { + if is_realm_admin(&user) { let client = Client::find_by_id(client_id) .filter(client::Column::RealmId.eq(realm_id)) .one(&state.db) @@ -75,7 +57,7 @@ pub async fn get_client( None => return Err(Error::Authenticate(AuthenticateError::NoResource)), }; } else { - if resource.client_id == client_id { + if user.resource.as_ref().unwrap().client_id == client_id { let client = Client::find_by_id(client_id).one(&state.db).await?; match client { Some(client) => return Ok(Json(client)), diff --git a/src/handlers/realm.rs b/src/handlers/realm.rs index 3725733..4013afe 100644 --- a/src/handlers/realm.rs +++ b/src/handlers/realm.rs @@ -1,60 +1,38 @@ -use std::sync::Arc; +use std::{fs, sync::Arc}; use axum::{extract::Path, Extension, Json}; -use sea_orm::{prelude::Uuid, EntityTrait}; +use chrono::Utc; +use sea_orm::{prelude::Uuid, ActiveModelTrait, EntityTrait, Set}; +use serde::{Deserialize, Serialize}; use crate::{ - database::{prelude::Realm, realm::Model}, + database::{ + prelude::Realm, + realm::{ActiveModel, Model}, + }, packages::{ db::AppState, errors::{AuthenticateError, Error}, token::TokenUser, }, + utils::{ + default_resource_checker::is_default_realm, + helpers::default_cred::DefaultCred, + role_checker::{is_master_realm_admin, is_realm_admin}, + }, }; pub async fn get_realms(user: TokenUser, Extension(state): Extension>) -> Result>, Error> { - let resource = match user.resource { - Some(resource) => resource, - None => return Err(Error::Authenticate(AuthenticateError::NoResource)), - }; - let role = resource.identifiers.get("role"); - let realm = resource.identifiers.get("realm"); - if role.is_none() { - return Err(Error::Authenticate(AuthenticateError::NoResource)); - } - if realm.is_none() { - return Err(Error::Authenticate(AuthenticateError::NoResource)); - } - - let is_admin = role.unwrap() == "admin"; - let is_master_realm = realm.unwrap() == "master"; - - if !is_admin || !is_master_realm { - return Err(Error::Authenticate(AuthenticateError::NoResource)); + if is_master_realm_admin(&user) { + let realms = Realm::find().all(&state.db).await?; + return Ok(Json(realms)); } - let realms = Realm::find().all(&state.db).await?; - Ok(Json(realms)) + return Err(Error::Authenticate(AuthenticateError::NoResource)); } pub async fn get_realm(user: TokenUser, Extension(state): Extension>, Path(realm_id): Path) -> Result, Error> { - let resource = match user.resource { - Some(resource) => resource, - None => return Err(Error::Authenticate(AuthenticateError::NoResource)), - }; - let role = resource.identifiers.get("role"); - let realm = resource.identifiers.get("realm"); - if role.is_none() { - return Err(Error::Authenticate(AuthenticateError::NoResource)); - } - if realm.is_none() { - return Err(Error::Authenticate(AuthenticateError::NoResource)); - } - - let is_admin = role.unwrap() == "admin"; - let is_master_realm = realm.unwrap() == "master"; - - if is_admin && is_master_realm { + if is_master_realm_admin(&user) { let fetched_realm = Realm::find().one(&state.db).await?; match fetched_realm { Some(fetched_realm) => Ok(Json(fetched_realm)), @@ -66,7 +44,11 @@ pub async fn get_realm(user: TokenUser, Extension(state): Extension { - if fetched_realm.slug == *realm.unwrap() { + if is_realm_admin(&user) + && user + .resource + .is_some_and(|x| x.identifiers.get("realm").is_some_and(|y| y == &fetched_realm.slug)) + { return Ok(Json(fetched_realm)); } else { return Err(Error::Authenticate(AuthenticateError::NoResource)); @@ -78,3 +60,90 @@ pub async fn get_realm(user: TokenUser, Extension(state): Extension>, + Json(payload): Json, +) -> Result, Error> { + if is_master_realm_admin(&user) { + let realm = ActiveModel { + name: Set(payload.name), + ..Default::default() + }; + let realm = realm.insert(&state.db).await?; + Ok(Json(realm)) + } else { + Err(Error::Authenticate(AuthenticateError::NoResource)) + } +} + +#[derive(Deserialize)] +pub struct UpdateRealmRequest { + name: String, + lock: Option, +} + +pub async fn update_realm( + user: TokenUser, + Extension(state): Extension>, + Path(realm_id): Path, + Json(payload): Json, +) -> Result, Error> { + if is_master_realm_admin(&user) || is_realm_admin(&user) { + let realm = Realm::find_by_id(realm_id).one(&state.db).await?; + match realm { + Some(realm) => { + if is_default_realm(realm.id) && payload.lock == Some(true) { + return Err(Error::cannot_perform_operation("Cannot lock the default realm")); + } + + let locked_at = match payload.lock { + Some(true) => Some(realm.locked_at.unwrap_or_else(|| Utc::now().naive_utc())), + Some(false) => None, + None => realm.locked_at, + }; + + let updated_realm = ActiveModel { + id: Set(realm.id), + name: Set(payload.name), + locked_at: Set(locked_at), + ..Default::default() + }; + let updated_realm = updated_realm.update(&state.db).await?; + Ok(Json(updated_realm)) + } + None => { + return Err(Error::Authenticate(AuthenticateError::NoResource)); + } + } + } else { + Err(Error::Authenticate(AuthenticateError::NoResource)) + } +} + +#[derive(Serialize)] +pub struct DeleteResponse { + ok: bool, +} + +pub async fn delete_realm( + user: TokenUser, + Extension(state): Extension>, + Path(realm_id): Path, +) -> Result, Error> { + if is_master_realm_admin(&user) { + if is_default_realm(realm_id) { + return Err(Error::cannot_perform_operation("Cannot delete the default realm")); + } + Realm::delete_by_id(realm_id).exec(&state.db).await?; + Ok(Json(DeleteResponse { ok: true })) + } else { + Err(Error::Authenticate(AuthenticateError::NoResource)) + } +} diff --git a/src/packages/admin.rs b/src/packages/admin.rs index bde5982..e074402 100644 --- a/src/packages/admin.rs +++ b/src/packages/admin.rs @@ -5,6 +5,7 @@ use std::{ }; use sea_orm::{prelude::Uuid, ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait, QueryFilter, Set}; +use serde::Deserialize; use tracing::info; use crate::{ @@ -14,18 +15,11 @@ use crate::{ realm, resource, resource_group, user, }, packages::settings::SETTINGS, - utils::hash::generate_password_hash, + utils::{hash::generate_password_hash, helpers::default_cred::DefaultCred}, }; use super::{db::AppState, errors::Error}; -#[allow(dead_code)] -#[derive(Debug)] -pub struct DefaultCred { - realm_id: Uuid, - client_id: Uuid, -} - pub async fn setup(state: &AppState) -> Result<(), Error> { info!("Checking ADMIN availability!"); let is_admin_user_exists = User::find().filter(user::Column::Email.eq(&SETTINGS.admin.email)).one(&state.db).await?; diff --git a/src/packages/errors.rs b/src/packages/errors.rs index 5e51f4f..ea411d5 100644 --- a/src/packages/errors.rs +++ b/src/packages/errors.rs @@ -4,7 +4,9 @@ use axum::Json; use bcrypt::BcryptError; use sea_orm::DbErr; use serde_json::json; +use std::io; use tokio::task::JoinError; +use tracing::error; #[derive(thiserror::Error, Debug)] #[error("...")] @@ -13,7 +15,7 @@ pub enum Error { Authenticate(#[from] AuthenticateError), #[error("{0}")] - BadRequest(#[from] BadRequest), + BadRequest(#[from] BadRequestError), #[error("Database error: {0}")] DatabaseError(#[from] DatabaseError), @@ -26,35 +28,37 @@ pub enum Error { #[error("{0}")] HashPassword(#[from] BcryptError), + + #[error("{0}")] + FileError(#[from] FileError), + + #[error("{0}")] + SerdeJson(#[from] serde_json::Error), } impl Error { fn get_codes(&self) -> (StatusCode, u16) { - match *self { + match self { // 4XX Errors - Error::BadRequest(_) => (StatusCode::BAD_REQUEST, 40002), - Error::NotFound(_) => (StatusCode::NOT_FOUND, 40003), - Error::Authenticate(AuthenticateError::WrongCredentials) => (StatusCode::UNAUTHORIZED, 40004), - Error::Authenticate(AuthenticateError::InvalidToken) => (StatusCode::UNAUTHORIZED, 40005), - Error::Authenticate(AuthenticateError::Locked) => (StatusCode::LOCKED, 40006), - Error::Authenticate(AuthenticateError::EmailNotVerified) => (StatusCode::FORBIDDEN, 40007), - Error::Authenticate(AuthenticateError::NoResource) => (StatusCode::FORBIDDEN, 40008), - Error::Authenticate(AuthenticateError::ActionForbidden) => (StatusCode::FORBIDDEN, 40009), + Error::BadRequest(err) => err.get_codes(), + Error::NotFound(err) => (StatusCode::NOT_FOUND, 40003), + Error::Authenticate(err) => err.get_codes(), // 5XX Errors - Error::Authenticate(AuthenticateError::TokenCreation) => (StatusCode::INTERNAL_SERVER_ERROR, 5001), Error::RunSyncTask(_) => (StatusCode::INTERNAL_SERVER_ERROR, 5005), Error::HashPassword(_) => (StatusCode::INTERNAL_SERVER_ERROR, 5006), Error::DatabaseError(_) => (StatusCode::INTERNAL_SERVER_ERROR, 5007), + Error::FileError(_) => (StatusCode::INTERNAL_SERVER_ERROR, 5008), + Error::SerdeJson(_) => (StatusCode::INTERNAL_SERVER_ERROR, 5009), } } pub fn bad_request() -> Self { - Error::BadRequest(BadRequest {}) + Error::BadRequest(BadRequestError::Generic) } pub fn not_found() -> Self { - Error::NotFound(NotFound {}) + Error::NotFound(NotFound::Generic) } pub fn db_error(err: E) -> Self @@ -70,10 +74,37 @@ impl Error { { (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()) } + + pub fn invalid_input(message: &str) -> Self { + Error::BadRequest(BadRequestError::InvalidInput(message.to_string())) + } + + pub fn missing_field(field: &str) -> Self { + Error::BadRequest(BadRequestError::MissingField(field.to_string())) + } + + pub fn cannot_perform_operation(message: &str) -> Self { + Error::BadRequest(BadRequestError::CannotPerformOperation(message.to_string())) + } + + pub fn context(self, context: &str) -> Self { + match self { + Error::BadRequest(err) => Error::BadRequest(err.with_context(context)), + Error::NotFound(err) => Error::NotFound(err.with_context(context)), + Error::Authenticate(err) => Error::Authenticate(err.with_context(context)), + _ => self, + } + } + + pub fn log(&self) { + let (status, code) = self.get_codes(); + error!("Error {}/{}: {}", status.as_u16(), code, self); + } } impl IntoResponse for Error { fn into_response(self) -> Response { + self.log(); let (status_code, code) = self.get_codes(); let message = self.to_string(); let body = Json(json!({ "code": code, "message": message })); @@ -101,20 +132,92 @@ pub enum AuthenticateError { Locked, } +impl AuthenticateError { + fn get_codes(&self) -> (StatusCode, u16) { + match self { + AuthenticateError::WrongCredentials => (StatusCode::UNAUTHORIZED, 40004), + AuthenticateError::InvalidToken => (StatusCode::UNAUTHORIZED, 40005), + AuthenticateError::Locked => (StatusCode::LOCKED, 40006), + AuthenticateError::EmailNotVerified => (StatusCode::FORBIDDEN, 40007), + AuthenticateError::NoResource => (StatusCode::FORBIDDEN, 40008), + AuthenticateError::ActionForbidden => (StatusCode::FORBIDDEN, 40009), + AuthenticateError::TokenCreation => (StatusCode::INTERNAL_SERVER_ERROR, 5001), + } + } + + fn with_context(self, context: &str) -> Self { + match self { + AuthenticateError::WrongCredentials => AuthenticateError::WrongCredentials, + AuthenticateError::TokenCreation => AuthenticateError::TokenCreation, + AuthenticateError::InvalidToken => AuthenticateError::InvalidToken, + AuthenticateError::NoResource => AuthenticateError::NoResource, + AuthenticateError::EmailNotVerified => AuthenticateError::EmailNotVerified, + AuthenticateError::ActionForbidden => AuthenticateError::ActionForbidden, + AuthenticateError::Locked => AuthenticateError::Locked, + } + } +} + #[derive(thiserror::Error, Debug)] -#[error("Bad Request")] -pub struct BadRequest {} +pub enum BadRequestError { + #[error("Bad Request")] + Generic, + #[error("Invalid input: {0}")] + InvalidInput(String), + #[error("Missing required field: {0}")] + MissingField(String), + #[error("Cannot perform operation: {0}")] + CannotPerformOperation(String), +} + +impl BadRequestError { + fn get_codes(&self) -> (StatusCode, u16) { + (StatusCode::BAD_REQUEST, 40002) + } + + fn with_context(self, context: &str) -> Self { + match self { + BadRequestError::Generic => BadRequestError::CannotPerformOperation(context.to_string()), + BadRequestError::InvalidInput(msg) => BadRequestError::InvalidInput(format!("{}: {}", context, msg)), + BadRequestError::MissingField(field) => BadRequestError::MissingField(format!("{}: {}", context, field)), + BadRequestError::CannotPerformOperation(msg) => BadRequestError::CannotPerformOperation(format!("{}: {}", context, msg)), + } + } +} #[derive(thiserror::Error, Debug)] -#[error("Not found")] -pub struct NotFound {} +pub enum NotFound { + #[error("Not found")] + Generic, + #[error("Resource not found: {0}")] + Resource(String), +} + +impl NotFound { + fn with_context(self, context: &str) -> Self { + match self { + NotFound::Generic => NotFound::Resource(context.to_string()), + NotFound::Resource(resource) => NotFound::Resource(format!("{}: {}", context, resource)), + } + } +} #[derive(thiserror::Error, Debug)] #[error("Database error: {0}")] pub struct DatabaseError(#[from] Box); +#[derive(thiserror::Error, Debug)] +#[error("File error: {0}")] +pub struct FileError(#[from] io::Error); + impl From for Error { fn from(err: DbErr) -> Self { Error::DatabaseError(DatabaseError(Box::new(err))) } } + +impl From for Error { + fn from(err: io::Error) -> Self { + Error::FileError(FileError(err)) + } +} diff --git a/src/routes/realm.rs b/src/routes/realm.rs index 2a6047a..5fbe14e 100644 --- a/src/routes/realm.rs +++ b/src/routes/realm.rs @@ -1,14 +1,14 @@ use axum::{routing::get, Router}; -use crate::handlers::realm::{get_realm, get_realms}; +use crate::handlers::realm::{create_realm, delete_realm, get_realm, get_realms, update_realm}; use super::{client, user}; pub fn create_routes() -> Router { - Router::new().route("/", get(get_realms)).nest( + Router::new().route("/", get(get_realms).post(create_realm)).nest( "/:realm_id", Router::new() - .route("/", get(get_realm)) + .route("/", get(get_realm).patch(update_realm).delete(delete_realm)) .nest("/clients", client::create_routes()) .nest("/users", user::create_routes()), ) diff --git a/src/utils/default_resource_checker.rs b/src/utils/default_resource_checker.rs new file mode 100644 index 0000000..b425345 --- /dev/null +++ b/src/utils/default_resource_checker.rs @@ -0,0 +1,16 @@ +use std::fs::read_to_string; + +use sea_orm::prelude::Uuid; + +use crate::packages::errors::Error; + +use super::helpers::default_cred::DefaultCred; + +pub fn is_default_realm(realm_id: Uuid) -> bool { + let default_cred_str = read_to_string("./logs/default_cred.txt").map_err(Error::from); + let default_cred_str = default_cred_str.unwrap(); + let default_cred = DefaultCred::from_str(&default_cred_str); + let default_cred = default_cred.unwrap(); + + realm_id == default_cred.realm_id +} diff --git a/src/utils/helpers/default_cred.rs b/src/utils/helpers/default_cred.rs new file mode 100644 index 0000000..9d6ea1b --- /dev/null +++ b/src/utils/helpers/default_cred.rs @@ -0,0 +1,45 @@ +use std::str::FromStr; + +use sea_orm::prelude::Uuid; +use serde::Deserialize; + +use crate::packages::errors::Error; + +#[allow(dead_code)] +#[derive(Debug, Deserialize)] +pub struct DefaultCred { + pub realm_id: Uuid, + pub client_id: Uuid, +} + +impl DefaultCred { + pub fn from_str(s: &str) -> Result { + let mut realm_id = String::new(); + let mut client_id = String::new(); + + for line in s.lines() { + if line.contains("realm_id:") { + realm_id = line + .split(':') + .nth(1) + .map(|s| s.trim().trim_end_matches(',').to_string()) + .unwrap_or_default(); + } + if line.contains("client_id:") { + client_id = line + .split(':') + .nth(1) + .map(|s| s.trim().trim_end_matches(',').to_string()) + .unwrap_or_default(); + } + } + + if realm_id.is_empty() || client_id.is_empty() { + return Err(Error::invalid_input("Failed to parse DefaultCred")); + } + + let realm_id = Uuid::from_str(&realm_id).map_err(|_| Error::invalid_input("Failed to parse DefaultCred"))?; + let client_id = Uuid::from_str(&client_id).map_err(|_| Error::invalid_input("Failed to parse DefaultCred"))?; + Ok(DefaultCred { realm_id, client_id }) + } +} diff --git a/src/utils/helpers/mod.rs b/src/utils/helpers/mod.rs new file mode 100644 index 0000000..ec9691a --- /dev/null +++ b/src/utils/helpers/mod.rs @@ -0,0 +1 @@ +pub mod default_cred; diff --git a/src/utils/mod.rs b/src/utils/mod.rs index dc1bed0..87ae8c2 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,2 +1,5 @@ pub mod authenticate_request; +pub mod default_resource_checker; pub mod hash; +pub mod helpers; +pub mod role_checker; diff --git a/src/utils/role_checker.rs b/src/utils/role_checker.rs new file mode 100644 index 0000000..3b8387c --- /dev/null +++ b/src/utils/role_checker.rs @@ -0,0 +1,27 @@ +use crate::packages::token::TokenUser; + +pub fn is_master_realm_admin(user: &TokenUser) -> bool { + let resource = match &user.resource { + Some(resource) => resource, + None => return false, + }; + let role = resource.identifiers.get("role"); + let realm = resource.identifiers.get("realm"); + if role.is_none() { + return false; + } + if realm.is_none() { + return false; + } + + let is_admin = role.unwrap() == "admin"; + let is_master_realm = realm.unwrap() == "master"; + + is_admin && is_master_realm +} + +pub fn is_realm_admin(user: &TokenUser) -> bool { + user.resource + .as_ref() + .is_some_and(|x| x.client_name == "client" && x.identifiers.get("role").is_some_and(|y| y == "admin")) +} From c7ca059bde0b8528f804e748ccae39e6f1c60a52 Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Sat, 28 Sep 2024 13:43:55 +0530 Subject: [PATCH 23/45] fix: dto and service code separated --- src/handlers/client.rs | 6 +-- src/handlers/realm.rs | 86 ++++++++------------------------------- src/main.rs | 2 + src/mappers/mod.rs | 1 + src/mappers/realm.rs | 17 ++++++++ src/packages/admin.rs | 3 +- src/services/mod.rs | 1 + src/services/realm.rs | 61 +++++++++++++++++++++++++++ src/utils/role_checker.rs | 10 ++++- 9 files changed, 113 insertions(+), 74 deletions(-) create mode 100644 src/mappers/mod.rs create mode 100644 src/mappers/realm.rs create mode 100644 src/services/mod.rs create mode 100644 src/services/realm.rs diff --git a/src/handlers/client.rs b/src/handlers/client.rs index 3b8da5b..1f1be83 100644 --- a/src/handlers/client.rs +++ b/src/handlers/client.rs @@ -7,7 +7,7 @@ use crate::{ errors::{AuthenticateError, Error}, token::TokenUser, }, - utils::role_checker::{is_master_realm_admin, is_realm_admin}, + utils::role_checker::{is_any_realm_admin, is_master_realm_admin}, }; use axum::{extract::Path, Extension, Json}; use sea_orm::{prelude::Uuid, ColumnTrait, EntityTrait, QueryFilter}; @@ -21,7 +21,7 @@ pub async fn get_clients( let clients = Client::find().filter(client::Column::RealmId.eq(realm_id)).all(&state.db).await?; Ok(Json(clients)) } else { - if is_realm_admin(&user) { + if is_any_realm_admin(&user) { let resource = user.resource.unwrap(); let clients = Client::find().filter(client::Column::RealmId.eq(realm_id)).all(&state.db).await?; let client = clients.iter().find(|&client| client.id == resource.client_id); @@ -47,7 +47,7 @@ pub async fn get_client( None => return Err(Error::Authenticate(AuthenticateError::NoResource)), } } else { - if is_realm_admin(&user) { + if is_any_realm_admin(&user) { let client = Client::find_by_id(client_id) .filter(client::Column::RealmId.eq(realm_id)) .one(&state.db) diff --git a/src/handlers/realm.rs b/src/handlers/realm.rs index 4013afe..1abae78 100644 --- a/src/handlers/realm.rs +++ b/src/handlers/realm.rs @@ -1,30 +1,26 @@ -use std::{fs, sync::Arc}; +use std::sync::Arc; use axum::{extract::Path, Extension, Json}; -use chrono::Utc; -use sea_orm::{prelude::Uuid, ActiveModelTrait, EntityTrait, Set}; -use serde::{Deserialize, Serialize}; +use sea_orm::prelude::Uuid; use crate::{ - database::{ - prelude::Realm, - realm::{ActiveModel, Model}, - }, + database::realm::Model, + mappers::realm::{CreateRealmRequest, DeleteResponse, UpdateRealmRequest}, packages::{ db::AppState, errors::{AuthenticateError, Error}, token::TokenUser, }, + services::realm::{delete_realm_by_id, get_all_realms, get_realm_by_id, insert_realm, update_realm_by_id}, utils::{ default_resource_checker::is_default_realm, - helpers::default_cred::DefaultCred, - role_checker::{is_master_realm_admin, is_realm_admin}, + role_checker::{is_current_realm_admin, is_master_realm_admin}, }, }; pub async fn get_realms(user: TokenUser, Extension(state): Extension>) -> Result>, Error> { if is_master_realm_admin(&user) { - let realms = Realm::find().all(&state.db).await?; + let realms = get_all_realms(&state.db).await?; return Ok(Json(realms)); } @@ -33,7 +29,7 @@ pub async fn get_realms(user: TokenUser, Extension(state): Extension>, Path(realm_id): Path) -> Result, Error> { if is_master_realm_admin(&user) { - let fetched_realm = Realm::find().one(&state.db).await?; + let fetched_realm = get_realm_by_id(&state.db, realm_id).await?; match fetched_realm { Some(fetched_realm) => Ok(Json(fetched_realm)), None => { @@ -41,14 +37,10 @@ pub async fn get_realm(user: TokenUser, Extension(state): Extension { - if is_realm_admin(&user) - && user - .resource - .is_some_and(|x| x.identifiers.get("realm").is_some_and(|y| y == &fetched_realm.slug)) - { + if is_current_realm_admin(&user, &fetched_realm.name) { return Ok(Json(fetched_realm)); } else { return Err(Error::Authenticate(AuthenticateError::NoResource)); @@ -61,77 +53,33 @@ pub async fn get_realm(user: TokenUser, Extension(state): Extension>, Json(payload): Json, ) -> Result, Error> { if is_master_realm_admin(&user) { - let realm = ActiveModel { - name: Set(payload.name), - ..Default::default() - }; - let realm = realm.insert(&state.db).await?; + let realm = insert_realm(&state.db, payload.name).await?; Ok(Json(realm)) } else { Err(Error::Authenticate(AuthenticateError::NoResource)) } } -#[derive(Deserialize)] -pub struct UpdateRealmRequest { - name: String, - lock: Option, -} - pub async fn update_realm( user: TokenUser, Extension(state): Extension>, Path(realm_id): Path, Json(payload): Json, ) -> Result, Error> { - if is_master_realm_admin(&user) || is_realm_admin(&user) { - let realm = Realm::find_by_id(realm_id).one(&state.db).await?; - match realm { - Some(realm) => { - if is_default_realm(realm.id) && payload.lock == Some(true) { - return Err(Error::cannot_perform_operation("Cannot lock the default realm")); - } - - let locked_at = match payload.lock { - Some(true) => Some(realm.locked_at.unwrap_or_else(|| Utc::now().naive_utc())), - Some(false) => None, - None => realm.locked_at, - }; - - let updated_realm = ActiveModel { - id: Set(realm.id), - name: Set(payload.name), - locked_at: Set(locked_at), - ..Default::default() - }; - let updated_realm = updated_realm.update(&state.db).await?; - Ok(Json(updated_realm)) - } - None => { - return Err(Error::Authenticate(AuthenticateError::NoResource)); - } - } + if is_master_realm_admin(&user) { + let realm = update_realm_by_id(&state.db, realm_id, payload).await?; + Ok(Json(realm)) } else { Err(Error::Authenticate(AuthenticateError::NoResource)) } } -#[derive(Serialize)] -pub struct DeleteResponse { - ok: bool, -} - pub async fn delete_realm( user: TokenUser, Extension(state): Extension>, @@ -141,8 +89,10 @@ pub async fn delete_realm( if is_default_realm(realm_id) { return Err(Error::cannot_perform_operation("Cannot delete the default realm")); } - Realm::delete_by_id(realm_id).exec(&state.db).await?; - Ok(Json(DeleteResponse { ok: true })) + let result = delete_realm_by_id(&state.db, realm_id).await?; + Ok(Json(DeleteResponse { + ok: result.rows_affected == 1, + })) } else { Err(Error::Authenticate(AuthenticateError::NoResource)) } diff --git a/src/main.rs b/src/main.rs index a902c54..5dcca42 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,10 +8,12 @@ use tracing::info; mod app; mod database; mod handlers; +mod mappers; mod middleware; mod models; mod packages; mod routes; +mod services; mod utils; #[tokio::main] diff --git a/src/mappers/mod.rs b/src/mappers/mod.rs new file mode 100644 index 0000000..abc366b --- /dev/null +++ b/src/mappers/mod.rs @@ -0,0 +1 @@ +pub mod realm; diff --git a/src/mappers/realm.rs b/src/mappers/realm.rs new file mode 100644 index 0000000..4ef6513 --- /dev/null +++ b/src/mappers/realm.rs @@ -0,0 +1,17 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize)] +pub struct CreateRealmRequest { + pub name: String, +} + +#[derive(Deserialize)] +pub struct UpdateRealmRequest { + pub name: String, + pub lock: Option, +} + +#[derive(Serialize)] +pub struct DeleteResponse { + pub ok: bool, +} diff --git a/src/packages/admin.rs b/src/packages/admin.rs index e074402..866440c 100644 --- a/src/packages/admin.rs +++ b/src/packages/admin.rs @@ -5,7 +5,6 @@ use std::{ }; use sea_orm::{prelude::Uuid, ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait, QueryFilter, Set}; -use serde::Deserialize; use tracing::info; use crate::{ @@ -140,7 +139,7 @@ async fn assign_resource_to_admin(conn: &DatabaseConnection, realm_id: Uuid, cli let new_resource_2 = resource::ActiveModel { group_id: Set(inserted_resource_group.id), name: Set("realm".to_owned()), - value: Set("master".to_owned()), + value: Set("Master".to_owned()), description: Set(Some("This role has been created at the time of initialization.".to_owned())), ..Default::default() }; diff --git a/src/services/mod.rs b/src/services/mod.rs new file mode 100644 index 0000000..abc366b --- /dev/null +++ b/src/services/mod.rs @@ -0,0 +1 @@ +pub mod realm; diff --git a/src/services/realm.rs b/src/services/realm.rs new file mode 100644 index 0000000..917bce9 --- /dev/null +++ b/src/services/realm.rs @@ -0,0 +1,61 @@ +use chrono::Utc; +use sea_orm::{prelude::Uuid, ActiveModelTrait, DatabaseConnection, DeleteResult, EntityTrait, Set}; + +use crate::{ + database::{ + prelude::Realm, + realm::{ActiveModel, Model}, + }, + mappers::realm::UpdateRealmRequest, + packages::errors::{AuthenticateError, Error}, + utils::default_resource_checker::is_default_realm, +}; + +pub async fn get_all_realms(db: &DatabaseConnection) -> Result, Error> { + Ok(Realm::find().all(db).await?) +} + +pub async fn get_realm_by_id(db: &DatabaseConnection, id: Uuid) -> Result, Error> { + Ok(Realm::find_by_id(id).one(db).await?) +} + +pub async fn insert_realm(db: &DatabaseConnection, name: String) -> Result { + let realm = ActiveModel { + name: Set(name), + ..Default::default() + }; + Ok(realm.insert(db).await?) +} + +pub async fn update_realm_by_id(db: &DatabaseConnection, id: Uuid, payload: UpdateRealmRequest) -> Result { + let realm = get_realm_by_id(db, id).await?; + match realm { + Some(realm) => { + if is_default_realm(realm.id) && payload.lock == Some(true) { + return Err(Error::cannot_perform_operation("Cannot lock the default realm")); + } + + let locked_at = match payload.lock { + Some(true) => Some(realm.locked_at.unwrap_or_else(|| Utc::now().naive_utc())), + Some(false) => None, + None => realm.locked_at, + }; + + let updated_realm = ActiveModel { + id: Set(realm.id), + name: Set(payload.name), + locked_at: Set(locked_at), + ..Default::default() + }; + let updated_realm = updated_realm.update(db).await?; + Ok(updated_realm) + } + None => { + return Err(Error::Authenticate(AuthenticateError::NoResource)); + } + } +} + +pub async fn delete_realm_by_id(db: &DatabaseConnection, id: Uuid) -> Result { + Ok(Realm::delete_by_id(id).exec(db).await?) +} diff --git a/src/utils/role_checker.rs b/src/utils/role_checker.rs index 3b8387c..5f52c5a 100644 --- a/src/utils/role_checker.rs +++ b/src/utils/role_checker.rs @@ -20,8 +20,16 @@ pub fn is_master_realm_admin(user: &TokenUser) -> bool { is_admin && is_master_realm } -pub fn is_realm_admin(user: &TokenUser) -> bool { +pub fn is_any_realm_admin(user: &TokenUser) -> bool { user.resource .as_ref() .is_some_and(|x| x.client_name == "client" && x.identifiers.get("role").is_some_and(|y| y == "admin")) } + +pub fn is_current_realm_admin(user: &TokenUser, realm_name: &str) -> bool { + user.resource.as_ref().is_some_and(|x| { + x.identifiers + .get("realm") + .is_some_and(|y| y == realm_name && x.client_name == "client" && x.identifiers.get("role").is_some_and(|z| z == "admin")) + }) +} From c180efd530737231c3c3a6acae21fc4f12b0e7c0 Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Sat, 28 Sep 2024 16:31:00 +0530 Subject: [PATCH 24/45] fix: default cred reading optimized and crud for client done --- Cargo.lock | 1 + Cargo.toml | 1 + src/app.rs | 8 +- src/handlers/auth.rs | 2 +- src/handlers/client.rs | 103 +++++++++++++++----------- src/handlers/realm.rs | 21 ++---- src/main.rs | 2 +- src/mappers/client.rs | 14 ++++ src/mappers/mod.rs | 8 ++ src/mappers/realm.rs | 7 +- src/packages/admin.rs | 23 +++--- src/packages/db.rs | 2 +- src/packages/logger.rs | 2 +- src/packages/settings.rs | 32 +++++++- src/routes/client.rs | 8 +- src/services/client.rs | 62 ++++++++++++++++ src/services/mod.rs | 1 + src/services/realm.rs | 8 +- src/utils/authenticate_request.rs | 2 +- src/utils/default_resource_checker.rs | 15 ++-- src/utils/helpers/default_cred.rs | 4 +- src/utils/role_checker.rs | 21 ++---- 22 files changed, 232 insertions(+), 115 deletions(-) create mode 100644 src/mappers/client.rs create mode 100644 src/services/client.rs diff --git a/Cargo.lock b/Cargo.lock index bd99b2b..3af4ee8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2158,6 +2158,7 @@ dependencies = [ "dotenvy", "jsonwebtoken", "once_cell", + "parking_lot", "sea-orm", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index b1c7a87..f842b17 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ cuid2 = "0.1.3" dotenvy = "0.15.7" jsonwebtoken = "9.3.0" once_cell = "1.19.0" +parking_lot = "0.12.3" sea-orm = { version = "1.0.1", features = [ "macros", "runtime-tokio-rustls", diff --git a/src/app.rs b/src/app.rs index b83d71b..9383a1b 100644 --- a/src/app.rs +++ b/src/app.rs @@ -4,6 +4,7 @@ use axum::{http::header, Extension, Router}; use tower_http::{ compression::CompressionLayer, cors::CorsLayer, propagate_header::PropagateHeaderLayer, sensitive_headers::SetSensitiveHeadersLayer, }; +use tracing::info; use crate::{ middleware::logger::logger, @@ -13,10 +14,13 @@ use crate::{ pub async fn create_app() -> Router { logger::setup(); - // let state = get_db_connection_pool().await.unwrap(); let state = Arc::new(get_db_connection_pool().await.unwrap()); - admin::setup(&state).await.expect("Failed to setup admin account"); + let is_settings_reloaded = admin::setup(&state).await.expect("Failed to setup admin account"); + if is_settings_reloaded { + info!("New admin credentials initialized and settings reloaded!"); + } + Router::new() .merge(routes::create_routes()) .layer(logger()) diff --git a/src/handlers/auth.rs b/src/handlers/auth.rs index 40a029f..a1ac772 100644 --- a/src/handlers/auth.rs +++ b/src/handlers/auth.rs @@ -91,7 +91,7 @@ pub async fn login( return Err(Error::Authenticate(AuthenticateError::Locked)); } - let access_token = create(user.clone(), client, resource_groups, resources, &SETTINGS.secrets.signing_key).unwrap(); + let access_token = create(user.clone(), client, resource_groups, resources, &SETTINGS.read().secrets.signing_key).unwrap(); Ok(Json(LoginResponse { access_token })) } diff --git a/src/handlers/client.rs b/src/handlers/client.rs index 1f1be83..4599bb3 100644 --- a/src/handlers/client.rs +++ b/src/handlers/client.rs @@ -1,37 +1,28 @@ use std::sync::Arc; use crate::{ - database::{client, prelude::Client}, + database::client::Model, + mappers::{ + client::{CreateClientRequest, UpdateClientRequest}, + DeleteResponse, + }, packages::{ db::AppState, errors::{AuthenticateError, Error}, token::TokenUser, }, - utils::role_checker::{is_any_realm_admin, is_master_realm_admin}, + services::client::{delete_client_by_id, get_all_clients, get_client_by_id, insert_client, update_client_by_id}, + utils::role_checker::{is_current_realm_admin, is_master_realm_admin}, }; use axum::{extract::Path, Extension, Json}; -use sea_orm::{prelude::Uuid, ColumnTrait, EntityTrait, QueryFilter}; +use sea_orm::prelude::Uuid; -pub async fn get_clients( - user: TokenUser, - Extension(state): Extension>, - Path(realm_id): Path, -) -> Result>, Error> { - if is_master_realm_admin(&user) { - let clients = Client::find().filter(client::Column::RealmId.eq(realm_id)).all(&state.db).await?; +pub async fn get_clients(user: TokenUser, Extension(state): Extension>, Path(realm_id): Path) -> Result>, Error> { + if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { + let clients = get_all_clients(&state.db, realm_id).await?; Ok(Json(clients)) } else { - if is_any_realm_admin(&user) { - let resource = user.resource.unwrap(); - let clients = Client::find().filter(client::Column::RealmId.eq(realm_id)).all(&state.db).await?; - let client = clients.iter().find(|&client| client.id == resource.client_id); - match client { - Some(_) => return Ok(Json(clients)), - None => return Err(Error::Authenticate(AuthenticateError::NoResource)), - }; - } else { - Err(Error::Authenticate(AuthenticateError::NoResource)) - } + Err(Error::Authenticate(AuthenticateError::NoResource)) } } @@ -39,33 +30,57 @@ pub async fn get_client( user: TokenUser, Extension(state): Extension>, Path((realm_id, client_id)): Path<(Uuid, Uuid)>, -) -> Result, Error> { - if is_master_realm_admin(&user) { - let client = Client::find_by_id(client_id).one(&state.db).await?; +) -> Result, Error> { + if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { + let client = get_client_by_id(&state.db, client_id).await?; match client { Some(client) => Ok(Json(client)), None => return Err(Error::Authenticate(AuthenticateError::NoResource)), } } else { - if is_any_realm_admin(&user) { - let client = Client::find_by_id(client_id) - .filter(client::Column::RealmId.eq(realm_id)) - .one(&state.db) - .await?; - match client { - Some(client) => return Ok(Json(client)), - None => return Err(Error::Authenticate(AuthenticateError::NoResource)), - }; - } else { - if user.resource.as_ref().unwrap().client_id == client_id { - let client = Client::find_by_id(client_id).one(&state.db).await?; - match client { - Some(client) => return Ok(Json(client)), - None => return Err(Error::Authenticate(AuthenticateError::NoResource)), - }; - } else { - return Err(Error::Authenticate(AuthenticateError::ActionForbidden)); - } - } + Err(Error::Authenticate(AuthenticateError::ActionForbidden)) + } +} + +pub async fn create_client( + user: TokenUser, + Extension(state): Extension>, + Path(realm_id): Path, + Json(payload): Json, +) -> Result, Error> { + if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { + let client = insert_client(&state.db, payload).await?; + Ok(Json(client)) + } else { + Err(Error::Authenticate(AuthenticateError::NoResource)) + } +} + +pub async fn update_client( + user: TokenUser, + Extension(state): Extension>, + Path((realm_id, client_id)): Path<(Uuid, Uuid)>, + Json(payload): Json, +) -> Result, Error> { + if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { + let client = update_client_by_id(&state.db, client_id, payload).await?; + Ok(Json(client)) + } else { + Err(Error::Authenticate(AuthenticateError::NoResource)) + } +} + +pub async fn delete_client( + user: TokenUser, + Extension(state): Extension>, + Path((realm_id, client_id)): Path<(Uuid, Uuid)>, +) -> Result, Error> { + if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { + let client = delete_client_by_id(&state.db, client_id).await?; + Ok(Json(DeleteResponse { + ok: client.rows_affected == 1, + })) + } else { + Err(Error::Authenticate(AuthenticateError::NoResource)) } } diff --git a/src/handlers/realm.rs b/src/handlers/realm.rs index 1abae78..df64ae8 100644 --- a/src/handlers/realm.rs +++ b/src/handlers/realm.rs @@ -5,7 +5,10 @@ use sea_orm::prelude::Uuid; use crate::{ database::realm::Model, - mappers::realm::{CreateRealmRequest, DeleteResponse, UpdateRealmRequest}, + mappers::{ + realm::{CreateRealmRequest, UpdateRealmRequest}, + DeleteResponse, + }, packages::{ db::AppState, errors::{AuthenticateError, Error}, @@ -28,7 +31,7 @@ pub async fn get_realms(user: TokenUser, Extension(state): Extension>, Path(realm_id): Path) -> Result, Error> { - if is_master_realm_admin(&user) { + if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { let fetched_realm = get_realm_by_id(&state.db, realm_id).await?; match fetched_realm { Some(fetched_realm) => Ok(Json(fetched_realm)), @@ -37,19 +40,7 @@ pub async fn get_realm(user: TokenUser, Extension(state): Extension { - if is_current_realm_admin(&user, &fetched_realm.name) { - return Ok(Json(fetched_realm)); - } else { - return Err(Error::Authenticate(AuthenticateError::NoResource)); - } - } - None => { - return Err(Error::Authenticate(AuthenticateError::NoResource)); - } - } + return Err(Error::Authenticate(AuthenticateError::NoResource)); } } diff --git a/src/main.rs b/src/main.rs index 5dcca42..637f181 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,7 +18,7 @@ mod utils; #[tokio::main] async fn main() -> Result<(), std::io::Error> { - let port = SETTINGS.server.port; + let port = SETTINGS.read().server.port; let address = SocketAddr::from(([127, 0, 0, 1], port)); let app = create_app().await; diff --git a/src/mappers/client.rs b/src/mappers/client.rs new file mode 100644 index 0000000..4c5a906 --- /dev/null +++ b/src/mappers/client.rs @@ -0,0 +1,14 @@ +use sea_orm::prelude::Uuid; +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize)] +pub struct CreateClientRequest { + pub name: String, + pub realm_id: Uuid, +} + +#[derive(Deserialize)] +pub struct UpdateClientRequest { + pub name: String, + pub lock: Option, +} diff --git a/src/mappers/mod.rs b/src/mappers/mod.rs index abc366b..eb07046 100644 --- a/src/mappers/mod.rs +++ b/src/mappers/mod.rs @@ -1 +1,9 @@ +use serde::Serialize; + +pub mod client; pub mod realm; + +#[derive(Serialize)] +pub struct DeleteResponse { + pub ok: bool, +} diff --git a/src/mappers/realm.rs b/src/mappers/realm.rs index 4ef6513..793214a 100644 --- a/src/mappers/realm.rs +++ b/src/mappers/realm.rs @@ -1,4 +1,4 @@ -use serde::{Deserialize, Serialize}; +use serde::Deserialize; #[derive(Deserialize)] pub struct CreateRealmRequest { @@ -10,8 +10,3 @@ pub struct UpdateRealmRequest { pub name: String, pub lock: Option, } - -#[derive(Serialize)] -pub struct DeleteResponse { - pub ok: bool, -} diff --git a/src/packages/admin.rs b/src/packages/admin.rs index 866440c..dd90777 100644 --- a/src/packages/admin.rs +++ b/src/packages/admin.rs @@ -13,28 +13,32 @@ use crate::{ prelude::{Realm, User}, realm, resource, resource_group, user, }, - packages::settings::SETTINGS, + packages::settings::{Settings, SETTINGS}, utils::{hash::generate_password_hash, helpers::default_cred::DefaultCred}, }; use super::{db::AppState, errors::Error}; -pub async fn setup(state: &AppState) -> Result<(), Error> { +pub async fn setup(state: &AppState) -> Result { info!("Checking ADMIN availability!"); - let is_admin_user_exists = User::find().filter(user::Column::Email.eq(&SETTINGS.admin.email)).one(&state.db).await?; + let is_admin_user_exists = User::find() + .filter(user::Column::Email.eq(&SETTINGS.read().admin.email)) + .one(&state.db) + .await?; if is_admin_user_exists.is_some() { info!("DB has been already initialized!"); info!("Starting the server..."); + Ok(false) } else { info!("DB has not been initialized!"); info!("⌛ Initializing the DB..."); initialize_db(&state.db).await?; info!("Admin initialization complete."); + Settings::reload().expect("Failed to reload settings"); + Ok(true) } - - Ok(()) } async fn initialize_db(conn: &DatabaseConnection) -> Result<(), Error> { @@ -98,12 +102,13 @@ async fn create_default_client(conn: &DatabaseConnection, realm_id: Uuid) -> Res } async fn create_admin_user(conn: &DatabaseConnection, realm_id: Uuid) -> Result { - let pw_hash = generate_password_hash(&SETTINGS.admin.password).await?; + let admin = SETTINGS.read().admin.clone(); + let pw_hash = generate_password_hash(admin.password).await?; let new_user = user::ActiveModel { - email: Set(SETTINGS.admin.email.to_owned()), + email: Set(admin.email.to_owned()), password_hash: Set(Some(pw_hash)), realm_id: Set(realm_id), - first_name: Set(SETTINGS.admin.email.to_owned()), + first_name: Set(admin.email.to_owned()), is_temp_password: Set(Some(false)), ..Default::default() }; @@ -139,7 +144,7 @@ async fn assign_resource_to_admin(conn: &DatabaseConnection, realm_id: Uuid, cli let new_resource_2 = resource::ActiveModel { group_id: Set(inserted_resource_group.id), name: Set("realm".to_owned()), - value: Set("Master".to_owned()), + value: Set(realm_id.to_string()), description: Set(Some("This role has been created at the time of initialization.".to_owned())), ..Default::default() }; diff --git a/src/packages/db.rs b/src/packages/db.rs index 600d4b5..9690d7f 100644 --- a/src/packages/db.rs +++ b/src/packages/db.rs @@ -10,7 +10,7 @@ pub struct AppState { } pub async fn get_db_connection_pool() -> Result { - let uri = &SETTINGS.database.uri; + let uri = &SETTINGS.read().database.uri; let mut opts = ConnectOptions::new(uri); opts.max_connections(20).connect_timeout(Duration::from_secs(5)); diff --git a/src/packages/logger.rs b/src/packages/logger.rs index 883ec1a..1960946 100644 --- a/src/packages/logger.rs +++ b/src/packages/logger.rs @@ -5,7 +5,7 @@ use super::settings::SETTINGS; pub fn setup() { if env::var_os("RUST_LOG").is_none() { let app_name = env::var("CARGO_PKG_NAME").unwrap(); - let level = SETTINGS.logger.level.as_str(); + let level = SETTINGS.read().logger.level.clone(); let env = format!("{app_name }={level},tower_http={level}"); env::set_var("RUST_LOG", env); diff --git a/src/packages/settings.rs b/src/packages/settings.rs index a8afd20..31e5c1b 100644 --- a/src/packages/settings.rs +++ b/src/packages/settings.rs @@ -1,10 +1,15 @@ +use crate::packages::errors::Error; use config::{Config, ConfigError, Environment, File}; use dotenvy::dotenv; use once_cell::sync::Lazy; +use parking_lot::RwLock; use serde::Deserialize; -use std::{env, fmt}; +use std::{env, fmt, fs::read_to_string, sync::Arc}; -pub static SETTINGS: Lazy = Lazy::new(|| Settings::new().expect("Failed to setup settings")); +use crate::utils::helpers::default_cred::DefaultCred; + +// pub static SETTINGS: Lazy = Lazy::new(|| Settings::new().expect("Failed to setup settings")); +pub static SETTINGS: Lazy>> = Lazy::new(|| Arc::new(RwLock::new(Settings::new().expect("Failed to setup settings")))); #[derive(Debug, Clone, Deserialize)] pub struct Server { @@ -41,6 +46,7 @@ pub struct Settings { pub database: Database, pub admin: Admin, pub secrets: Secrets, + pub default_cred: DefaultCred, } impl Settings { @@ -69,11 +75,33 @@ impl Settings { builder = builder.set_override("admin.password", admin_password)?; } + let default_cred_str = read_to_string("./logs/default_cred.txt").map_err(Error::from); + let default_cred_str = default_cred_str.unwrap(); + let default_cred = DefaultCred::from_str(&default_cred_str); + let default_cred = default_cred.unwrap(); + builder = builder.set_override("default_cred.realm_id", default_cred.realm_id.to_string())?; + builder = builder.set_override("default_cred.client_id", default_cred.client_id.to_string())?; + builder .build()? // Deserialize (and thus freeze) the entire configuration. .try_deserialize() } + + pub fn reload() -> Result<(), ConfigError> { + let new_settings = Settings::new()?; + let mut settings = SETTINGS.write(); + *settings = new_settings; + Ok(()) + } + + pub fn get(f: F) -> T + where + F: FnOnce(&Settings) -> T, + { + let settings = SETTINGS.read(); + f(&settings) + } } impl fmt::Display for Server { diff --git a/src/routes/client.rs b/src/routes/client.rs index d0bbc59..c56664e 100644 --- a/src/routes/client.rs +++ b/src/routes/client.rs @@ -1,12 +1,14 @@ use axum::{routing::get, Router}; -use crate::handlers::client::{get_client, get_clients}; +use crate::handlers::client::{create_client, delete_client, get_client, get_clients, update_client}; use super::auth; pub fn create_routes() -> Router { - Router::new().route("/", get(get_clients)).nest( + Router::new().route("/", get(get_clients).post(create_client)).nest( "/:client_id", - Router::new().route("/", get(get_client)).nest("/auth", auth::create_routes()), + Router::new() + .route("/", get(get_client).patch(update_client).delete(delete_client)) + .nest("/auth", auth::create_routes()), ) } diff --git a/src/services/client.rs b/src/services/client.rs new file mode 100644 index 0000000..0d43cb5 --- /dev/null +++ b/src/services/client.rs @@ -0,0 +1,62 @@ +use chrono::Utc; +use sea_orm::{prelude::Uuid, ActiveModelTrait, ColumnTrait, DatabaseConnection, DeleteResult, EntityTrait, QueryFilter, Set}; + +use crate::{ + database::{ + client::{ActiveModel, Column, Model}, + prelude::Client, + }, + mappers::client::{CreateClientRequest, UpdateClientRequest}, + packages::errors::{AuthenticateError, Error}, + utils::default_resource_checker::is_default_client, +}; + +pub async fn get_all_clients(db: &DatabaseConnection, realm_id: Uuid) -> Result, Error> { + Ok(Client::find().filter(Column::RealmId.eq(realm_id)).all(db).await?) +} + +pub async fn get_client_by_id(db: &DatabaseConnection, client_id: Uuid) -> Result, Error> { + Ok(Client::find_by_id(client_id).one(db).await?) +} + +pub async fn insert_client(db: &DatabaseConnection, payload: CreateClientRequest) -> Result { + let client = ActiveModel { + name: Set(payload.name.to_owned()), + realm_id: Set(payload.realm_id), + ..Default::default() + }; + Ok(client.insert(db).await?) +} + +pub async fn update_client_by_id(db: &DatabaseConnection, client_id: Uuid, payload: UpdateClientRequest) -> Result { + if is_default_client(client_id) && payload.lock == Some(true) { + return Err(Error::cannot_perform_operation("Cannot lock the default client")); + } + + let client = get_client_by_id(db, client_id).await?; + match client { + Some(client) => { + let locked_at = match payload.lock { + Some(true) => Some(client.locked_at.unwrap_or_else(|| Utc::now().naive_utc())), + Some(false) => None, + None => client.locked_at, + }; + + let updated_client = ActiveModel { + id: Set(client.id), + name: Set(payload.name), + locked_at: Set(locked_at), + ..Default::default() + }; + let updated_client = updated_client.update(db).await?; + Ok(updated_client) + } + None => { + return Err(Error::Authenticate(AuthenticateError::NoResource)); + } + } +} + +pub async fn delete_client_by_id(db: &DatabaseConnection, id: Uuid) -> Result { + Ok(Client::delete_by_id(id).exec(db).await?) +} diff --git a/src/services/mod.rs b/src/services/mod.rs index abc366b..2cf4974 100644 --- a/src/services/mod.rs +++ b/src/services/mod.rs @@ -1 +1,2 @@ +pub mod client; pub mod realm; diff --git a/src/services/realm.rs b/src/services/realm.rs index 917bce9..843361e 100644 --- a/src/services/realm.rs +++ b/src/services/realm.rs @@ -28,13 +28,13 @@ pub async fn insert_realm(db: &DatabaseConnection, name: String) -> Result Result { + if is_default_realm(id) && payload.lock == Some(true) { + return Err(Error::cannot_perform_operation("Cannot lock the default realm")); + } + let realm = get_realm_by_id(db, id).await?; match realm { Some(realm) => { - if is_default_realm(realm.id) && payload.lock == Some(true) { - return Err(Error::cannot_perform_operation("Cannot lock the default realm")); - } - let locked_at = match payload.lock { Some(true) => Some(realm.locked_at.unwrap_or_else(|| Utc::now().naive_utc())), Some(false) => None, diff --git a/src/utils/authenticate_request.rs b/src/utils/authenticate_request.rs index 6d19210..84581da 100644 --- a/src/utils/authenticate_request.rs +++ b/src/utils/authenticate_request.rs @@ -24,7 +24,7 @@ where .await .map_err(|_| AuthenticateError::InvalidToken)?; - let secret = &SETTINGS.secrets.signing_key; + let secret = &SETTINGS.read().secrets.signing_key; let token_data = token::decode(bearer.token(), secret).map_err(|_| AuthenticateError::InvalidToken)?; Ok(TokenUser::from_claim(token_data.claims)) diff --git a/src/utils/default_resource_checker.rs b/src/utils/default_resource_checker.rs index b425345..43b36c6 100644 --- a/src/utils/default_resource_checker.rs +++ b/src/utils/default_resource_checker.rs @@ -1,16 +1,11 @@ -use std::fs::read_to_string; - use sea_orm::prelude::Uuid; -use crate::packages::errors::Error; - -use super::helpers::default_cred::DefaultCred; +use crate::packages::settings::SETTINGS; pub fn is_default_realm(realm_id: Uuid) -> bool { - let default_cred_str = read_to_string("./logs/default_cred.txt").map_err(Error::from); - let default_cred_str = default_cred_str.unwrap(); - let default_cred = DefaultCred::from_str(&default_cred_str); - let default_cred = default_cred.unwrap(); + realm_id == SETTINGS.read().default_cred.realm_id +} - realm_id == default_cred.realm_id +pub fn is_default_client(client_id: Uuid) -> bool { + client_id == SETTINGS.read().default_cred.client_id } diff --git a/src/utils/helpers/default_cred.rs b/src/utils/helpers/default_cred.rs index 9d6ea1b..499d2f9 100644 --- a/src/utils/helpers/default_cred.rs +++ b/src/utils/helpers/default_cred.rs @@ -1,12 +1,12 @@ use std::str::FromStr; use sea_orm::prelude::Uuid; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use crate::packages::errors::Error; #[allow(dead_code)] -#[derive(Debug, Deserialize)] +#[derive(Clone, Debug, Deserialize, Serialize)] pub struct DefaultCred { pub realm_id: Uuid, pub client_id: Uuid, diff --git a/src/utils/role_checker.rs b/src/utils/role_checker.rs index 5f52c5a..0f23631 100644 --- a/src/utils/role_checker.rs +++ b/src/utils/role_checker.rs @@ -1,5 +1,9 @@ +use sea_orm::prelude::Uuid; + use crate::packages::token::TokenUser; +use super::default_resource_checker::is_default_realm; + pub fn is_master_realm_admin(user: &TokenUser) -> bool { let resource = match &user.resource { Some(resource) => resource, @@ -7,29 +11,20 @@ pub fn is_master_realm_admin(user: &TokenUser) -> bool { }; let role = resource.identifiers.get("role"); let realm = resource.identifiers.get("realm"); - if role.is_none() { - return false; - } - if realm.is_none() { + if role.is_none() || realm.is_none() { return false; } let is_admin = role.unwrap() == "admin"; - let is_master_realm = realm.unwrap() == "master"; + let is_master_realm = is_default_realm(resource.identifiers.get("realm").unwrap().parse::().unwrap()); is_admin && is_master_realm } -pub fn is_any_realm_admin(user: &TokenUser) -> bool { - user.resource - .as_ref() - .is_some_and(|x| x.client_name == "client" && x.identifiers.get("role").is_some_and(|y| y == "admin")) -} - -pub fn is_current_realm_admin(user: &TokenUser, realm_name: &str) -> bool { +pub fn is_current_realm_admin(user: &TokenUser, realm_id: &str) -> bool { user.resource.as_ref().is_some_and(|x| { x.identifiers .get("realm") - .is_some_and(|y| y == realm_name && x.client_name == "client" && x.identifiers.get("role").is_some_and(|z| z == "admin")) + .is_some_and(|y| y == realm_id && x.identifiers.get("role").is_some_and(|z| z == "admin")) }) } From 3ad077aa56e2b917723d2bb95d99cb97d6cd1b02 Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Sat, 28 Sep 2024 16:32:54 +0530 Subject: [PATCH 25/45] fix: settings.rs dead code commented --- src/mappers/client.rs | 2 +- src/packages/settings.rs | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/mappers/client.rs b/src/mappers/client.rs index 4c5a906..7625804 100644 --- a/src/mappers/client.rs +++ b/src/mappers/client.rs @@ -1,5 +1,5 @@ use sea_orm::prelude::Uuid; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; #[derive(Deserialize)] pub struct CreateClientRequest { diff --git a/src/packages/settings.rs b/src/packages/settings.rs index 31e5c1b..e51eaee 100644 --- a/src/packages/settings.rs +++ b/src/packages/settings.rs @@ -24,7 +24,7 @@ pub struct Logger { #[derive(Debug, Clone, Deserialize)] pub struct Database { pub uri: String, - pub name: String, + // pub name: String, } #[derive(Debug, Clone, Deserialize)] @@ -40,7 +40,7 @@ pub struct Secrets { #[derive(Debug, Clone, Deserialize)] pub struct Settings { - pub environment: String, + // pub environment: String, pub server: Server, pub logger: Logger, pub database: Database, @@ -95,13 +95,13 @@ impl Settings { Ok(()) } - pub fn get(f: F) -> T - where - F: FnOnce(&Settings) -> T, - { - let settings = SETTINGS.read(); - f(&settings) - } + // pub fn get(f: F) -> T + // where + // F: FnOnce(&Settings) -> T, + // { + // let settings = SETTINGS.read(); + // f(&settings) + // } } impl fmt::Display for Server { From 5d93af54dc1a79a19b092291fb7355e21bce2a55 Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Sat, 28 Sep 2024 17:35:34 +0530 Subject: [PATCH 26/45] fix: role check implemented for realm and client --- src/handlers/auth.rs | 2 +- src/handlers/client.rs | 12 +++++++++++- src/handlers/realm.rs | 5 ++++- src/packages/errors.rs | 2 +- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/handlers/auth.rs b/src/handlers/auth.rs index a1ac772..5ee3c5b 100644 --- a/src/handlers/auth.rs +++ b/src/handlers/auth.rs @@ -95,7 +95,7 @@ pub async fn login( Ok(Json(LoginResponse { access_token })) } -pub async fn register(user: TokenUser, Extension(state): Extension>) -> Result, Error> { +pub async fn register(user: TokenUser, Extension(_state): Extension>) -> Result, Error> { debug!("🚀 Register request received!"); Ok(Json(LoginResponse { diff --git a/src/handlers/client.rs b/src/handlers/client.rs index 4599bb3..ef013db 100644 --- a/src/handlers/client.rs +++ b/src/handlers/client.rs @@ -12,7 +12,10 @@ use crate::{ token::TokenUser, }, services::client::{delete_client_by_id, get_all_clients, get_client_by_id, insert_client, update_client_by_id}, - utils::role_checker::{is_current_realm_admin, is_master_realm_admin}, + utils::{ + default_resource_checker::is_default_client, + role_checker::{is_current_realm_admin, is_master_realm_admin}, + }, }; use axum::{extract::Path, Extension, Json}; use sea_orm::prelude::Uuid; @@ -20,6 +23,9 @@ use sea_orm::prelude::Uuid; pub async fn get_clients(user: TokenUser, Extension(state): Extension>, Path(realm_id): Path) -> Result>, Error> { if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { let clients = get_all_clients(&state.db, realm_id).await?; + if clients.is_empty() { + return Err(Error::not_found()); + } Ok(Json(clients)) } else { Err(Error::Authenticate(AuthenticateError::NoResource)) @@ -75,6 +81,10 @@ pub async fn delete_client( Extension(state): Extension>, Path((realm_id, client_id)): Path<(Uuid, Uuid)>, ) -> Result, Error> { + if is_default_client(client_id) { + return Err(Error::cannot_perform_operation("Cannot delete the default client")); + } + if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { let client = delete_client_by_id(&state.db, client_id).await?; Ok(Json(DeleteResponse { diff --git a/src/handlers/realm.rs b/src/handlers/realm.rs index df64ae8..f777e10 100644 --- a/src/handlers/realm.rs +++ b/src/handlers/realm.rs @@ -24,6 +24,9 @@ use crate::{ pub async fn get_realms(user: TokenUser, Extension(state): Extension>) -> Result>, Error> { if is_master_realm_admin(&user) { let realms = get_all_realms(&state.db).await?; + if realms.is_empty() { + return Err(Error::not_found()); + } return Ok(Json(realms)); } @@ -36,7 +39,7 @@ pub async fn get_realm(user: TokenUser, Extension(state): Extension Ok(Json(fetched_realm)), None => { - return Err(Error::Authenticate(AuthenticateError::NoResource)); + return Err(Error::not_found()); } } } else { diff --git a/src/packages/errors.rs b/src/packages/errors.rs index ea411d5..9e46da7 100644 --- a/src/packages/errors.rs +++ b/src/packages/errors.rs @@ -41,7 +41,7 @@ impl Error { match self { // 4XX Errors Error::BadRequest(err) => err.get_codes(), - Error::NotFound(err) => (StatusCode::NOT_FOUND, 40003), + Error::NotFound(_) => (StatusCode::NOT_FOUND, 40003), Error::Authenticate(err) => err.get_codes(), // 5XX Errors From 1fb04b44222c9bd53e25fda4103d4db0bb7e124e Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Sat, 28 Sep 2024 21:07:36 +0530 Subject: [PATCH 27/45] fix: user signup, signin, and able to fetch resources --- Cargo.lock | 14 ++++++++++ Cargo.toml | 1 + src/database/resource.rs | 3 ++- src/database/user.rs | 3 ++- src/handlers/auth.rs | 24 ++++++++++++----- src/handlers/user.rs | 57 ++++++++++++++++++++++++++++++++++++++++ src/mappers/auth.rs | 20 ++++++++++++++ src/mappers/mod.rs | 1 + src/routes/user.rs | 9 +++++-- src/services/mod.rs | 1 + src/services/user.rs | 52 ++++++++++++++++++++++++++++++++++++ 11 files changed, 174 insertions(+), 11 deletions(-) create mode 100644 src/mappers/auth.rs create mode 100644 src/services/user.rs diff --git a/Cargo.lock b/Cargo.lock index 3af4ee8..1e99945 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -759,6 +759,7 @@ checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", + "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -809,6 +810,17 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + [[package]] name = "futures-sink" version = "0.3.30" @@ -830,6 +842,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-io", + "futures-macro", "futures-sink", "futures-task", "memchr", @@ -2156,6 +2169,7 @@ dependencies = [ "config", "cuid2", "dotenvy", + "futures", "jsonwebtoken", "once_cell", "parking_lot", diff --git a/Cargo.toml b/Cargo.toml index f842b17..0416f86 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ chrono = { version = "0.4.38", features = ["serde"] } config = { version = "0.14.0", features = ["yaml"] } cuid2 = "0.1.3" dotenvy = "0.15.7" +futures = "0.3.30" jsonwebtoken = "9.3.0" once_cell = "1.19.0" parking_lot = "0.12.3" diff --git a/src/database/resource.rs b/src/database/resource.rs index 08285a8..80e9aa8 100644 --- a/src/database/resource.rs +++ b/src/database/resource.rs @@ -1,8 +1,9 @@ //! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 use sea_orm::entity::prelude::*; +use serde::Serialize; -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize)] #[sea_orm(table_name = "resource")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] diff --git a/src/database/user.rs b/src/database/user.rs index 07c5574..e82d8f8 100644 --- a/src/database/user.rs +++ b/src/database/user.rs @@ -1,8 +1,9 @@ //! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 use sea_orm::entity::prelude::*; +use serde::Serialize; -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize)] #[sea_orm(table_name = "user")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] diff --git a/src/handlers/auth.rs b/src/handlers/auth.rs index 5ee3c5b..2c0ff06 100644 --- a/src/handlers/auth.rs +++ b/src/handlers/auth.rs @@ -3,14 +3,18 @@ use std::sync::Arc; use crate::{ database::{ prelude::{Client, Resource, ResourceGroup, User}, - resource, resource_group, user, + resource, resource_group, + user::{self, Model}, }, + mappers::auth::CreateUserRequest, packages::{ db::AppState, errors::{AuthenticateError, Error}, settings::SETTINGS, token::{create, TokenUser}, }, + services::user::insert_user, + utils::role_checker::{is_current_realm_admin, is_master_realm_admin}, }; use axum::{extract::Path, Extension, Json}; use sea_orm::{prelude::Uuid, ColumnTrait, EntityTrait, QueryFilter}; @@ -95,12 +99,18 @@ pub async fn login( Ok(Json(LoginResponse { access_token })) } -pub async fn register(user: TokenUser, Extension(_state): Extension>) -> Result, Error> { - debug!("🚀 Register request received!"); - - Ok(Json(LoginResponse { - access_token: format!("Bearer {:#?}", user), - })) +pub async fn register( + user: TokenUser, + Extension(state): Extension>, + Path((realm_id, client_id)): Path<(Uuid, Uuid)>, + Json(payload): Json, +) -> Result, Error> { + if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { + let user = insert_user(&state.db, realm_id, client_id, payload).await?; + Ok(Json(user)) + } else { + return Err(Error::Authenticate(AuthenticateError::ActionForbidden)); + } } pub async fn verify() { diff --git a/src/handlers/user.rs b/src/handlers/user.rs index 68ae880..3f10f83 100644 --- a/src/handlers/user.rs +++ b/src/handlers/user.rs @@ -1,5 +1,21 @@ +use std::sync::Arc; + +use crate::database::prelude::{Resource, ResourceGroup, User}; +use crate::database::{resource, resource::Model as ResourceModel, resource_group}; +use crate::mappers::DeleteResponse; use axum::extract::Path; +use axum::{Extension, Json}; use sea_orm::prelude::Uuid; +use sea_orm::{ColumnTrait, EntityTrait, QueryFilter}; + +use crate::packages::db::AppState; +use crate::{ + packages::{ + errors::{AuthenticateError, Error}, + token::TokenUser, + }, + utils::role_checker::{is_current_realm_admin, is_master_realm_admin}, +}; pub async fn get_users(Path(realm_id): Path) -> String { format!("Hi from users of {realm_id}") @@ -9,3 +25,44 @@ pub async fn get_user(Path((realm_id, user_id)): Path<(Uuid, Uuid)>) -> String { println!("This is user Name: {} - {}", &realm_id, &user_id); format!("user is - {} - {}", realm_id, user_id) } + +pub async fn delete_user( + user: TokenUser, + Extension(state): Extension>, + Path((realm_id, user_id)): Path<(Uuid, Uuid)>, +) -> Result, Error> { + if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { + let result = User::delete_by_id(user_id).exec(&state.db).await?; + Ok(Json(DeleteResponse { + ok: result.rows_affected == 1, + })) + } else { + Err(Error::Authenticate(AuthenticateError::ActionForbidden)) + } +} + +pub async fn get_resources( + user: TokenUser, + Extension(state): Extension>, + Path((realm_id, user_id)): Path<(Uuid, Uuid)>, +) -> Result>, Error> { + if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { + let resource_groups = ResourceGroup::find() + .filter(resource_group::Column::RealmId.eq(realm_id)) + .filter(resource_group::Column::UserId.eq(user_id)) + .all(&state.db) + .await?; + + let mut resource_group_ids = Vec::new(); + for resource_group in resource_groups { + resource_group_ids.push(resource_group.id); + } + let resources = Resource::find() + .filter(resource::Column::GroupId.is_in(resource_group_ids)) + .all(&state.db) + .await?; + Ok(Json(resources)) + } else { + Err(Error::Authenticate(AuthenticateError::ActionForbidden)) + } +} diff --git a/src/mappers/auth.rs b/src/mappers/auth.rs new file mode 100644 index 0000000..1e479df --- /dev/null +++ b/src/mappers/auth.rs @@ -0,0 +1,20 @@ +use std::collections::HashMap; + +use serde::Deserialize; + +#[derive(Deserialize)] +pub struct ResourceSubset { + pub group_name: String, + pub identifiers: HashMap, +} + +#[derive(Deserialize)] +pub struct CreateUserRequest { + pub email: String, + pub password: String, + pub first_name: String, + pub last_name: Option, + pub phone: Option, + pub image: Option, + pub resource: ResourceSubset, +} diff --git a/src/mappers/mod.rs b/src/mappers/mod.rs index eb07046..e0d584b 100644 --- a/src/mappers/mod.rs +++ b/src/mappers/mod.rs @@ -1,5 +1,6 @@ use serde::Serialize; +pub mod auth; pub mod client; pub mod realm; diff --git a/src/routes/user.rs b/src/routes/user.rs index 47a3808..81ca2d9 100644 --- a/src/routes/user.rs +++ b/src/routes/user.rs @@ -1,7 +1,12 @@ use axum::{routing::get, Router}; -use crate::handlers::user::{get_user, get_users}; +use crate::handlers::user::{delete_user, get_resources, get_user, get_users}; pub fn create_routes() -> Router { - Router::new().route("/", get(get_users)).route("/:user_id", get(get_user)) + Router::new().route("/", get(get_users)).nest( + "/:user_id", + Router::new() + .route("/", get(get_user).delete(delete_user)) + .route("/resources", get(get_resources)), + ) } diff --git a/src/services/mod.rs b/src/services/mod.rs index 2cf4974..febc0a5 100644 --- a/src/services/mod.rs +++ b/src/services/mod.rs @@ -1,2 +1,3 @@ pub mod client; pub mod realm; +pub mod user; diff --git a/src/services/user.rs b/src/services/user.rs new file mode 100644 index 0000000..caaefce --- /dev/null +++ b/src/services/user.rs @@ -0,0 +1,52 @@ +use crate::{ + database::{resource, resource_group, user}, + mappers::auth::CreateUserRequest, + packages::errors::Error, + utils::hash::generate_password_hash, +}; +use futures::future::join_all; +use sea_orm::{prelude::Uuid, ActiveModelTrait, DatabaseConnection, Set}; + +pub async fn insert_user(db: &DatabaseConnection, realm_id: Uuid, client_id: Uuid, payload: CreateUserRequest) -> Result { + let password_hash = generate_password_hash(payload.password).await?; + let user = user::ActiveModel { + realm_id: Set(realm_id), + email: Set(payload.email), + password_hash: Set(Some(password_hash)), + first_name: Set(payload.first_name), + last_name: Set(payload.last_name), + phone: Set(payload.phone), + image: Set(payload.image), + ..Default::default() + }; + + let user = user.insert(db).await?; + + let resource_group = resource_group::ActiveModel { + realm_id: Set(user.realm_id), + client_id: Set(client_id), + user_id: Set(user.id), + name: Set(payload.resource.group_name), + ..Default::default() + }; + let resource_group = resource_group.insert(db).await?; + + let futures: Vec<_> = payload + .resource + .identifiers + .iter() + .map(|(name, value)| { + let resource = resource::ActiveModel { + group_id: Set(resource_group.id), + name: Set(name.to_string()), + value: Set(value.to_string()), + ..Default::default() + }; + resource.insert(db) + }) + .collect(); + + join_all(futures).await; + + Ok(user) +} From 9220fa33d211e61f2a729a69d3bba7bd98de5a1b Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Sun, 29 Sep 2024 00:52:46 +0530 Subject: [PATCH 28/45] fix: resources crud implemented --- src/handlers/auth.rs | 10 +- src/handlers/user.rs | 172 ++++++++++++++++++++++++-- src/mappers/mod.rs | 1 + src/mappers/user.rs | 19 +++ src/packages/admin.rs | 35 ++++-- src/packages/settings.rs | 27 ++-- src/routes/user.rs | 16 ++- src/utils/default_resource_checker.rs | 8 ++ src/utils/helpers/default_cred.rs | 37 ++---- 9 files changed, 266 insertions(+), 59 deletions(-) create mode 100644 src/mappers/user.rs diff --git a/src/handlers/auth.rs b/src/handlers/auth.rs index 2c0ff06..236cae5 100644 --- a/src/handlers/auth.rs +++ b/src/handlers/auth.rs @@ -30,6 +30,9 @@ pub struct Credentials { #[derive(Serialize)] pub struct LoginResponse { access_token: String, + user: Model, + realm_id: Uuid, + client_id: Uuid, } pub async fn login( @@ -96,7 +99,12 @@ pub async fn login( } let access_token = create(user.clone(), client, resource_groups, resources, &SETTINGS.read().secrets.signing_key).unwrap(); - Ok(Json(LoginResponse { access_token })) + Ok(Json(LoginResponse { + access_token, + user, + realm_id, + client_id, + })) } pub async fn register( diff --git a/src/handlers/user.rs b/src/handlers/user.rs index 3f10f83..d7f0cb6 100644 --- a/src/handlers/user.rs +++ b/src/handlers/user.rs @@ -1,12 +1,21 @@ use std::sync::Arc; use crate::database::prelude::{Resource, ResourceGroup, User}; -use crate::database::{resource, resource::Model as ResourceModel, resource_group}; +use crate::database::{ + resource, + resource::{ActiveModel as ResourceActiveModel, Model as ResourceModel}, + resource_group, user, + user::{ActiveModel as UserActiveModel, Model as UserModel}, +}; +use crate::mappers::user::{AddResourceRequest, UpdateResourceRequest}; use crate::mappers::DeleteResponse; +use crate::utils::default_resource_checker::{is_default_resource, is_default_user}; use axum::extract::Path; use axum::{Extension, Json}; +use chrono::Utc; +use futures::future::try_join_all; use sea_orm::prelude::Uuid; -use sea_orm::{ColumnTrait, EntityTrait, QueryFilter}; +use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, Set}; use crate::packages::db::AppState; use crate::{ @@ -17,13 +26,36 @@ use crate::{ utils::role_checker::{is_current_realm_admin, is_master_realm_admin}, }; -pub async fn get_users(Path(realm_id): Path) -> String { - format!("Hi from users of {realm_id}") +pub async fn get_users( + user: TokenUser, + Extension(state): Extension>, + Path(realm_id): Path, +) -> Result>, Error> { + if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { + let users = User::find().filter(user::Column::RealmId.eq(realm_id)).all(&state.db).await?; + if users.is_empty() { + return Err(Error::not_found()); + } + Ok(Json(users)) + } else { + Err(Error::Authenticate(AuthenticateError::NoResource)) + } } -pub async fn get_user(Path((realm_id, user_id)): Path<(Uuid, Uuid)>) -> String { - println!("This is user Name: {} - {}", &realm_id, &user_id); - format!("user is - {} - {}", realm_id, user_id) +pub async fn get_user( + user: TokenUser, + Extension(state): Extension>, + Path((realm_id, user_id)): Path<(Uuid, Uuid)>, +) -> Result, Error> { + if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { + let user = User::find_by_id(user_id).one(&state.db).await?; + match user { + Some(user) => Ok(Json(user)), + None => return Err(Error::Authenticate(AuthenticateError::NoResource)), + } + } else { + Err(Error::Authenticate(AuthenticateError::NoResource)) + } } pub async fn delete_user( @@ -32,6 +64,13 @@ pub async fn delete_user( Path((realm_id, user_id)): Path<(Uuid, Uuid)>, ) -> Result, Error> { if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { + if is_default_user(user_id) { + return Err(Error::cannot_perform_operation("Cannot delete the default user")); + } + if user_id == user.sub { + return Err(Error::cannot_perform_operation("Cannot delete the current user")); + } + let result = User::delete_by_id(user_id).exec(&state.db).await?; Ok(Json(DeleteResponse { ok: result.rows_affected == 1, @@ -66,3 +105,122 @@ pub async fn get_resources( Err(Error::Authenticate(AuthenticateError::ActionForbidden)) } } + +pub async fn add_resources( + user: TokenUser, + Extension(state): Extension>, + Path((realm_id, user_id)): Path<(Uuid, Uuid)>, + Json(payload): Json, +) -> Result>, Error> { + if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { + if payload.group_id.is_some() { + let futures: Vec<_> = payload + .identifiers + .iter() + .map(|(name, value)| { + let resource = resource::ActiveModel { + group_id: Set(payload.group_id.unwrap()), + name: Set(name.to_string()), + value: Set(value.to_string()), + ..Default::default() + }; + resource.insert(&state.db) + }) + .collect(); + let resources = try_join_all(futures).await?; + Ok(Json(resources)) + } else if payload.group_name.is_some() { + let resource_groups = ResourceGroup::find() + .filter(resource_group::Column::RealmId.eq(realm_id)) + .filter(resource_group::Column::UserId.eq(user_id)) + .filter(resource_group::Column::Name.eq(payload.group_name)) + .one(&state.db) + .await?; + if resource_groups.is_none() { + return Err(Error::not_found()); + } + let resource_group = resource_groups.unwrap(); + + let futures: Vec<_> = payload + .identifiers + .iter() + .map(|(name, value)| { + let resource = resource::ActiveModel { + group_id: Set(resource_group.id), + name: Set(name.to_string()), + value: Set(value.to_string()), + ..Default::default() + }; + resource.insert(&state.db) + }) + .collect(); + let resources = try_join_all(futures).await?; + Ok(Json(resources)) + } else { + Err(Error::cannot_perform_operation("Either group_name or group_id must be provided")) + } + } else { + Err(Error::Authenticate(AuthenticateError::ActionForbidden)) + } +} + +pub async fn update_resource( + user: TokenUser, + Extension(state): Extension>, + Path((realm_id, _, resource_id)): Path<(Uuid, Uuid, Uuid)>, + Json(payload): Json, +) -> Result, Error> { + if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { + if is_default_resource(resource_id) { + return Err(Error::cannot_perform_operation("Cannot update the default resource")); + } + + let resource = Resource::find_by_id(resource_id).one(&state.db).await?; + if resource.is_none() { + return Err(Error::not_found()); + } + + let locked_at = match payload.lock { + Some(true) => Some(resource.as_ref().unwrap().locked_at.unwrap_or_else(|| Utc::now().naive_utc())), + Some(false) => None, + None => None, + }; + let resource = ResourceActiveModel { + id: Set(resource_id), + group_id: Set(resource.unwrap().group_id), + name: Set(payload.name), + value: Set(payload.value), + description: Set(payload.description), + locked_at: Set(locked_at), + ..Default::default() + }; + let resource = resource.update(&state.db).await?; + Ok(Json(resource)) + } else { + Err(Error::Authenticate(AuthenticateError::ActionForbidden)) + } +} + +pub async fn delete_resource( + user: TokenUser, + Extension(state): Extension>, + Path((realm_id, _, resource_id)): Path<(Uuid, Uuid, Uuid)>, +) -> Result, Error> { + if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { + if is_default_resource(resource_id) { + return Err(Error::cannot_perform_operation("Cannot delete the default resource")); + } + + let resource = Resource::find_by_id(resource_id).one(&state.db).await?; + if resource.is_none() { + return Err(Error::not_found()); + } + + let result = Resource::delete_by_id(resource_id).exec(&state.db).await?; + Ok(Json(DeleteResponse { + ok: result.rows_affected == 1, + })) + } else { + Err(Error::Authenticate(AuthenticateError::ActionForbidden)) + } +} diff --git a/src/mappers/mod.rs b/src/mappers/mod.rs index e0d584b..97181a5 100644 --- a/src/mappers/mod.rs +++ b/src/mappers/mod.rs @@ -3,6 +3,7 @@ use serde::Serialize; pub mod auth; pub mod client; pub mod realm; +pub mod user; #[derive(Serialize)] pub struct DeleteResponse { diff --git a/src/mappers/user.rs b/src/mappers/user.rs new file mode 100644 index 0000000..233c129 --- /dev/null +++ b/src/mappers/user.rs @@ -0,0 +1,19 @@ +use std::collections::HashMap; + +use sea_orm::prelude::Uuid; +use serde::Deserialize; + +#[derive(Deserialize)] +pub struct AddResourceRequest { + pub group_name: Option, + pub group_id: Option, + pub identifiers: HashMap, +} + +#[derive(Deserialize)] +pub struct UpdateResourceRequest { + pub name: String, + pub value: String, + pub description: Option, + pub lock: Option, +} diff --git a/src/packages/admin.rs b/src/packages/admin.rs index dd90777..71081e3 100644 --- a/src/packages/admin.rs +++ b/src/packages/admin.rs @@ -46,24 +46,28 @@ async fn initialize_db(conn: &DatabaseConnection) -> Result<(), Error> { let result = (|| async { let client = create_default_client(conn, realm.id).await?; let user = create_admin_user(conn, realm.id).await?; - assign_resource_to_admin(conn, realm.id, client.id, user.id).await?; + let resource_assignment_result = assign_resource_to_admin(conn, realm.id, client.id, user.id).await?; let default_cred = DefaultCred { realm_id: realm.id, client_id: client.id, + master_admin_user_id: user.id, + resource_group_id: resource_assignment_result.resource_group_id, + resource_ids: resource_assignment_result.resource_ids, }; info!("🗝️ Please note these credentials!"); println!("{:?}", default_cred); - let file_path = "./logs/default_cred.txt"; // Use relative path for better portability + let file_path = "./logs/default_cred.json"; let path = Path::new(file_path); if let Some(parent_dir) = path.parent() { - create_dir_all(parent_dir).expect("Failed to create directory"); + create_dir_all(parent_dir)?; } else { panic!("Invalid file path"); } - let mut file = File::create(file_path).expect("Failed to create file"); - let content = format!("{:#?}", default_cred); - file.write_all(content.as_bytes()).expect("Failed to write to file"); + + let json = serde_json::to_string_pretty(&default_cred)?; + let mut file = File::create(file_path)?; + file.write_all(json.as_bytes())?; info!("📝 However above credentials have been '/logs/default_cred.txt' file."); Ok(()) @@ -118,7 +122,17 @@ async fn create_admin_user(conn: &DatabaseConnection, realm_id: Uuid) -> Result< Ok(inserted_user) } -async fn assign_resource_to_admin(conn: &DatabaseConnection, realm_id: Uuid, client_id: Uuid, user_id: Uuid) -> Result { +struct ResourceAssignmentResult { + resource_group_id: Uuid, + resource_ids: Vec, +} + +async fn assign_resource_to_admin( + conn: &DatabaseConnection, + realm_id: Uuid, + client_id: Uuid, + user_id: Uuid, +) -> Result { let new_resource_group = resource_group::ActiveModel { client_id: Set(client_id), realm_id: Set(realm_id), @@ -148,7 +162,10 @@ async fn assign_resource_to_admin(conn: &DatabaseConnection, realm_id: Uuid, cli description: Set(Some("This role has been created at the time of initialization.".to_owned())), ..Default::default() }; - let _inserted_resource_2 = new_resource_2.insert(conn).await?; + let inserted_resource_2 = new_resource_2.insert(conn).await?; info!("✅ 5/5: Default resource created"); - Ok(inserted_resource) + Ok(ResourceAssignmentResult { + resource_group_id: inserted_resource_group.id, + resource_ids: vec![inserted_resource.id, inserted_resource_2.id], + }) } diff --git a/src/packages/settings.rs b/src/packages/settings.rs index e51eaee..f475ed5 100644 --- a/src/packages/settings.rs +++ b/src/packages/settings.rs @@ -1,10 +1,10 @@ use crate::packages::errors::Error; -use config::{Config, ConfigError, Environment, File}; +use config::{Config, ConfigError, Environment, File, Value}; use dotenvy::dotenv; use once_cell::sync::Lazy; use parking_lot::RwLock; use serde::Deserialize; -use std::{env, fmt, fs::read_to_string, sync::Arc}; +use std::{env, fmt, fs::read_to_string, path::Path, sync::Arc}; use crate::utils::helpers::default_cred::DefaultCred; @@ -75,12 +75,23 @@ impl Settings { builder = builder.set_override("admin.password", admin_password)?; } - let default_cred_str = read_to_string("./logs/default_cred.txt").map_err(Error::from); - let default_cred_str = default_cred_str.unwrap(); - let default_cred = DefaultCred::from_str(&default_cred_str); - let default_cred = default_cred.unwrap(); - builder = builder.set_override("default_cred.realm_id", default_cred.realm_id.to_string())?; - builder = builder.set_override("default_cred.client_id", default_cred.client_id.to_string())?; + // "./logs/default_cred.txt" exists then read it else skip + if Path::new("./logs/default_cred.json").exists() { + let default_cred = DefaultCred::from_file().expect("Failed to read credentials"); + builder = builder.set_override("default_cred.realm_id", default_cred.realm_id.to_string())?; + builder = builder.set_override("default_cred.client_id", default_cred.client_id.to_string())?; + builder = builder.set_override("default_cred.master_admin_user_id", default_cred.master_admin_user_id.to_string())?; + builder = builder.set_override("default_cred.resource_group_id", default_cred.resource_group_id.to_string())?; + + let resource_ids_value: Vec = default_cred.resource_ids.iter().map(|uuid| Value::new(None, uuid.to_string())).collect(); + builder = builder.set_override("default_cred.resource_ids", resource_ids_value)?; + } else { + builder = builder.set_override("default_cred.realm_id", "00000000-0000-0000-0000-000000000000")?; + builder = builder.set_override("default_cred.client_id", "00000000-0000-0000-0000-000000000000")?; + builder = builder.set_override("default_cred.master_admin_user_id", "00000000-0000-0000-0000-000000000000")?; + builder = builder.set_override("default_cred.resource_group_id", "00000000-0000-0000-0000-000000000000")?; + builder = builder.set_override("default_cred.resource_ids", vec!["00000000-0000-0000-0000-000000000000"])?; + } builder .build()? diff --git a/src/routes/user.rs b/src/routes/user.rs index 81ca2d9..d8684f5 100644 --- a/src/routes/user.rs +++ b/src/routes/user.rs @@ -1,12 +1,18 @@ -use axum::{routing::get, Router}; +use axum::{ + routing::{get, patch}, + Router, +}; -use crate::handlers::user::{delete_user, get_resources, get_user, get_users}; +use crate::handlers::user::{add_resources, delete_resource, delete_user, get_resources, get_user, get_users, update_resource}; pub fn create_routes() -> Router { Router::new().route("/", get(get_users)).nest( "/:user_id", - Router::new() - .route("/", get(get_user).delete(delete_user)) - .route("/resources", get(get_resources)), + Router::new().route("/", get(get_user).delete(delete_user)).nest( + "/resources", + Router::new() + .route("/", get(get_resources).post(add_resources)) + .route("/:resource_id", patch(update_resource).delete(delete_resource)), + ), ) } diff --git a/src/utils/default_resource_checker.rs b/src/utils/default_resource_checker.rs index 43b36c6..47a95d3 100644 --- a/src/utils/default_resource_checker.rs +++ b/src/utils/default_resource_checker.rs @@ -9,3 +9,11 @@ pub fn is_default_realm(realm_id: Uuid) -> bool { pub fn is_default_client(client_id: Uuid) -> bool { client_id == SETTINGS.read().default_cred.client_id } + +pub fn is_default_user(user_id: Uuid) -> bool { + user_id == SETTINGS.read().default_cred.master_admin_user_id +} + +pub fn is_default_resource(resource_id: Uuid) -> bool { + SETTINGS.read().default_cred.resource_ids.contains(&resource_id) +} diff --git a/src/utils/helpers/default_cred.rs b/src/utils/helpers/default_cred.rs index 499d2f9..1209f10 100644 --- a/src/utils/helpers/default_cred.rs +++ b/src/utils/helpers/default_cred.rs @@ -1,4 +1,4 @@ -use std::str::FromStr; +use std::fs::read_to_string; use sea_orm::prelude::Uuid; use serde::{Deserialize, Serialize}; @@ -10,36 +10,15 @@ use crate::packages::errors::Error; pub struct DefaultCred { pub realm_id: Uuid, pub client_id: Uuid, + pub master_admin_user_id: Uuid, + pub resource_group_id: Uuid, + pub resource_ids: Vec, } impl DefaultCred { - pub fn from_str(s: &str) -> Result { - let mut realm_id = String::new(); - let mut client_id = String::new(); - - for line in s.lines() { - if line.contains("realm_id:") { - realm_id = line - .split(':') - .nth(1) - .map(|s| s.trim().trim_end_matches(',').to_string()) - .unwrap_or_default(); - } - if line.contains("client_id:") { - client_id = line - .split(':') - .nth(1) - .map(|s| s.trim().trim_end_matches(',').to_string()) - .unwrap_or_default(); - } - } - - if realm_id.is_empty() || client_id.is_empty() { - return Err(Error::invalid_input("Failed to parse DefaultCred")); - } - - let realm_id = Uuid::from_str(&realm_id).map_err(|_| Error::invalid_input("Failed to parse DefaultCred"))?; - let client_id = Uuid::from_str(&client_id).map_err(|_| Error::invalid_input("Failed to parse DefaultCred"))?; - Ok(DefaultCred { realm_id, client_id }) + pub fn from_file() -> Result { + let contents = read_to_string("./logs/default_cred.json").map_err(Error::from)?; + let default_cred: DefaultCred = serde_json::from_str(&contents)?; + Ok(default_cred) } } From d4f5e9659995be784ed48f6ee6d29d865b91f1fb Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Sun, 29 Sep 2024 01:39:13 +0530 Subject: [PATCH 29/45] fix: resource_group crud added --- src/database/resource_group.rs | 3 +- src/handlers/auth.rs | 6 +- src/handlers/user.rs | 111 +++++++++++++++++++++++++- src/mappers/auth.rs | 9 ++- src/mappers/user.rs | 8 ++ src/routes/auth.rs | 8 +- src/routes/user.rs | 26 ++++-- src/utils/default_resource_checker.rs | 4 + 8 files changed, 159 insertions(+), 16 deletions(-) diff --git a/src/database/resource_group.rs b/src/database/resource_group.rs index d5a5b63..81b56e1 100644 --- a/src/database/resource_group.rs +++ b/src/database/resource_group.rs @@ -1,8 +1,9 @@ //! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 use sea_orm::entity::prelude::*; +use serde::Serialize; -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize)] #[sea_orm(table_name = "resource_group")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] diff --git a/src/handlers/auth.rs b/src/handlers/auth.rs index 236cae5..3dac0ad 100644 --- a/src/handlers/auth.rs +++ b/src/handlers/auth.rs @@ -6,7 +6,7 @@ use crate::{ resource, resource_group, user::{self, Model}, }, - mappers::auth::CreateUserRequest, + mappers::auth::{CreateUserRequest, LogoutResponse}, packages::{ db::AppState, errors::{AuthenticateError, Error}, @@ -121,6 +121,10 @@ pub async fn register( } } +pub async fn logout(user: TokenUser, Extension(_state): Extension>) -> Result, Error> { + Ok(Json(LogoutResponse { ok: true, user_id: user.sub })) +} + pub async fn verify() { debug!("🚀 Verify request received!"); todo!(); diff --git a/src/handlers/user.rs b/src/handlers/user.rs index d7f0cb6..f3fba1f 100644 --- a/src/handlers/user.rs +++ b/src/handlers/user.rs @@ -4,12 +4,14 @@ use crate::database::prelude::{Resource, ResourceGroup, User}; use crate::database::{ resource, resource::{ActiveModel as ResourceActiveModel, Model as ResourceModel}, - resource_group, user, - user::{ActiveModel as UserActiveModel, Model as UserModel}, + resource_group, + resource_group::{ActiveModel as ResourceGroupActiveModel, Model as ResourceGroupModel}, + user, + user::Model as UserModel, }; -use crate::mappers::user::{AddResourceRequest, UpdateResourceRequest}; +use crate::mappers::user::{AddResourceRequest, UpdateResourceGroupRequest, UpdateResourceRequest}; use crate::mappers::DeleteResponse; -use crate::utils::default_resource_checker::{is_default_resource, is_default_user}; +use crate::utils::default_resource_checker::{is_default_resource, is_default_resource_group, is_default_user}; use axum::extract::Path; use axum::{Extension, Json}; use chrono::Utc; @@ -80,6 +82,107 @@ pub async fn delete_user( } } +pub async fn get_resource_groups( + user: TokenUser, + Extension(state): Extension>, + Path((realm_id, user_id)): Path<(Uuid, Uuid)>, +) -> Result>, Error> { + if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { + let resource_groups = ResourceGroup::find() + .filter(resource_group::Column::RealmId.eq(realm_id)) + .filter(resource_group::Column::UserId.eq(user_id)) + .all(&state.db) + .await?; + Ok(Json(resource_groups)) + } else { + Err(Error::Authenticate(AuthenticateError::ActionForbidden)) + } +} + +pub async fn get_resource_group( + user: TokenUser, + Extension(state): Extension>, + Path((realm_id, _, resource_group_id)): Path<(Uuid, Uuid, Uuid)>, +) -> Result, Error> { + if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { + let resource_group = ResourceGroup::find_by_id(resource_group_id).one(&state.db).await?; + match resource_group { + Some(resource_group) => Ok(Json(resource_group)), + None => return Err(Error::not_found()), + } + } else { + Err(Error::Authenticate(AuthenticateError::ActionForbidden)) + } +} + +pub async fn update_resource_group( + user: TokenUser, + Extension(state): Extension>, + Path((realm_id, _, resource_group_id)): Path<(Uuid, Uuid, Uuid)>, + Json(payload): Json, +) -> Result, Error> { + if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { + if is_default_resource_group(resource_group_id) { + return Err(Error::cannot_perform_operation("Cannot update the default resource group")); + } + + let resource_group = ResourceGroup::find_by_id(resource_group_id).one(&state.db).await?; + if resource_group.is_none() { + return Err(Error::not_found()); + } + + let locked_at = match payload.lock { + Some(true) => Some(resource_group.as_ref().unwrap().locked_at.unwrap_or_else(|| Utc::now().naive_utc())), + Some(false) => None, + None => resource_group.as_ref().unwrap().locked_at, + }; + let is_default = match payload.is_default { + Some(true) => Some(true), + _ => resource_group.as_ref().unwrap().is_default, + }; + + let resource_group = ResourceGroupActiveModel { + id: Set(resource_group_id), + realm_id: Set(resource_group.as_ref().unwrap().realm_id), + client_id: Set(resource_group.as_ref().unwrap().client_id), + user_id: Set(resource_group.as_ref().unwrap().user_id), + name: Set(payload.name), + description: Set(payload.description), + is_default: Set(is_default), + locked_at: Set(locked_at), + ..Default::default() + }; + let resource_group = resource_group.update(&state.db).await?; + Ok(Json(resource_group)) + } else { + Err(Error::Authenticate(AuthenticateError::ActionForbidden)) + } +} + +pub async fn delete_resource_group( + user: TokenUser, + Extension(state): Extension>, + Path((realm_id, _, resource_group_id)): Path<(Uuid, Uuid, Uuid)>, +) -> Result, Error> { + if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { + if is_default_resource_group(resource_group_id) { + return Err(Error::cannot_perform_operation("Cannot delete the default resource group")); + } + + let resource_group = ResourceGroup::find_by_id(resource_group_id).one(&state.db).await?; + if resource_group.is_none() { + return Err(Error::not_found()); + } + + let result = ResourceGroup::delete_by_id(resource_group_id).exec(&state.db).await?; + Ok(Json(DeleteResponse { + ok: result.rows_affected == 1, + })) + } else { + Err(Error::Authenticate(AuthenticateError::ActionForbidden)) + } +} + pub async fn get_resources( user: TokenUser, Extension(state): Extension>, diff --git a/src/mappers/auth.rs b/src/mappers/auth.rs index 1e479df..5836e9c 100644 --- a/src/mappers/auth.rs +++ b/src/mappers/auth.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; -use serde::Deserialize; +use sea_orm::prelude::Uuid; +use serde::{Deserialize, Serialize}; #[derive(Deserialize)] pub struct ResourceSubset { @@ -18,3 +19,9 @@ pub struct CreateUserRequest { pub image: Option, pub resource: ResourceSubset, } + +#[derive(Serialize)] +pub struct LogoutResponse { + pub ok: bool, + pub user_id: Uuid, +} diff --git a/src/mappers/user.rs b/src/mappers/user.rs index 233c129..1f92442 100644 --- a/src/mappers/user.rs +++ b/src/mappers/user.rs @@ -17,3 +17,11 @@ pub struct UpdateResourceRequest { pub description: Option, pub lock: Option, } + +#[derive(Deserialize)] +pub struct UpdateResourceGroupRequest { + pub name: String, + pub description: Option, + pub is_default: Option, + pub lock: Option, +} diff --git a/src/routes/auth.rs b/src/routes/auth.rs index 87c44ed..9b7e7da 100644 --- a/src/routes/auth.rs +++ b/src/routes/auth.rs @@ -1,10 +1,14 @@ -use axum::{routing::post, Router}; +use axum::{ + routing::{get, post}, + Router, +}; -use crate::handlers::auth::{login, register, verify}; +use crate::handlers::auth::{login, logout, register, verify}; pub fn create_routes() -> Router { Router::new() .route("/login", post(login)) + .route("/logout", get(logout)) .route("/register", post(register)) .route("/verify", post(verify)) } diff --git a/src/routes/user.rs b/src/routes/user.rs index d8684f5..7202fec 100644 --- a/src/routes/user.rs +++ b/src/routes/user.rs @@ -3,16 +3,28 @@ use axum::{ Router, }; -use crate::handlers::user::{add_resources, delete_resource, delete_user, get_resources, get_user, get_users, update_resource}; +use crate::handlers::user::{ + add_resources, delete_resource, delete_resource_group, delete_user, get_resource_group, get_resource_groups, get_resources, get_user, get_users, + update_resource, update_resource_group, +}; pub fn create_routes() -> Router { Router::new().route("/", get(get_users)).nest( "/:user_id", - Router::new().route("/", get(get_user).delete(delete_user)).nest( - "/resources", - Router::new() - .route("/", get(get_resources).post(add_resources)) - .route("/:resource_id", patch(update_resource).delete(delete_resource)), - ), + Router::new() + .route("/", get(get_user).delete(delete_user)) + .nest( + "/resource-group", + Router::new().route("/", get(get_resource_groups)).nest( + "/:resource_group_id", + Router::new().route("/", get(get_resource_group).patch(update_resource_group).delete(delete_resource_group)), + ), + ) + .nest( + "/resources", + Router::new() + .route("/", get(get_resources).post(add_resources)) + .route("/:resource_id", patch(update_resource).delete(delete_resource)), + ), ) } diff --git a/src/utils/default_resource_checker.rs b/src/utils/default_resource_checker.rs index 47a95d3..2a8a733 100644 --- a/src/utils/default_resource_checker.rs +++ b/src/utils/default_resource_checker.rs @@ -14,6 +14,10 @@ pub fn is_default_user(user_id: Uuid) -> bool { user_id == SETTINGS.read().default_cred.master_admin_user_id } +pub fn is_default_resource_group(resource_group_id: Uuid) -> bool { + resource_group_id == SETTINGS.read().default_cred.resource_group_id +} + pub fn is_default_resource(resource_id: Uuid) -> bool { SETTINGS.read().default_cred.resource_ids.contains(&resource_id) } From a05cbfa2eebda6364587df2b414ea9641b63540a Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Sun, 29 Sep 2024 02:29:15 +0530 Subject: [PATCH 30/45] fix: session implementation in-progress --- migrations/down.sql | 5 ++++ migrations/up.sql | 60 ++++++++++++++++++++++++++++++++++++++++- src/database/client.rs | 9 +++++++ src/database/realm.rs | 1 + src/database/session.rs | 19 +++++++++++-- 5 files changed, 91 insertions(+), 3 deletions(-) diff --git a/migrations/down.sql b/migrations/down.sql index e17e256..3dfa8e0 100644 --- a/migrations/down.sql +++ b/migrations/down.sql @@ -2,10 +2,15 @@ -- Drop triggers first DROP TRIGGER IF EXISTS ensure_single_default_resource_group ON resource_group; DROP TRIGGER IF EXISTS before_insert_and_update_realm ON realm; +DROP TRIGGER IF EXISTS session_cleanup_trigger ON session; +DROP TRIGGER IF EXISTS enforce_max_concurrent_sessions ON client; + -- Drop functions DROP FUNCTION IF EXISTS manage_default_resource_group(); DROP FUNCTION IF EXISTS generate_slug(); +DROP FUNCTION IF EXISTS cleanup_expired_sessions(); +DROP FUNCTION IF EXISTS check_max_concurrent_sessions(); DROP FUNCTION IF EXISTS uuid_generate_v7(); -- Drop tables diff --git a/migrations/up.sql b/migrations/up.sql index 136d381..d1e7e32 100644 --- a/migrations/up.sql +++ b/migrations/up.sql @@ -23,6 +23,7 @@ CREATE TABLE realm ( id UUID PRIMARY KEY DEFAULT uuid_generate_v7(), name TEXT NOT NULL UNIQUE, slug TEXT NOT NULL UNIQUE, + max_concurrent_sessions INTEGER, locked_at TIMESTAMP, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP @@ -47,6 +48,7 @@ CREATE TABLE client ( id UUID PRIMARY KEY DEFAULT uuid_generate_v7(), name TEXT NOT NULL, two_factor_enabled_at TIMESTAMP, + max_concurrent_sessions INTEGER NOT NULL DEFAULT 1, locked_at TIMESTAMP, realm_id UUID NOT NULL REFERENCES realm(id) ON DELETE CASCADE, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, @@ -57,6 +59,47 @@ CREATE TABLE client ( CREATE UNIQUE INDEX realm_id_name_key ON client (realm_id, name); CREATE INDEX idx_client_realm_locked ON client (realm_id, locked_at); +-- Create trigger function to check max_concurrent_sessions constraint +CREATE OR REPLACE FUNCTION check_max_concurrent_sessions() +RETURNS TRIGGER AS $$ +DECLARE + realm_max_sessions INTEGER; + current_total_sessions INTEGER; +BEGIN + -- Fetch the max_concurrent_sessions for the realm + SELECT max_concurrent_sessions INTO realm_max_sessions + FROM realm + WHERE id = NEW.realm_id; + + -- Only perform the check if the realm has a max_concurrent_sessions limit set + IF realm_max_sessions IS NOT NULL THEN + -- Calculate the total max_concurrent_sessions for all clients in this realm, including the new or updated client + SELECT COALESCE(SUM(max_concurrent_sessions), 0) INTO current_total_sessions + FROM client + WHERE realm_id = NEW.realm_id + AND id <> NEW.id; -- Exclude the current client during an update + + -- Add the new client's max_concurrent_sessions to the total + current_total_sessions := current_total_sessions + NEW.max_concurrent_sessions; + + -- Check if the total exceeds the realm's max_concurrent_sessions + IF current_total_sessions > realm_max_sessions THEN + RAISE EXCEPTION 'Total max_concurrent_sessions for all clients in this realm (%s) exceeds the realm''s limit (%s)', + current_total_sessions, realm_max_sessions; + END IF; + END IF; + + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +-- Create trigger for enforcing the constraint on insert and update +CREATE TRIGGER enforce_max_concurrent_sessions +BEFORE INSERT OR UPDATE ON client +FOR EACH ROW +EXECUTE FUNCTION check_max_concurrent_sessions(); + + -- Create users table CREATE TABLE "user" ( id UUID PRIMARY KEY DEFAULT uuid_generate_v7(), @@ -175,13 +218,28 @@ CREATE TABLE account ( -- Create sessions table CREATE TABLE session ( - session_token TEXT PRIMARY KEY, + id UUID PRIMARY KEY DEFAULT uuid_generate_v7(), user_id UUID NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, + client_id UUID NOT NULL REFERENCES client(id) ON DELETE CASCADE, expires TIMESTAMP NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ); +CREATE OR REPLACE FUNCTION cleanup_expired_sessions() +RETURNS TRIGGER AS $$ +BEGIN + DELETE FROM session + WHERE expires < CURRENT_TIMESTAMP; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER session_cleanup_trigger +AFTER INSERT OR UPDATE ON session +FOR EACH STATEMENT +EXECUTE FUNCTION cleanup_expired_sessions(); + -- Create verification_token table CREATE TABLE verification_token ( identifier TEXT NOT NULL, diff --git a/src/database/client.rs b/src/database/client.rs index c320782..bdf6645 100644 --- a/src/database/client.rs +++ b/src/database/client.rs @@ -15,6 +15,7 @@ pub struct Model { pub realm_id: Uuid, pub created_at: DateTime, pub updated_at: DateTime, + pub max_concurrent_sessions: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] @@ -29,6 +30,8 @@ pub enum Relation { Realm, #[sea_orm(has_many = "super::resource_group::Entity")] ResourceGroup, + #[sea_orm(has_many = "super::session::Entity")] + Session, } impl Related for Entity { @@ -43,4 +46,10 @@ impl Related for Entity { } } +impl Related for Entity { + fn to() -> RelationDef { + Relation::Session.def() + } +} + impl ActiveModelBehavior for ActiveModel {} diff --git a/src/database/realm.rs b/src/database/realm.rs index 9569f00..a2fc624 100644 --- a/src/database/realm.rs +++ b/src/database/realm.rs @@ -15,6 +15,7 @@ pub struct Model { pub locked_at: Option, pub created_at: DateTime, pub updated_at: DateTime, + pub max_concurrent_sessions: Option, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/src/database/session.rs b/src/database/session.rs index 2f2b088..05efbe0 100644 --- a/src/database/session.rs +++ b/src/database/session.rs @@ -5,9 +5,10 @@ use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] #[sea_orm(table_name = "session")] pub struct Model { - #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] - pub session_token: String, + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, pub user_id: Uuid, + pub client_id: Uuid, pub expires: DateTime, pub created_at: DateTime, pub updated_at: DateTime, @@ -15,6 +16,14 @@ pub struct Model { #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { + #[sea_orm( + belongs_to = "super::client::Entity", + from = "Column::ClientId", + to = "super::client::Column::Id", + on_update = "NoAction", + on_delete = "Cascade" + )] + Client, #[sea_orm( belongs_to = "super::user::Entity", from = "Column::UserId", @@ -25,6 +34,12 @@ pub enum Relation { User, } +impl Related for Entity { + fn to() -> RelationDef { + Relation::Client.def() + } +} + impl Related for Entity { fn to() -> RelationDef { Relation::User.def() From a03db5491ac4a5b5e54d1f47736d2f563f24eae4 Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Sun, 29 Sep 2024 16:36:56 +0530 Subject: [PATCH 31/45] fix: session info capturing middleware implemented --- Cargo.lock | 116 ++++++++++++++++++++++- Cargo.toml | 3 +- config/{ => env}/default.yml | 0 config/{ => env}/production.yml | 0 config/{ => env}/test.yml | 0 config/regexes.yml | 18 ++++ migrations/up.sql | 11 +++ src/app.rs | 3 +- src/handlers/auth.rs | 4 +- src/middleware/mod.rs | 1 + src/middleware/session_info_extractor.rs | 67 +++++++++++++ src/packages/settings.rs | 6 +- src/routes/auth.rs | 7 +- 13 files changed, 223 insertions(+), 13 deletions(-) rename config/{ => env}/default.yml (100%) rename config/{ => env}/production.yml (100%) rename config/{ => env}/test.yml (100%) create mode 100644 config/regexes.yml create mode 100644 src/middleware/session_info_extractor.rs diff --git a/Cargo.lock b/Cargo.lock index 1e99945..31ccf89 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,6 +41,15 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "aliasable" version = "0.1.3" @@ -152,9 +161,9 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "axum" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f43644eed690f5374f1af436ecd6aea01cd201f6fbdf0178adaf6907afb2cec" +checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae" dependencies = [ "async-trait", "axum-core", @@ -186,9 +195,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6b8ba012a258d63c9adfa28b9ddcf66149da6f986c5b5452e629d5ee64bf00" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" dependencies = [ "async-trait", "bytes", @@ -463,7 +472,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7328b20597b53c2454f0b1919720c25c7339051c02b72b7e05409e00b14132be" dependencies = [ "async-trait", - "convert_case", + "convert_case 0.6.0", "json5", "lazy_static", "nom", @@ -502,6 +511,12 @@ dependencies = [ "tiny-keccak", ] +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + [[package]] name = "convert_case" version = "0.6.0" @@ -612,6 +627,19 @@ dependencies = [ "serde", ] +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "convert_case 0.4.0", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.77", +] + [[package]] name = "digest" version = "0.10.7" @@ -1772,6 +1800,35 @@ dependencies = [ "bitflags", ] +[[package]] +name = "regex" +version = "1.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + [[package]] name = "rend" version = "0.4.2" @@ -1889,6 +1946,15 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.37" @@ -2054,6 +2120,12 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + [[package]] name = "serde" version = "1.0.210" @@ -2117,6 +2189,19 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "sha1" version = "0.10.6" @@ -2181,6 +2266,7 @@ dependencies = [ "tower-http", "tracing", "tracing-subscriber", + "uaparser", ] [[package]] @@ -2889,6 +2975,20 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "uaparser" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c9e1c3f893758f154004195fc2d2c52fbda462df725220ceaef830ac29affa" +dependencies = [ + "derive_more", + "lazy_static", + "regex", + "serde", + "serde_derive", + "serde_yaml", +] + [[package]] name = "ucd-trie" version = "0.1.6" @@ -2934,6 +3034,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "untrusted" version = "0.9.0" diff --git a/Cargo.toml b/Cargo.toml index 0416f86..0b878e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -axum = "0.7.6" +axum = "0.7.7" axum-extra = { version = "0.9.4", features = ["typed-header"] } bcrypt = "0.15.1" chrono = { version = "0.4.38", features = ["serde"] } @@ -33,3 +33,4 @@ tower-http = { version = "0.6.1", features = [ ] } tracing = "0.1.40" tracing-subscriber = "0.3.18" +uaparser = "0.6.4" diff --git a/config/default.yml b/config/env/default.yml similarity index 100% rename from config/default.yml rename to config/env/default.yml diff --git a/config/production.yml b/config/env/production.yml similarity index 100% rename from config/production.yml rename to config/env/production.yml diff --git a/config/test.yml b/config/env/test.yml similarity index 100% rename from config/test.yml rename to config/env/test.yml diff --git a/config/regexes.yml b/config/regexes.yml new file mode 100644 index 0000000..9c338f2 --- /dev/null +++ b/config/regexes.yml @@ -0,0 +1,18 @@ +user_agent_parsers: + - regex: '(ESPN)[%20| ]+Radio/(\d+)\.(\d+)\.(\d+) CFNetwork' + - regex: '(Namoroka|Shiretoko|Minefield)/(\d+)\.(\d+)\.(\d+(?:pre|))' + family_replacement: "Firefox ($1)" + - regex: "(Android) Eclair" + v1_replacement: "2" + v2_replacement: "1" + +os_parsers: + - regex: "Win(?:dows)? ?(95|98|3.1|NT|ME|2000|XP|Vista|7|CE)" + os_replacement: "Windows" + os_v1_replacement: "$1" + +device_parsers: + - regex: '\bSmartWatch *\( *([^;]+) *; *([^;]+) *;' + device_replacement: "$1 $2" + brand_replacement: "$1" + model_replacement: "$2" diff --git a/migrations/up.sql b/migrations/up.sql index d1e7e32..075a794 100644 --- a/migrations/up.sql +++ b/migrations/up.sql @@ -221,11 +221,22 @@ CREATE TABLE session ( id UUID PRIMARY KEY DEFAULT uuid_generate_v7(), user_id UUID NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, client_id UUID NOT NULL REFERENCES client(id) ON DELETE CASCADE, + ip_address INET NOT NULL, + user_agent TEXT, + browser VARCHAR(255), + browser_version VARCHAR(100), + operating_system VARCHAR(255), + device_type VARCHAR(50), + country_code CHAR(2), expires TIMESTAMP NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ); +CREATE INDEX idx_session_user_id ON session (user_id, expires); +CREATE INDEX idx_session_client_id ON session (client_id, expires); +CREATE INDEX idx_session_expires ON session (expires); + CREATE OR REPLACE FUNCTION cleanup_expired_sessions() RETURNS TRIGGER AS $$ BEGIN diff --git a/src/app.rs b/src/app.rs index 9383a1b..352b64b 100644 --- a/src/app.rs +++ b/src/app.rs @@ -24,8 +24,7 @@ pub async fn create_app() -> Router { Router::new() .merge(routes::create_routes()) .layer(logger()) - // Mark the `Authorization` request header as sensitive so it doesn't - // show in logs. + // Mark the `Authorization` request header as sensitive so it doesn't show in logs. .layer(SetSensitiveHeadersLayer::new(std::iter::once(header::AUTHORIZATION))) // Compress responses .layer(CompressionLayer::new()) diff --git a/src/handlers/auth.rs b/src/handlers/auth.rs index 3dac0ad..37c769a 100644 --- a/src/handlers/auth.rs +++ b/src/handlers/auth.rs @@ -7,6 +7,7 @@ use crate::{ user::{self, Model}, }, mappers::auth::{CreateUserRequest, LogoutResponse}, + middleware::session_info_extractor::SessionInfo, packages::{ db::AppState, errors::{AuthenticateError, Error}, @@ -37,10 +38,11 @@ pub struct LoginResponse { pub async fn login( Extension(state): Extension>, + Extension(session_info): Extension>, Path((realm_id, client_id)): Path<(Uuid, Uuid)>, Json(payload): Json, ) -> Result, Error> { - debug!("🚀 Login request received!"); + debug!("🚀 Login request received! {:#?}", session_info); let user_with_resource_groups = User::find() .filter(user::Column::Email.eq(payload.email)) .find_also_related(ResourceGroup) diff --git a/src/middleware/mod.rs b/src/middleware/mod.rs index d991728..1c44357 100644 --- a/src/middleware/mod.rs +++ b/src/middleware/mod.rs @@ -1 +1,2 @@ pub mod logger; +pub mod session_info_extractor; diff --git a/src/middleware/session_info_extractor.rs b/src/middleware/session_info_extractor.rs new file mode 100644 index 0000000..d257511 --- /dev/null +++ b/src/middleware/session_info_extractor.rs @@ -0,0 +1,67 @@ +use axum::{ + body::Body, + http::{HeaderMap, Request}, + middleware::Next, + response::Response, +}; +// use maxminddb::Reader; +use std::{net::IpAddr, sync::Arc}; +use uaparser::{Parser, UserAgentParser}; + +// You might want to put this in a separate module +#[derive(Clone, Debug)] +pub struct SessionInfo { + ip_address: IpAddr, + user_agent: String, + browser: String, + browser_version: String, + operating_system: String, + device_type: String, + country_code: String, +} + +pub async fn session_info_middleware(mut req: Request, next: Next) -> Response { + let headers = req.headers(); + let ip_address = extract_ip_from_headers(headers); + let user_agent = req.headers().get("user-agent").and_then(|h| h.to_str().ok()).unwrap_or("").to_string(); + + // Parse user agent + let ua_parser = UserAgentParser::from_yaml("config/regexes.yml").expect("Failed to parse regexes.yml"); + let ua = ua_parser.parse(&user_agent); + + // Get country code using MaxMind GeoIP database + // let reader = Reader::open("path/to/GeoLite2-Country.mmdb").unwrap(); + // let country_code = reader + // .lookup(addr.ip()) + // .ok() + // .and_then(|r: maxminddb::geoip2::Country| r.country) + // .and_then(|c| c.iso_code) + // .unwrap_or("Unknown") + // .to_string(); + + let session_info = SessionInfo { + ip_address, + browser: ua.device.family.to_string(), + browser_version: format!("{:?}", ua.device.brand), + operating_system: format!("{:?}", ua.os.family), + device_type: format!("{:?}, {:?}, {:?}", ua.device.brand, ua.device.family, ua.device.model), + country_code: "IN".to_string(), + user_agent: user_agent.to_string(), + }; + // println!("USER AGENT SESSION INFO: {:#?}, USER agent: {:#?}", session_info, ua); + + // Insert the updated AppState into the request extensions + req.extensions_mut().insert(Arc::new(session_info)); + + next.run(req).await +} + +fn extract_ip_from_headers(headers: &HeaderMap) -> IpAddr { + headers + .get("x-forwarded-for") + .and_then(|h| h.to_str().ok()) + .and_then(|s| s.split(',').next()) + .and_then(|s| s.parse().ok()) + .or_else(|| headers.get("x-real-ip").and_then(|h| h.to_str().ok()).and_then(|s| s.parse().ok())) + .unwrap_or(IpAddr::V4(std::net::Ipv4Addr::new(127, 0, 0, 1))) +} diff --git a/src/packages/settings.rs b/src/packages/settings.rs index f475ed5..1c73940 100644 --- a/src/packages/settings.rs +++ b/src/packages/settings.rs @@ -55,9 +55,9 @@ impl Settings { let run_mode = env::var("RUN_MODE").unwrap_or_else(|_| "development".into()); let mut builder = Config::builder() - .add_source(File::with_name("config/default")) - .add_source(File::with_name(&format!("config/{run_mode}")).required(false)) - .add_source(File::with_name("config/local").required(false)) + .add_source(File::with_name("config/env/default")) + .add_source(File::with_name(&format!("config/env/{run_mode}")).required(false)) + .add_source(File::with_name("config/env/local").required(false)) .add_source(Environment::default().separator("__")); // Some cloud services like Heroku exposes a randomly assigned port in diff --git a/src/routes/auth.rs b/src/routes/auth.rs index 9b7e7da..e9470a8 100644 --- a/src/routes/auth.rs +++ b/src/routes/auth.rs @@ -1,9 +1,13 @@ use axum::{ + middleware, routing::{get, post}, Router, }; -use crate::handlers::auth::{login, logout, register, verify}; +use crate::{ + handlers::auth::{login, logout, register, verify}, + middleware::session_info_extractor::session_info_middleware, +}; pub fn create_routes() -> Router { Router::new() @@ -11,4 +15,5 @@ pub fn create_routes() -> Router { .route("/logout", get(logout)) .route("/register", post(register)) .route("/verify", post(verify)) + .layer(middleware::from_fn(session_info_middleware)) } From 314b1febc8a90bde565cc257b175f9a95f443160 Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Sun, 29 Sep 2024 18:32:35 +0530 Subject: [PATCH 32/45] fix: session creation implemented alongwith max concurrent session limit --- config/env/default.yml | 4 +- migrations/up.sql | 116 +++++++++++++++-------- src/database/account.rs | 4 +- src/database/client.rs | 13 ++- src/database/password_reset_token.rs | 2 +- src/database/realm.rs | 9 +- src/database/resource.rs | 6 +- src/database/resource_group.rs | 6 +- src/database/session.rs | 15 ++- src/database/two_factor_confirmation.rs | 2 +- src/database/two_factor_token.rs | 2 +- src/database/user.rs | 10 +- src/database/verification_token.rs | 2 +- src/handlers/auth.rs | 45 ++++++++- src/handlers/user.rs | 4 +- src/middleware/session_info_extractor.rs | 14 +-- src/packages/errors.rs | 4 + src/packages/settings.rs | 11 ++- src/packages/token.rs | 29 ++++-- src/services/client.rs | 2 +- src/services/realm.rs | 2 +- 21 files changed, 210 insertions(+), 92 deletions(-) diff --git a/config/env/default.yml b/config/env/default.yml index c796897..276f0d3 100644 --- a/config/env/default.yml +++ b/config/env/default.yml @@ -1,6 +1,8 @@ environment: development server: - port: 5556 + port: 5555 + domain: localhost + host: http://localhost:5555 database: uri: "postgres://postgres:1234@localhost:5432/shield" name: shield diff --git a/migrations/up.sql b/migrations/up.sql index 075a794..a6cf336 100644 --- a/migrations/up.sql +++ b/migrations/up.sql @@ -24,9 +24,12 @@ CREATE TABLE realm ( name TEXT NOT NULL UNIQUE, slug TEXT NOT NULL UNIQUE, max_concurrent_sessions INTEGER, - locked_at TIMESTAMP, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP + session_lifetime INTEGER NOT NULL DEFAULT 300, + refresh_token_lifetime INTEGER NOT NULL DEFAULT 3600, + refresh_token_reuse_limit INTEGER NOT NULL DEFAULT 0, + locked_at TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP ); -- Add trigger for auto-generating slug @@ -47,31 +50,49 @@ EXECUTE FUNCTION generate_slug(); CREATE TABLE client ( id UUID PRIMARY KEY DEFAULT uuid_generate_v7(), name TEXT NOT NULL, - two_factor_enabled_at TIMESTAMP, + two_factor_enabled_at TIMESTAMPTZ, max_concurrent_sessions INTEGER NOT NULL DEFAULT 1, - locked_at TIMESTAMP, + session_lifetime INTEGER NOT NULL DEFAULT 300, + refresh_token_lifetime INTEGER NOT NULL DEFAULT 3600, + refresh_token_reuse_limit INTEGER NOT NULL DEFAULT 0, + locked_at TIMESTAMPTZ, realm_id UUID NOT NULL REFERENCES realm(id) ON DELETE CASCADE, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT chk_locked_at CHECK (locked_at IS NULL OR locked_at <= CURRENT_TIMESTAMP) ); CREATE UNIQUE INDEX realm_id_name_key ON client (realm_id, name); CREATE INDEX idx_client_realm_locked ON client (realm_id, locked_at); +CREATE INDEX idx_client_realm_max_sessions ON client (realm_id, max_concurrent_sessions); +CREATE INDEX idx_client_realm_constraints ON client (realm_id, session_lifetime, refresh_token_lifetime, refresh_token_reuse_limit); +CREATE INDEX idx_client_realm ON client (realm_id); --- Create trigger function to check max_concurrent_sessions constraint -CREATE OR REPLACE FUNCTION check_max_concurrent_sessions() +-- Create or replace the combined trigger function to check all client constraints +CREATE OR REPLACE FUNCTION check_client_constraints() RETURNS TRIGGER AS $$ DECLARE realm_max_sessions INTEGER; + realm_session_lifetime INTEGER; + realm_refresh_token_lifetime INTEGER; + realm_refresh_token_reuse_limit INTEGER; current_total_sessions INTEGER; BEGIN - -- Fetch the max_concurrent_sessions for the realm - SELECT max_concurrent_sessions INTO realm_max_sessions + -- Fetch all necessary values from the realm + SELECT + max_concurrent_sessions, + session_lifetime, + refresh_token_lifetime, + refresh_token_reuse_limit + INTO + realm_max_sessions, + realm_session_lifetime, + realm_refresh_token_lifetime, + realm_refresh_token_reuse_limit FROM realm WHERE id = NEW.realm_id; - -- Only perform the check if the realm has a max_concurrent_sessions limit set + -- Check max_concurrent_sessions IF realm_max_sessions IS NOT NULL THEN -- Calculate the total max_concurrent_sessions for all clients in this realm, including the new or updated client SELECT COALESCE(SUM(max_concurrent_sessions), 0) INTO current_total_sessions @@ -84,21 +105,38 @@ BEGIN -- Check if the total exceeds the realm's max_concurrent_sessions IF current_total_sessions > realm_max_sessions THEN - RAISE EXCEPTION 'Total max_concurrent_sessions for all clients in this realm (%s) exceeds the realm''s limit (%s)', - current_total_sessions, realm_max_sessions; + RAISE EXCEPTION 'Total max_concurrent_sessions for all clients in this realm (%) exceeds the realm''s limit (%)', + current_total_sessions, realm_max_sessions; END IF; END IF; + -- Check session_lifetime + IF NEW.session_lifetime > realm_session_lifetime THEN + RAISE EXCEPTION 'Client session_lifetime (%) exceeds the realm''s limit (%)', + NEW.session_lifetime, realm_session_lifetime; + END IF; + + -- Check refresh_token_lifetime + IF NEW.refresh_token_lifetime > realm_refresh_token_lifetime THEN + RAISE EXCEPTION 'Client refresh_token_lifetime (%) exceeds the realm''s limit (%)', + NEW.refresh_token_lifetime, realm_refresh_token_lifetime; + END IF; + + -- Check refresh_token_reuse_limit + IF NEW.refresh_token_reuse_limit > realm_refresh_token_reuse_limit THEN + RAISE EXCEPTION 'Client refresh_token_reuse_limit (%) exceeds the realm''s limit (%)', + NEW.refresh_token_reuse_limit, realm_refresh_token_reuse_limit; + END IF; + RETURN NEW; END; $$ LANGUAGE plpgsql; --- Create trigger for enforcing the constraint on insert and update -CREATE TRIGGER enforce_max_concurrent_sessions +-- Create or replace the trigger for enforcing all constraints on insert and update +CREATE OR REPLACE TRIGGER enforce_client_constraints BEFORE INSERT OR UPDATE ON client FOR EACH ROW -EXECUTE FUNCTION check_max_concurrent_sessions(); - +EXECUTE FUNCTION check_client_constraints(); -- Create users table CREATE TABLE "user" ( @@ -106,16 +144,16 @@ CREATE TABLE "user" ( first_name TEXT NOT NULL, last_name TEXT, email TEXT NOT NULL, - email_verified_at TIMESTAMP, + email_verified_at TIMESTAMPTZ, phone TEXT, image TEXT, - two_factor_enabled_at TIMESTAMP, + two_factor_enabled_at TIMESTAMPTZ, password_hash TEXT, is_temp_password BOOLEAN DEFAULT TRUE, - locked_at TIMESTAMP, + locked_at TIMESTAMPTZ, realm_id UUID NOT NULL REFERENCES realm(id) ON DELETE CASCADE, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT chk_email_format CHECK (email ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}$'), CONSTRAINT chk_locked_at CHECK (locked_at IS NULL OR locked_at <= CURRENT_TIMESTAMP), CONSTRAINT chk_email_verified_at CHECK (email_verified_at IS NULL OR email_verified_at >= created_at AND email_verified_at <= CURRENT_TIMESTAMP), @@ -136,9 +174,9 @@ CREATE TABLE resource_group ( name TEXT NOT NULL, description TEXT, is_default BOOLEAN DEFAULT FALSE, - locked_at TIMESTAMP, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + locked_at TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT chk_locked_at CHECK (locked_at IS NULL OR locked_at <= CURRENT_TIMESTAMP) ); @@ -190,9 +228,9 @@ CREATE TABLE resource ( name TEXT NOT NULL, value TEXT NOT NULL, description TEXT, - locked_at TIMESTAMP, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + locked_at TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT chk_locked_at CHECK (locked_at IS NULL OR locked_at <= CURRENT_TIMESTAMP) ); @@ -211,8 +249,8 @@ CREATE TABLE account ( scope TEXT, id_token TEXT, session_state TEXT, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (provider, provider_account_id) ); @@ -221,16 +259,16 @@ CREATE TABLE session ( id UUID PRIMARY KEY DEFAULT uuid_generate_v7(), user_id UUID NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, client_id UUID NOT NULL REFERENCES client(id) ON DELETE CASCADE, - ip_address INET NOT NULL, + ip_address TEXT NOT NULL, user_agent TEXT, browser VARCHAR(255), browser_version VARCHAR(100), operating_system VARCHAR(255), device_type VARCHAR(50), country_code CHAR(2), - expires TIMESTAMP NOT NULL, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP + expires TIMESTAMPTZ NOT NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX idx_session_user_id ON session (user_id, expires); @@ -255,7 +293,7 @@ EXECUTE FUNCTION cleanup_expired_sessions(); CREATE TABLE verification_token ( identifier TEXT NOT NULL, token TEXT NOT NULL, - expires TIMESTAMP NOT NULL, + expires TIMESTAMPTZ NOT NULL, PRIMARY KEY (identifier, token) ); @@ -263,7 +301,7 @@ CREATE TABLE verification_token ( CREATE TABLE password_reset_token ( identifier TEXT NOT NULL, token TEXT NOT NULL, - expires TIMESTAMP NOT NULL, + expires TIMESTAMPTZ NOT NULL, PRIMARY KEY (identifier, token) ); @@ -271,7 +309,7 @@ CREATE TABLE password_reset_token ( CREATE TABLE two_factor_token ( identifier TEXT NOT NULL, token TEXT NOT NULL, - expires TIMESTAMP NOT NULL, + expires TIMESTAMPTZ NOT NULL, PRIMARY KEY (identifier, token) ); @@ -279,7 +317,7 @@ CREATE TABLE two_factor_token ( CREATE TABLE two_factor_confirmation ( identifier TEXT NOT NULL, token TEXT NOT NULL, - expires TIMESTAMP NOT NULL, + expires TIMESTAMPTZ NOT NULL, PRIMARY KEY (identifier, token) ); diff --git a/src/database/account.rs b/src/database/account.rs index 4a37839..40bb81e 100644 --- a/src/database/account.rs +++ b/src/database/account.rs @@ -25,8 +25,8 @@ pub struct Model { pub id_token: Option, #[sea_orm(column_type = "Text", nullable)] pub session_state: Option, - pub created_at: DateTime, - pub updated_at: DateTime, + pub created_at: DateTimeWithTimeZone, + pub updated_at: DateTimeWithTimeZone, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/src/database/client.rs b/src/database/client.rs index bdf6645..d1b1150 100644 --- a/src/database/client.rs +++ b/src/database/client.rs @@ -10,12 +10,15 @@ pub struct Model { pub id: Uuid, #[sea_orm(column_type = "Text")] pub name: String, - pub two_factor_enabled_at: Option, - pub locked_at: Option, - pub realm_id: Uuid, - pub created_at: DateTime, - pub updated_at: DateTime, + pub two_factor_enabled_at: Option, pub max_concurrent_sessions: i32, + pub session_lifetime: i32, + pub refresh_token_lifetime: i32, + pub refresh_token_reuse_limit: i32, + pub locked_at: Option, + pub realm_id: Uuid, + pub created_at: DateTimeWithTimeZone, + pub updated_at: DateTimeWithTimeZone, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/src/database/password_reset_token.rs b/src/database/password_reset_token.rs index 1a449a1..c8a189f 100644 --- a/src/database/password_reset_token.rs +++ b/src/database/password_reset_token.rs @@ -9,7 +9,7 @@ pub struct Model { pub identifier: String, #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] pub token: String, - pub expires: DateTime, + pub expires: DateTimeWithTimeZone, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/src/database/realm.rs b/src/database/realm.rs index a2fc624..4f67ff9 100644 --- a/src/database/realm.rs +++ b/src/database/realm.rs @@ -12,10 +12,13 @@ pub struct Model { pub name: String, #[sea_orm(column_type = "Text", unique)] pub slug: String, - pub locked_at: Option, - pub created_at: DateTime, - pub updated_at: DateTime, pub max_concurrent_sessions: Option, + pub session_lifetime: i32, + pub refresh_token_lifetime: i32, + pub refresh_token_reuse_limit: i32, + pub locked_at: Option, + pub created_at: DateTimeWithTimeZone, + pub updated_at: DateTimeWithTimeZone, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/src/database/resource.rs b/src/database/resource.rs index 80e9aa8..cdb516d 100644 --- a/src/database/resource.rs +++ b/src/database/resource.rs @@ -15,9 +15,9 @@ pub struct Model { pub value: String, #[sea_orm(column_type = "Text", nullable)] pub description: Option, - pub locked_at: Option, - pub created_at: DateTime, - pub updated_at: DateTime, + pub locked_at: Option, + pub created_at: DateTimeWithTimeZone, + pub updated_at: DateTimeWithTimeZone, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/src/database/resource_group.rs b/src/database/resource_group.rs index 81b56e1..5e78cb5 100644 --- a/src/database/resource_group.rs +++ b/src/database/resource_group.rs @@ -16,9 +16,9 @@ pub struct Model { #[sea_orm(column_type = "Text", nullable)] pub description: Option, pub is_default: Option, - pub locked_at: Option, - pub created_at: DateTime, - pub updated_at: DateTime, + pub locked_at: Option, + pub created_at: DateTimeWithTimeZone, + pub updated_at: DateTimeWithTimeZone, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/src/database/session.rs b/src/database/session.rs index 05efbe0..baa03eb 100644 --- a/src/database/session.rs +++ b/src/database/session.rs @@ -9,9 +9,18 @@ pub struct Model { pub id: Uuid, pub user_id: Uuid, pub client_id: Uuid, - pub expires: DateTime, - pub created_at: DateTime, - pub updated_at: DateTime, + #[sea_orm(column_type = "Text")] + pub ip_address: String, + #[sea_orm(column_type = "Text", nullable)] + pub user_agent: Option, + pub browser: Option, + pub browser_version: Option, + pub operating_system: Option, + pub device_type: Option, + pub country_code: Option, + pub expires: DateTimeWithTimeZone, + pub created_at: DateTimeWithTimeZone, + pub updated_at: DateTimeWithTimeZone, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/src/database/two_factor_confirmation.rs b/src/database/two_factor_confirmation.rs index ffe62d2..88b179c 100644 --- a/src/database/two_factor_confirmation.rs +++ b/src/database/two_factor_confirmation.rs @@ -9,7 +9,7 @@ pub struct Model { pub identifier: String, #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] pub token: String, - pub expires: DateTime, + pub expires: DateTimeWithTimeZone, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/src/database/two_factor_token.rs b/src/database/two_factor_token.rs index f95666b..104d918 100644 --- a/src/database/two_factor_token.rs +++ b/src/database/two_factor_token.rs @@ -9,7 +9,7 @@ pub struct Model { pub identifier: String, #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] pub token: String, - pub expires: DateTime, + pub expires: DateTimeWithTimeZone, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/src/database/user.rs b/src/database/user.rs index e82d8f8..dc9c867 100644 --- a/src/database/user.rs +++ b/src/database/user.rs @@ -14,19 +14,19 @@ pub struct Model { pub last_name: Option, #[sea_orm(column_type = "Text")] pub email: String, - pub email_verified_at: Option, + pub email_verified_at: Option, #[sea_orm(column_type = "Text", nullable)] pub phone: Option, #[sea_orm(column_type = "Text", nullable)] pub image: Option, - pub two_factor_enabled_at: Option, + pub two_factor_enabled_at: Option, #[sea_orm(column_type = "Text", nullable)] pub password_hash: Option, pub is_temp_password: Option, - pub locked_at: Option, + pub locked_at: Option, pub realm_id: Uuid, - pub created_at: DateTime, - pub updated_at: DateTime, + pub created_at: DateTimeWithTimeZone, + pub updated_at: DateTimeWithTimeZone, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/src/database/verification_token.rs b/src/database/verification_token.rs index 8e2627f..82ae94c 100644 --- a/src/database/verification_token.rs +++ b/src/database/verification_token.rs @@ -9,7 +9,7 @@ pub struct Model { pub identifier: String, #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] pub token: String, - pub expires: DateTime, + pub expires: DateTimeWithTimeZone, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/src/handlers/auth.rs b/src/handlers/auth.rs index 37c769a..13780d2 100644 --- a/src/handlers/auth.rs +++ b/src/handlers/auth.rs @@ -1,9 +1,12 @@ +use chrono::{FixedOffset, Utc}; +use sea_orm::{ActiveModelTrait, Set}; use std::sync::Arc; use crate::{ database::{ - prelude::{Client, Resource, ResourceGroup, User}, - resource, resource_group, + prelude::{Client, Resource, ResourceGroup, Session, User}, + resource, resource_group, session, + session::ActiveModel as SessionActiveModel, user::{self, Model}, }, mappers::auth::{CreateUserRequest, LogoutResponse}, @@ -18,7 +21,7 @@ use crate::{ utils::role_checker::{is_current_realm_admin, is_master_realm_admin}, }; use axum::{extract::Path, Extension, Json}; -use sea_orm::{prelude::Uuid, ColumnTrait, EntityTrait, QueryFilter}; +use sea_orm::{prelude::Uuid, ColumnTrait, EntityTrait, PaginatorTrait, QueryFilter}; use serde::{Deserialize, Serialize}; use tracing::debug; @@ -88,6 +91,16 @@ pub async fn login( return Err(Error::Authenticate(AuthenticateError::Locked)); } + let sessions = Session::find() + .filter(session::Column::ClientId.eq(client.id)) + .filter(session::Column::UserId.eq(user.id)) + .count(&state.db) + .await?; + + if sessions >= client.max_concurrent_sessions as u64 { + debug!("Client has reached max concurrent sessions"); + return Err(Error::Authenticate(AuthenticateError::MaxConcurrentSessions)); + } // Fetch resources let resources = Resource::find() .filter(resource::Column::GroupId.eq(resource_groups.id)) @@ -100,7 +113,31 @@ pub async fn login( return Err(Error::Authenticate(AuthenticateError::Locked)); } - let access_token = create(user.clone(), client, resource_groups, resources, &SETTINGS.read().secrets.signing_key).unwrap(); + let session = SessionActiveModel { + user_id: Set(user.id), + client_id: Set(client.id), + ip_address: Set(session_info.ip_address.to_string()), + user_agent: Set(Some(session_info.user_agent.to_string())), + browser: Set(Some(session_info.browser.to_string())), + browser_version: Set(Some(session_info.browser_version.to_string())), + operating_system: Set(Some(session_info.operating_system.to_string())), + device_type: Set(Some(session_info.device_type.to_string())), + country_code: Set(Some(session_info.country_code.to_string())), + expires: Set((Utc::now() + chrono::Duration::seconds(client.session_lifetime as i64)).into()), + ..Default::default() + }; + let session = session.insert(&state.db).await?; + + let access_token = create( + user.clone(), + client, + resource_groups, + resources, + session, + &SETTINGS.read().secrets.signing_key, + ) + .unwrap(); + Ok(Json(LoginResponse { access_token, user, diff --git a/src/handlers/user.rs b/src/handlers/user.rs index f3fba1f..ca1ebdc 100644 --- a/src/handlers/user.rs +++ b/src/handlers/user.rs @@ -132,7 +132,7 @@ pub async fn update_resource_group( } let locked_at = match payload.lock { - Some(true) => Some(resource_group.as_ref().unwrap().locked_at.unwrap_or_else(|| Utc::now().naive_utc())), + Some(true) => Some(resource_group.as_ref().unwrap().locked_at.unwrap_or_else(|| Utc::now().into())), Some(false) => None, None => resource_group.as_ref().unwrap().locked_at, }; @@ -284,7 +284,7 @@ pub async fn update_resource( } let locked_at = match payload.lock { - Some(true) => Some(resource.as_ref().unwrap().locked_at.unwrap_or_else(|| Utc::now().naive_utc())), + Some(true) => Some(resource.as_ref().unwrap().locked_at.unwrap_or_else(|| Utc::now().into())), Some(false) => None, None => None, }; diff --git a/src/middleware/session_info_extractor.rs b/src/middleware/session_info_extractor.rs index d257511..5043fd0 100644 --- a/src/middleware/session_info_extractor.rs +++ b/src/middleware/session_info_extractor.rs @@ -11,13 +11,13 @@ use uaparser::{Parser, UserAgentParser}; // You might want to put this in a separate module #[derive(Clone, Debug)] pub struct SessionInfo { - ip_address: IpAddr, - user_agent: String, - browser: String, - browser_version: String, - operating_system: String, - device_type: String, - country_code: String, + pub ip_address: IpAddr, + pub user_agent: String, + pub browser: String, + pub browser_version: String, + pub operating_system: String, + pub device_type: String, + pub country_code: String, } pub async fn session_info_middleware(mut req: Request, next: Next) -> Response { diff --git a/src/packages/errors.rs b/src/packages/errors.rs index 9e46da7..881033b 100644 --- a/src/packages/errors.rs +++ b/src/packages/errors.rs @@ -118,6 +118,8 @@ impl IntoResponse for Error { pub enum AuthenticateError { #[error("Wrong authentication credentials")] WrongCredentials, + #[error("Max concurrent sessions reached")] + MaxConcurrentSessions, #[error("Failed to create authentication token")] TokenCreation, #[error("Invalid authentication credentials")] @@ -141,6 +143,7 @@ impl AuthenticateError { AuthenticateError::EmailNotVerified => (StatusCode::FORBIDDEN, 40007), AuthenticateError::NoResource => (StatusCode::FORBIDDEN, 40008), AuthenticateError::ActionForbidden => (StatusCode::FORBIDDEN, 40009), + AuthenticateError::MaxConcurrentSessions => (StatusCode::LOCKED, 40010), AuthenticateError::TokenCreation => (StatusCode::INTERNAL_SERVER_ERROR, 5001), } } @@ -153,6 +156,7 @@ impl AuthenticateError { AuthenticateError::NoResource => AuthenticateError::NoResource, AuthenticateError::EmailNotVerified => AuthenticateError::EmailNotVerified, AuthenticateError::ActionForbidden => AuthenticateError::ActionForbidden, + AuthenticateError::MaxConcurrentSessions => AuthenticateError::MaxConcurrentSessions, AuthenticateError::Locked => AuthenticateError::Locked, } } diff --git a/src/packages/settings.rs b/src/packages/settings.rs index 1c73940..1faf807 100644 --- a/src/packages/settings.rs +++ b/src/packages/settings.rs @@ -1,10 +1,9 @@ -use crate::packages::errors::Error; use config::{Config, ConfigError, Environment, File, Value}; use dotenvy::dotenv; use once_cell::sync::Lazy; use parking_lot::RwLock; use serde::Deserialize; -use std::{env, fmt, fs::read_to_string, path::Path, sync::Arc}; +use std::{env, fmt, path::Path, sync::Arc}; use crate::utils::helpers::default_cred::DefaultCred; @@ -14,6 +13,8 @@ pub static SETTINGS: Lazy>> = Lazy::new(|| Arc::new(RwLock: #[derive(Debug, Clone, Deserialize)] pub struct Server { pub port: u16, + pub domain: String, + pub host: String, } #[derive(Debug, Clone, Deserialize)] @@ -65,6 +66,12 @@ impl Settings { if let Ok(port) = env::var("PORT") { builder = builder.set_override("server.port", port)?; } + if let Ok(domain) = env::var("DOMAIN") { + builder = builder.set_override("server.domain", domain)?; + } + if let Ok(host) = env::var("HOST") { + builder = builder.set_override("server.host", host)?; + } if let Ok(database_uri) = env::var("DATABASE_URL") { builder = builder.set_override("database.uri", database_uri)?; } diff --git a/src/packages/token.rs b/src/packages/token.rs index 93d2b67..2f1eec4 100644 --- a/src/packages/token.rs +++ b/src/packages/token.rs @@ -5,9 +5,12 @@ use serde::{Deserialize, Serialize}; use std::collections::HashMap; use crate::database::{ - client::Model as ClientModel, resource::Model as ResourceModel, resource_group::Model as ResourceGroupModel, user::Model as UserModel, + client::Model as ClientModel, resource::Model as ResourceModel, resource_group::Model as ResourceGroupModel, session::Model as SessionModel, + user::Model as UserModel, }; +use super::settings::SETTINGS; + type TokenResult = Result, Error>; static VALIDATION: Lazy = Lazy::new(Validation::default); @@ -76,9 +79,11 @@ impl TokenUser { #[derive(Debug, Serialize, Deserialize)] pub struct Claims { - pub exp: usize, // Expiration time (as UTC timestamp). validate_exp defaults to true in validation - pub iat: usize, // Issued at (as UTC timestamp) - pub sub: Uuid, + pub exp: usize, // Expiration time (as UTC timestamp). validate_exp defaults to true in validation + pub iat: usize, // Issued at (as UTC timestamp) + pub sub: Uuid, // Subject + pub sid: Uuid, // Session ID + pub iss: String, // Issuer pub first_name: String, pub last_name: String, pub email: String, @@ -87,12 +92,21 @@ pub struct Claims { } impl Claims { - pub fn new(user: UserModel, client: ClientModel, resource_group: ResourceGroupModel, resources: Vec) -> Self { + pub fn new( + user: UserModel, + client: ClientModel, + resource_group: ResourceGroupModel, + resources: Vec, + session: SessionModel, + ) -> Self { let user = TokenUser::from(user, client, resource_group, resources); + Self { - exp: (chrono::Local::now() + chrono::Duration::days(30)).timestamp() as usize, + exp: session.expires.timestamp() as usize, iat: chrono::Local::now().timestamp() as usize, sub: user.sub, + sid: session.id, + iss: SETTINGS.read().server.host.clone(), first_name: user.first_name, last_name: user.last_name, email: user.email, @@ -107,10 +121,11 @@ pub fn create( client: ClientModel, resource_group: ResourceGroupModel, resources: Vec, + session: SessionModel, secret: &str, ) -> Result { let encoding_key = EncodingKey::from_secret(secret.as_ref()); - let claims = Claims::new(user, client, resource_group, resources); + let claims = Claims::new(user, client, resource_group, resources, session); jsonwebtoken::encode(&HEADER, &claims, &encoding_key) } diff --git a/src/services/client.rs b/src/services/client.rs index 0d43cb5..def4d79 100644 --- a/src/services/client.rs +++ b/src/services/client.rs @@ -37,7 +37,7 @@ pub async fn update_client_by_id(db: &DatabaseConnection, client_id: Uuid, paylo match client { Some(client) => { let locked_at = match payload.lock { - Some(true) => Some(client.locked_at.unwrap_or_else(|| Utc::now().naive_utc())), + Some(true) => Some(client.locked_at.unwrap_or_else(|| Utc::now().into())), Some(false) => None, None => client.locked_at, }; diff --git a/src/services/realm.rs b/src/services/realm.rs index 843361e..5da8979 100644 --- a/src/services/realm.rs +++ b/src/services/realm.rs @@ -36,7 +36,7 @@ pub async fn update_realm_by_id(db: &DatabaseConnection, id: Uuid, payload: Upda match realm { Some(realm) => { let locked_at = match payload.lock { - Some(true) => Some(realm.locked_at.unwrap_or_else(|| Utc::now().naive_utc())), + Some(true) => Some(realm.locked_at.unwrap_or_else(|| Utc::now().into())), Some(false) => None, None => realm.locked_at, }; From af2cea7ac5a29cafb308a67f1401562df7edffc0 Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Sun, 29 Sep 2024 20:34:51 +0530 Subject: [PATCH 33/45] fix: logout and introspect routes done --- src/handlers/auth.rs | 206 ++++++++++++++++++++++++++++++++++++++++-- src/mappers/auth.rs | 28 ++++++ src/packages/token.rs | 9 +- src/routes/auth.rs | 7 +- 4 files changed, 234 insertions(+), 16 deletions(-) diff --git a/src/handlers/auth.rs b/src/handlers/auth.rs index 13780d2..16b379b 100644 --- a/src/handlers/auth.rs +++ b/src/handlers/auth.rs @@ -1,21 +1,22 @@ -use chrono::{FixedOffset, Utc}; +use chrono::Utc; use sea_orm::{ActiveModelTrait, Set}; use std::sync::Arc; use crate::{ database::{ + client, prelude::{Client, Resource, ResourceGroup, Session, User}, - resource, resource_group, session, - session::ActiveModel as SessionActiveModel, + resource, resource_group, + session::{self, ActiveModel as SessionActiveModel}, user::{self, Model}, }, - mappers::auth::{CreateUserRequest, LogoutResponse}, + mappers::auth::{CreateUserRequest, IntrospectRequest, IntrospectResponse, LogoutRequest, LogoutResponse}, middleware::session_info_extractor::SessionInfo, packages::{ db::AppState, errors::{AuthenticateError, Error}, settings::SETTINGS, - token::{create, TokenUser}, + token::{create, decode, TokenUser}, }, services::user::insert_user, utils::role_checker::{is_current_realm_admin, is_master_realm_admin}, @@ -94,6 +95,7 @@ pub async fn login( let sessions = Session::find() .filter(session::Column::ClientId.eq(client.id)) .filter(session::Column::UserId.eq(user.id)) + .filter(session::Column::Expires.gt(chrono::Utc::now())) .count(&state.db) .await?; @@ -160,11 +162,195 @@ pub async fn register( } } -pub async fn logout(user: TokenUser, Extension(_state): Extension>) -> Result, Error> { - Ok(Json(LogoutResponse { ok: true, user_id: user.sub })) +pub async fn logout_current_session(user: TokenUser, Extension(state): Extension>) -> Result, Error> { + let result = Session::delete_by_id(user.sid).exec(&state.db).await?; + Ok(Json(LogoutResponse { + ok: result.rows_affected == 1, + user_id: user.sub, + session_id: user.sid, + })) +} + +pub async fn logout( + user: TokenUser, + Extension(state): Extension>, + Path((realm_id, _)): Path<(Uuid, Uuid)>, + Json(payload): Json, +) -> Result, Error> { + if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { + match payload.access_token { + Some(access_token) => { + let sid = decode(&access_token, &SETTINGS.read().secrets.signing_key) + .map_err(|_| AuthenticateError::InvalidToken)? + .claims + .sid; + let result = Session::delete_by_id(sid).exec(&state.db).await?; + Ok(Json(LogoutResponse { + ok: result.rows_affected == 1, + user_id: user.sub, + session_id: user.sid, + })) + } + None => match payload.refresh_token { + Some(refresh_token) => { + let sid = decode(&refresh_token, &SETTINGS.read().secrets.signing_key) + .map_err(|_| AuthenticateError::InvalidToken)? + .claims + .sid; + let result = Session::delete_by_id(sid).exec(&state.db).await?; + Ok(Json(LogoutResponse { + ok: result.rows_affected == 1, + user_id: user.sub, + session_id: user.sid, + })) + } + None => Err(Error::Authenticate(AuthenticateError::NoResource)), + }, + } + } else { + Err(Error::Authenticate(AuthenticateError::ActionForbidden)) + } +} + +pub async fn logout_my_all_sessions( + user: TokenUser, + Extension(state): Extension>, + Path((_, client_id)): Path<(Uuid, Uuid)>, +) -> Result, Error> { + let result = Session::delete_many() + .filter(session::Column::ClientId.eq(client_id)) + .filter(session::Column::UserId.eq(user.sub)) + .exec(&state.db) + .await?; + Ok(Json(LogoutResponse { + ok: result.rows_affected > 0, + user_id: user.sub, + session_id: user.sid, + })) +} + +pub async fn logout_all( + user: TokenUser, + Extension(state): Extension>, + Path((realm_id, client_id)): Path<(Uuid, Uuid)>, + Json(payload): Json, +) -> Result, Error> { + if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { + match payload.access_token { + Some(access_token) => { + let sub = decode(&access_token, &SETTINGS.read().secrets.signing_key) + .map_err(|_| AuthenticateError::InvalidToken)? + .claims + .sub; + let result = Session::delete_many() + .filter(session::Column::ClientId.eq(client_id)) + .filter(session::Column::UserId.eq(sub)) + .exec(&state.db) + .await?; + Ok(Json(LogoutResponse { + ok: result.rows_affected > 0, + user_id: user.sub, + session_id: user.sid, + })) + } + None => match payload.refresh_token { + Some(refresh_token) => { + let sub = decode(&refresh_token, &SETTINGS.read().secrets.signing_key) + .map_err(|_| AuthenticateError::InvalidToken)? + .claims + .sub; + let result = Session::delete_many() + .filter(session::Column::ClientId.eq(client_id)) + .filter(session::Column::UserId.eq(sub)) + .exec(&state.db) + .await?; + Ok(Json(LogoutResponse { + ok: result.rows_affected > 0, + user_id: user.sub, + session_id: user.sid, + })) + } + None => Err(Error::Authenticate(AuthenticateError::NoResource)), + }, + } + } else { + Err(Error::Authenticate(AuthenticateError::ActionForbidden)) + } } -pub async fn verify() { - debug!("🚀 Verify request received!"); - todo!(); +pub async fn introspect( + user: TokenUser, + Extension(state): Extension>, + Path((realm_id, client_id)): Path<(Uuid, Uuid)>, + Json(payload): Json, +) -> Result, Error> { + if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { + let token_data = decode(&payload.access_token, &SETTINGS.read().secrets.signing_key).expect("Failed to decode token"); + + if token_data.claims.resource.is_none() || token_data.claims.resource.is_some() && token_data.claims.resource.unwrap().client_id != client_id + { + return Err(Error::Authenticate(AuthenticateError::NoResource)); + } + + let session = Session::find_by_id(token_data.claims.sid).one(&state.db).await?; + match session { + Some(session) => { + let user = User::find_by_id(session.user_id) + .filter(user::Column::LockedAt.is_null()) + .one(&state.db) + .await?; + + match user { + Some(user) => { + let client = Client::find_by_id(session.client_id) + .filter(client::Column::LockedAt.is_null()) + .one(&state.db) + .await?; + + match client { + Some(client) => { + let resource_group = ResourceGroup::find() + .filter(resource_group::Column::RealmId.eq(realm_id)) + .filter(resource_group::Column::ClientId.eq(client.id)) + .filter(resource_group::Column::UserId.eq(user.id)) + .filter(resource_group::Column::LockedAt.is_null()) + .one(&state.db) + .await?; + + match resource_group { + Some(resource_group) => { + let resources = Resource::find() + .filter(resource::Column::GroupId.eq(resource_group.id)) + .filter(resource::Column::LockedAt.is_null()) + .all(&state.db) + .await?; + Ok(Json(IntrospectResponse { + active: true, + client_id: client.id, + first_name: user.first_name.to_string(), + last_name: Some(user.last_name.unwrap_or("".to_string())), + sub: user.id, + token_type: "bearer".to_string(), + exp: token_data.claims.exp, + iat: token_data.claims.iat, + iss: SETTINGS.read().server.host.clone(), + client_name: client.name, + resource_group: resource_group.name, + resources: resources.iter().map(|r| r.name.clone()).collect::>(), + })) + } + None => Err(Error::Authenticate(AuthenticateError::NoResource))?, + } + } + None => Err(Error::Authenticate(AuthenticateError::NoResource)), + } + } + None => Err(Error::Authenticate(AuthenticateError::NoResource)), + } + } + None => Err(Error::Authenticate(AuthenticateError::NoResource)), + } + } else { + Err(Error::Authenticate(AuthenticateError::ActionForbidden)) + } } diff --git a/src/mappers/auth.rs b/src/mappers/auth.rs index 5836e9c..c405454 100644 --- a/src/mappers/auth.rs +++ b/src/mappers/auth.rs @@ -20,8 +20,36 @@ pub struct CreateUserRequest { pub resource: ResourceSubset, } +#[derive(Deserialize)] +pub struct LogoutRequest { + pub access_token: Option, + pub refresh_token: Option, +} + #[derive(Serialize)] pub struct LogoutResponse { pub ok: bool, pub user_id: Uuid, + pub session_id: Uuid, +} + +#[derive(Deserialize)] +pub struct IntrospectRequest { + pub access_token: String, +} + +#[derive(Serialize)] +pub struct IntrospectResponse { + pub active: bool, + pub client_id: Uuid, + pub sub: Uuid, + pub first_name: String, + pub last_name: Option, + pub token_type: String, + pub exp: usize, + pub iat: usize, + pub iss: String, + pub client_name: String, + pub resource_group: String, + pub resources: Vec, } diff --git a/src/packages/token.rs b/src/packages/token.rs index 2f1eec4..1a8d0ac 100644 --- a/src/packages/token.rs +++ b/src/packages/token.rs @@ -43,6 +43,7 @@ impl Resource { #[derive(Debug, Serialize, Deserialize)] pub struct TokenUser { pub sub: Uuid, + pub sid: Uuid, #[serde(rename = "firstName")] pub first_name: String, #[serde(rename = "lastName")] @@ -54,9 +55,10 @@ pub struct TokenUser { } impl TokenUser { - fn from(user: UserModel, client: ClientModel, resource_group: ResourceGroupModel, resources: Vec) -> Self { + fn from(user: UserModel, client: ClientModel, resource_group: ResourceGroupModel, resources: Vec, session: &SessionModel) -> Self { Self { sub: user.id, + sid: session.id, first_name: user.first_name.clone(), last_name: user.last_name.unwrap_or_else(|| "".into()), email: user.email.clone(), @@ -68,6 +70,7 @@ impl TokenUser { pub fn from_claim(claims: Claims) -> Self { Self { sub: claims.sub, + sid: claims.sid, first_name: claims.first_name, last_name: claims.last_name, email: claims.email, @@ -99,13 +102,13 @@ impl Claims { resources: Vec, session: SessionModel, ) -> Self { - let user = TokenUser::from(user, client, resource_group, resources); + let user = TokenUser::from(user, client, resource_group, resources, &session); Self { exp: session.expires.timestamp() as usize, iat: chrono::Local::now().timestamp() as usize, sub: user.sub, - sid: session.id, + sid: user.sid, iss: SETTINGS.read().server.host.clone(), first_name: user.first_name, last_name: user.last_name, diff --git a/src/routes/auth.rs b/src/routes/auth.rs index e9470a8..0b7eea1 100644 --- a/src/routes/auth.rs +++ b/src/routes/auth.rs @@ -5,15 +5,16 @@ use axum::{ }; use crate::{ - handlers::auth::{login, logout, register, verify}, + handlers::auth::{introspect, login, logout, logout_all, logout_current_session, logout_my_all_sessions, register}, middleware::session_info_extractor::session_info_middleware, }; pub fn create_routes() -> Router { Router::new() .route("/login", post(login)) - .route("/logout", get(logout)) + .route("/logout", get(logout_current_session).post(logout)) + .route("/logout-all", get(logout_my_all_sessions).post(logout_all)) .route("/register", post(register)) - .route("/verify", post(verify)) + .route("/introspect", post(introspect)) .layer(middleware::from_fn(session_info_middleware)) } From 4176c665dddc0124b5c4c7bb7d4f46505b28006b Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Sun, 29 Sep 2024 21:16:23 +0530 Subject: [PATCH 34/45] fix: realm and client update functions updatec --- src/mappers/client.rs | 4 ++++ src/mappers/realm.rs | 4 ++++ src/services/client.rs | 16 ++++++++++++++++ src/services/realm.rs | 13 +++++++++++++ 4 files changed, 37 insertions(+) diff --git a/src/mappers/client.rs b/src/mappers/client.rs index 7625804..129dbca 100644 --- a/src/mappers/client.rs +++ b/src/mappers/client.rs @@ -11,4 +11,8 @@ pub struct CreateClientRequest { pub struct UpdateClientRequest { pub name: String, pub lock: Option, + pub max_concurrent_sessions: Option, + pub session_lifetime: Option, // in seconds + pub refresh_token_lifetime: Option, // in seconds + pub refresh_token_reuse_limit: Option, } diff --git a/src/mappers/realm.rs b/src/mappers/realm.rs index 793214a..74dcd09 100644 --- a/src/mappers/realm.rs +++ b/src/mappers/realm.rs @@ -9,4 +9,8 @@ pub struct CreateRealmRequest { pub struct UpdateRealmRequest { pub name: String, pub lock: Option, + pub max_concurrent_sessions: Option, + pub session_lifetime: Option, // in seconds + pub refresh_token_lifetime: Option, // in seconds + pub refresh_token_reuse_limit: Option, } diff --git a/src/services/client.rs b/src/services/client.rs index def4d79..a3e11db 100644 --- a/src/services/client.rs +++ b/src/services/client.rs @@ -45,6 +45,22 @@ pub async fn update_client_by_id(db: &DatabaseConnection, client_id: Uuid, paylo let updated_client = ActiveModel { id: Set(client.id), name: Set(payload.name), + max_concurrent_sessions: Set(match payload.max_concurrent_sessions { + Some(max_concurrent_sessions) => max_concurrent_sessions, + None => client.max_concurrent_sessions, + }), + session_lifetime: Set(match payload.session_lifetime { + Some(session_lifetime) => session_lifetime, + None => client.session_lifetime, + }), + refresh_token_lifetime: Set(match payload.refresh_token_lifetime { + Some(refresh_token_lifetime) => refresh_token_lifetime, + None => client.refresh_token_lifetime, + }), + refresh_token_reuse_limit: Set(match payload.refresh_token_reuse_limit { + Some(refresh_token_reuse_limit) => refresh_token_reuse_limit, + None => client.refresh_token_reuse_limit, + }), locked_at: Set(locked_at), ..Default::default() }; diff --git a/src/services/realm.rs b/src/services/realm.rs index 5da8979..6b6736b 100644 --- a/src/services/realm.rs +++ b/src/services/realm.rs @@ -44,6 +44,19 @@ pub async fn update_realm_by_id(db: &DatabaseConnection, id: Uuid, payload: Upda let updated_realm = ActiveModel { id: Set(realm.id), name: Set(payload.name), + max_concurrent_sessions: Set(payload.max_concurrent_sessions), + session_lifetime: Set(match payload.session_lifetime { + Some(session_lifetime) => session_lifetime, + None => realm.session_lifetime, + }), + refresh_token_lifetime: Set(match payload.refresh_token_lifetime { + Some(refresh_token_lifetime) => refresh_token_lifetime, + None => realm.refresh_token_lifetime, + }), + refresh_token_reuse_limit: Set(match payload.refresh_token_reuse_limit { + Some(refresh_token_reuse_limit) => refresh_token_reuse_limit, + None => realm.refresh_token_reuse_limit, + }), locked_at: Set(locked_at), ..Default::default() }; From d4d4b71b451fcc8dcfc0a9a330a57d63ac6b995a Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Sun, 29 Sep 2024 23:29:41 +0530 Subject: [PATCH 35/45] fix: containerization is in progress --- .dockerignore | 6 ++++++ Dockerfile | 41 +++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 27 +++++++++++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..25c2274 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +.circleci +.github +.vscode +.idea +.git +target diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7a21cb9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,41 @@ +# Use the official Rust image as the base image for building +FROM rust:latest as builder + +# Set the working directory in the container +WORKDIR /usr/src/shield + +# Copy the Cargo.toml and Cargo.lock files +COPY Cargo.toml Cargo.lock ./ + +# Copy the source code and other necessary files +COPY src ./src +COPY config ./config +COPY migrations ./migrations + +# Build the application +RUN cargo build --release + +# Use Ubuntu 22.04 as the base image for the runtime stage +FROM ubuntu:22.04 + +# Install necessary dependencies +RUN apt-get update && apt-get install -y libpq-dev && rm -rf /var/lib/apt/lists/* + +# Copy the built executable from the builder stage +COPY --from=builder /usr/src/shield/target/release/shield /usr/local/bin/shield + +# Copy configuration files +COPY --from=builder /usr/src/shield/config /usr/local/bin/config + +# Copy schema.sql +COPY --from=builder /usr/src/shield/migrations /usr/local/bin/migrations + +# Set the working directory +WORKDIR /usr/local/bin + +# Set the environment variable for the application name +ENV CARGO_PKG_NAME=shield + + +# Set the startup command +CMD ["shield"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..e197ff4 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,27 @@ +version: '3.8' + +services: + shield: + build: . + ports: + - "5555:5555" # Adjust the port as needed + depends_on: + - db + environment: + - DATABASE_URL=postgres://postgres:1234@db:5435/shield + + db: + image: postgres:17 + # command: ["postgres", "-c", "custom_command=/usr/local/bin/migrations/up.sql"] + command: ["postgres", "-c", "fsync=off", "-c", "shared_buffers=128MB", "-c", "work_mem=64MB", "-c", "checkpoint_timeout=5min", "-c", "wal_level=hot_standby", "-c", "archive_mode=always", "-c", "archive_command='test ! -d /var/lib/postgresql/archive && mkdir /var/lib/postgresql/archive; cp %p /var/lib/postgresql/archive/%f'"] + volumes: + - postgres_data:/var/lib/postgresql/data + environment: + - POSTGRES_USER=postgres + - POSTGRES_PASSWORD=1234 + - POSTGRES_DB=shield + ports: + - "5435:5432" + +volumes: + postgres_data: \ No newline at end of file From 13733e4282c03c05b20754c62e13c8fe7659ca87 Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Mon, 30 Sep 2024 19:17:26 +0530 Subject: [PATCH 36/45] fix: workspace created and database segrated, db and admin initialization done --- Cargo.lock | 632 +++++++++++++++--- Cargo.toml | 10 +- config/env/default.yml | 2 +- diesel.toml | 9 - entity/Cargo.toml | 9 + entity/src/lib.rs | 4 + entity/src/middlewares/mod.rs | 1 + entity/src/middlewares/realm.rs | 21 + entity/src/models/client.rs | 58 ++ entity/src/models/mod.rs | 10 + entity/src/models/prelude.rs | 8 + entity/src/models/realm.rs | 49 ++ entity/src/models/resource.rs | 38 ++ entity/src/models/resource_group.rs | 78 +++ entity/src/models/session.rs | 58 ++ entity/src/models/user.rs | 61 ++ migration/Cargo.toml | 22 + migration/README.md | 41 ++ migration/src/lib.rs | 24 + .../m20220101_000001_create_realm_table.rs | 58 ++ .../m20220101_000002_create_client_table.rs | 69 ++ .../src/m20220101_000003_create_user_table.rs | 74 ++ ...0101_000004_create_resource_group_table.rs | 90 +++ .../m20220101_000005_create_resource_table.rs | 69 ++ .../m20220101_000006_create_session_table.rs | 80 +++ migration/src/main.rs | 6 + src/packages/admin.rs | 129 ++-- src/packages/db.rs | 48 +- src/packages/settings.rs | 9 +- 29 files changed, 1607 insertions(+), 160 deletions(-) delete mode 100644 diesel.toml create mode 100644 entity/Cargo.toml create mode 100644 entity/src/lib.rs create mode 100644 entity/src/middlewares/mod.rs create mode 100644 entity/src/middlewares/realm.rs create mode 100644 entity/src/models/client.rs create mode 100644 entity/src/models/mod.rs create mode 100644 entity/src/models/prelude.rs create mode 100644 entity/src/models/realm.rs create mode 100644 entity/src/models/resource.rs create mode 100644 entity/src/models/resource_group.rs create mode 100644 entity/src/models/session.rs create mode 100644 entity/src/models/user.rs create mode 100644 migration/Cargo.toml create mode 100644 migration/README.md create mode 100644 migration/src/lib.rs create mode 100644 migration/src/m20220101_000001_create_realm_table.rs create mode 100644 migration/src/m20220101_000002_create_client_table.rs create mode 100644 migration/src/m20220101_000003_create_user_table.rs create mode 100644 migration/src/m20220101_000004_create_resource_group_table.rs create mode 100644 migration/src/m20220101_000005_create_resource_table.rs create mode 100644 migration/src/m20220101_000006_create_session_table.rs create mode 100644 migration/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 31ccf89..f4406a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -92,12 +92,94 @@ dependencies = [ "libc", ] +[[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "anstyle-parse" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + [[package]] name = "arrayvec" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "async-attributes" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + [[package]] name = "async-compression" version = "0.4.12" @@ -111,6 +193,92 @@ dependencies = [ "tokio", ] +[[package]] +name = "async-executor" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" +dependencies = [ + "async-channel 2.3.1", + "async-executor", + "async-io", + "async-lock", + "blocking", + "futures-lite", + "once_cell", + "tokio", +] + +[[package]] +name = "async-io" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" +dependencies = [ + "async-lock", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix", + "slab", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener 5.3.1", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-std" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c634475f29802fde2b8f0b505b1bd00dfe4df7d4a000f0b36f7671197d5c3615" +dependencies = [ + "async-attributes", + "async-channel 1.9.0", + "async-global-executor", + "async-io", + "async-lock", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + [[package]] name = "async-stream" version = "0.3.5" @@ -133,6 +301,12 @@ dependencies = [ "syn 2.0.77", ] +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + [[package]] name = "async-trait" version = "0.1.82" @@ -153,6 +327,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.3.0" @@ -324,6 +504,19 @@ dependencies = [ "generic-array", ] +[[package]] +name = "blocking" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +dependencies = [ + "async-channel 2.3.1", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + [[package]] name = "blowfish" version = "0.9.1" @@ -465,6 +658,61 @@ dependencies = [ "inout", ] +[[package]] +name = "clap" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + +[[package]] +name = "colorchoice" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "config" version = "0.14.0" @@ -587,25 +835,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "cuid-util" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d59a706635108a7e8eaae7ec8e6154504fafa4a415ef38690d94fccea051757" - -[[package]] -name = "cuid2" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50e281dc36864ea88fae2ec4e21eb280e8239487acb1ddc59b528b0afa7997bd" -dependencies = [ - "cuid-util", - "getrandom", - "num", - "rand", - "sha3", -] - [[package]] name = "der" version = "0.7.9" @@ -640,6 +869,12 @@ dependencies = [ "syn 2.0.77", ] +[[package]] +name = "deunicode" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339544cc9e2c4dc3fc7149fd630c5f22263a4fdf18a98afd0075784968b5cf00" + [[package]] name = "digest" version = "0.10.7" @@ -688,6 +923,14 @@ dependencies = [ "serde", ] +[[package]] +name = "entity" +version = "0.1.0" +dependencies = [ + "sea-orm", + "slug", +] + [[package]] name = "enum-ordinalize" version = "4.3.0" @@ -741,6 +984,27 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener 5.3.1", + "pin-project-lite", +] + [[package]] name = "fastrand" version = "2.1.1" @@ -838,6 +1102,19 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +[[package]] +name = "futures-lite" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + [[package]] name = "futures-macro" version = "0.3.30" @@ -908,6 +1185,24 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -975,12 +1270,24 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "hex" version = "0.4.3" @@ -1159,6 +1466,12 @@ dependencies = [ "generic-array", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itoa" version = "1.0.11" @@ -1201,12 +1514,12 @@ dependencies = [ ] [[package]] -name = "keccak" -version = "0.1.5" +name = "kv-log-macro" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" dependencies = [ - "cpufeatures", + "log", ] [[package]] @@ -1268,6 +1581,18 @@ name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +dependencies = [ + "value-bag", +] + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] [[package]] name = "matchit" @@ -1291,6 +1616,14 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "migration" +version = "0.1.0" +dependencies = [ + "async-std", + "sea-orm-migration", +] + [[package]] name = "mime" version = "0.3.17" @@ -1318,7 +1651,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", "wasi", "windows-sys 0.52.0", @@ -1344,20 +1677,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "num" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - [[package]] name = "num-bigint" version = "0.4.6" @@ -1385,15 +1704,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - [[package]] name = "num-conv" version = "0.1.0" @@ -1420,17 +1730,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -1452,9 +1751,12 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1" +dependencies = [ + "portable-atomic", +] [[package]] name = "ordered-float" @@ -1492,7 +1794,7 @@ version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec4c6225c69b4ca778c0aea097321a64c421cf4577b331c61b229267edabb6f8" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro-error", "proc-macro2", "quote", @@ -1505,6 +1807,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + [[package]] name = "parking_lot" version = "0.12.3" @@ -1642,6 +1950,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + [[package]] name = "pkcs1" version = "0.7.5" @@ -1669,6 +1988,27 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +[[package]] +name = "polling" +version = "3.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.4.0", + "pin-project-lite", + "rustix", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "portable-atomic" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" + [[package]] name = "powerfmt" version = "0.2.0" @@ -1808,8 +2148,17 @@ checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", - "regex-automata", - "regex-syntax", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", ] [[package]] @@ -1820,9 +2169,15 @@ checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.8.4", ] +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.8.4" @@ -2032,7 +2387,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bd3534a9978d0aa7edd2808dc1f8f31c4d0ecd31ddf71d997b3c98e9f3c9114" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro-error", "proc-macro2", "quote", @@ -2067,13 +2422,30 @@ dependencies = [ "uuid", ] +[[package]] +name = "sea-orm-cli" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0b8869c75cf3fbb1bd860abb025033cd2e514c5f4fa43e792697cb1fe6c882" +dependencies = [ + "chrono", + "clap", + "dotenvy", + "glob", + "regex", + "sea-schema", + "tracing", + "tracing-subscriber", + "url", +] + [[package]] name = "sea-orm-macros" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8737b566799ed0444f278d13c300c4c6f1a91782f60ff5825a591852d5502030" dependencies = [ - "heck", + "heck 0.4.1", "proc-macro2", "quote", "sea-bae", @@ -2081,6 +2453,23 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sea-orm-migration" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216643749e26ce27ab6c51d3475f2692981d4a902d34455bcd322f412900df5c" +dependencies = [ + "async-trait", + "clap", + "dotenvy", + "futures", + "sea-orm", + "sea-orm-cli", + "sea-schema", + "tracing", + "tracing-subscriber", +] + [[package]] name = "sea-query" version = "0.31.0" @@ -2093,6 +2482,7 @@ dependencies = [ "inherent", "ordered-float", "rust_decimal", + "sea-query-derive", "serde_json", "time", "uuid", @@ -2114,6 +2504,42 @@ dependencies = [ "uuid", ] +[[package]] +name = "sea-query-derive" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25a82fcb49253abcb45cdcb2adf92956060ec0928635eb21b4f7a6d8f25ab0bc" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 2.0.77", + "thiserror", +] + +[[package]] +name = "sea-schema" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad52149fc81836ea7424c3425d8f6ed8ad448dd16d2e4f6a3907ba46f3f2fd78" +dependencies = [ + "futures", + "sea-query", + "sea-schema-derive", +] + +[[package]] +name = "sea-schema-derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "debdc8729c37fdbf88472f97fd470393089f997a909e535ff67c544d18cfccf0" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 2.0.77", +] + [[package]] name = "seahash" version = "4.1.0" @@ -2224,16 +2650,6 @@ dependencies = [ "digest", ] -[[package]] -name = "sha3" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" -dependencies = [ - "digest", - "keccak", -] - [[package]] name = "sharded-slab" version = "0.1.7" @@ -2252,13 +2668,15 @@ dependencies = [ "bcrypt", "chrono", "config", - "cuid2", "dotenvy", + "entity", "futures", "jsonwebtoken", + "migration", "once_cell", "parking_lot", "sea-orm", + "sea-orm-migration", "serde", "serde_json", "thiserror", @@ -2267,6 +2685,7 @@ dependencies = [ "tracing", "tracing-subscriber", "uaparser", + "uuid", ] [[package]] @@ -2321,6 +2740,16 @@ dependencies = [ "autocfg", ] +[[package]] +name = "slug" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882a80f72ee45de3cc9a5afeb2da0331d58df69e4e7d8eeb5d3c7784ae67e724" +dependencies = [ + "deunicode", + "wasm-bindgen", +] + [[package]] name = "smallvec" version = "1.13.2" @@ -2394,7 +2823,7 @@ dependencies = [ "crc", "crossbeam-queue", "either", - "event-listener", + "event-listener 2.5.3", "futures-channel", "futures-core", "futures-intrusive", @@ -2447,7 +2876,7 @@ checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8" dependencies = [ "dotenvy", "either", - "heck", + "heck 0.4.1", "hex", "once_cell", "proc-macro2", @@ -2599,6 +3028,12 @@ dependencies = [ "unicode-properties", ] +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "strum" version = "0.26.3" @@ -2961,10 +3396,14 @@ version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ + "matchers", "nu-ansi-term", + "once_cell", + "regex", "sharded-slab", "smallvec", "thread_local", + "tracing", "tracing-core", "tracing-log", ] @@ -3063,12 +3502,19 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "uuid" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ + "getrandom", "serde", ] @@ -3078,6 +3524,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "value-bag" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" + [[package]] name = "vcpkg" version = "0.2.15" @@ -3128,6 +3580,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.93" @@ -3157,6 +3621,16 @@ version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +[[package]] +name = "web-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "webpki-roots" version = "0.25.4" diff --git a/Cargo.toml b/Cargo.toml index 0b878e2..192d9b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,23 +3,28 @@ name = "shield" version = "0.1.0" edition = "2021" +[workspace] +members = [".", "entity", "migration"] + [dependencies] +entity = { path = "entity" } +migration = { path = "migration" } axum = "0.7.7" axum-extra = { version = "0.9.4", features = ["typed-header"] } bcrypt = "0.15.1" chrono = { version = "0.4.38", features = ["serde"] } config = { version = "0.14.0", features = ["yaml"] } -cuid2 = "0.1.3" dotenvy = "0.15.7" futures = "0.3.30" jsonwebtoken = "9.3.0" -once_cell = "1.19.0" +once_cell = "1.20.1" parking_lot = "0.12.3" sea-orm = { version = "1.0.1", features = [ "macros", "runtime-tokio-rustls", "sqlx-postgres", ] } +sea-orm-migration = "1.0.1" serde = { version = "1.0.210", features = ["derive"] } serde_json = "1.0.128" thiserror = "1.0.64" @@ -34,3 +39,4 @@ tower-http = { version = "0.6.1", features = [ tracing = "0.1.40" tracing-subscriber = "0.3.18" uaparser = "0.6.4" +uuid = { version = "1.10.0", features = ["v7"] } diff --git a/config/env/default.yml b/config/env/default.yml index 276f0d3..741d548 100644 --- a/config/env/default.yml +++ b/config/env/default.yml @@ -4,7 +4,7 @@ server: domain: localhost host: http://localhost:5555 database: - uri: "postgres://postgres:1234@localhost:5432/shield" + uri: "postgres://postgres:1234@localhost:5432" name: shield secrets: signing_key: secret diff --git a/diesel.toml b/diesel.toml deleted file mode 100644 index aaef931..0000000 --- a/diesel.toml +++ /dev/null @@ -1,9 +0,0 @@ -# For documentation on how to configure this file, -# see https://diesel.rs/guides/configuring-diesel-cli - -[print_schema] -file = "src/schemas/db.rs" -custom_type_derives = ["diesel::query_builder::QueryId", "Clone"] - -[migrations_directory] -dir = "migrations" diff --git a/entity/Cargo.toml b/entity/Cargo.toml new file mode 100644 index 0000000..8c97bec --- /dev/null +++ b/entity/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "entity" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +sea-orm = { version = "1.0.1" } +slug = "0.1.6" diff --git a/entity/src/lib.rs b/entity/src/lib.rs new file mode 100644 index 0000000..f432ba9 --- /dev/null +++ b/entity/src/lib.rs @@ -0,0 +1,4 @@ +mod middlewares; +mod models; + +pub use models::*; diff --git a/entity/src/middlewares/mod.rs b/entity/src/middlewares/mod.rs new file mode 100644 index 0000000..abc366b --- /dev/null +++ b/entity/src/middlewares/mod.rs @@ -0,0 +1 @@ +pub mod realm; diff --git a/entity/src/middlewares/realm.rs b/entity/src/middlewares/realm.rs new file mode 100644 index 0000000..f1d42e6 --- /dev/null +++ b/entity/src/middlewares/realm.rs @@ -0,0 +1,21 @@ +use crate::models::realm::ActiveModel; +use async_trait::async_trait; +use sea_orm::{entity::prelude::*, ActiveValue}; +use slug::slugify; + +#[async_trait] +impl ActiveModelBehavior for ActiveModel { + /// Will be triggered before insert / update + async fn before_save(mut self, _db: &C, _insert: bool) -> Result + where + C: ConnectionTrait, + { + println!("🚀 Before save {:#?}", self); + if let ActiveValue::Set(ref name) = self.name { + let slug = slugify(name); + self.slug = ActiveValue::Set(slug); + } + + Ok(self) + } +} diff --git a/entity/src/models/client.rs b/entity/src/models/client.rs new file mode 100644 index 0000000..e662818 --- /dev/null +++ b/entity/src/models/client.rs @@ -0,0 +1,58 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "client")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, + #[sea_orm(unique)] + pub name: String, + pub two_factor_enabled_at: Option, + pub max_concurrent_sessions: Option, + pub session_lifetime: i32, + pub refresh_token_lifetime: i32, + pub refresh_token_reuse_limit: i32, + pub locked_at: Option, + #[sea_orm(unique)] + pub realm_id: Uuid, + pub created_at: DateTimeWithTimeZone, + pub updated_at: DateTimeWithTimeZone, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::realm::Entity", + from = "Column::RealmId", + to = "super::realm::Column::Id", + on_update = "NoAction", + on_delete = "Cascade" + )] + Realm, + #[sea_orm(has_one = "super::resource_group::Entity")] + ResourceGroup, + #[sea_orm(has_one = "super::session::Entity")] + Session, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Realm.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::ResourceGroup.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Session.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/entity/src/models/mod.rs b/entity/src/models/mod.rs new file mode 100644 index 0000000..67f3b19 --- /dev/null +++ b/entity/src/models/mod.rs @@ -0,0 +1,10 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 + +pub mod prelude; + +pub mod client; +pub mod realm; +pub mod resource; +pub mod resource_group; +pub mod session; +pub mod user; diff --git a/entity/src/models/prelude.rs b/entity/src/models/prelude.rs new file mode 100644 index 0000000..e8ce87e --- /dev/null +++ b/entity/src/models/prelude.rs @@ -0,0 +1,8 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 + +pub use super::client::Entity as Client; +pub use super::realm::Entity as Realm; +pub use super::resource::Entity as Resource; +pub use super::resource_group::Entity as ResourceGroup; +pub use super::session::Entity as Session; +pub use super::user::Entity as User; diff --git a/entity/src/models/realm.rs b/entity/src/models/realm.rs new file mode 100644 index 0000000..8607547 --- /dev/null +++ b/entity/src/models/realm.rs @@ -0,0 +1,49 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "realm")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, + #[sea_orm(unique)] + pub name: String, + #[sea_orm(unique)] + pub slug: String, + pub max_concurrent_sessions: Option, + pub session_lifetime: i32, + pub refresh_token_lifetime: i32, + pub refresh_token_reuse_limit: i32, + pub locked_at: Option, + pub created_at: DateTimeWithTimeZone, + pub updated_at: DateTimeWithTimeZone, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm(has_one = "super::client::Entity")] + Client, + #[sea_orm(has_one = "super::resource_group::Entity")] + ResourceGroup, + #[sea_orm(has_one = "super::user::Entity")] + User, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Client.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::ResourceGroup.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::User.def() + } +} diff --git a/entity/src/models/resource.rs b/entity/src/models/resource.rs new file mode 100644 index 0000000..98d012c --- /dev/null +++ b/entity/src/models/resource.rs @@ -0,0 +1,38 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "resource")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, + #[sea_orm(unique)] + pub group_id: Uuid, + pub name: String, + pub value: String, + pub description: Option, + pub locked_at: Option, + pub created_at: DateTimeWithTimeZone, + pub updated_at: DateTimeWithTimeZone, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::resource_group::Entity", + from = "Column::GroupId", + to = "super::resource_group::Column::Id", + on_update = "NoAction", + on_delete = "Cascade" + )] + ResourceGroup, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::ResourceGroup.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/entity/src/models/resource_group.rs b/entity/src/models/resource_group.rs new file mode 100644 index 0000000..d9d605c --- /dev/null +++ b/entity/src/models/resource_group.rs @@ -0,0 +1,78 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "resource_group")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, + #[sea_orm(unique)] + pub realm_id: Uuid, + #[sea_orm(unique)] + pub client_id: Uuid, + #[sea_orm(unique)] + pub user_id: Uuid, + pub name: String, + pub description: Option, + pub is_default: bool, + pub locked_at: Option, + pub created_at: DateTimeWithTimeZone, + pub updated_at: DateTimeWithTimeZone, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::client::Entity", + from = "Column::ClientId", + to = "super::client::Column::Id", + on_update = "NoAction", + on_delete = "Cascade" + )] + Client, + #[sea_orm( + belongs_to = "super::realm::Entity", + from = "Column::RealmId", + to = "super::realm::Column::Id", + on_update = "NoAction", + on_delete = "Cascade" + )] + Realm, + #[sea_orm(has_one = "super::resource::Entity")] + Resource, + #[sea_orm( + belongs_to = "super::user::Entity", + from = "Column::UserId", + to = "super::user::Column::Id", + on_update = "NoAction", + on_delete = "Cascade" + )] + User, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Client.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Realm.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Resource.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::User.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/entity/src/models/session.rs b/entity/src/models/session.rs new file mode 100644 index 0000000..ed06bdc --- /dev/null +++ b/entity/src/models/session.rs @@ -0,0 +1,58 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "session")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, + #[sea_orm(unique)] + pub client_id: Uuid, + #[sea_orm(unique)] + pub user_id: Uuid, + pub ip_address: String, + pub user_agent: Option, + pub browser: Option, + pub browser_version: Option, + pub operating_system: Option, + pub device_type: Option, + pub country_code: String, + pub expires: DateTimeWithTimeZone, + pub created_at: DateTimeWithTimeZone, + pub updated_at: DateTimeWithTimeZone, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::client::Entity", + from = "Column::ClientId", + to = "super::client::Column::Id", + on_update = "NoAction", + on_delete = "Cascade" + )] + Client, + #[sea_orm( + belongs_to = "super::user::Entity", + from = "Column::UserId", + to = "super::user::Column::Id", + on_update = "NoAction", + on_delete = "Cascade" + )] + User, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Client.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::User.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/entity/src/models/user.rs b/entity/src/models/user.rs new file mode 100644 index 0000000..62c9afb --- /dev/null +++ b/entity/src/models/user.rs @@ -0,0 +1,61 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 + +use sea_orm::entity::prelude::*; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[sea_orm(table_name = "user")] +pub struct Model { + #[sea_orm(primary_key, auto_increment = false)] + pub id: Uuid, + pub first_name: String, + pub last_name: Option, + #[sea_orm(unique)] + pub email: String, + pub email_verified_at: Option, + pub phone: Option, + pub image: Option, + pub two_factor_enabled_at: Option, + pub password_hash: Option, + pub is_temp_password: bool, + pub locked_at: Option, + #[sea_orm(unique)] + pub realm_id: Uuid, + pub created_at: DateTimeWithTimeZone, + pub updated_at: DateTimeWithTimeZone, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation { + #[sea_orm( + belongs_to = "super::realm::Entity", + from = "Column::RealmId", + to = "super::realm::Column::Id", + on_update = "NoAction", + on_delete = "Cascade" + )] + Realm, + #[sea_orm(has_one = "super::resource_group::Entity")] + ResourceGroup, + #[sea_orm(has_one = "super::session::Entity")] + Session, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Realm.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::ResourceGroup.def() + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Session.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/migration/Cargo.toml b/migration/Cargo.toml new file mode 100644 index 0000000..2878ded --- /dev/null +++ b/migration/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "migration" +version = "0.1.0" +edition = "2021" +publish = false + +[lib] +name = "migration" +path = "src/lib.rs" + +[dependencies] +async-std = { version = "1", features = ["attributes", "tokio1"] } + +[dependencies.sea-orm-migration] +version = "1.0.1" +features = [ + # Enable at least one `ASYNC_RUNTIME` and `DATABASE_DRIVER` feature if you want to run migration via CLI. + # View the list of supported features at https://www.sea-ql.org/SeaORM/docs/install-and-config/database-and-async-runtime. + # e.g. + "runtime-tokio-rustls", # `ASYNC_RUNTIME` feature + "sqlx-postgres", # `DATABASE_DRIVER` feature +] diff --git a/migration/README.md b/migration/README.md new file mode 100644 index 0000000..3b438d8 --- /dev/null +++ b/migration/README.md @@ -0,0 +1,41 @@ +# Running Migrator CLI + +- Generate a new migration file + ```sh + cargo run -- generate MIGRATION_NAME + ``` +- Apply all pending migrations + ```sh + cargo run + ``` + ```sh + cargo run -- up + ``` +- Apply first 10 pending migrations + ```sh + cargo run -- up -n 10 + ``` +- Rollback last applied migrations + ```sh + cargo run -- down + ``` +- Rollback last 10 applied migrations + ```sh + cargo run -- down -n 10 + ``` +- Drop all tables from the database, then reapply all migrations + ```sh + cargo run -- fresh + ``` +- Rollback all applied migrations, then reapply all migrations + ```sh + cargo run -- refresh + ``` +- Rollback all applied migrations + ```sh + cargo run -- reset + ``` +- Check the status of all migrations + ```sh + cargo run -- status + ``` diff --git a/migration/src/lib.rs b/migration/src/lib.rs new file mode 100644 index 0000000..af6e533 --- /dev/null +++ b/migration/src/lib.rs @@ -0,0 +1,24 @@ +pub use sea_orm_migration::prelude::*; + +mod m20220101_000001_create_realm_table; +mod m20220101_000002_create_client_table; +mod m20220101_000003_create_user_table; +mod m20220101_000004_create_resource_group_table; +mod m20220101_000005_create_resource_table; +mod m20220101_000006_create_session_table; + +pub struct Migrator; + +#[async_trait::async_trait] +impl MigratorTrait for Migrator { + fn migrations() -> Vec> { + vec![ + Box::new(m20220101_000001_create_realm_table::Migration), + Box::new(m20220101_000002_create_client_table::Migration), + Box::new(m20220101_000003_create_user_table::Migration), + Box::new(m20220101_000004_create_resource_group_table::Migration), + Box::new(m20220101_000005_create_resource_table::Migration), + Box::new(m20220101_000006_create_session_table::Migration), + ] + } +} diff --git a/migration/src/m20220101_000001_create_realm_table.rs b/migration/src/m20220101_000001_create_realm_table.rs new file mode 100644 index 0000000..32098b6 --- /dev/null +++ b/migration/src/m20220101_000001_create_realm_table.rs @@ -0,0 +1,58 @@ +use sea_orm::{prelude::Uuid, sqlx::types::chrono}; +use sea_orm_migration::prelude::*; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_table( + Table::create() + .table(Realm::Table) + .if_not_exists() + .col(ColumnDef::new(Realm::Id).uuid().not_null().primary_key().default(Uuid::now_v7())) + .col(ColumnDef::new(Realm::Name).string().unique_key().not_null()) + .col(ColumnDef::new(Realm::Slug).string().unique_key().not_null()) + .col(ColumnDef::new(Realm::MaxConcurrentSessions).integer()) + .col(ColumnDef::new(Realm::SessionLifetime).integer().not_null().default(300)) + .col(ColumnDef::new(Realm::RefreshTokenLifetime).integer().not_null().default(3600)) + .col(ColumnDef::new(Realm::RefreshTokenReuseLimit).integer().not_null().default(0)) + .col(ColumnDef::new(Realm::LockedAt).timestamp_with_time_zone()) + .col( + ColumnDef::new(Realm::CreatedAt) + .timestamp_with_time_zone() + .not_null() + .default(chrono::Utc::now()), + ) + .col( + ColumnDef::new(Realm::UpdatedAt) + .timestamp_with_time_zone() + .not_null() + .default(chrono::Utc::now()), + ) + .to_owned(), + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager.drop_table(Table::drop().table(Realm::Table).to_owned()).await + } +} + +#[derive(DeriveIden)] +pub enum Realm { + Table, + Id, + Name, + Slug, + MaxConcurrentSessions, + SessionLifetime, + RefreshTokenLifetime, + RefreshTokenReuseLimit, + LockedAt, + CreatedAt, + UpdatedAt, +} diff --git a/migration/src/m20220101_000002_create_client_table.rs b/migration/src/m20220101_000002_create_client_table.rs new file mode 100644 index 0000000..03e6dc2 --- /dev/null +++ b/migration/src/m20220101_000002_create_client_table.rs @@ -0,0 +1,69 @@ +use super::m20220101_000001_create_realm_table::Realm; +use sea_orm::{prelude::Uuid, sqlx::types::chrono}; +use sea_orm_migration::prelude::*; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_table( + Table::create() + .table(Client::Table) + .if_not_exists() + .col(ColumnDef::new(Client::Id).uuid().not_null().primary_key().default(Uuid::now_v7())) + .col(ColumnDef::new(Client::Name).string().unique_key().not_null()) + .col(ColumnDef::new(Client::TwoFactorEnabledAt).timestamp_with_time_zone()) + .col(ColumnDef::new(Client::MaxConcurrentSessions).integer()) + .col(ColumnDef::new(Client::SessionLifetime).integer().not_null().default(300)) + .col(ColumnDef::new(Client::RefreshTokenLifetime).integer().not_null().default(3600)) + .col(ColumnDef::new(Client::RefreshTokenReuseLimit).integer().not_null().default(0)) + .col(ColumnDef::new(Client::LockedAt).timestamp_with_time_zone()) + .col(ColumnDef::new(Client::RealmId).uuid().not_null().unique_key()) + .foreign_key( + ForeignKey::create() + .name("fk_client_realm_id") + .from(Client::Table, Client::RealmId) + .to(Realm::Table, Realm::Id) + .on_delete(ForeignKeyAction::Cascade), + ) + .col( + ColumnDef::new(Client::CreatedAt) + .timestamp_with_time_zone() + .not_null() + .default(chrono::Utc::now()), + ) + .col( + ColumnDef::new(Client::UpdatedAt) + .timestamp_with_time_zone() + .not_null() + .default(chrono::Utc::now()), + ) + .index(Index::create().unique().name("realm_id_name_key").col(Client::Name).col(Client::RealmId)) + .to_owned(), + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager.drop_table(Table::drop().table(Client::Table).to_owned()).await + } +} + +#[derive(DeriveIden)] +pub enum Client { + Table, + Id, + Name, + TwoFactorEnabledAt, + MaxConcurrentSessions, + SessionLifetime, + RefreshTokenLifetime, + RefreshTokenReuseLimit, + LockedAt, + RealmId, + CreatedAt, + UpdatedAt, +} diff --git a/migration/src/m20220101_000003_create_user_table.rs b/migration/src/m20220101_000003_create_user_table.rs new file mode 100644 index 0000000..9927c8f --- /dev/null +++ b/migration/src/m20220101_000003_create_user_table.rs @@ -0,0 +1,74 @@ +use super::m20220101_000001_create_realm_table::Realm; +use sea_orm::{prelude::Uuid, sqlx::types::chrono}; +use sea_orm_migration::prelude::*; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_table( + Table::create() + .table(User::Table) + .if_not_exists() + .col(ColumnDef::new(User::Id).uuid().not_null().primary_key().default(Uuid::now_v7())) + .col(ColumnDef::new(User::FirstName).string().not_null()) + .col(ColumnDef::new(User::LastName).string()) + .col(ColumnDef::new(User::Email).unique_key().string().not_null()) + .col(ColumnDef::new(User::EmailVerifiedAt).timestamp_with_time_zone()) + .col(ColumnDef::new(User::Phone).string()) + .col(ColumnDef::new(User::Image).string()) + .col(ColumnDef::new(User::TwoFactorEnabledAt).timestamp_with_time_zone()) + .col(ColumnDef::new(User::PasswordHash).string()) + .col(ColumnDef::new(User::IsTempPassword).boolean().not_null().default(true)) + .col(ColumnDef::new(User::LockedAt).timestamp_with_time_zone()) + .col(ColumnDef::new(User::RealmId).uuid().not_null().unique_key()) + .foreign_key( + ForeignKey::create() + .name("fk_user_realm_id") + .from(User::Table, User::RealmId) + .to(Realm::Table, Realm::Id) + .on_delete(ForeignKeyAction::Cascade), + ) + .col( + ColumnDef::new(User::CreatedAt) + .timestamp_with_time_zone() + .not_null() + .default(chrono::Utc::now()), + ) + .col( + ColumnDef::new(User::UpdatedAt) + .timestamp_with_time_zone() + .not_null() + .default(chrono::Utc::now()), + ) + .to_owned(), + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager.drop_table(Table::drop().table(User::Table).to_owned()).await + } +} + +#[derive(DeriveIden)] +pub enum User { + Table, + Id, + FirstName, + LastName, + Email, + EmailVerifiedAt, + Phone, + Image, + TwoFactorEnabledAt, + PasswordHash, + IsTempPassword, + LockedAt, + RealmId, + CreatedAt, + UpdatedAt, +} diff --git a/migration/src/m20220101_000004_create_resource_group_table.rs b/migration/src/m20220101_000004_create_resource_group_table.rs new file mode 100644 index 0000000..acc3f9a --- /dev/null +++ b/migration/src/m20220101_000004_create_resource_group_table.rs @@ -0,0 +1,90 @@ +use super::m20220101_000001_create_realm_table::Realm; +use super::m20220101_000002_create_client_table::Client; +use super::m20220101_000003_create_user_table::User; +use sea_orm::{prelude::Uuid, sqlx::types::chrono}; +use sea_orm_migration::prelude::*; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_table( + Table::create() + .table(ResourceGroup::Table) + .if_not_exists() + .col(ColumnDef::new(ResourceGroup::Id).uuid().not_null().primary_key().default(Uuid::now_v7())) + .col(ColumnDef::new(ResourceGroup::RealmId).uuid().not_null().unique_key()) + .foreign_key( + ForeignKey::create() + .name("fk_resource_group_realm_id") + .from(ResourceGroup::Table, ResourceGroup::RealmId) + .to(Realm::Table, Realm::Id) + .on_delete(ForeignKeyAction::Cascade), + ) + .col(ColumnDef::new(ResourceGroup::ClientId).uuid().not_null().unique_key()) + .foreign_key( + ForeignKey::create() + .name("fk_resource_group_client_id") + .from(ResourceGroup::Table, ResourceGroup::ClientId) + .to(Client::Table, Client::Id) + .on_delete(ForeignKeyAction::Cascade), + ) + .col(ColumnDef::new(ResourceGroup::UserId).uuid().not_null().unique_key()) + .foreign_key( + ForeignKey::create() + .name("fk_resource_group_user_id") + .from(ResourceGroup::Table, ResourceGroup::UserId) + .to(User::Table, User::Id) + .on_delete(ForeignKeyAction::Cascade), + ) + .col(ColumnDef::new(ResourceGroup::Name).string().not_null()) + .col(ColumnDef::new(ResourceGroup::Description).string()) + .col(ColumnDef::new(ResourceGroup::IsDefault).boolean().not_null().default(false)) + .col(ColumnDef::new(ResourceGroup::LockedAt).timestamp_with_time_zone()) + .col( + ColumnDef::new(ResourceGroup::CreatedAt) + .timestamp_with_time_zone() + .not_null() + .default(chrono::Utc::now()), + ) + .col( + ColumnDef::new(ResourceGroup::UpdatedAt) + .timestamp_with_time_zone() + .not_null() + .default(chrono::Utc::now()), + ) + .index( + Index::create() + .unique() + .name("client_user_resource_group_name_idx") + .col(ResourceGroup::Name) + .col(ResourceGroup::ClientId) + .col(ResourceGroup::UserId), + ) + .to_owned(), + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager.drop_table(Table::drop().table(ResourceGroup::Table).to_owned()).await + } +} + +#[derive(DeriveIden)] +pub enum ResourceGroup { + Table, + Id, + RealmId, + ClientId, + UserId, + Name, + Description, + IsDefault, + LockedAt, + CreatedAt, + UpdatedAt, +} diff --git a/migration/src/m20220101_000005_create_resource_table.rs b/migration/src/m20220101_000005_create_resource_table.rs new file mode 100644 index 0000000..25fc0b2 --- /dev/null +++ b/migration/src/m20220101_000005_create_resource_table.rs @@ -0,0 +1,69 @@ +use super::m20220101_000004_create_resource_group_table::ResourceGroup; +use sea_orm::{prelude::Uuid, sqlx::types::chrono}; +use sea_orm_migration::prelude::*; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_table( + Table::create() + .table(Resource::Table) + .if_not_exists() + .col(ColumnDef::new(Resource::Id).uuid().not_null().primary_key().default(Uuid::now_v7())) + .col(ColumnDef::new(Resource::GroupId).uuid().not_null()) + .foreign_key( + ForeignKey::create() + .name("fk_resource_group_id") + .from(Resource::Table, Resource::GroupId) + .to(ResourceGroup::Table, ResourceGroup::Id) + .on_delete(ForeignKeyAction::Cascade), + ) + .col(ColumnDef::new(Resource::Name).string().not_null()) + .col(ColumnDef::new(Resource::Value).string().not_null()) + .col(ColumnDef::new(Resource::Description).string()) + .col(ColumnDef::new(Resource::LockedAt).timestamp_with_time_zone()) + .col( + ColumnDef::new(Resource::CreatedAt) + .timestamp_with_time_zone() + .not_null() + .default(chrono::Utc::now()), + ) + .col( + ColumnDef::new(Resource::UpdatedAt) + .timestamp_with_time_zone() + .not_null() + .default(chrono::Utc::now()), + ) + .index( + Index::create() + .unique() + .name("resource_group_id_and_resource_name_idx") + .col(Resource::Name) + .col(Resource::GroupId), + ) + .to_owned(), + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager.drop_table(Table::drop().table(Resource::Table).to_owned()).await + } +} + +#[derive(DeriveIden)] +pub enum Resource { + Table, + Id, + GroupId, + Name, + Value, + Description, + LockedAt, + CreatedAt, + UpdatedAt, +} diff --git a/migration/src/m20220101_000006_create_session_table.rs b/migration/src/m20220101_000006_create_session_table.rs new file mode 100644 index 0000000..b8f8005 --- /dev/null +++ b/migration/src/m20220101_000006_create_session_table.rs @@ -0,0 +1,80 @@ +use super::m20220101_000002_create_client_table::Client; +use super::m20220101_000003_create_user_table::User; +use sea_orm::{prelude::Uuid, sqlx::types::chrono}; +use sea_orm_migration::prelude::*; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_table( + Table::create() + .table(Session::Table) + .if_not_exists() + .col(ColumnDef::new(Session::Id).uuid().not_null().primary_key().default(Uuid::now_v7())) + .col(ColumnDef::new(Session::ClientId).uuid().not_null().unique_key()) + .foreign_key( + ForeignKey::create() + .name("fk_session_client_id") + .from(Session::Table, Session::ClientId) + .to(Client::Table, Client::Id) + .on_delete(ForeignKeyAction::Cascade), + ) + .col(ColumnDef::new(Session::UserId).uuid().not_null().unique_key()) + .foreign_key( + ForeignKey::create() + .name("fk_session_user_id") + .from(Session::Table, Session::UserId) + .to(User::Table, User::Id) + .on_delete(ForeignKeyAction::Cascade), + ) + .col(ColumnDef::new(Session::IpAddress).string().not_null()) + .col(ColumnDef::new(Session::UserAgent).string()) + .col(ColumnDef::new(Session::Browser).string()) + .col(ColumnDef::new(Session::BrowserVersion).string()) + .col(ColumnDef::new(Session::OperatingSystem).string()) + .col(ColumnDef::new(Session::DeviceType).string()) + .col(ColumnDef::new(Session::CountryCode).string().not_null()) + .col(ColumnDef::new(Session::Expires).timestamp_with_time_zone().not_null()) + .col( + ColumnDef::new(Session::CreatedAt) + .timestamp_with_time_zone() + .not_null() + .default(chrono::Utc::now()), + ) + .col( + ColumnDef::new(Session::UpdatedAt) + .timestamp_with_time_zone() + .not_null() + .default(chrono::Utc::now()), + ) + .to_owned(), + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager.drop_table(Table::drop().table(Session::Table).to_owned()).await + } +} + +#[derive(DeriveIden)] +pub enum Session { + Table, + Id, + UserId, + ClientId, + IpAddress, + UserAgent, + Browser, + BrowserVersion, + OperatingSystem, + DeviceType, + CountryCode, + Expires, + CreatedAt, + UpdatedAt, +} diff --git a/migration/src/main.rs b/migration/src/main.rs new file mode 100644 index 0000000..c6b6e48 --- /dev/null +++ b/migration/src/main.rs @@ -0,0 +1,6 @@ +use sea_orm_migration::prelude::*; + +#[async_std::main] +async fn main() { + cli::run_cli(migration::Migrator).await; +} diff --git a/src/packages/admin.rs b/src/packages/admin.rs index 71081e3..2fd6171 100644 --- a/src/packages/admin.rs +++ b/src/packages/admin.rs @@ -1,27 +1,27 @@ +use entity::{client, realm, resource, resource_group, user}; +use futures::future; +use sea_orm::{ + prelude::Uuid, ActiveModelTrait, ColumnTrait, DatabaseConnection, DatabaseTransaction, EntityTrait, QueryFilter, Set, TransactionError, + TransactionTrait, +}; use std::{ fs::{create_dir_all, File}, io::Write, path::Path, }; -use sea_orm::{prelude::Uuid, ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait, QueryFilter, Set}; use tracing::info; use crate::{ - database::{ - client, - prelude::{Realm, User}, - realm, resource, resource_group, user, - }, packages::settings::{Settings, SETTINGS}, utils::{hash::generate_password_hash, helpers::default_cred::DefaultCred}, }; use super::{db::AppState, errors::Error}; -pub async fn setup(state: &AppState) -> Result { +pub async fn setup(state: &AppState) -> Result> { info!("Checking ADMIN availability!"); - let is_admin_user_exists = User::find() + let is_admin_user_exists = user::Entity::find() .filter(user::Column::Email.eq(&SETTINGS.read().admin.email)) .one(&state.db) .await?; @@ -41,82 +41,64 @@ pub async fn setup(state: &AppState) -> Result { } } -async fn initialize_db(conn: &DatabaseConnection) -> Result<(), Error> { - let realm = create_master_realm(conn).await?; - let result = (|| async { - let client = create_default_client(conn, realm.id).await?; - let user = create_admin_user(conn, realm.id).await?; - let resource_assignment_result = assign_resource_to_admin(conn, realm.id, client.id, user.id).await?; - let default_cred = DefaultCred { - realm_id: realm.id, - client_id: client.id, - master_admin_user_id: user.id, - resource_group_id: resource_assignment_result.resource_group_id, - resource_ids: resource_assignment_result.resource_ids, - }; - info!("🗝️ Please note these credentials!"); - println!("{:?}", default_cred); - - let file_path = "./logs/default_cred.json"; - let path = Path::new(file_path); - if let Some(parent_dir) = path.parent() { - create_dir_all(parent_dir)?; - } else { - panic!("Invalid file path"); - } - - let json = serde_json::to_string_pretty(&default_cred)?; - let mut file = File::create(file_path)?; - file.write_all(json.as_bytes())?; - - info!("📝 However above credentials have been '/logs/default_cred.txt' file."); - Ok(()) - })() - .await; - - if result.is_err() { - Realm::delete_by_id(realm.id).exec(conn).await?; - Err(result.unwrap_err()) - } else { - Ok(()) - } +async fn initialize_db(conn: &DatabaseConnection) -> Result<(), TransactionError> { + conn.transaction(|txn| { + Box::pin(async move { + let realm = create_master_realm(txn).await?; + let client = create_default_client(txn, realm.id).await?; + let user = create_admin_user(txn, realm.id).await?; + let resource_assignment_result = assign_resource_to_admin(txn, realm.id, client.id, user.id).await?; + + let default_cred = DefaultCred { + realm_id: realm.id, + client_id: client.id, + master_admin_user_id: user.id, + resource_group_id: resource_assignment_result.resource_group_id, + resource_ids: resource_assignment_result.resource_ids, + }; + + write_default_cred(default_cred)?; + Ok(()) + }) + }) + .await } -async fn create_master_realm(conn: &DatabaseConnection) -> Result { - let new_realm = realm::ActiveModel { +async fn create_master_realm(conn: &DatabaseTransaction) -> Result { + let realm_model = realm::ActiveModel { name: Set("Master".to_owned()), ..Default::default() }; - let inserted_realm = new_realm.insert(conn).await?; + let inserted_realm = realm_model.insert(conn).await?; info!("✅ 1/5: Master realm created"); Ok(inserted_realm) } -async fn create_default_client(conn: &DatabaseConnection, realm_id: Uuid) -> Result { - let new_client = client::ActiveModel { +async fn create_default_client(conn: &DatabaseTransaction, realm_id: Uuid) -> Result { + let client_model = client::ActiveModel { name: Set("client".to_owned()), realm_id: Set(realm_id), ..Default::default() }; - let inserted_client = new_client.insert(conn).await?; + let inserted_client = client_model.insert(conn).await?; info!("✅ 2/5: Default client created"); Ok(inserted_client) } -async fn create_admin_user(conn: &DatabaseConnection, realm_id: Uuid) -> Result { +async fn create_admin_user(conn: &DatabaseTransaction, realm_id: Uuid) -> Result { let admin = SETTINGS.read().admin.clone(); let pw_hash = generate_password_hash(admin.password).await?; - let new_user = user::ActiveModel { + let user_model = user::ActiveModel { email: Set(admin.email.to_owned()), password_hash: Set(Some(pw_hash)), realm_id: Set(realm_id), first_name: Set(admin.email.to_owned()), - is_temp_password: Set(Some(false)), + is_temp_password: Set(false), ..Default::default() }; - let inserted_user = new_user.insert(conn).await?; + let inserted_user = user_model.insert(conn).await?; info!("✅ 3/5: Admin user created"); Ok(inserted_user) @@ -128,12 +110,12 @@ struct ResourceAssignmentResult { } async fn assign_resource_to_admin( - conn: &DatabaseConnection, + conn: &DatabaseTransaction, realm_id: Uuid, client_id: Uuid, user_id: Uuid, ) -> Result { - let new_resource_group = resource_group::ActiveModel { + let resource_group_model = resource_group::ActiveModel { client_id: Set(client_id), realm_id: Set(realm_id), user_id: Set(user_id), @@ -143,29 +125,50 @@ async fn assign_resource_to_admin( )), ..Default::default() }; - let inserted_resource_group = new_resource_group.insert(conn).await?; + let inserted_resource_group = resource_group_model.insert(conn).await?; info!("✅ 4/5: Default resource group created"); - let new_resource = resource::ActiveModel { + let resource_model = resource::ActiveModel { + id: Set(Uuid::now_v7()), group_id: Set(inserted_resource_group.id), name: Set("role".to_owned()), value: Set("admin".to_owned()), description: Set(Some("This role has been created at the time of initialization.".to_owned())), ..Default::default() }; - let inserted_resource = new_resource.insert(conn).await?; let new_resource_2 = resource::ActiveModel { + id: Set(Uuid::now_v7()), group_id: Set(inserted_resource_group.id), name: Set("realm".to_owned()), value: Set(realm_id.to_string()), description: Set(Some("This role has been created at the time of initialization.".to_owned())), ..Default::default() }; - let inserted_resource_2 = new_resource_2.insert(conn).await?; + let (inserted_resource, inserted_resource_2) = future::try_join(resource_model.insert(conn), new_resource_2.insert(conn)).await?; info!("✅ 5/5: Default resource created"); Ok(ResourceAssignmentResult { resource_group_id: inserted_resource_group.id, resource_ids: vec![inserted_resource.id, inserted_resource_2.id], }) } + +fn write_default_cred(default_cred: DefaultCred) -> Result<(), Error> { + info!("🗝️ Please note these credentials!"); + println!("{:#?}", default_cred); + + let file_path = "./logs/default_cred.json"; + let path = Path::new(file_path); + if let Some(parent_dir) = path.parent() { + create_dir_all(parent_dir)?; + } else { + panic!("Invalid file path"); + } + + let json = serde_json::to_string_pretty(&default_cred)?; + let mut file = File::create(file_path)?; + file.write_all(json.as_bytes())?; + + info!("📝 However above credentials have been '/logs/default_cred.json' file."); + Ok(()) +} diff --git a/src/packages/db.rs b/src/packages/db.rs index 9690d7f..8036619 100644 --- a/src/packages/db.rs +++ b/src/packages/db.rs @@ -1,6 +1,7 @@ use std::time::Duration; -use sea_orm::{ConnectOptions, Database, DatabaseConnection, DbErr}; +use migration::{Migrator, MigratorTrait}; +use sea_orm::{ConnectOptions, ConnectionTrait, Database, DatabaseConnection, DbBackend, DbErr, Statement}; use super::settings::SETTINGS; @@ -11,10 +12,51 @@ pub struct AppState { pub async fn get_db_connection_pool() -> Result { let uri = &SETTINGS.read().database.uri; - let mut opts = ConnectOptions::new(uri); + let db_name = &SETTINGS.read().database.name; + let connection_string = format!("{}/{}", uri, db_name); + + let mut opts = ConnectOptions::new(&connection_string); opts.max_connections(20).connect_timeout(Duration::from_secs(5)); - let db = Database::connect(opts).await?; + let db = Database::connect(uri).await?; + let db = match db.get_database_backend() { + DbBackend::MySql => { + db.execute(Statement::from_string( + db.get_database_backend(), + format!("CREATE DATABASE IF NOT EXISTS `{}`;", db_name), + )) + .await?; + + Database::connect(opts).await? + } + DbBackend::Postgres => { + let exists = db + .query_one(Statement::from_string( + db.get_database_backend(), + format!("SELECT 1 FROM pg_database WHERE datname = '{}'", db_name), + )) + .await?; + + match exists { + None => { + println!("🪹 Database does not exist, creating it"); + db.execute(Statement::from_string( + db.get_database_backend(), + format!("CREATE DATABASE \"{}\";", db_name), + )) + .await?; + } + _ => { + println!("🛢️ Database already exists"); + } + } + + Database::connect(opts).await? + } + DbBackend::Sqlite => db, + }; + + Migrator::up(&db, None).await?; Ok(AppState { db }) } diff --git a/src/packages/settings.rs b/src/packages/settings.rs index 1faf807..219e3fb 100644 --- a/src/packages/settings.rs +++ b/src/packages/settings.rs @@ -13,7 +13,7 @@ pub static SETTINGS: Lazy>> = Lazy::new(|| Arc::new(RwLock: #[derive(Debug, Clone, Deserialize)] pub struct Server { pub port: u16, - pub domain: String, + // pub domain: String, pub host: String, } @@ -25,7 +25,7 @@ pub struct Logger { #[derive(Debug, Clone, Deserialize)] pub struct Database { pub uri: String, - // pub name: String, + pub name: String, } #[derive(Debug, Clone, Deserialize)] @@ -75,6 +75,9 @@ impl Settings { if let Ok(database_uri) = env::var("DATABASE_URL") { builder = builder.set_override("database.uri", database_uri)?; } + if let Ok(database_name) = env::var("DATABASE_NAME") { + builder = builder.set_override("database.name", database_name)?; + } if let Ok(admin_email) = env::var("ADMIN_USERNAME") { builder = builder.set_override("admin.email", admin_email)?; } @@ -82,7 +85,7 @@ impl Settings { builder = builder.set_override("admin.password", admin_password)?; } - // "./logs/default_cred.txt" exists then read it else skip + // "./logs/default_cred.json" exists then read it else skip if Path::new("./logs/default_cred.json").exists() { let default_cred = DefaultCred::from_file().expect("Failed to read credentials"); builder = builder.set_override("default_cred.realm_id", default_cred.realm_id.to_string())?; From 30c3be8f3fea095a6dc6eef000ad6c84b699b2ed Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Mon, 30 Sep 2024 21:39:24 +0530 Subject: [PATCH 37/45] fix: all connection and db queries shifted to segregated workspace entity --- Cargo.lock | 21 +++-- Rocket.toml | 2 - Sea.toml | 2 + entity/Cargo.toml | 3 + {src/models => entity/src/extensions}/mod.rs | 0 {src/models => entity/src/extensions}/user.rs | 4 +- entity/src/lib.rs | 2 + entity/src/middlewares/client.rs | 83 +++++++++++++++++++ entity/src/middlewares/mod.rs | 5 ++ entity/src/middlewares/realm.rs | 7 +- entity/src/middlewares/resource.rs | 18 ++++ entity/src/middlewares/resource_group.rs | 47 +++++++++++ entity/src/middlewares/session.rs | 20 +++++ entity/src/middlewares/user.rs | 45 ++++++++++ entity/src/models/client.rs | 5 +- entity/src/models/realm.rs | 3 +- entity/src/models/resource.rs | 5 +- entity/src/models/resource_group.rs | 5 +- entity/src/models/session.rs | 2 - entity/src/models/user.rs | 5 +- entity/src/utils/mod.rs | 14 ++++ {migrations => sql}/down.sql | 0 {migrations => sql}/up.sql | 0 src/database/account.rs | 50 ----------- src/database/authenticator.rs | 42 ---------- src/database/client.rs | 58 ------------- src/database/mod.rs | 16 ---- src/database/password_reset_token.rs | 18 ---- src/database/prelude.rs | 14 ---- src/database/realm.rs | 52 ------------ src/database/resource.rs | 41 --------- src/database/resource_group.rs | 78 ----------------- src/database/session.rs | 58 ------------- src/database/two_factor_confirmation.rs | 18 ---- src/database/two_factor_token.rs | 18 ---- src/database/user.rs | 82 ------------------ src/database/verification_token.rs | 18 ---- src/handlers/auth.rs | 51 +++++------- src/handlers/client.rs | 14 ++-- src/handlers/realm.rs | 10 +-- src/handlers/user.rs | 62 ++++++-------- src/main.rs | 2 - src/packages/token.rs | 35 ++++---- src/services/client.rs | 25 +++--- src/services/realm.rs | 23 +++-- src/services/user.rs | 8 +- 46 files changed, 374 insertions(+), 717 deletions(-) delete mode 100644 Rocket.toml create mode 100644 Sea.toml rename {src/models => entity/src/extensions}/mod.rs (100%) rename {src/models => entity/src/extensions}/user.rs (82%) create mode 100644 entity/src/middlewares/client.rs create mode 100644 entity/src/middlewares/resource.rs create mode 100644 entity/src/middlewares/resource_group.rs create mode 100644 entity/src/middlewares/session.rs create mode 100644 entity/src/middlewares/user.rs create mode 100644 entity/src/utils/mod.rs rename {migrations => sql}/down.sql (100%) rename {migrations => sql}/up.sql (100%) delete mode 100644 src/database/account.rs delete mode 100644 src/database/authenticator.rs delete mode 100644 src/database/client.rs delete mode 100644 src/database/mod.rs delete mode 100644 src/database/password_reset_token.rs delete mode 100644 src/database/prelude.rs delete mode 100644 src/database/realm.rs delete mode 100644 src/database/resource.rs delete mode 100644 src/database/resource_group.rs delete mode 100644 src/database/session.rs delete mode 100644 src/database/two_factor_confirmation.rs delete mode 100644 src/database/two_factor_token.rs delete mode 100644 src/database/user.rs delete mode 100644 src/database/verification_token.rs diff --git a/Cargo.lock b/Cargo.lock index f4406a7..5b6b2fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -927,7 +927,10 @@ dependencies = [ name = "entity" version = "0.1.0" dependencies = [ + "bcrypt", + "regex", "sea-orm", + "serde", "slug", ] @@ -2142,14 +2145,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", ] [[package]] @@ -2163,13 +2166,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -2180,9 +2183,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rend" diff --git a/Rocket.toml b/Rocket.toml deleted file mode 100644 index 20017e5..0000000 --- a/Rocket.toml +++ /dev/null @@ -1,2 +0,0 @@ -[default.databases.shield_db] -url = "postgresql://postgres:1234@localhost:5432/shield" diff --git a/Sea.toml b/Sea.toml new file mode 100644 index 0000000..ca1a130 --- /dev/null +++ b/Sea.toml @@ -0,0 +1,2 @@ +[generate] +with_serde = true diff --git a/entity/Cargo.toml b/entity/Cargo.toml index 8c97bec..9ade5c7 100644 --- a/entity/Cargo.toml +++ b/entity/Cargo.toml @@ -5,5 +5,8 @@ edition = "2021" publish = false [dependencies] +bcrypt = "0.15.1" +regex = "1.11.0" sea-orm = { version = "1.0.1" } +serde = { version = "1.0.210", features = ["derive"] } slug = "0.1.6" diff --git a/src/models/mod.rs b/entity/src/extensions/mod.rs similarity index 100% rename from src/models/mod.rs rename to entity/src/extensions/mod.rs diff --git a/src/models/user.rs b/entity/src/extensions/user.rs similarity index 82% rename from src/models/user.rs rename to entity/src/extensions/user.rs index dcc1387..fe3f21b 100644 --- a/src/models/user.rs +++ b/entity/src/extensions/user.rs @@ -1,6 +1,6 @@ -use crate::database::user::Model; +use crate::models::user; -impl Model { +impl user::Model { pub fn verify_password(&self, password: &str) -> bool { match self.password_hash { Some(ref hash) => bcrypt::verify(password, hash).unwrap_or(false), diff --git a/entity/src/lib.rs b/entity/src/lib.rs index f432ba9..2b5db87 100644 --- a/entity/src/lib.rs +++ b/entity/src/lib.rs @@ -1,4 +1,6 @@ +mod extensions; mod middlewares; mod models; +mod utils; pub use models::*; diff --git a/entity/src/middlewares/client.rs b/entity/src/middlewares/client.rs new file mode 100644 index 0000000..9a37aec --- /dev/null +++ b/entity/src/middlewares/client.rs @@ -0,0 +1,83 @@ +use crate::models::client; +use crate::models::realm; +use crate::utils::check_locked_at_constraint; +use async_trait::async_trait; +use sea_orm::QuerySelect; +use sea_orm::{entity::prelude::*, ActiveValue}; + +#[async_trait] +impl ActiveModelBehavior for client::ActiveModel { + /// Will be triggered before insert / update + async fn before_save(mut self, db: &C, _insert: bool) -> Result + where + C: ConnectionTrait, + { + if let ActiveValue::Set(ref locked_at) = self.locked_at { + check_locked_at_constraint(locked_at)? + } + + // Fetch the realm information based on the realm_id in the client + let realm_id = self.realm_id.clone().unwrap(); // Assume realm_id is set + + let realm = realm::Entity::find_by_id(realm_id.clone()) + .one(db) + .await? + .ok_or(DbErr::Custom("Realm not found".to_owned()))?; + + // Check max_concurrent_sessions + if let Some(realm_max_sessions) = realm.max_concurrent_sessions { + // Calculate the total max_concurrent_sessions for all clients in this realm (excluding the current client if it's an update) + let mut total_sessions = client::Entity::find() + .filter(client::Column::RealmId.eq(realm_id.clone())) + .filter(client::Column::Id.ne(self.id.clone().unwrap())) // Exclude current client during update + .select_only() + .column_as(client::Column::MaxConcurrentSessions.sum(), "total") + .into_tuple::() + .one(db) + .await? + .unwrap_or(0); + + // Add the new/updated client's max_concurrent_sessions to the total + if let Some(client_max_sessions) = self.max_concurrent_sessions.as_ref() { + total_sessions += client_max_sessions; + } + + // Check if total exceeds the realm's max_concurrent_sessions + if total_sessions > realm_max_sessions { + return Err(DbErr::Custom(format!( + "Total max_concurrent_sessions for all clients in this realm ({}) exceeds the realm's limit ({})", + total_sessions, realm_max_sessions + ))); + } + } + + // Check session_lifetime + if self.session_lifetime.as_ref() > &realm.session_lifetime { + return Err(DbErr::Custom(format!( + "Client session_lifetime ({}) exceeds the realm's limit ({})", + self.session_lifetime.as_ref(), + &realm.session_lifetime + ))); + } + + // Check refresh_token_lifetime + if self.refresh_token_lifetime.as_ref() > &realm.refresh_token_lifetime { + return Err(DbErr::Custom(format!( + "Client refresh_token_lifetime ({}) exceeds the realm's limit ({})", + self.refresh_token_lifetime.as_ref(), + &realm.refresh_token_lifetime + ))); + } + + // Check refresh_token_reuse_limit + if self.refresh_token_reuse_limit.as_ref() > &realm.refresh_token_reuse_limit { + return Err(DbErr::Custom(format!( + "Client refresh_token_reuse_limit ({}) exceeds the realm's limit ({})", + self.refresh_token_reuse_limit.as_ref(), + &realm.refresh_token_reuse_limit + ))); + } + + Ok(self) + } +} diff --git a/entity/src/middlewares/mod.rs b/entity/src/middlewares/mod.rs index abc366b..20da074 100644 --- a/entity/src/middlewares/mod.rs +++ b/entity/src/middlewares/mod.rs @@ -1 +1,6 @@ +pub mod client; pub mod realm; +pub mod resource; +pub mod resource_group; +pub mod session; +pub mod user; diff --git a/entity/src/middlewares/realm.rs b/entity/src/middlewares/realm.rs index f1d42e6..4084ded 100644 --- a/entity/src/middlewares/realm.rs +++ b/entity/src/middlewares/realm.rs @@ -1,4 +1,4 @@ -use crate::models::realm::ActiveModel; +use crate::{models::realm::ActiveModel, utils::check_locked_at_constraint}; use async_trait::async_trait; use sea_orm::{entity::prelude::*, ActiveValue}; use slug::slugify; @@ -10,7 +10,10 @@ impl ActiveModelBehavior for ActiveModel { where C: ConnectionTrait, { - println!("🚀 Before save {:#?}", self); + if let ActiveValue::Set(ref locked_at) = self.locked_at { + check_locked_at_constraint(locked_at)? + } + if let ActiveValue::Set(ref name) = self.name { let slug = slugify(name); self.slug = ActiveValue::Set(slug); diff --git a/entity/src/middlewares/resource.rs b/entity/src/middlewares/resource.rs new file mode 100644 index 0000000..4fab5c2 --- /dev/null +++ b/entity/src/middlewares/resource.rs @@ -0,0 +1,18 @@ +use crate::{models::resource, utils::check_locked_at_constraint}; +use async_trait::async_trait; +use sea_orm::{entity::prelude::*, ActiveValue}; + +#[async_trait] +impl ActiveModelBehavior for resource::ActiveModel { + /// Will be triggered before insert / update + async fn before_save(mut self, _db: &C, _insert: bool) -> Result + where + C: ConnectionTrait, + { + if let ActiveValue::Set(ref locked_at) = self.locked_at { + check_locked_at_constraint(locked_at)? + } + + Ok(self) + } +} diff --git a/entity/src/middlewares/resource_group.rs b/entity/src/middlewares/resource_group.rs new file mode 100644 index 0000000..024a377 --- /dev/null +++ b/entity/src/middlewares/resource_group.rs @@ -0,0 +1,47 @@ +use crate::{models::resource_group, utils::check_locked_at_constraint}; +use async_trait::async_trait; +use sea_orm::{entity::prelude::*, ActiveValue}; + +#[async_trait] +impl ActiveModelBehavior for resource_group::ActiveModel { + /// Will be triggered before insert / update + async fn before_save(mut self, db: &C, _insert: bool) -> Result + where + C: ConnectionTrait, + { + if let ActiveValue::Set(ref locked_at) = self.locked_at { + check_locked_at_constraint(locked_at)? + } + + // If the new row is being set as default + if let ActiveValue::Set(is_default) = self.is_default { + if is_default { + // Set all other resource groups for the same user and client to non-default + resource_group::Entity::update_many() + .col_expr(resource_group::Column::IsDefault, Expr::value(false)) + .filter(resource_group::Column::UserId.eq(self.user_id.clone().unwrap())) + .filter(resource_group::Column::ClientId.eq(self.client_id.clone().unwrap())) + .filter(resource_group::Column::Id.ne(self.id.clone().unwrap())) + .exec(db) + .await?; + } else { + // Check if this was the only default group + let default_exists = resource_group::Entity::find() + .filter(resource_group::Column::UserId.eq(self.user_id.clone().unwrap())) + .filter(resource_group::Column::ClientId.eq(self.client_id.clone().unwrap())) + .filter(resource_group::Column::IsDefault.eq(true)) + .filter(resource_group::Column::Id.ne(self.id.clone().unwrap())) + .one(db) + .await? + .is_some(); + + // If no other default exists, force this group to be default + if !default_exists { + self.is_default = ActiveValue::Set(true); + } + } + } + + Ok(self) + } +} diff --git a/entity/src/middlewares/session.rs b/entity/src/middlewares/session.rs new file mode 100644 index 0000000..ecd3df4 --- /dev/null +++ b/entity/src/middlewares/session.rs @@ -0,0 +1,20 @@ +use crate::models::session; +use async_trait::async_trait; +use sea_orm::{entity::prelude::*, sqlx::types::chrono::Utc}; + +#[async_trait] +impl ActiveModelBehavior for session::ActiveModel { + /// Will be triggered before insert / update + async fn before_save(mut self, db: &C, _insert: bool) -> Result + where + C: ConnectionTrait, + { + // Perform session cleanup: delete all sessions that have expired + session::Entity::delete_many() + .filter(session::Column::Expires.lt(Utc::now())) + .exec(db) + .await?; + + Ok(self) + } +} diff --git a/entity/src/middlewares/user.rs b/entity/src/middlewares/user.rs new file mode 100644 index 0000000..49ceaad --- /dev/null +++ b/entity/src/middlewares/user.rs @@ -0,0 +1,45 @@ +use crate::{models::user, utils::check_locked_at_constraint}; +use async_trait::async_trait; +use regex::Regex; +use sea_orm::{entity::prelude::*, sqlx::types::chrono::Utc, ActiveValue}; + +#[async_trait] +impl ActiveModelBehavior for user::ActiveModel { + /// Will be triggered before insert / update + async fn before_save(mut self, _db: &C, _insert: bool) -> Result + where + C: ConnectionTrait, + { + if let ActiveValue::Set(ref locked_at) = self.locked_at { + check_locked_at_constraint(locked_at)? + } + + // Check email format constraint + if let ActiveValue::Set(ref email) = self.email { + let email_regex = Regex::new(r"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}$") + .map_err(|e| DbErr::Custom(format!("Failed to compile email regex: {}", e)))?; + + if !email_regex.is_match(email) { + return Err(DbErr::Custom(format!("Invalid email format: {}", email))); + } + } + + // Check email_verified_at constraint + if let (ActiveValue::Set(Some(email_verified_at)), ActiveValue::Set(created_at)) = (&self.email_verified_at, &self.created_at) { + if email_verified_at < created_at || email_verified_at > &Utc::now() { + return Err(DbErr::Custom("Email verified date must be between created date and now".to_owned())); + } + } + + // Check phone format constraint + if let ActiveValue::Set(Some(ref phone)) = self.phone { + let phone_regex = Regex::new(r"^\+?[0-9]{10,14}$").map_err(|e| DbErr::Custom(format!("Failed to compile phone regex: {}", e)))?; + + if !phone_regex.is_match(phone) { + return Err(DbErr::Custom(format!("Invalid phone number format: {}", phone))); + } + } + + Ok(self) + } +} diff --git a/entity/src/models/client.rs b/entity/src/models/client.rs index e662818..f2167d5 100644 --- a/entity/src/models/client.rs +++ b/entity/src/models/client.rs @@ -1,8 +1,9 @@ //! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 use sea_orm::entity::prelude::*; +use serde::Serialize; -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize)] #[sea_orm(table_name = "client")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] @@ -54,5 +55,3 @@ impl Related for Entity { Relation::Session.def() } } - -impl ActiveModelBehavior for ActiveModel {} diff --git a/entity/src/models/realm.rs b/entity/src/models/realm.rs index 8607547..59c19c5 100644 --- a/entity/src/models/realm.rs +++ b/entity/src/models/realm.rs @@ -1,8 +1,9 @@ //! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 use sea_orm::entity::prelude::*; +use serde::Serialize; -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize)] #[sea_orm(table_name = "realm")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] diff --git a/entity/src/models/resource.rs b/entity/src/models/resource.rs index 98d012c..d4a1236 100644 --- a/entity/src/models/resource.rs +++ b/entity/src/models/resource.rs @@ -1,8 +1,9 @@ //! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 use sea_orm::entity::prelude::*; +use serde::Serialize; -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize)] #[sea_orm(table_name = "resource")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] @@ -34,5 +35,3 @@ impl Related for Entity { Relation::ResourceGroup.def() } } - -impl ActiveModelBehavior for ActiveModel {} diff --git a/entity/src/models/resource_group.rs b/entity/src/models/resource_group.rs index d9d605c..0a24bdc 100644 --- a/entity/src/models/resource_group.rs +++ b/entity/src/models/resource_group.rs @@ -1,8 +1,9 @@ //! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 use sea_orm::entity::prelude::*; +use serde::Serialize; -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize)] #[sea_orm(table_name = "resource_group")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] @@ -74,5 +75,3 @@ impl Related for Entity { Relation::User.def() } } - -impl ActiveModelBehavior for ActiveModel {} diff --git a/entity/src/models/session.rs b/entity/src/models/session.rs index ed06bdc..db83d36 100644 --- a/entity/src/models/session.rs +++ b/entity/src/models/session.rs @@ -54,5 +54,3 @@ impl Related for Entity { Relation::User.def() } } - -impl ActiveModelBehavior for ActiveModel {} diff --git a/entity/src/models/user.rs b/entity/src/models/user.rs index 62c9afb..839ab45 100644 --- a/entity/src/models/user.rs +++ b/entity/src/models/user.rs @@ -1,8 +1,9 @@ //! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 use sea_orm::entity::prelude::*; +use serde::Serialize; -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize)] #[sea_orm(table_name = "user")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] @@ -57,5 +58,3 @@ impl Related for Entity { Relation::Session.def() } } - -impl ActiveModelBehavior for ActiveModel {} diff --git a/entity/src/utils/mod.rs b/entity/src/utils/mod.rs new file mode 100644 index 0000000..a840c0d --- /dev/null +++ b/entity/src/utils/mod.rs @@ -0,0 +1,14 @@ +use sea_orm::{ + sqlx::types::chrono::{FixedOffset, Utc}, + DbErr, +}; + +pub fn check_locked_at_constraint(locked_at: &Option>) -> Result<(), DbErr> { + if locked_at.is_some() { + // NOTE: If required, we can enable the feature to lock the client in the future. + if locked_at.unwrap() > Utc::now() { + return Err(DbErr::Custom("Cannot lock the client".to_owned())); + } + } + return Ok(()); +} diff --git a/migrations/down.sql b/sql/down.sql similarity index 100% rename from migrations/down.sql rename to sql/down.sql diff --git a/migrations/up.sql b/sql/up.sql similarity index 100% rename from migrations/up.sql rename to sql/up.sql diff --git a/src/database/account.rs b/src/database/account.rs deleted file mode 100644 index 40bb81e..0000000 --- a/src/database/account.rs +++ /dev/null @@ -1,50 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "account")] -pub struct Model { - pub user_id: Uuid, - #[sea_orm(column_type = "Text")] - pub r#type: String, - #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] - pub provider: String, - #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] - pub provider_account_id: String, - #[sea_orm(column_type = "Text", nullable)] - pub refresh_token: Option, - #[sea_orm(column_type = "Text", nullable)] - pub access_token: Option, - pub expires_at: Option, - #[sea_orm(column_type = "Text", nullable)] - pub token_type: Option, - #[sea_orm(column_type = "Text", nullable)] - pub scope: Option, - #[sea_orm(column_type = "Text", nullable)] - pub id_token: Option, - #[sea_orm(column_type = "Text", nullable)] - pub session_state: Option, - pub created_at: DateTimeWithTimeZone, - pub updated_at: DateTimeWithTimeZone, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm( - belongs_to = "super::user::Entity", - from = "Column::UserId", - to = "super::user::Column::Id", - on_update = "NoAction", - on_delete = "Cascade" - )] - User, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::User.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/src/database/authenticator.rs b/src/database/authenticator.rs deleted file mode 100644 index 1e07385..0000000 --- a/src/database/authenticator.rs +++ /dev/null @@ -1,42 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "authenticator")] -pub struct Model { - #[sea_orm(primary_key, auto_increment = false, column_type = "Text", unique)] - pub credential_id: String, - #[sea_orm(primary_key, auto_increment = false)] - pub user_id: Uuid, - #[sea_orm(column_type = "Text")] - pub provider_account_id: String, - #[sea_orm(column_type = "Text")] - pub credential_public_key: String, - pub counter: i32, - #[sea_orm(column_type = "Text")] - pub credential_device_type: String, - pub credential_backed_up: bool, - #[sea_orm(column_type = "Text", nullable)] - pub transports: Option, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm( - belongs_to = "super::user::Entity", - from = "Column::UserId", - to = "super::user::Column::Id", - on_update = "NoAction", - on_delete = "Cascade" - )] - User, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::User.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/src/database/client.rs b/src/database/client.rs deleted file mode 100644 index d1b1150..0000000 --- a/src/database/client.rs +++ /dev/null @@ -1,58 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 - -use sea_orm::entity::prelude::*; -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Deserialize, Serialize)] -#[sea_orm(table_name = "client")] -pub struct Model { - #[sea_orm(primary_key, auto_increment = false)] - pub id: Uuid, - #[sea_orm(column_type = "Text")] - pub name: String, - pub two_factor_enabled_at: Option, - pub max_concurrent_sessions: i32, - pub session_lifetime: i32, - pub refresh_token_lifetime: i32, - pub refresh_token_reuse_limit: i32, - pub locked_at: Option, - pub realm_id: Uuid, - pub created_at: DateTimeWithTimeZone, - pub updated_at: DateTimeWithTimeZone, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm( - belongs_to = "super::realm::Entity", - from = "Column::RealmId", - to = "super::realm::Column::Id", - on_update = "NoAction", - on_delete = "Cascade" - )] - Realm, - #[sea_orm(has_many = "super::resource_group::Entity")] - ResourceGroup, - #[sea_orm(has_many = "super::session::Entity")] - Session, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Realm.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::ResourceGroup.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Session.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/src/database/mod.rs b/src/database/mod.rs deleted file mode 100644 index bd81ac0..0000000 --- a/src/database/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 - -pub mod prelude; - -pub mod account; -pub mod authenticator; -pub mod client; -pub mod password_reset_token; -pub mod realm; -pub mod resource; -pub mod resource_group; -pub mod session; -pub mod two_factor_confirmation; -pub mod two_factor_token; -pub mod user; -pub mod verification_token; diff --git a/src/database/password_reset_token.rs b/src/database/password_reset_token.rs deleted file mode 100644 index c8a189f..0000000 --- a/src/database/password_reset_token.rs +++ /dev/null @@ -1,18 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "password_reset_token")] -pub struct Model { - #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] - pub identifier: String, - #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] - pub token: String, - pub expires: DateTimeWithTimeZone, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation {} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/src/database/prelude.rs b/src/database/prelude.rs deleted file mode 100644 index 8c6dbd4..0000000 --- a/src/database/prelude.rs +++ /dev/null @@ -1,14 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 - -pub use super::account::Entity as Account; -pub use super::authenticator::Entity as Authenticator; -pub use super::client::Entity as Client; -pub use super::password_reset_token::Entity as PasswordResetToken; -pub use super::realm::Entity as Realm; -pub use super::resource::Entity as Resource; -pub use super::resource_group::Entity as ResourceGroup; -pub use super::session::Entity as Session; -pub use super::two_factor_confirmation::Entity as TwoFactorConfirmation; -pub use super::two_factor_token::Entity as TwoFactorToken; -pub use super::user::Entity as User; -pub use super::verification_token::Entity as VerificationToken; diff --git a/src/database/realm.rs b/src/database/realm.rs deleted file mode 100644 index 4f67ff9..0000000 --- a/src/database/realm.rs +++ /dev/null @@ -1,52 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 - -use sea_orm::entity::prelude::*; -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Deserialize, Serialize)] -#[sea_orm(table_name = "realm")] -pub struct Model { - #[sea_orm(primary_key, auto_increment = false)] - pub id: Uuid, - #[sea_orm(column_type = "Text", unique)] - pub name: String, - #[sea_orm(column_type = "Text", unique)] - pub slug: String, - pub max_concurrent_sessions: Option, - pub session_lifetime: i32, - pub refresh_token_lifetime: i32, - pub refresh_token_reuse_limit: i32, - pub locked_at: Option, - pub created_at: DateTimeWithTimeZone, - pub updated_at: DateTimeWithTimeZone, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm(has_many = "super::client::Entity")] - Client, - #[sea_orm(has_many = "super::resource_group::Entity")] - ResourceGroup, - #[sea_orm(has_many = "super::user::Entity")] - User, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Client.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::ResourceGroup.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::User.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/src/database/resource.rs b/src/database/resource.rs deleted file mode 100644 index cdb516d..0000000 --- a/src/database/resource.rs +++ /dev/null @@ -1,41 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 - -use sea_orm::entity::prelude::*; -use serde::Serialize; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize)] -#[sea_orm(table_name = "resource")] -pub struct Model { - #[sea_orm(primary_key, auto_increment = false)] - pub id: Uuid, - pub group_id: Uuid, - #[sea_orm(column_type = "Text")] - pub name: String, - #[sea_orm(column_type = "Text")] - pub value: String, - #[sea_orm(column_type = "Text", nullable)] - pub description: Option, - pub locked_at: Option, - pub created_at: DateTimeWithTimeZone, - pub updated_at: DateTimeWithTimeZone, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm( - belongs_to = "super::resource_group::Entity", - from = "Column::GroupId", - to = "super::resource_group::Column::Id", - on_update = "NoAction", - on_delete = "Cascade" - )] - ResourceGroup, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::ResourceGroup.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/src/database/resource_group.rs b/src/database/resource_group.rs deleted file mode 100644 index 5e78cb5..0000000 --- a/src/database/resource_group.rs +++ /dev/null @@ -1,78 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 - -use sea_orm::entity::prelude::*; -use serde::Serialize; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize)] -#[sea_orm(table_name = "resource_group")] -pub struct Model { - #[sea_orm(primary_key, auto_increment = false)] - pub id: Uuid, - pub realm_id: Uuid, - pub client_id: Uuid, - pub user_id: Uuid, - #[sea_orm(column_type = "Text")] - pub name: String, - #[sea_orm(column_type = "Text", nullable)] - pub description: Option, - pub is_default: Option, - pub locked_at: Option, - pub created_at: DateTimeWithTimeZone, - pub updated_at: DateTimeWithTimeZone, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm( - belongs_to = "super::client::Entity", - from = "Column::ClientId", - to = "super::client::Column::Id", - on_update = "NoAction", - on_delete = "Cascade" - )] - Client, - #[sea_orm( - belongs_to = "super::realm::Entity", - from = "Column::RealmId", - to = "super::realm::Column::Id", - on_update = "NoAction", - on_delete = "Cascade" - )] - Realm, - #[sea_orm(has_many = "super::resource::Entity")] - Resource, - #[sea_orm( - belongs_to = "super::user::Entity", - from = "Column::UserId", - to = "super::user::Column::Id", - on_update = "NoAction", - on_delete = "Cascade" - )] - User, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Client.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Realm.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Resource.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::User.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/src/database/session.rs b/src/database/session.rs deleted file mode 100644 index baa03eb..0000000 --- a/src/database/session.rs +++ /dev/null @@ -1,58 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "session")] -pub struct Model { - #[sea_orm(primary_key, auto_increment = false)] - pub id: Uuid, - pub user_id: Uuid, - pub client_id: Uuid, - #[sea_orm(column_type = "Text")] - pub ip_address: String, - #[sea_orm(column_type = "Text", nullable)] - pub user_agent: Option, - pub browser: Option, - pub browser_version: Option, - pub operating_system: Option, - pub device_type: Option, - pub country_code: Option, - pub expires: DateTimeWithTimeZone, - pub created_at: DateTimeWithTimeZone, - pub updated_at: DateTimeWithTimeZone, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm( - belongs_to = "super::client::Entity", - from = "Column::ClientId", - to = "super::client::Column::Id", - on_update = "NoAction", - on_delete = "Cascade" - )] - Client, - #[sea_orm( - belongs_to = "super::user::Entity", - from = "Column::UserId", - to = "super::user::Column::Id", - on_update = "NoAction", - on_delete = "Cascade" - )] - User, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Client.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::User.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/src/database/two_factor_confirmation.rs b/src/database/two_factor_confirmation.rs deleted file mode 100644 index 88b179c..0000000 --- a/src/database/two_factor_confirmation.rs +++ /dev/null @@ -1,18 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "two_factor_confirmation")] -pub struct Model { - #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] - pub identifier: String, - #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] - pub token: String, - pub expires: DateTimeWithTimeZone, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation {} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/src/database/two_factor_token.rs b/src/database/two_factor_token.rs deleted file mode 100644 index 104d918..0000000 --- a/src/database/two_factor_token.rs +++ /dev/null @@ -1,18 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "two_factor_token")] -pub struct Model { - #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] - pub identifier: String, - #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] - pub token: String, - pub expires: DateTimeWithTimeZone, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation {} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/src/database/user.rs b/src/database/user.rs deleted file mode 100644 index dc9c867..0000000 --- a/src/database/user.rs +++ /dev/null @@ -1,82 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 - -use sea_orm::entity::prelude::*; -use serde::Serialize; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize)] -#[sea_orm(table_name = "user")] -pub struct Model { - #[sea_orm(primary_key, auto_increment = false)] - pub id: Uuid, - #[sea_orm(column_type = "Text")] - pub first_name: String, - #[sea_orm(column_type = "Text", nullable)] - pub last_name: Option, - #[sea_orm(column_type = "Text")] - pub email: String, - pub email_verified_at: Option, - #[sea_orm(column_type = "Text", nullable)] - pub phone: Option, - #[sea_orm(column_type = "Text", nullable)] - pub image: Option, - pub two_factor_enabled_at: Option, - #[sea_orm(column_type = "Text", nullable)] - pub password_hash: Option, - pub is_temp_password: Option, - pub locked_at: Option, - pub realm_id: Uuid, - pub created_at: DateTimeWithTimeZone, - pub updated_at: DateTimeWithTimeZone, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation { - #[sea_orm(has_many = "super::account::Entity")] - Account, - #[sea_orm(has_many = "super::authenticator::Entity")] - Authenticator, - #[sea_orm( - belongs_to = "super::realm::Entity", - from = "Column::RealmId", - to = "super::realm::Column::Id", - on_update = "NoAction", - on_delete = "Cascade" - )] - Realm, - #[sea_orm(has_many = "super::resource_group::Entity")] - ResourceGroup, - #[sea_orm(has_many = "super::session::Entity")] - Session, -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Account.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Authenticator.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Realm.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::ResourceGroup.def() - } -} - -impl Related for Entity { - fn to() -> RelationDef { - Relation::Session.def() - } -} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/src/database/verification_token.rs b/src/database/verification_token.rs deleted file mode 100644 index 82ae94c..0000000 --- a/src/database/verification_token.rs +++ /dev/null @@ -1,18 +0,0 @@ -//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 - -use sea_orm::entity::prelude::*; - -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] -#[sea_orm(table_name = "verification_token")] -pub struct Model { - #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] - pub identifier: String, - #[sea_orm(primary_key, auto_increment = false, column_type = "Text")] - pub token: String, - pub expires: DateTimeWithTimeZone, -} - -#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation {} - -impl ActiveModelBehavior for ActiveModel {} diff --git a/src/handlers/auth.rs b/src/handlers/auth.rs index 16b379b..50800f8 100644 --- a/src/handlers/auth.rs +++ b/src/handlers/auth.rs @@ -1,15 +1,9 @@ use chrono::Utc; +use entity::{client, resource, resource_group, session, user}; use sea_orm::{ActiveModelTrait, Set}; use std::sync::Arc; use crate::{ - database::{ - client, - prelude::{Client, Resource, ResourceGroup, Session, User}, - resource, resource_group, - session::{self, ActiveModel as SessionActiveModel}, - user::{self, Model}, - }, mappers::auth::{CreateUserRequest, IntrospectRequest, IntrospectResponse, LogoutRequest, LogoutResponse}, middleware::session_info_extractor::SessionInfo, packages::{ @@ -35,7 +29,7 @@ pub struct Credentials { #[derive(Serialize)] pub struct LoginResponse { access_token: String, - user: Model, + user: user::Model, realm_id: Uuid, client_id: Uuid, } @@ -47,9 +41,9 @@ pub async fn login( Json(payload): Json, ) -> Result, Error> { debug!("🚀 Login request received! {:#?}", session_info); - let user_with_resource_groups = User::find() + let user_with_resource_groups = user::Entity::find() .filter(user::Column::Email.eq(payload.email)) - .find_also_related(ResourceGroup) + .find_also_related(resource_group::Entity) .filter(resource_group::Column::RealmId.eq(realm_id)) .filter(resource_group::Column::ClientId.eq(client_id)) .one(&state.db) @@ -82,7 +76,7 @@ pub async fn login( } // Fetch client separately - let client = Client::find_by_id(client_id).one(&state.db).await?.ok_or_else(|| { + let client = client::Entity::find_by_id(client_id).one(&state.db).await?.ok_or_else(|| { debug!("No client found"); Error::not_found() })?; @@ -92,19 +86,20 @@ pub async fn login( return Err(Error::Authenticate(AuthenticateError::Locked)); } - let sessions = Session::find() + let sessions = session::Entity::find() .filter(session::Column::ClientId.eq(client.id)) .filter(session::Column::UserId.eq(user.id)) .filter(session::Column::Expires.gt(chrono::Utc::now())) .count(&state.db) .await?; - if sessions >= client.max_concurrent_sessions as u64 { + if sessions >= client.max_concurrent_sessions.unwrap() as u64 { debug!("Client has reached max concurrent sessions"); return Err(Error::Authenticate(AuthenticateError::MaxConcurrentSessions)); } + // Fetch resources - let resources = Resource::find() + let resources = resource::Entity::find() .filter(resource::Column::GroupId.eq(resource_groups.id)) .filter(resource::Column::LockedAt.is_null()) .all(&state.db) @@ -115,7 +110,7 @@ pub async fn login( return Err(Error::Authenticate(AuthenticateError::Locked)); } - let session = SessionActiveModel { + let session = session::ActiveModel { user_id: Set(user.id), client_id: Set(client.id), ip_address: Set(session_info.ip_address.to_string()), @@ -124,7 +119,7 @@ pub async fn login( browser_version: Set(Some(session_info.browser_version.to_string())), operating_system: Set(Some(session_info.operating_system.to_string())), device_type: Set(Some(session_info.device_type.to_string())), - country_code: Set(Some(session_info.country_code.to_string())), + country_code: Set(session_info.country_code.to_string()), expires: Set((Utc::now() + chrono::Duration::seconds(client.session_lifetime as i64)).into()), ..Default::default() }; @@ -153,7 +148,7 @@ pub async fn register( Extension(state): Extension>, Path((realm_id, client_id)): Path<(Uuid, Uuid)>, Json(payload): Json, -) -> Result, Error> { +) -> Result, Error> { if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { let user = insert_user(&state.db, realm_id, client_id, payload).await?; Ok(Json(user)) @@ -163,7 +158,7 @@ pub async fn register( } pub async fn logout_current_session(user: TokenUser, Extension(state): Extension>) -> Result, Error> { - let result = Session::delete_by_id(user.sid).exec(&state.db).await?; + let result = session::Entity::delete_by_id(user.sid).exec(&state.db).await?; Ok(Json(LogoutResponse { ok: result.rows_affected == 1, user_id: user.sub, @@ -184,7 +179,7 @@ pub async fn logout( .map_err(|_| AuthenticateError::InvalidToken)? .claims .sid; - let result = Session::delete_by_id(sid).exec(&state.db).await?; + let result = session::Entity::delete_by_id(sid).exec(&state.db).await?; Ok(Json(LogoutResponse { ok: result.rows_affected == 1, user_id: user.sub, @@ -197,7 +192,7 @@ pub async fn logout( .map_err(|_| AuthenticateError::InvalidToken)? .claims .sid; - let result = Session::delete_by_id(sid).exec(&state.db).await?; + let result = session::Entity::delete_by_id(sid).exec(&state.db).await?; Ok(Json(LogoutResponse { ok: result.rows_affected == 1, user_id: user.sub, @@ -217,7 +212,7 @@ pub async fn logout_my_all_sessions( Extension(state): Extension>, Path((_, client_id)): Path<(Uuid, Uuid)>, ) -> Result, Error> { - let result = Session::delete_many() + let result = session::Entity::delete_many() .filter(session::Column::ClientId.eq(client_id)) .filter(session::Column::UserId.eq(user.sub)) .exec(&state.db) @@ -242,7 +237,7 @@ pub async fn logout_all( .map_err(|_| AuthenticateError::InvalidToken)? .claims .sub; - let result = Session::delete_many() + let result = session::Entity::delete_many() .filter(session::Column::ClientId.eq(client_id)) .filter(session::Column::UserId.eq(sub)) .exec(&state.db) @@ -259,7 +254,7 @@ pub async fn logout_all( .map_err(|_| AuthenticateError::InvalidToken)? .claims .sub; - let result = Session::delete_many() + let result = session::Entity::delete_many() .filter(session::Column::ClientId.eq(client_id)) .filter(session::Column::UserId.eq(sub)) .exec(&state.db) @@ -292,24 +287,24 @@ pub async fn introspect( return Err(Error::Authenticate(AuthenticateError::NoResource)); } - let session = Session::find_by_id(token_data.claims.sid).one(&state.db).await?; + let session = session::Entity::find_by_id(token_data.claims.sid).one(&state.db).await?; match session { Some(session) => { - let user = User::find_by_id(session.user_id) + let user = user::Entity::find_by_id(session.user_id) .filter(user::Column::LockedAt.is_null()) .one(&state.db) .await?; match user { Some(user) => { - let client = Client::find_by_id(session.client_id) + let client = client::Entity::find_by_id(session.client_id) .filter(client::Column::LockedAt.is_null()) .one(&state.db) .await?; match client { Some(client) => { - let resource_group = ResourceGroup::find() + let resource_group = resource_group::Entity::find() .filter(resource_group::Column::RealmId.eq(realm_id)) .filter(resource_group::Column::ClientId.eq(client.id)) .filter(resource_group::Column::UserId.eq(user.id)) @@ -319,7 +314,7 @@ pub async fn introspect( match resource_group { Some(resource_group) => { - let resources = Resource::find() + let resources = resource::Entity::find() .filter(resource::Column::GroupId.eq(resource_group.id)) .filter(resource::Column::LockedAt.is_null()) .all(&state.db) diff --git a/src/handlers/client.rs b/src/handlers/client.rs index ef013db..fc5a08b 100644 --- a/src/handlers/client.rs +++ b/src/handlers/client.rs @@ -1,7 +1,6 @@ use std::sync::Arc; use crate::{ - database::client::Model, mappers::{ client::{CreateClientRequest, UpdateClientRequest}, DeleteResponse, @@ -18,9 +17,14 @@ use crate::{ }, }; use axum::{extract::Path, Extension, Json}; +use entity::client; use sea_orm::prelude::Uuid; -pub async fn get_clients(user: TokenUser, Extension(state): Extension>, Path(realm_id): Path) -> Result>, Error> { +pub async fn get_clients( + user: TokenUser, + Extension(state): Extension>, + Path(realm_id): Path, +) -> Result>, Error> { if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { let clients = get_all_clients(&state.db, realm_id).await?; if clients.is_empty() { @@ -36,7 +40,7 @@ pub async fn get_client( user: TokenUser, Extension(state): Extension>, Path((realm_id, client_id)): Path<(Uuid, Uuid)>, -) -> Result, Error> { +) -> Result, Error> { if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { let client = get_client_by_id(&state.db, client_id).await?; match client { @@ -53,7 +57,7 @@ pub async fn create_client( Extension(state): Extension>, Path(realm_id): Path, Json(payload): Json, -) -> Result, Error> { +) -> Result, Error> { if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { let client = insert_client(&state.db, payload).await?; Ok(Json(client)) @@ -67,7 +71,7 @@ pub async fn update_client( Extension(state): Extension>, Path((realm_id, client_id)): Path<(Uuid, Uuid)>, Json(payload): Json, -) -> Result, Error> { +) -> Result, Error> { if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { let client = update_client_by_id(&state.db, client_id, payload).await?; Ok(Json(client)) diff --git a/src/handlers/realm.rs b/src/handlers/realm.rs index f777e10..4fbfcdf 100644 --- a/src/handlers/realm.rs +++ b/src/handlers/realm.rs @@ -1,10 +1,10 @@ use std::sync::Arc; use axum::{extract::Path, Extension, Json}; +use entity::realm; use sea_orm::prelude::Uuid; use crate::{ - database::realm::Model, mappers::{ realm::{CreateRealmRequest, UpdateRealmRequest}, DeleteResponse, @@ -21,7 +21,7 @@ use crate::{ }, }; -pub async fn get_realms(user: TokenUser, Extension(state): Extension>) -> Result>, Error> { +pub async fn get_realms(user: TokenUser, Extension(state): Extension>) -> Result>, Error> { if is_master_realm_admin(&user) { let realms = get_all_realms(&state.db).await?; if realms.is_empty() { @@ -33,7 +33,7 @@ pub async fn get_realms(user: TokenUser, Extension(state): Extension>, Path(realm_id): Path) -> Result, Error> { +pub async fn get_realm(user: TokenUser, Extension(state): Extension>, Path(realm_id): Path) -> Result, Error> { if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { let fetched_realm = get_realm_by_id(&state.db, realm_id).await?; match fetched_realm { @@ -51,7 +51,7 @@ pub async fn create_realm( user: TokenUser, Extension(state): Extension>, Json(payload): Json, -) -> Result, Error> { +) -> Result, Error> { if is_master_realm_admin(&user) { let realm = insert_realm(&state.db, payload.name).await?; Ok(Json(realm)) @@ -65,7 +65,7 @@ pub async fn update_realm( Extension(state): Extension>, Path(realm_id): Path, Json(payload): Json, -) -> Result, Error> { +) -> Result, Error> { if is_master_realm_admin(&user) { let realm = update_realm_by_id(&state.db, realm_id, payload).await?; Ok(Json(realm)) diff --git a/src/handlers/user.rs b/src/handlers/user.rs index ca1ebdc..3fbee65 100644 --- a/src/handlers/user.rs +++ b/src/handlers/user.rs @@ -1,20 +1,12 @@ use std::sync::Arc; -use crate::database::prelude::{Resource, ResourceGroup, User}; -use crate::database::{ - resource, - resource::{ActiveModel as ResourceActiveModel, Model as ResourceModel}, - resource_group, - resource_group::{ActiveModel as ResourceGroupActiveModel, Model as ResourceGroupModel}, - user, - user::Model as UserModel, -}; use crate::mappers::user::{AddResourceRequest, UpdateResourceGroupRequest, UpdateResourceRequest}; use crate::mappers::DeleteResponse; use crate::utils::default_resource_checker::{is_default_resource, is_default_resource_group, is_default_user}; use axum::extract::Path; use axum::{Extension, Json}; use chrono::Utc; +use entity::{resource, resource_group, user}; use futures::future::try_join_all; use sea_orm::prelude::Uuid; use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, Set}; @@ -32,9 +24,9 @@ pub async fn get_users( user: TokenUser, Extension(state): Extension>, Path(realm_id): Path, -) -> Result>, Error> { +) -> Result>, Error> { if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { - let users = User::find().filter(user::Column::RealmId.eq(realm_id)).all(&state.db).await?; + let users = user::Entity::find().filter(user::Column::RealmId.eq(realm_id)).all(&state.db).await?; if users.is_empty() { return Err(Error::not_found()); } @@ -48,9 +40,9 @@ pub async fn get_user( user: TokenUser, Extension(state): Extension>, Path((realm_id, user_id)): Path<(Uuid, Uuid)>, -) -> Result, Error> { +) -> Result, Error> { if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { - let user = User::find_by_id(user_id).one(&state.db).await?; + let user = user::Entity::find_by_id(user_id).one(&state.db).await?; match user { Some(user) => Ok(Json(user)), None => return Err(Error::Authenticate(AuthenticateError::NoResource)), @@ -73,7 +65,7 @@ pub async fn delete_user( return Err(Error::cannot_perform_operation("Cannot delete the current user")); } - let result = User::delete_by_id(user_id).exec(&state.db).await?; + let result = user::Entity::delete_by_id(user_id).exec(&state.db).await?; Ok(Json(DeleteResponse { ok: result.rows_affected == 1, })) @@ -86,9 +78,9 @@ pub async fn get_resource_groups( user: TokenUser, Extension(state): Extension>, Path((realm_id, user_id)): Path<(Uuid, Uuid)>, -) -> Result>, Error> { +) -> Result>, Error> { if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { - let resource_groups = ResourceGroup::find() + let resource_groups = resource_group::Entity::find() .filter(resource_group::Column::RealmId.eq(realm_id)) .filter(resource_group::Column::UserId.eq(user_id)) .all(&state.db) @@ -103,9 +95,9 @@ pub async fn get_resource_group( user: TokenUser, Extension(state): Extension>, Path((realm_id, _, resource_group_id)): Path<(Uuid, Uuid, Uuid)>, -) -> Result, Error> { +) -> Result, Error> { if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { - let resource_group = ResourceGroup::find_by_id(resource_group_id).one(&state.db).await?; + let resource_group = resource_group::Entity::find_by_id(resource_group_id).one(&state.db).await?; match resource_group { Some(resource_group) => Ok(Json(resource_group)), None => return Err(Error::not_found()), @@ -120,13 +112,13 @@ pub async fn update_resource_group( Extension(state): Extension>, Path((realm_id, _, resource_group_id)): Path<(Uuid, Uuid, Uuid)>, Json(payload): Json, -) -> Result, Error> { +) -> Result, Error> { if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { if is_default_resource_group(resource_group_id) { return Err(Error::cannot_perform_operation("Cannot update the default resource group")); } - let resource_group = ResourceGroup::find_by_id(resource_group_id).one(&state.db).await?; + let resource_group = resource_group::Entity::find_by_id(resource_group_id).one(&state.db).await?; if resource_group.is_none() { return Err(Error::not_found()); } @@ -138,17 +130,17 @@ pub async fn update_resource_group( }; let is_default = match payload.is_default { Some(true) => Some(true), - _ => resource_group.as_ref().unwrap().is_default, + _ => Some(resource_group.as_ref().unwrap().is_default), }; - let resource_group = ResourceGroupActiveModel { + let resource_group = resource_group::ActiveModel { id: Set(resource_group_id), realm_id: Set(resource_group.as_ref().unwrap().realm_id), client_id: Set(resource_group.as_ref().unwrap().client_id), user_id: Set(resource_group.as_ref().unwrap().user_id), name: Set(payload.name), description: Set(payload.description), - is_default: Set(is_default), + is_default: Set(is_default.unwrap()), locked_at: Set(locked_at), ..Default::default() }; @@ -169,12 +161,12 @@ pub async fn delete_resource_group( return Err(Error::cannot_perform_operation("Cannot delete the default resource group")); } - let resource_group = ResourceGroup::find_by_id(resource_group_id).one(&state.db).await?; + let resource_group = resource_group::Entity::find_by_id(resource_group_id).one(&state.db).await?; if resource_group.is_none() { return Err(Error::not_found()); } - let result = ResourceGroup::delete_by_id(resource_group_id).exec(&state.db).await?; + let result = resource_group::Entity::delete_by_id(resource_group_id).exec(&state.db).await?; Ok(Json(DeleteResponse { ok: result.rows_affected == 1, })) @@ -187,9 +179,9 @@ pub async fn get_resources( user: TokenUser, Extension(state): Extension>, Path((realm_id, user_id)): Path<(Uuid, Uuid)>, -) -> Result>, Error> { +) -> Result>, Error> { if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { - let resource_groups = ResourceGroup::find() + let resource_groups = resource_group::Entity::find() .filter(resource_group::Column::RealmId.eq(realm_id)) .filter(resource_group::Column::UserId.eq(user_id)) .all(&state.db) @@ -199,7 +191,7 @@ pub async fn get_resources( for resource_group in resource_groups { resource_group_ids.push(resource_group.id); } - let resources = Resource::find() + let resources = resource::Entity::find() .filter(resource::Column::GroupId.is_in(resource_group_ids)) .all(&state.db) .await?; @@ -214,7 +206,7 @@ pub async fn add_resources( Extension(state): Extension>, Path((realm_id, user_id)): Path<(Uuid, Uuid)>, Json(payload): Json, -) -> Result>, Error> { +) -> Result>, Error> { if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { if payload.group_id.is_some() { let futures: Vec<_> = payload @@ -233,7 +225,7 @@ pub async fn add_resources( let resources = try_join_all(futures).await?; Ok(Json(resources)) } else if payload.group_name.is_some() { - let resource_groups = ResourceGroup::find() + let resource_groups = resource_group::Entity::find() .filter(resource_group::Column::RealmId.eq(realm_id)) .filter(resource_group::Column::UserId.eq(user_id)) .filter(resource_group::Column::Name.eq(payload.group_name)) @@ -272,13 +264,13 @@ pub async fn update_resource( Extension(state): Extension>, Path((realm_id, _, resource_id)): Path<(Uuid, Uuid, Uuid)>, Json(payload): Json, -) -> Result, Error> { +) -> Result, Error> { if is_master_realm_admin(&user) || is_current_realm_admin(&user, &realm_id.to_string()) { if is_default_resource(resource_id) { return Err(Error::cannot_perform_operation("Cannot update the default resource")); } - let resource = Resource::find_by_id(resource_id).one(&state.db).await?; + let resource = resource::Entity::find_by_id(resource_id).one(&state.db).await?; if resource.is_none() { return Err(Error::not_found()); } @@ -288,7 +280,7 @@ pub async fn update_resource( Some(false) => None, None => None, }; - let resource = ResourceActiveModel { + let resource = resource::ActiveModel { id: Set(resource_id), group_id: Set(resource.unwrap().group_id), name: Set(payload.name), @@ -314,12 +306,12 @@ pub async fn delete_resource( return Err(Error::cannot_perform_operation("Cannot delete the default resource")); } - let resource = Resource::find_by_id(resource_id).one(&state.db).await?; + let resource = resource::Entity::find_by_id(resource_id).one(&state.db).await?; if resource.is_none() { return Err(Error::not_found()); } - let result = Resource::delete_by_id(resource_id).exec(&state.db).await?; + let result = resource::Entity::delete_by_id(resource_id).exec(&state.db).await?; Ok(Json(DeleteResponse { ok: result.rows_affected == 1, })) diff --git a/src/main.rs b/src/main.rs index 637f181..4106bd6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,11 +6,9 @@ use tokio::net::TcpListener; use tracing::info; mod app; -mod database; mod handlers; mod mappers; mod middleware; -mod models; mod packages; mod routes; mod services; diff --git a/src/packages/token.rs b/src/packages/token.rs index 1a8d0ac..aa1065e 100644 --- a/src/packages/token.rs +++ b/src/packages/token.rs @@ -4,10 +4,7 @@ use sea_orm::prelude::Uuid; use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use crate::database::{ - client::Model as ClientModel, resource::Model as ResourceModel, resource_group::Model as ResourceGroupModel, session::Model as SessionModel, - user::Model as UserModel, -}; +use entity::{client, resource, resource_group, session, user}; use super::settings::SETTINGS; @@ -25,7 +22,7 @@ pub struct Resource { } impl Resource { - fn from(client: ClientModel, resource_group: ResourceGroupModel, resources: Vec) -> Self { + fn from(client: client::Model, resource_group: resource_group::Model, resources: Vec) -> Self { let mut identifiers = HashMap::new(); for resource in resources { identifiers.insert(resource.name, resource.value); @@ -55,7 +52,13 @@ pub struct TokenUser { } impl TokenUser { - fn from(user: UserModel, client: ClientModel, resource_group: ResourceGroupModel, resources: Vec, session: &SessionModel) -> Self { + fn from( + user: user::Model, + client: client::Model, + resource_group: resource_group::Model, + resources: Vec, + session: &session::Model, + ) -> Self { Self { sub: user.id, sid: session.id, @@ -96,11 +99,11 @@ pub struct Claims { impl Claims { pub fn new( - user: UserModel, - client: ClientModel, - resource_group: ResourceGroupModel, - resources: Vec, - session: SessionModel, + user: user::Model, + client: client::Model, + resource_group: resource_group::Model, + resources: Vec, + session: session::Model, ) -> Self { let user = TokenUser::from(user, client, resource_group, resources, &session); @@ -120,11 +123,11 @@ impl Claims { } pub fn create( - user: UserModel, - client: ClientModel, - resource_group: ResourceGroupModel, - resources: Vec, - session: SessionModel, + user: user::Model, + client: client::Model, + resource_group: resource_group::Model, + resources: Vec, + session: session::Model, secret: &str, ) -> Result { let encoding_key = EncodingKey::from_secret(secret.as_ref()); diff --git a/src/services/client.rs b/src/services/client.rs index a3e11db..85d9512 100644 --- a/src/services/client.rs +++ b/src/services/client.rs @@ -2,25 +2,22 @@ use chrono::Utc; use sea_orm::{prelude::Uuid, ActiveModelTrait, ColumnTrait, DatabaseConnection, DeleteResult, EntityTrait, QueryFilter, Set}; use crate::{ - database::{ - client::{ActiveModel, Column, Model}, - prelude::Client, - }, mappers::client::{CreateClientRequest, UpdateClientRequest}, packages::errors::{AuthenticateError, Error}, utils::default_resource_checker::is_default_client, }; +use entity::client; -pub async fn get_all_clients(db: &DatabaseConnection, realm_id: Uuid) -> Result, Error> { - Ok(Client::find().filter(Column::RealmId.eq(realm_id)).all(db).await?) +pub async fn get_all_clients(db: &DatabaseConnection, realm_id: Uuid) -> Result, Error> { + Ok(client::Entity::find().filter(client::Column::RealmId.eq(realm_id)).all(db).await?) } -pub async fn get_client_by_id(db: &DatabaseConnection, client_id: Uuid) -> Result, Error> { - Ok(Client::find_by_id(client_id).one(db).await?) +pub async fn get_client_by_id(db: &DatabaseConnection, client_id: Uuid) -> Result, Error> { + Ok(client::Entity::find_by_id(client_id).one(db).await?) } -pub async fn insert_client(db: &DatabaseConnection, payload: CreateClientRequest) -> Result { - let client = ActiveModel { +pub async fn insert_client(db: &DatabaseConnection, payload: CreateClientRequest) -> Result { + let client = client::ActiveModel { name: Set(payload.name.to_owned()), realm_id: Set(payload.realm_id), ..Default::default() @@ -28,7 +25,7 @@ pub async fn insert_client(db: &DatabaseConnection, payload: CreateClientRequest Ok(client.insert(db).await?) } -pub async fn update_client_by_id(db: &DatabaseConnection, client_id: Uuid, payload: UpdateClientRequest) -> Result { +pub async fn update_client_by_id(db: &DatabaseConnection, client_id: Uuid, payload: UpdateClientRequest) -> Result { if is_default_client(client_id) && payload.lock == Some(true) { return Err(Error::cannot_perform_operation("Cannot lock the default client")); } @@ -42,11 +39,11 @@ pub async fn update_client_by_id(db: &DatabaseConnection, client_id: Uuid, paylo None => client.locked_at, }; - let updated_client = ActiveModel { + let updated_client = client::ActiveModel { id: Set(client.id), name: Set(payload.name), max_concurrent_sessions: Set(match payload.max_concurrent_sessions { - Some(max_concurrent_sessions) => max_concurrent_sessions, + Some(max_concurrent_sessions) => Some(max_concurrent_sessions), None => client.max_concurrent_sessions, }), session_lifetime: Set(match payload.session_lifetime { @@ -74,5 +71,5 @@ pub async fn update_client_by_id(db: &DatabaseConnection, client_id: Uuid, paylo } pub async fn delete_client_by_id(db: &DatabaseConnection, id: Uuid) -> Result { - Ok(Client::delete_by_id(id).exec(db).await?) + Ok(client::Entity::delete_by_id(id).exec(db).await?) } diff --git a/src/services/realm.rs b/src/services/realm.rs index 6b6736b..8c214d6 100644 --- a/src/services/realm.rs +++ b/src/services/realm.rs @@ -2,32 +2,29 @@ use chrono::Utc; use sea_orm::{prelude::Uuid, ActiveModelTrait, DatabaseConnection, DeleteResult, EntityTrait, Set}; use crate::{ - database::{ - prelude::Realm, - realm::{ActiveModel, Model}, - }, mappers::realm::UpdateRealmRequest, packages::errors::{AuthenticateError, Error}, utils::default_resource_checker::is_default_realm, }; +use entity::realm; -pub async fn get_all_realms(db: &DatabaseConnection) -> Result, Error> { - Ok(Realm::find().all(db).await?) +pub async fn get_all_realms(db: &DatabaseConnection) -> Result, Error> { + Ok(realm::Entity::find().all(db).await?) } -pub async fn get_realm_by_id(db: &DatabaseConnection, id: Uuid) -> Result, Error> { - Ok(Realm::find_by_id(id).one(db).await?) +pub async fn get_realm_by_id(db: &DatabaseConnection, id: Uuid) -> Result, Error> { + Ok(realm::Entity::find_by_id(id).one(db).await?) } -pub async fn insert_realm(db: &DatabaseConnection, name: String) -> Result { - let realm = ActiveModel { +pub async fn insert_realm(db: &DatabaseConnection, name: String) -> Result { + let realm = realm::ActiveModel { name: Set(name), ..Default::default() }; Ok(realm.insert(db).await?) } -pub async fn update_realm_by_id(db: &DatabaseConnection, id: Uuid, payload: UpdateRealmRequest) -> Result { +pub async fn update_realm_by_id(db: &DatabaseConnection, id: Uuid, payload: UpdateRealmRequest) -> Result { if is_default_realm(id) && payload.lock == Some(true) { return Err(Error::cannot_perform_operation("Cannot lock the default realm")); } @@ -41,7 +38,7 @@ pub async fn update_realm_by_id(db: &DatabaseConnection, id: Uuid, payload: Upda None => realm.locked_at, }; - let updated_realm = ActiveModel { + let updated_realm = realm::ActiveModel { id: Set(realm.id), name: Set(payload.name), max_concurrent_sessions: Set(payload.max_concurrent_sessions), @@ -70,5 +67,5 @@ pub async fn update_realm_by_id(db: &DatabaseConnection, id: Uuid, payload: Upda } pub async fn delete_realm_by_id(db: &DatabaseConnection, id: Uuid) -> Result { - Ok(Realm::delete_by_id(id).exec(db).await?) + Ok(realm::Entity::delete_by_id(id).exec(db).await?) } diff --git a/src/services/user.rs b/src/services/user.rs index caaefce..66c7b20 100644 --- a/src/services/user.rs +++ b/src/services/user.rs @@ -1,9 +1,5 @@ -use crate::{ - database::{resource, resource_group, user}, - mappers::auth::CreateUserRequest, - packages::errors::Error, - utils::hash::generate_password_hash, -}; +use crate::{mappers::auth::CreateUserRequest, packages::errors::Error, utils::hash::generate_password_hash}; +use entity::{resource, resource_group, user}; use futures::future::join_all; use sea_orm::{prelude::Uuid, ActiveModelTrait, DatabaseConnection, Set}; From 7bdfa9555875de42d9b6d0930b4b9f01c025a69a Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Mon, 30 Sep 2024 23:18:38 +0530 Subject: [PATCH 38/45] fix: entity generated with --serde serialized --- entity/src/middlewares/client.rs | 59 ++++++++++++------- entity/src/models/resource.rs | 1 - entity/src/models/resource_group.rs | 2 +- entity/src/models/session.rs | 3 +- .../m20220101_000002_create_client_table.rs | 2 +- 5 files changed, 41 insertions(+), 26 deletions(-) diff --git a/entity/src/middlewares/client.rs b/entity/src/middlewares/client.rs index 9a37aec..63d7db0 100644 --- a/entity/src/middlewares/client.rs +++ b/entity/src/middlewares/client.rs @@ -19,7 +19,7 @@ impl ActiveModelBehavior for client::ActiveModel { // Fetch the realm information based on the realm_id in the client let realm_id = self.realm_id.clone().unwrap(); // Assume realm_id is set - let realm = realm::Entity::find_by_id(realm_id.clone()) + let realm = realm::Entity::find_by_id(realm_id) .one(db) .await? .ok_or(DbErr::Custom("Realm not found".to_owned()))?; @@ -28,7 +28,7 @@ impl ActiveModelBehavior for client::ActiveModel { if let Some(realm_max_sessions) = realm.max_concurrent_sessions { // Calculate the total max_concurrent_sessions for all clients in this realm (excluding the current client if it's an update) let mut total_sessions = client::Entity::find() - .filter(client::Column::RealmId.eq(realm_id.clone())) + .filter(client::Column::RealmId.eq(realm_id)) .filter(client::Column::Id.ne(self.id.clone().unwrap())) // Exclude current client during update .select_only() .column_as(client::Column::MaxConcurrentSessions.sum(), "total") @@ -52,30 +52,45 @@ impl ActiveModelBehavior for client::ActiveModel { } // Check session_lifetime - if self.session_lifetime.as_ref() > &realm.session_lifetime { - return Err(DbErr::Custom(format!( - "Client session_lifetime ({}) exceeds the realm's limit ({})", - self.session_lifetime.as_ref(), - &realm.session_lifetime - ))); + match self.session_lifetime { + ActiveValue::Set(session_lifetime) => { + if session_lifetime > realm.session_lifetime { + return Err(DbErr::Custom(format!( + "Client session_lifetime ({}) exceeds the realm's limit ({})", + self.session_lifetime.as_ref(), + &realm.session_lifetime + ))); + } + } + _ => {} } - // Check refresh_token_lifetime - if self.refresh_token_lifetime.as_ref() > &realm.refresh_token_lifetime { - return Err(DbErr::Custom(format!( - "Client refresh_token_lifetime ({}) exceeds the realm's limit ({})", - self.refresh_token_lifetime.as_ref(), - &realm.refresh_token_lifetime - ))); + // // Check refresh_token_lifetime + match self.refresh_token_lifetime { + ActiveValue::Set(refresh_token_lifetime) => { + if refresh_token_lifetime > realm.refresh_token_lifetime { + return Err(DbErr::Custom(format!( + "Client refresh_token_lifetime ({}) exceeds the realm's limit ({})", + self.refresh_token_lifetime.as_ref(), + &realm.refresh_token_lifetime + ))); + } + } + _ => {} } - // Check refresh_token_reuse_limit - if self.refresh_token_reuse_limit.as_ref() > &realm.refresh_token_reuse_limit { - return Err(DbErr::Custom(format!( - "Client refresh_token_reuse_limit ({}) exceeds the realm's limit ({})", - self.refresh_token_reuse_limit.as_ref(), - &realm.refresh_token_reuse_limit - ))); + // // Check refresh_token_reuse_limit + match self.refresh_token_reuse_limit { + ActiveValue::Set(refresh_token_reuse_limit) => { + if refresh_token_reuse_limit > realm.refresh_token_reuse_limit { + return Err(DbErr::Custom(format!( + "Client refresh_token_reuse_limit ({}) exceeds the realm's limit ({})", + self.refresh_token_reuse_limit.as_ref(), + &realm.refresh_token_reuse_limit + ))); + } + } + _ => {} } Ok(self) diff --git a/entity/src/models/resource.rs b/entity/src/models/resource.rs index d4a1236..ec32f9a 100644 --- a/entity/src/models/resource.rs +++ b/entity/src/models/resource.rs @@ -8,7 +8,6 @@ use serde::Serialize; pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: Uuid, - #[sea_orm(unique)] pub group_id: Uuid, pub name: String, pub value: String, diff --git a/entity/src/models/resource_group.rs b/entity/src/models/resource_group.rs index 0a24bdc..94d0dcd 100644 --- a/entity/src/models/resource_group.rs +++ b/entity/src/models/resource_group.rs @@ -40,7 +40,7 @@ pub enum Relation { on_delete = "Cascade" )] Realm, - #[sea_orm(has_one = "super::resource::Entity")] + #[sea_orm(has_many = "super::resource::Entity")] Resource, #[sea_orm( belongs_to = "super::user::Entity", diff --git a/entity/src/models/session.rs b/entity/src/models/session.rs index db83d36..188d258 100644 --- a/entity/src/models/session.rs +++ b/entity/src/models/session.rs @@ -1,8 +1,9 @@ //! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.1 use sea_orm::entity::prelude::*; +use serde::Serialize; -#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize)] #[sea_orm(table_name = "session")] pub struct Model { #[sea_orm(primary_key, auto_increment = false)] diff --git a/migration/src/m20220101_000002_create_client_table.rs b/migration/src/m20220101_000002_create_client_table.rs index 03e6dc2..bd007a1 100644 --- a/migration/src/m20220101_000002_create_client_table.rs +++ b/migration/src/m20220101_000002_create_client_table.rs @@ -16,7 +16,7 @@ impl MigrationTrait for Migration { .col(ColumnDef::new(Client::Id).uuid().not_null().primary_key().default(Uuid::now_v7())) .col(ColumnDef::new(Client::Name).string().unique_key().not_null()) .col(ColumnDef::new(Client::TwoFactorEnabledAt).timestamp_with_time_zone()) - .col(ColumnDef::new(Client::MaxConcurrentSessions).integer()) + .col(ColumnDef::new(Client::MaxConcurrentSessions).integer().not_null().default(1)) .col(ColumnDef::new(Client::SessionLifetime).integer().not_null().default(300)) .col(ColumnDef::new(Client::RefreshTokenLifetime).integer().not_null().default(3600)) .col(ColumnDef::new(Client::RefreshTokenReuseLimit).integer().not_null().default(0)) From 83943636f0b547595a018207d11ccfae3be5f2d1 Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Mon, 30 Sep 2024 23:57:07 +0530 Subject: [PATCH 39/45] fix: few issues fixed in orm middleware and at other places --- entity/src/middlewares/client.rs | 7 +++++-- entity/src/models/client.rs | 4 ++-- entity/src/models/session.rs | 2 -- entity/src/models/user.rs | 2 +- migration/src/m20220101_000006_create_session_table.rs | 4 ++-- src/handlers/auth.rs | 7 ++++--- src/mappers/client.rs | 2 +- src/services/client.rs | 8 ++++++-- 8 files changed, 21 insertions(+), 15 deletions(-) diff --git a/entity/src/middlewares/client.rs b/entity/src/middlewares/client.rs index 63d7db0..ea23ed9 100644 --- a/entity/src/middlewares/client.rs +++ b/entity/src/middlewares/client.rs @@ -38,8 +38,11 @@ impl ActiveModelBehavior for client::ActiveModel { .unwrap_or(0); // Add the new/updated client's max_concurrent_sessions to the total - if let Some(client_max_sessions) = self.max_concurrent_sessions.as_ref() { - total_sessions += client_max_sessions; + match self.max_concurrent_sessions { + ActiveValue::Set(max_concurrent_sessions) => { + total_sessions += max_concurrent_sessions; + } + _ => {} } // Check if total exceeds the realm's max_concurrent_sessions diff --git a/entity/src/models/client.rs b/entity/src/models/client.rs index f2167d5..f51f319 100644 --- a/entity/src/models/client.rs +++ b/entity/src/models/client.rs @@ -11,7 +11,7 @@ pub struct Model { #[sea_orm(unique)] pub name: String, pub two_factor_enabled_at: Option, - pub max_concurrent_sessions: Option, + pub max_concurrent_sessions: i32, pub session_lifetime: i32, pub refresh_token_lifetime: i32, pub refresh_token_reuse_limit: i32, @@ -34,7 +34,7 @@ pub enum Relation { Realm, #[sea_orm(has_one = "super::resource_group::Entity")] ResourceGroup, - #[sea_orm(has_one = "super::session::Entity")] + #[sea_orm(has_many = "super::session::Entity")] Session, } diff --git a/entity/src/models/session.rs b/entity/src/models/session.rs index 188d258..9cf5226 100644 --- a/entity/src/models/session.rs +++ b/entity/src/models/session.rs @@ -8,9 +8,7 @@ use serde::Serialize; pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: Uuid, - #[sea_orm(unique)] pub client_id: Uuid, - #[sea_orm(unique)] pub user_id: Uuid, pub ip_address: String, pub user_agent: Option, diff --git a/entity/src/models/user.rs b/entity/src/models/user.rs index 839ab45..7870122 100644 --- a/entity/src/models/user.rs +++ b/entity/src/models/user.rs @@ -37,7 +37,7 @@ pub enum Relation { Realm, #[sea_orm(has_one = "super::resource_group::Entity")] ResourceGroup, - #[sea_orm(has_one = "super::session::Entity")] + #[sea_orm(has_many = "super::session::Entity")] Session, } diff --git a/migration/src/m20220101_000006_create_session_table.rs b/migration/src/m20220101_000006_create_session_table.rs index b8f8005..c8c57c1 100644 --- a/migration/src/m20220101_000006_create_session_table.rs +++ b/migration/src/m20220101_000006_create_session_table.rs @@ -15,7 +15,7 @@ impl MigrationTrait for Migration { .table(Session::Table) .if_not_exists() .col(ColumnDef::new(Session::Id).uuid().not_null().primary_key().default(Uuid::now_v7())) - .col(ColumnDef::new(Session::ClientId).uuid().not_null().unique_key()) + .col(ColumnDef::new(Session::ClientId).uuid().not_null()) .foreign_key( ForeignKey::create() .name("fk_session_client_id") @@ -23,7 +23,7 @@ impl MigrationTrait for Migration { .to(Client::Table, Client::Id) .on_delete(ForeignKeyAction::Cascade), ) - .col(ColumnDef::new(Session::UserId).uuid().not_null().unique_key()) + .col(ColumnDef::new(Session::UserId).uuid().not_null()) .foreign_key( ForeignKey::create() .name("fk_session_user_id") diff --git a/src/handlers/auth.rs b/src/handlers/auth.rs index 50800f8..9386199 100644 --- a/src/handlers/auth.rs +++ b/src/handlers/auth.rs @@ -93,7 +93,7 @@ pub async fn login( .count(&state.db) .await?; - if sessions >= client.max_concurrent_sessions.unwrap() as u64 { + if sessions >= client.max_concurrent_sessions as u64 { debug!("Client has reached max concurrent sessions"); return Err(Error::Authenticate(AuthenticateError::MaxConcurrentSessions)); } @@ -110,7 +110,8 @@ pub async fn login( return Err(Error::Authenticate(AuthenticateError::Locked)); } - let session = session::ActiveModel { + let session_model = session::ActiveModel { + id: Set(Uuid::now_v7()), user_id: Set(user.id), client_id: Set(client.id), ip_address: Set(session_info.ip_address.to_string()), @@ -123,7 +124,7 @@ pub async fn login( expires: Set((Utc::now() + chrono::Duration::seconds(client.session_lifetime as i64)).into()), ..Default::default() }; - let session = session.insert(&state.db).await?; + let session = session_model.insert(&state.db).await?; let access_token = create( user.clone(), diff --git a/src/mappers/client.rs b/src/mappers/client.rs index 129dbca..ba94f2a 100644 --- a/src/mappers/client.rs +++ b/src/mappers/client.rs @@ -9,7 +9,7 @@ pub struct CreateClientRequest { #[derive(Deserialize)] pub struct UpdateClientRequest { - pub name: String, + pub name: Option, pub lock: Option, pub max_concurrent_sessions: Option, pub session_lifetime: Option, // in seconds diff --git a/src/services/client.rs b/src/services/client.rs index 85d9512..388b6d0 100644 --- a/src/services/client.rs +++ b/src/services/client.rs @@ -41,9 +41,13 @@ pub async fn update_client_by_id(db: &DatabaseConnection, client_id: Uuid, paylo let updated_client = client::ActiveModel { id: Set(client.id), - name: Set(payload.name), + realm_id: Set(client.realm_id), + name: Set(match payload.name { + Some(name) => name, + None => client.name, + }), max_concurrent_sessions: Set(match payload.max_concurrent_sessions { - Some(max_concurrent_sessions) => Some(max_concurrent_sessions), + Some(max_concurrent_sessions) => max_concurrent_sessions, None => client.max_concurrent_sessions, }), session_lifetime: Set(match payload.session_lifetime { From 0852707b914bec04af66801fa76159a3fdb53d39 Mon Sep 17 00:00:00 2001 From: Mukesh Singh Date: Tue, 1 Oct 2024 00:04:26 +0530 Subject: [PATCH 40/45] fix: uuid_v7 explicitly added and removed from default in migrations --- migration/src/m20220101_000001_create_realm_table.rs | 2 +- migration/src/m20220101_000002_create_client_table.rs | 2 +- migration/src/m20220101_000003_create_user_table.rs | 2 +- migration/src/m20220101_000004_create_resource_group_table.rs | 2 +- migration/src/m20220101_000005_create_resource_table.rs | 2 +- migration/src/m20220101_000006_create_session_table.rs | 2 +- src/handlers/user.rs | 2 ++ src/packages/admin.rs | 3 +++ src/services/client.rs | 1 + src/services/realm.rs | 1 + src/services/user.rs | 2 ++ 11 files changed, 15 insertions(+), 6 deletions(-) diff --git a/migration/src/m20220101_000001_create_realm_table.rs b/migration/src/m20220101_000001_create_realm_table.rs index 32098b6..4cab928 100644 --- a/migration/src/m20220101_000001_create_realm_table.rs +++ b/migration/src/m20220101_000001_create_realm_table.rs @@ -12,7 +12,7 @@ impl MigrationTrait for Migration { Table::create() .table(Realm::Table) .if_not_exists() - .col(ColumnDef::new(Realm::Id).uuid().not_null().primary_key().default(Uuid::now_v7())) + .col(ColumnDef::new(Realm::Id).uuid().not_null().primary_key()) .col(ColumnDef::new(Realm::Name).string().unique_key().not_null()) .col(ColumnDef::new(Realm::Slug).string().unique_key().not_null()) .col(ColumnDef::new(Realm::MaxConcurrentSessions).integer()) diff --git a/migration/src/m20220101_000002_create_client_table.rs b/migration/src/m20220101_000002_create_client_table.rs index bd007a1..bf7ab6f 100644 --- a/migration/src/m20220101_000002_create_client_table.rs +++ b/migration/src/m20220101_000002_create_client_table.rs @@ -13,7 +13,7 @@ impl MigrationTrait for Migration { Table::create() .table(Client::Table) .if_not_exists() - .col(ColumnDef::new(Client::Id).uuid().not_null().primary_key().default(Uuid::now_v7())) + .col(ColumnDef::new(Client::Id).uuid().not_null().primary_key()) .col(ColumnDef::new(Client::Name).string().unique_key().not_null()) .col(ColumnDef::new(Client::TwoFactorEnabledAt).timestamp_with_time_zone()) .col(ColumnDef::new(Client::MaxConcurrentSessions).integer().not_null().default(1)) diff --git a/migration/src/m20220101_000003_create_user_table.rs b/migration/src/m20220101_000003_create_user_table.rs index 9927c8f..73ed64d 100644 --- a/migration/src/m20220101_000003_create_user_table.rs +++ b/migration/src/m20220101_000003_create_user_table.rs @@ -13,7 +13,7 @@ impl MigrationTrait for Migration { Table::create() .table(User::Table) .if_not_exists() - .col(ColumnDef::new(User::Id).uuid().not_null().primary_key().default(Uuid::now_v7())) + .col(ColumnDef::new(User::Id).uuid().not_null().primary_key()) .col(ColumnDef::new(User::FirstName).string().not_null()) .col(ColumnDef::new(User::LastName).string()) .col(ColumnDef::new(User::Email).unique_key().string().not_null()) diff --git a/migration/src/m20220101_000004_create_resource_group_table.rs b/migration/src/m20220101_000004_create_resource_group_table.rs index acc3f9a..0f8d629 100644 --- a/migration/src/m20220101_000004_create_resource_group_table.rs +++ b/migration/src/m20220101_000004_create_resource_group_table.rs @@ -15,7 +15,7 @@ impl MigrationTrait for Migration { Table::create() .table(ResourceGroup::Table) .if_not_exists() - .col(ColumnDef::new(ResourceGroup::Id).uuid().not_null().primary_key().default(Uuid::now_v7())) + .col(ColumnDef::new(ResourceGroup::Id).uuid().not_null().primary_key()) .col(ColumnDef::new(ResourceGroup::RealmId).uuid().not_null().unique_key()) .foreign_key( ForeignKey::create() diff --git a/migration/src/m20220101_000005_create_resource_table.rs b/migration/src/m20220101_000005_create_resource_table.rs index 25fc0b2..5b8cd2f 100644 --- a/migration/src/m20220101_000005_create_resource_table.rs +++ b/migration/src/m20220101_000005_create_resource_table.rs @@ -13,7 +13,7 @@ impl MigrationTrait for Migration { Table::create() .table(Resource::Table) .if_not_exists() - .col(ColumnDef::new(Resource::Id).uuid().not_null().primary_key().default(Uuid::now_v7())) + .col(ColumnDef::new(Resource::Id).uuid().not_null().primary_key()) .col(ColumnDef::new(Resource::GroupId).uuid().not_null()) .foreign_key( ForeignKey::create() diff --git a/migration/src/m20220101_000006_create_session_table.rs b/migration/src/m20220101_000006_create_session_table.rs index c8c57c1..c578291 100644 --- a/migration/src/m20220101_000006_create_session_table.rs +++ b/migration/src/m20220101_000006_create_session_table.rs @@ -14,7 +14,7 @@ impl MigrationTrait for Migration { Table::create() .table(Session::Table) .if_not_exists() - .col(ColumnDef::new(Session::Id).uuid().not_null().primary_key().default(Uuid::now_v7())) + .col(ColumnDef::new(Session::Id).uuid().not_null().primary_key()) .col(ColumnDef::new(Session::ClientId).uuid().not_null()) .foreign_key( ForeignKey::create() diff --git a/src/handlers/user.rs b/src/handlers/user.rs index 3fbee65..8ede04c 100644 --- a/src/handlers/user.rs +++ b/src/handlers/user.rs @@ -214,6 +214,7 @@ pub async fn add_resources( .iter() .map(|(name, value)| { let resource = resource::ActiveModel { + id: Set(Uuid::now_v7()), group_id: Set(payload.group_id.unwrap()), name: Set(name.to_string()), value: Set(value.to_string()), @@ -241,6 +242,7 @@ pub async fn add_resources( .iter() .map(|(name, value)| { let resource = resource::ActiveModel { + id: Set(Uuid::now_v7()), group_id: Set(resource_group.id), name: Set(name.to_string()), value: Set(value.to_string()), diff --git a/src/packages/admin.rs b/src/packages/admin.rs index 2fd6171..388cb29 100644 --- a/src/packages/admin.rs +++ b/src/packages/admin.rs @@ -66,6 +66,7 @@ async fn initialize_db(conn: &DatabaseConnection) -> Result<(), TransactionError async fn create_master_realm(conn: &DatabaseTransaction) -> Result { let realm_model = realm::ActiveModel { + id: Set(Uuid::now_v7()), name: Set("Master".to_owned()), ..Default::default() }; @@ -77,6 +78,7 @@ async fn create_master_realm(conn: &DatabaseTransaction) -> Result Result { let client_model = client::ActiveModel { + id: Set(Uuid::now_v7()), name: Set("client".to_owned()), realm_id: Set(realm_id), ..Default::default() @@ -91,6 +93,7 @@ async fn create_admin_user(conn: &DatabaseTransaction, realm_id: Uuid) -> Result let admin = SETTINGS.read().admin.clone(); let pw_hash = generate_password_hash(admin.password).await?; let user_model = user::ActiveModel { + id: Set(Uuid::now_v7()), email: Set(admin.email.to_owned()), password_hash: Set(Some(pw_hash)), realm_id: Set(realm_id), diff --git a/src/services/client.rs b/src/services/client.rs index 388b6d0..363299a 100644 --- a/src/services/client.rs +++ b/src/services/client.rs @@ -18,6 +18,7 @@ pub async fn get_client_by_id(db: &DatabaseConnection, client_id: Uuid) -> Resul pub async fn insert_client(db: &DatabaseConnection, payload: CreateClientRequest) -> Result { let client = client::ActiveModel { + id: Set(Uuid::now_v7()), name: Set(payload.name.to_owned()), realm_id: Set(payload.realm_id), ..Default::default() diff --git a/src/services/realm.rs b/src/services/realm.rs index 8c214d6..53458a5 100644 --- a/src/services/realm.rs +++ b/src/services/realm.rs @@ -18,6 +18,7 @@ pub async fn get_realm_by_id(db: &DatabaseConnection, id: Uuid) -> Result