diff --git a/backend/.env b/backend/.env new file mode 100644 index 0000000..5b5a9be --- /dev/null +++ b/backend/.env @@ -0,0 +1 @@ +DATABASE_URL="postgresql://chatapp:chatapp@100.118.108.58:5432/chatapp" diff --git a/backend/Cargo.lock b/backend/Cargo.lock index b55a222..84ea2bb 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -17,6 +17,41 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + [[package]] name = "ahash" version = "0.8.12" @@ -54,6 +89,18 @@ dependencies = [ "libc", ] +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures", + "password-hash", +] + [[package]] name = "async-stream" version = "0.3.6" @@ -127,13 +174,18 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" name = "backend" version = "0.1.0" dependencies = [ + "argon2", "chrono", "futures-util", + "rand 0.9.2", "reqwest", "rocket", "rocket_cors", "rocket_db_pools", + "rocket_dyn_templates", "serde", + "sha2", + "sqlx", "tokio", ] @@ -164,17 +216,41 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" + [[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.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +dependencies = [ + "serde", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] [[package]] name = "block-buffer" @@ -185,6 +261,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bstr" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "bumpalo" version = "3.19.0" @@ -193,9 +279,9 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "bytemuck" -version = "1.23.2" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" [[package]] name = "byteorder" @@ -211,9 +297,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cc" -version = "1.2.39" +version = "1.2.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1354349954c6fc9cb0deab020f27f783cf0b604e8bb754dc4658ecf0d29c35f" +checksum = "e1d05d92f4b1fd76aad469d46cdd858ca761576082cd37df81416691e50199fb" dependencies = [ "find-msvc-tools", "shlex", @@ -239,13 +325,57 @@ dependencies = [ "windows-link 0.2.0", ] +[[package]] +name = "chrono-tz" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93698b29de5e97ad0ae26447b344c482a7284c737d9ddc5f9e52b74a336671bb" +dependencies = [ + "chrono", + "chrono-tz-build", + "phf", +] + +[[package]] +name = "chrono-tz-build" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c088aee841df9c3041febbb73934cfc39708749bf96dc827e3359cd39ef11b1" +dependencies = [ + "parse-zoneinfo", + "phf", + "phf_codegen", +] + +[[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 = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "cookie" version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" dependencies = [ + "aes-gcm", + "base64 0.22.1", + "hkdf", "percent-encoding", + "rand 0.8.5", + "sha2", + "subtle", "time", "version_check", ] @@ -290,6 +420,34 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-queue" version = "0.3.12" @@ -312,9 +470,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", + "rand_core 0.6.4", "typenum", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + [[package]] name = "deranged" version = "0.5.4" @@ -324,6 +503,12 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "deunicode" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abd57806937c9cc163efc8ea3910e00a62e2aeb0b8119f1793a978088f8f6b04" + [[package]] name = "devise" version = "0.4.2" @@ -350,7 +535,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b035a542cf7abf01f2e3c4d5a7acbaebfefe120ae4efc7bde3df98186e4b8af7" dependencies = [ - "bitflags", + "bitflags 2.9.4", "proc-macro2", "proc-macro2-diagnostics", "quote", @@ -364,6 +549,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", "subtle", ] @@ -457,10 +643,33 @@ dependencies = [ ] [[package]] -name = "find-msvc-tools" -version = "0.1.2" +name = "filetime" +version = "0.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" +checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.60.2", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0399f9d26e5191ce32c498bebd31e7a3ceabc2745f0ac54af3f335126c3f24b3" + +[[package]] +name = "flume" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "futures-core", + "futures-sink", + "spin", +] [[package]] name = "fnv" @@ -492,6 +701,15 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fsevent-sys" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +dependencies = [ + "libc", +] + [[package]] name = "futures" version = "0.3.31" @@ -522,6 +740,17 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-intrusive" version = "0.5.0" @@ -626,6 +855,16 @@ dependencies = [ "wasi 0.14.7+wasi-0.2.4", ] +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + [[package]] name = "gimli" version = "0.32.3" @@ -638,6 +877,30 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +[[package]] +name = "globset" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a1028dfc5f5df5da8a56a73e6c153c9a9708ec57232470703592a3f18e49f5" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "globwalk" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757" +dependencies = [ + "bitflags 2.9.4", + "ignore", + "walkdir", +] + [[package]] name = "h2" version = "0.3.27" @@ -817,6 +1080,15 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "humansize" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" +dependencies = [ + "libm", +] + [[package]] name = "hyper" version = "0.14.32" @@ -1052,6 +1324,22 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "ignore" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata", + "same-file", + "walkdir", + "winapi-util", +] + [[package]] name = "indexmap" version = "2.11.4" @@ -1070,13 +1358,42 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" +[[package]] +name = "inotify" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" +dependencies = [ + "bitflags 1.3.2", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + [[package]] name = "io-uring" version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" dependencies = [ - "bitflags", + "bitflags 2.9.4", "cfg-if", "libc", ] @@ -1124,11 +1441,34 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kqueue" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + [[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] [[package]] name = "libc" @@ -1136,6 +1476,34 @@ version = "0.2.176" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] +name = "libredox" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +dependencies = [ + "bitflags 2.9.4", + "libc", + "redox_syscall", +] + +[[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 = "linux-raw-sys" version = "0.11.0" @@ -1150,11 +1518,10 @@ checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lock_api" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] @@ -1225,6 +1592,18 @@ dependencies = [ "adler2", ] +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "log", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.48.0", +] + [[package]] name = "mio" version = "1.0.4" @@ -1282,6 +1661,34 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "normpath" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf23ab2b905654b4cb177e30b629937b3868311d4e1cba859f899c041046e69b" +dependencies = [ + "windows-sys 0.61.1", +] + +[[package]] +name = "notify" +version = "6.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" +dependencies = [ + "bitflags 2.9.4", + "crossbeam-channel", + "filetime", + "fsevent-sys", + "inotify", + "kqueue", + "libc", + "log", + "mio 0.8.11", + "walkdir", + "windows-sys 0.48.0", +] + [[package]] name = "nu-ansi-term" version = "0.50.1" @@ -1291,12 +1698,49 @@ dependencies = [ "windows-sys 0.52.0", ] +[[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 0.8.5", + "smallvec", + "zeroize", +] + [[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" +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-traits" version = "0.2.19" @@ -1304,6 +1748,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -1331,13 +1776,19 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + [[package]] name = "openssl" version = "0.10.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" dependencies = [ - "bitflags", + "bitflags 2.9.4", "cfg-if", "foreign-types", "libc", @@ -1377,9 +1828,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -1387,15 +1838,35 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.11" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-link 0.2.0", +] + +[[package]] +name = "parse-zoneinfo" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24" +dependencies = [ + "regex", +] + +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", ] [[package]] @@ -1427,12 +1898,102 @@ dependencies = [ "syn 2.0.106", ] +[[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.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "pest" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "989e7521a040efde50c3ab6bbadafbe15ab6dc042686926be59ac35d74607df4" +dependencies = [ + "memchr", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "187da9a3030dbafabbbfb20cb323b976dc7b7ce91fcd84f2f74d6e31d378e2de" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49b401d98f5757ebe97a26085998d6c0eecec4995cad6ab7fc30ffdf4b052843" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "pest_meta" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f27a2cfee9f9039c4d86faa5af122a0ac3851441a34865b8a043b46be0065a" +dependencies = [ + "pest", + "sha2", +] + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared", + "rand 0.8.5", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project-lite" version = "0.2.16" @@ -1445,12 +2006,45 @@ 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.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "potential_utf" version = "0.1.3" @@ -1519,8 +2113,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", ] [[package]] @@ -1530,7 +2134,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", ] [[package]] @@ -1543,12 +2157,21 @@ dependencies = [ ] [[package]] -name = "redox_syscall" -version = "0.5.17" +name = "rand_core" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "bitflags", + "getrandom 0.3.3", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.9.4", ] [[package]] @@ -1675,7 +2298,7 @@ dependencies = [ "num_cpus", "parking_lot", "pin-project-lite", - "rand", + "rand 0.8.5", "ref-cast", "rocket_codegen", "rocket_http", @@ -1748,6 +2371,19 @@ dependencies = [ "quote", ] +[[package]] +name = "rocket_dyn_templates" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bbab919c9e67df3f7ac6624a32ef897df4cd61c0969f4d66f3ced0534660d7a" +dependencies = [ + "normpath", + "notify", + "rocket", + "tera", + "walkdir", +] + [[package]] name = "rocket_http" version = "0.5.1" @@ -1775,6 +2411,26 @@ dependencies = [ "uncased", ] +[[package]] +name = "rsa" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "signature", + "spki", + "subtle", + "zeroize", +] + [[package]] name = "rustc-demangle" version = "0.1.26" @@ -1787,7 +2443,7 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags", + "bitflags 2.9.4", "errno", "libc", "linux-raw-sys", @@ -1869,6 +2525,15 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.28" @@ -1906,7 +2571,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags", + "bitflags 2.9.4", "core-foundation", "core-foundation-sys", "libc", @@ -1987,6 +2652,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.9" @@ -2022,12 +2698,38 @@ 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 0.6.4", +] + +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + [[package]] name = "slab" version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +[[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.15.1" @@ -2059,6 +2761,19 @@ 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 = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] [[package]] name = "sqlformat" @@ -2078,7 +2793,9 @@ checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa" dependencies = [ "sqlx-core", "sqlx-macros", + "sqlx-mysql", "sqlx-postgres", + "sqlx-sqlite", ] [[package]] @@ -2116,6 +2833,7 @@ dependencies = [ "smallvec", "sqlformat", "thiserror", + "time", "tokio", "tokio-stream", "tracing", @@ -2153,13 +2871,58 @@ dependencies = [ "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", + "bitflags 2.9.4", + "byteorder", + "bytes", + "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 0.8.5", + "rsa", + "serde", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "time", + "tracing", + "whoami", +] + [[package]] name = "sqlx-postgres" version = "0.7.4" @@ -2168,7 +2931,7 @@ checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" dependencies = [ "atoi", "base64 0.21.7", - "bitflags", + "bitflags 2.9.4", "byteorder", "crc", "dotenvy", @@ -2186,7 +2949,7 @@ dependencies = [ "md-5", "memchr", "once_cell", - "rand", + "rand 0.8.5", "serde", "serde_json", "sha2", @@ -2194,10 +2957,35 @@ dependencies = [ "sqlx-core", "stringprep", "thiserror", + "time", "tracing", "whoami", ] +[[package]] +name = "sqlx-sqlite" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa" +dependencies = [ + "atoi", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "sqlx-core", + "time", + "tracing", + "url", + "urlencoding", +] + [[package]] name = "stable-pattern" version = "0.1.0" @@ -2287,7 +3075,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags", + "bitflags 2.9.4", "core-foundation", "system-configuration-sys", ] @@ -2315,6 +3103,28 @@ dependencies = [ "windows-sys 0.61.1", ] +[[package]] +name = "tera" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab9d851b45e865f178319da0abdbfe6acbc4328759ff18dafc3a41c16b4cd2ee" +dependencies = [ + "chrono", + "chrono-tz", + "globwalk", + "humansize", + "lazy_static", + "percent-encoding", + "pest", + "pest_derive", + "rand 0.8.5", + "regex", + "serde", + "serde_json", + "slug", + "unic-segment", +] + [[package]] name = "thiserror" version = "1.0.69" @@ -2410,7 +3220,7 @@ dependencies = [ "bytes", "io-uring", "libc", - "mio", + "mio 1.0.4", "parking_lot", "pin-project-lite", "signal-hook-registry", @@ -2537,7 +3347,7 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" dependencies = [ - "bitflags", + "bitflags 2.9.4", "bytes", "futures-util", "http 1.3.1", @@ -2631,9 +3441,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "ubyte" @@ -2644,6 +3454,12 @@ dependencies = [ "serde", ] +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + [[package]] name = "uncased" version = "0.9.10" @@ -2654,6 +3470,56 @@ dependencies = [ "version_check", ] +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-segment" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ed5d26be57f84f176157270c112ef57b86debac9cd21daaabbe56db0f88f23" +dependencies = [ + "unic-ucd-segment", +] + +[[package]] +name = "unic-ucd-segment" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2079c122a62205b421f499da10f3ee0f7697f012f55b675e002483c73ea34700" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + [[package]] name = "unicase" version = "2.8.1" @@ -2715,6 +3581,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "untrusted" version = "0.9.0" @@ -2733,6 +3609,12 @@ dependencies = [ "serde", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "utf8_iter" version = "1.0.4" @@ -2757,6 +3639,16 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -2886,14 +3778,23 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "whoami" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6994d13118ab492c3c80c1f81928718159254c53c472bf9ce36f8dae4add02a7" +checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" dependencies = [ - "redox_syscall", + "libredox", "wasite", ] +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.1", +] + [[package]] name = "windows" version = "0.48.0" @@ -3024,6 +3925,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.4", +] + [[package]] name = "windows-sys" version = "0.61.1" @@ -3057,13 +3967,30 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "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-targets" +version = "0.53.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b" +dependencies = [ + "windows-link 0.2.0", + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -3076,6 +4003,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -3088,6 +4021,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -3100,12 +4039,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[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_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -3118,6 +4069,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -3130,6 +4087,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -3142,6 +4105,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -3154,6 +4123,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "winnow" version = "0.7.13" diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 0eef865..d87fbeb 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -4,11 +4,16 @@ version = "0.1.0" edition = "2024" [dependencies] +argon2 = "0.5.3" chrono = { version = "0.4.42", features = ["serde"] } futures-util = "0.3.31" +rand = "0.9.2" reqwest = { version = "0.12.23", features = ["json"] } -rocket = { version = "0.5.1", features = ["json"] } +rocket = { version = "0.5.1", features = ["json", "secrets"] } rocket_cors = "0.6.0" -rocket_db_pools = { version = "0.2.0", features = ["sqlx_postgres"] } +rocket_db_pools = { version = "0.2.0", features = ["sqlx_macros", "sqlx_postgres"] } +rocket_dyn_templates = { version = "0.2.0", features = ["tera"] } serde = { version = "1.0.228", features = ["derive"] } +sha2 = "0.10.9" +sqlx = { version = "0.7.4", features = ["macros", "time"] } tokio = { version = "1.47.1", features = ["full"] } diff --git a/backend/Rocket.toml b/backend/Rocket.toml index ae8e551..0d6fba7 100644 --- a/backend/Rocket.toml +++ b/backend/Rocket.toml @@ -1,2 +1,6 @@ [debug] -port = 8001 +secret_key = "yYhvCGnRh/TrcHtB8sZqCFifrVmJxoKFLBYw/WWBZeU=" +port = 8000 + +[default.databases.postgres_db] +url = "postgresql://chatapp:chatapp@100.118.108.58:5432/chatapp" diff --git a/backend/cdn/background.png b/backend/cdn/background.png new file mode 100644 index 0000000..9dda602 Binary files /dev/null and b/backend/cdn/background.png differ diff --git a/backend/cdn/icons/call.svg b/backend/cdn/icons/call.svg new file mode 100644 index 0000000..d527069 --- /dev/null +++ b/backend/cdn/icons/call.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backend/cdn/icons/down_arrow.svg b/backend/cdn/icons/down_arrow.svg new file mode 100644 index 0000000..8aca477 --- /dev/null +++ b/backend/cdn/icons/down_arrow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backend/cdn/icons/location.svg b/backend/cdn/icons/location.svg new file mode 100644 index 0000000..872023c --- /dev/null +++ b/backend/cdn/icons/location.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backend/cdn/icons/pin.svg b/backend/cdn/icons/pin.svg new file mode 100644 index 0000000..4375bde --- /dev/null +++ b/backend/cdn/icons/pin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backend/cdn/icons/search.svg b/backend/cdn/icons/search.svg new file mode 100644 index 0000000..b78a3fe --- /dev/null +++ b/backend/cdn/icons/search.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backend/cdn/icons/send.svg b/backend/cdn/icons/send.svg new file mode 100644 index 0000000..26dfe0e --- /dev/null +++ b/backend/cdn/icons/send.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/backend/cdn/map.png b/backend/cdn/map.png new file mode 100644 index 0000000..8d46e33 Binary files /dev/null and b/backend/cdn/map.png differ diff --git a/backend/cdn/profiles/8.jpg b/backend/cdn/profiles/8.jpg new file mode 100644 index 0000000..0a10fb2 Binary files /dev/null and b/backend/cdn/profiles/8.jpg differ diff --git a/backend/cdn/profiles/default.jpg b/backend/cdn/profiles/default.jpg new file mode 100644 index 0000000..fec1bb4 Binary files /dev/null and b/backend/cdn/profiles/default.jpg differ diff --git a/backend/migrations/20251001212022_prototype-v1.sql b/backend/migrations/20251001212022_prototype-v1.sql new file mode 100644 index 0000000..857f28d --- /dev/null +++ b/backend/migrations/20251001212022_prototype-v1.sql @@ -0,0 +1,49 @@ +-- Add migration script here +CREATE TABLE users ( + id SERIAL PRIMARY KEY, + username VARCHAR(50) UNIQUE NOT NULL, + password VARCHAR(50) NOT NULL, + display_name VARCHAR(50), + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE channels ( + id SERIAL PRIMARY KEY, + name VARCHAR(50) NOT NULL, + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE messages ( + id SERIAL PRIMARY KEY, + channel_id INTEGER NOT NULL REFERENCES channels(id) ON DELETE CASCADE, + user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + content TEXT NOT NULL, + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, + is_edited BOOLEAN DEFAULT FALSE +); + +create table attachments ( + id SERIAL PRIMARY KEY, + message_id INTEGER NOT NULL REFERENCES messages(id) ON DELETE CASCADE, + path TEXT NOT NULL +); + +CREATE INDEX idx_messages_channel_id ON messages (channel_id, id DESC); +CREATE INDEX idx_new_messages ON messages(created_at DESC); + +-- Create a function to update the updated_at timestamp +CREATE OR REPLACE FUNCTION update_updated_at_column() +RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_at = CURRENT_TIMESTAMP; + RETURN NEW; +END; +$$ language 'plpgsql'; + +-- Create trigger for messages table +CREATE TRIGGER update_messages_updated_at + BEFORE UPDATE ON messages + FOR EACH ROW + EXECUTE FUNCTION update_updated_at_column(); diff --git a/backend/migrations/20251005014201_session-tokens.sql b/backend/migrations/20251005014201_session-tokens.sql new file mode 100644 index 0000000..42a2be4 --- /dev/null +++ b/backend/migrations/20251005014201_session-tokens.sql @@ -0,0 +1,20 @@ +-- Add migration script here +CREATE TABLE sessions ( + id SERIAL PRIMARY KEY, + user_id INTEGER NOT NULL REFERENCES users(id), + token TEXT NOT NULL UNIQUE, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + expires_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP + INTERVAL '7 days' +); + +CREATE OR REPLACE FUNCTION cleanup_expired_sessions() +RETURNS TRIGGER AS $$ +BEGIN + DELETE FROM sessions WHERE expires_at < NOW(); + RETURN NULL; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trigger_cleanup_sessions + AFTER INSERT ON sessions + EXECUTE FUNCTION cleanup_expired_sessions(); diff --git a/backend/src/auth.rs b/backend/src/auth.rs index 8b87106..890f77d 100644 --- a/backend/src/auth.rs +++ b/backend/src/auth.rs @@ -1,6 +1,21 @@ -use rocket::{post, serde::json::Json}; -use rocket_db_pools::{Connection, Database, sqlx}; +use std::time::{SystemTime, UNIX_EPOCH}; + +use rand::Rng; +use rocket::{ + Request, + http::{CookieJar, Status}, + outcome::Outcome, + post, + request::{self, FromRequest}, + serde::json::Json, +}; +use rocket_db_pools::{ + Connection, Database, + sqlx::{self}, +}; +use rocket_dyn_templates::{Template, context}; use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; #[derive(Database)] #[database("postgres_db")] @@ -14,12 +29,44 @@ pub struct UserCredentials { #[post("/signup", data = "")] pub async fn signup( - conn: Connection, cred: Json, + jar: &CookieJar<'_>, + mut db: Connection, ) -> Result, String> { + let result = sqlx::query!( + "INSERT INTO users (username, password) VALUES ($1, $2) RETURNING id", + cred.username, + cred.password + ) + .fetch_one(&mut **db) + .await + .map_err(|e| e.to_string())?; + + let session = SessionToken::new(result.id as usize); + let result = sqlx::query!( + "INSERT INTO sessions (user_id, token) VALUES ($1, $2)", + result.id, + session.token, + ) + .execute(&mut **db) + .await; + + if let Err(e) = result { + eprintln!("Failed to create session: {}", e); + return Err(e.to_string()); + } + + jar.add_private(("session", session.token)); + + println!("Signup successful"); Ok(Json("Signup successful".to_string())) } +#[get("/signup")] +pub async fn signup_page() -> Template { + Template::render("signup", context!()) +} + #[post("/login", data = "")] pub async fn login( conn: Connection, @@ -28,3 +75,58 @@ pub async fn login( // TODO: implement actual login logic, e.g. verify password and generate token Ok(Json("Login successful".to_string())) } + +pub struct SessionToken { + pub token: String, + pub user_id: usize, +} + +impl SessionToken { + pub fn new(user_id: usize) -> Self { + let current_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); + let random: u32 = rand::rng().random(); + let token = format!("{}-{}", current_time.as_secs(), random); + let hashed = format!("{:x}", Sha256::digest(token.as_bytes())); + SessionToken { + token: hashed, + user_id, + } + } +} + +type UserID = usize; + +#[derive(Debug)] +pub struct AuthGuard(pub UserID); + +#[rocket::async_trait] +impl<'r> FromRequest<'r> for AuthGuard { + type Error = (); + + async fn from_request(request: &'r Request<'_>) -> request::Outcome { + if let Some(c) = request.cookies().get_private("session") { + let mut pool = match request.guard::>().await { + Outcome::Success(pool) => pool, + _ => return Outcome::Error((Status::Unauthorized, ())), + }; + + let value = c.value(); + let result = sqlx::query!( + "SELECT user_id FROM sessions WHERE token = $1 AND expires_at > NOW()", + value + ) + .fetch_optional(&mut **pool) + .await + .expect("query failed!"); + + if let Some(token) = result { + let user_id = token.user_id; + Outcome::Success(AuthGuard(user_id as usize)) + } else { + Outcome::Error((Status::Unauthorized, ())) + } + } else { + Outcome::Error((Status::Unauthorized, ())) + } + } +} diff --git a/backend/src/cdn.rs b/backend/src/cdn.rs new file mode 100644 index 0000000..a7d7819 --- /dev/null +++ b/backend/src/cdn.rs @@ -0,0 +1,25 @@ +use std::path::{Path, PathBuf}; + +use rocket::fs::NamedFile; + +pub fn routes() -> Vec { + routes![profile_pic, general] +} + +#[get("/profile/")] +pub async fn profile_pic(user_id: usize) -> Option { + if let Ok(image) = + NamedFile::open(Path::new("./cdn/profiles/").join(format!("{}.jpg", user_id))).await + { + Some(image) + } else { + Some(NamedFile::open("./cdn/profiles/default.jpg").await.ok()?) + } +} + +#[get("/")] +pub async fn general(file_name: PathBuf) -> Option { + NamedFile::open(Path::new("./cdn/").join(file_name)) + .await + .ok() +} diff --git a/backend/src/llm.rs b/backend/src/llm.rs index 3d635e8..792f2c4 100644 --- a/backend/src/llm.rs +++ b/backend/src/llm.rs @@ -1,6 +1,8 @@ // src/llm.rs use serde::{Deserialize, Serialize}; +use crate::messages::ChatMsg; + #[derive(Serialize)] struct LlmRequest { model: String, @@ -13,36 +15,51 @@ struct Message { content: String, } -pub async fn query_llm(text: &str) -> Result { - let client = reqwest::Client::new(); - - // Build the request body - let payload = LlmRequest { - model: "gemma2-9b-it".into(), // whatever model you run locally - messages: vec![Message { - role: "user".into(), - content: text.into(), - }], - }; - - // POST to lm‑studio (default 127.0.0.1:1234) - let resp = client - .post("http://127.0.0.1:1234/v1/chat/completions") - .json(&payload) - .send() - .await - .unwrap(); - - // The API returns a JSON with `choices[].message.content` - #[derive(Deserialize)] - struct LlmResponse { - choices: Vec, - } - #[derive(Deserialize)] - struct Choice { - message: Message, - } - - let llm_resp: LlmResponse = resp.json().await.unwrap(); - Ok(llm_resp.choices[0].message.content.clone()) +pub struct LlmWorker { + uri: String, +} + +impl LlmWorker { + pub fn new(uri: String) -> Self { + Self { uri } + } + + pub async fn query(&self, message: &ChatMsg) -> Result { + let client = reqwest::Client::new(); + + // Build the request body + let payload = LlmRequest { + model: "gemma2-9b-it".into(), // whatever model you run locally + messages: vec![Message { + role: "user".into(), + content: message.text.clone().into(), + }], + }; + + // POST to lm‑studio (default 127.0.0.1:1234) + let resp = client + .post(self.uri.clone()) + .json(&payload) + .send() + .await + .unwrap(); + + // The API returns a JSON with `choices[].message.content` + #[derive(Deserialize)] + struct LlmResponse { + choices: Vec, + } + #[derive(Deserialize)] + struct Choice { + message: Message, + } + + let llm_resp: LlmResponse = resp.json().await.unwrap(); + + Ok(ChatMsg { + user_id: 0, + text: llm_resp.choices[0].message.content.clone(), + timestamp: chrono::Local::now().timestamp() as usize, + }) + } } diff --git a/backend/src/main.rs b/backend/src/main.rs index 1558156..a24bb90 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -3,134 +3,44 @@ extern crate rocket; use rocket::fairing::Fairing; +use rocket::fs::FileServer; use rocket::http::Method; use rocket::response::stream::{Event, EventStream}; use rocket::serde::json::Json; use rocket::{Build, Rocket}; use rocket_cors::{AllowedOrigins, CorsOptions}; +use rocket_db_pools::{Connection, Database}; +use rocket_dyn_templates::{Template, context}; use serde::{Deserialize, Serialize}; use std::sync::Arc; use tokio::sync::broadcast; -use crate::llm::query_llm; +use crate::auth::{AuthGuard, DbConn}; +use crate::llm::LlmWorker; +use crate::messages::ChatBroadcaster; pub mod auth; +pub mod cdn; pub mod llm; +pub mod messages; -/// ---------- shared broadcaster ---------- -struct ChatBroadcaster { - sender: broadcast::Sender, +#[get("/users", rank = 2)] +async fn users(_ag: AuthGuard, mut db: Connection) -> Json> { + sqlx::query!("SELECT id FROM users") + .fetch_all(&mut **db) + .await + .map(|rows| rows.into_iter().map(|row| row.id).collect()) + .unwrap_or_else(|_| Vec::new()) + .into() } -impl ChatBroadcaster { - fn new(buffer_size: usize) -> Self { - let (sender, _rx) = broadcast::channel::(buffer_size); - Self { sender } - } - - async fn publish(&self, msg: ChatMsg) { - let _ = self.sender.send(msg); - } - - fn subscribe(&self) -> broadcast::Receiver { - self.sender.subscribe() - } -} - -/// ---------- Rocket routes ---------- -#[derive(Debug, Serialize, Deserialize, Clone)] -struct ChatMsg { - userid: usize, - text: String, - timestamp: usize, -} - -#[post("/chat", format = "json", data = "")] -async fn post_message( - msg: Json, - chat: &rocket::State>, -) -> &'static str { - chat.publish(msg.into_inner()).await; - "Message sent" -} - -#[get("/events")] -async fn event_stream(chat: &rocket::State>) -> EventStream![] { - let mut rx = chat.subscribe(); - - EventStream! { - loop { - match rx.recv().await { - Ok(msg) => yield Event::json(&msg), - Err(broadcast::error::RecvError::Lagged(_)) => { - yield Event::comment("lagged"); - } - Err(broadcast::error::RecvError::Closed) => break, - } - } - } -} - -// ---------- LLM worker ---------- -async fn start_llm_worker(chat: Arc) { - let mut rx = chat.subscribe(); - - loop { - match rx.recv().await { - Ok(msg) => { - if msg.userid == 0 { - // ignore bot messages - continue; - } - - let user_text = msg.text.clone(); - let chat_clone = chat.clone(); - - rocket::tokio::spawn(async move { - match query_llm(&user_text).await { - Ok(reply) => { - let bot_msg = ChatMsg { - userid: 0, - text: reply, - timestamp: chrono::Local::now().timestamp() as usize, - }; - chat_clone.publish(bot_msg).await; - } - Err(e) => eprintln!("LLM error: {}", e), - } - }); - } - Err(_) => break, // channel closed - } - } -} - -pub struct LlmWorkerFairing; - -#[rocket::async_trait] -impl Fairing for LlmWorkerFairing { - fn info(&self) -> rocket::fairing::Info { - rocket::fairing::Info { - name: "LLM background worker", - kind: rocket::fairing::Kind::Ignite, - } - } - - async fn on_ignite(&self, rocket: Rocket) -> rocket::fairing::Result { - // Grab the shared broadcaster from state - let chat = rocket - .state::>() - .expect("ChatBroadcaster not managed"); - // Clone it so we can move into async block - let chat_clone = Arc::clone(chat); - - // Spawn the background worker **inside** on_ignite - tokio::spawn(async move { - start_llm_worker(chat_clone).await; - }); - - Ok(rocket) - } +#[get("/users/", rank = 1)] +async fn username_for_id(id: usize, _ag: AuthGuard, mut db: Connection) -> String { + sqlx::query!("SELECT username FROM users WHERE id = $1", id as i32) + .fetch_one(&mut **db) + .await + .map(|row| row.username) + .unwrap_or_else(|_| "User not found".to_string()) } /// ---------- launch ---------- @@ -151,9 +61,22 @@ fn rocket() -> Rocket { rocket::build() .manage(chat) .attach(cors.to_cors().unwrap()) - .attach(LlmWorkerFairing {}) + .attach(DbConn::init()) + .attach(Template::fairing()) + .mount("/static", FileServer::from("static")) + .mount("/cdn", cdn::routes()) .mount( "/", - routes![post_message, event_stream, auth::signup, auth::login], + routes![ + users, + username_for_id, + messages::chat_page, + messages::get_messages, + messages::post_message, + messages::event_stream, + auth::signup, + auth::signup_page, + auth::login + ], ) } diff --git a/backend/src/messages.rs b/backend/src/messages.rs new file mode 100644 index 0000000..dd54d09 --- /dev/null +++ b/backend/src/messages.rs @@ -0,0 +1,136 @@ +use std::sync::Arc; + +use rocket::{ + response::stream::{Event, EventStream}, + serde::json::Json, +}; +use rocket_db_pools::Connection; +use rocket_dyn_templates::{Template, context}; +use serde::{Deserialize, Serialize}; +use tokio::sync::broadcast; + +use crate::{ + auth::{AuthGuard, DbConn}, + llm::LlmWorker, +}; + +/// ---------- shared broadcaster ---------- +pub struct ChatBroadcaster { + sender: broadcast::Sender, +} + +impl ChatBroadcaster { + pub fn new(buffer_size: usize) -> Self { + let (sender, _rx) = broadcast::channel::(buffer_size); + Self { sender } + } + + pub async fn publish(&self, msg: ChatMsg) { + let _ = self.sender.send(msg); + } + + pub fn subscribe(&self) -> broadcast::Receiver { + self.sender.subscribe() + } +} + +/// ---------- Rocket routes ---------- +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct ChatMsg { + pub user_id: usize, + pub text: String, + pub timestamp: usize, +} + +#[post("/chat", format = "json", data = "")] +pub async fn post_message( + mut msg: Json, + chat: &rocket::State>, + mut db: Connection, + ag: AuthGuard, +) -> Result<(), String> { + const CHANNEL_ID: i32 = 1; + const LMSTUDIO_URI: &'static str = "http://127.0.0.1:1234/v1/chat/completions"; + + let chat = chat.inner().clone(); + + msg.user_id = ag.0; + chat.publish(msg.clone().into_inner()).await; + + sqlx::query!( + "INSERT INTO messages (channel_id, user_id, content) VALUES ($1, $2, $3)", + CHANNEL_ID, + msg.user_id as i32, + msg.text + ) + .execute(&mut **db) + .await + .map_err(|_| "Failed".to_string())?; + + // get response + tokio::spawn(async move { + let response = LlmWorker::new(LMSTUDIO_URI.to_string()).query(&msg).await; + + if let Ok(message) = response { + chat.publish(message.clone()).await; + + sqlx::query!( + "INSERT INTO messages (channel_id, user_id, content) VALUES ($1, $2, $3)", + CHANNEL_ID, + message.user_id as i32, + message.text + ) + .execute(&mut **db) + .await + .map_err(|_| "Failed".to_string()) + .unwrap(); + } + }); + + Ok(()) +} + +#[get("/messages")] +pub async fn get_messages(mut db: Connection, _ag: AuthGuard) -> Json> { + Json( + sqlx::query!( + "SELECT user_id, content, created_at FROM messages ORDER BY created_at DESC LIMIT 100" + ) + .fetch_all(&mut **db) + .await + .unwrap_or_else(|_| Vec::new()) + .into_iter() + .rev() + .map(|row| ChatMsg { + user_id: row.user_id as usize, + text: row.content, + timestamp: row.created_at.unwrap().unix_timestamp() as usize, + }) + .collect(), + ) +} + +#[get("/events")] +pub async fn event_stream( + chat: &rocket::State>, + _ag: AuthGuard, +) -> EventStream![] { + let mut rx = chat.subscribe(); + + EventStream! { + loop { + match rx.recv().await { + Ok(msg) => yield Event::json(&msg), + Err(broadcast::error::RecvError::Lagged(_)) => { + yield Event::comment("lagged"); + } + Err(broadcast::error::RecvError::Closed) => break, + } + } + } +} + +#[get("/")] +pub async fn chat_page(ag: AuthGuard) -> Template { + Template::render("chat", context!(user_id: ag.0)) +} diff --git a/backend/static/css/index.css b/backend/static/css/index.css new file mode 100644 index 0000000..e9e4efa --- /dev/null +++ b/backend/static/css/index.css @@ -0,0 +1,774 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; + background: #0a0a0a; + color: #e0e0e0; + height: 100vh; + overflow: hidden; +} + +.chat-container { + display: flex; + flex-direction: column; + height: 100vh; + max-width: 50vh; + margin: 0 auto; + background: #121212; + position: relative; + overflow: hidden; +} + +/* Chat Header */ +.chat-header { + padding: 10px; + background: #1a1a1a; + border-bottom: 1px solid #252525; +} + +.chat-title { + display: flex; + align-items: center; + gap: 12px; +} + +.status-dot { + width: 10px; + height: 10px; + background: #ff4444; + border-radius: 50%; + animation: pulse 2s infinite; +} + +@keyframes pulse { + 0%, + 100% { + transform: scale(1); + opacity: 1; + } + 50% { + transform: scale(1.3); + opacity: 0.7; + } +} + +.chat-title h1 { + font-size: 17px; + font-weight: 600; + color: #ffffff; +} + +/* Live Location Notification Bubble */ +.notification-container { + padding: 15px 20px 10px 20px; + display: flex; + flex-direction: column; + gap: 10px; + position: absolute; + top: 70px; + left: 0; + right: 0; + z-index: 10; + pointer-events: none; +} + +.live-location-bubble { + padding: 0; + border-radius: 20px; + position: relative; + overflow: hidden; + cursor: pointer; + transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); + border: 1px solid rgba(138, 43, 226, 0.3); + box-shadow: + 0 8px 32px rgba(106, 90, 205, 0.2), + inset 0 1px 0 rgba(255, 255, 255, 0.1); + pointer-events: auto; + max-height: 64px; + background: transparent; +} + +.live-location-bubble::before { + content: ""; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient( + 135deg, + rgba(106, 90, 205, 0.25) 0%, + rgba(72, 61, 139, 0.2) 50%, + rgba(123, 104, 238, 0.15) 100% + ); + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); + z-index: 0; +} + +.live-location-bubble.expanded::before { + opacity: 0; +} + +.live-location-bubble > * { + position: relative; + z-index: 1; +} + +.live-location-bubble.expanded { + max-height: 400px; + cursor: default; +} + +.map-container { + width: 100%; + height: 0; + opacity: 0; + transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); + overflow: hidden; +} + +.live-location-bubble.expanded .map-container { + height: 260px; + opacity: 1; +} + +.map-container img { + width: 100%; + height: 100%; + object-fit: cover; + display: block; +} + +.location-content { + display: flex; + align-items: center; + gap: 12px; + padding: 16px 20px; + background: linear-gradient( + 135deg, + rgba(106, 90, 205, 0.25) 0%, + rgba(72, 61, 139, 0.2) 50%, + rgba(123, 104, 238, 0.15) 100% + ); + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); +} + +.live-location-bubble.expanded .location-content { + background: linear-gradient( + to bottom, + rgba(106, 90, 205, 0.45) 0%, + rgba(72, 61, 139, 0.4) 50%, + rgba(123, 104, 238, 0.35) 100% + ); +} + +.location-content { + display: flex; + align-items: center; + gap: 12px; +} + +.live-location-bubble::before { + content: ""; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 1px; + background: linear-gradient( + 90deg, + transparent, + rgba(255, 255, 255, 0.2), + transparent + ); +} + +.live-location-bubble:hover { + transform: translateY(-2px); + box-shadow: + 0 12px 40px rgba(106, 90, 205, 0.35), + inset 0 1px 0 rgba(255, 255, 255, 0.15); + background: linear-gradient( + 135deg, + rgba(106, 90, 205, 0.3) 0%, + rgba(72, 61, 139, 0.25) 50%, + rgba(123, 104, 238, 0.2) 100% + ); +} + +.live-location-bubble.active { + background: linear-gradient( + 135deg, + rgba(106, 90, 205, 0.35) 0%, + rgba(72, 61, 139, 0.3) 50%, + rgba(123, 104, 238, 0.25) 100% + ); + border-color: rgba(138, 43, 226, 0.5); +} + +.location-content { + display: flex; + align-items: center; + gap: 12px; +} + +.location-icon { + width: 32px; + height: 32px; + background: rgba(255, 255, 255, 0.15); + backdrop-filter: blur(10px); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + border: 1px solid rgba(255, 255, 255, 0.2); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3); + transition: all 0.3s ease; + flex-shrink: 0; +} + +.location-icon svg { + width: 18px; + height: 18px; + fill: #ea4335; + filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3)); +} + +.live-location-bubble.expanded .location-icon { + display: none; +} + +.join-button { + display: none; + padding: 8px 20px; + background: rgba(255, 255, 255, 0.15); + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.2); + border-radius: 20px; + color: #ffffff; + font-size: 14px; + font-weight: 600; + cursor: pointer; + transition: all 0.2s ease; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); + flex-shrink: 0; +} + +.live-location-bubble.expanded .join-button { + display: block; +} + +.join-button:hover { + background: rgba(255, 255, 255, 0.25); + transform: scale(1.05); +} + +.join-button:active { + transform: scale(0.95); +} + +.join-button.active { + background: rgba(106, 90, 205, 0.4); + border-color: rgba(138, 43, 226, 0.5); +} + +.live-location-bubble.active .location-icon { + background: rgba(255, 255, 255, 0.25); +} + +.location-text { + font-size: 15px; + font-weight: 600; + color: #ffffff; + flex: 1; + letter-spacing: 0.3px; +} + +.location-users { + display: flex; + align-items: center; +} + +.location-user-pic { + width: 32px; + height: 32px; + border-radius: 35%; + margin-left: -15px; + position: relative; + z-index: 1; + transition: all 0.2s ease; +} + +.location-user-pic:first-child { + margin-left: 0; +} + +.location-user-pic:hover { + z-index: 10; + transform: scale(1.15); +} + +.location-count { + width: 32px; + height: 32px; + border-radius: 35%; + background: rgba(0, 0, 0, 0.5); + backdrop-filter: blur(10px); + margin-left: -15px; + display: flex; + align-items: center; + justify-content: center; + font-size: 10px; + font-weight: 600; + color: #ffffff; + z-index: 2; +} + +.messages-container::before { + content: ""; + flex: 1 0 auto; +} + +/* Messages Container */ +.messages-container { + display: flex; + flex-direction: column; + /*justify-content: flex-end;*/ + flex: 1; + padding: 15px 0 15px 0; + overflow-y: scroll; + background: #121212; +} + +.message { + margin: 10px 20px; + padding: 10px 10px; + border-radius: 10px; + background: rgba(30, 30, 30, 0.4); + backdrop-filter: blur(10px); + border: 1px solid #252525; + animation: slideIn 0.3s ease-out; + transition: all 0.2s ease; + display: flex; + gap: 10px; +} + +.message:hover { + background: #1f1f1f; + border-color: #2a2a2a; +} + +@keyframes slideIn { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.user-avatar { + width: 48px; + height: 48px; + border-radius: 25%; + background-size: cover; + border: 2px solid #252525; + flex-shrink: 0; + background-image: url("static/profile_pics/default.jpg"); +} + +.user-avatar.blue { + background: linear-gradient(135deg, #4169e1, #6495ed); +} + +.message-content { + flex: 1; + min-width: 0; +} + +.message-header { + display: flex; + align-items: baseline; + gap: 8px; + margin-bottom: 4px; +} + +.username { + font-weight: 600; + font-size: 15px; + color: #e0e0e0; +} + +.timestamp { + font-size: 11px; + color: #666; + font-weight: 400; +} + +.message-text { + font-size: 14px; + color: #b0b0b0; + line-height: 1.4; + word-wrap: break-word; +} + +/* Input Container */ +.input-container { + padding: 10px; + background: #1a1a1a; + border-top: 1px solid #252525; +} + +.input-wrapper { + display: flex; + align-items: center; + gap: 10px; + background: #252525; + border-radius: 10px; + padding: 5px 5px; + border: 1px solid #2a2a2a; + transition: all 0.2s ease; +} + +.input-wrapper:focus-within { + background: #2a2a2a; + border-color: #6a5acd; + box-shadow: 0 0 0 3px rgba(106, 90, 205, 0.1); +} + +.input-wrapper input { + flex: 1; + background: none; + border: none; + color: #e0e0e0; + font-size: 14px; + outline: none; +} + +.input-wrapper input::placeholder { + color: #666; +} + +.send-button { + width: 32px; + height: 32px; + background: none; + border-radius: 10px; + border: none; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + font-size: 14px; + transition: all 0.2s ease; + flex-shrink: 0; +} + +.send-button:hover { + transform: scale(1.1); + box-shadow: 0 4px 15px rgba(106, 90, 205, 0.4); + background: rgba(255, 255, 255, 0.4); +} + +.send-button:active { + transform: scale(0.95); +} + +/* Scrollbar styling */ +.messages-container::-webkit-scrollbar { + width: 6px; +} + +.messages-container::-webkit-scrollbar-track { + background: #1a1a1a; +} + +.messages-container::-webkit-scrollbar-thumb { + background: #333; + border-radius: 3px; +} + +.messages-container::-webkit-scrollbar-thumb:hover { + background: #444; +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; + background: #0a0a0a; + color: #e0e0e0; + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + padding: 20px; +} + +.signup-container { + width: 100%; + max-width: 480px; + background: #121212; + border-radius: 16px; + overflow: hidden; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); + animation: slideIn 0.4s ease-out; +} + +@keyframes slideIn { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.signup-header { + padding: 40px 40px 30px; + text-align: center; + background: linear-gradient( + 135deg, + rgba(106, 90, 205, 0.15) 0%, + rgba(72, 61, 139, 0.1) 100% + ); + border-bottom: 1px solid #252525; +} + +.logo { + width: 80px; + height: 80px; + margin: 0 auto 20px; + background: linear-gradient(135deg, #6a5acd, #483d8b); + border-radius: 25%; + display: flex; + align-items: center; + justify-content: center; + font-size: 36px; + font-weight: bold; + color: #ffffff; + box-shadow: 0 4px 16px rgba(106, 90, 205, 0.3); +} + +.signup-header h1 { + font-size: 28px; + font-weight: 600; + color: #ffffff; + margin-bottom: 8px; +} + +.signup-header p { + font-size: 14px; + color: #888; +} + +.signup-form { + padding: 40px; +} + +.form-group { + margin-bottom: 24px; +} + +.form-group label { + display: block; + font-size: 13px; + font-weight: 600; + color: #b0b0b0; + margin-bottom: 8px; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.input-wrapper { + position: relative; +} + +.form-group input { + width: 100%; + padding: 12px 16px; + background: #1a1a1a; + border: 1px solid #252525; + border-radius: 8px; + color: #e0e0e0; + font-size: 15px; + transition: all 0.2s ease; + outline: none; +} + +.form-group input:focus { + background: #1f1f1f; + border-color: #6a5acd; + box-shadow: 0 0 0 3px rgba(106, 90, 205, 0.1); +} + +.form-group input::placeholder { + color: #555; +} + +.error-message { + display: none; + margin-top: 8px; + font-size: 12px; + color: #ff4444; +} + +.form-group.error input { + border-color: #ff4444; +} + +.form-group.error .error-message { + display: block; +} + +.password-toggle { + position: absolute; + right: 12px; + top: 50%; + transform: translateY(-50%); + background: none; + border: none; + color: #666; + cursor: pointer; + padding: 4px; + font-size: 12px; + transition: color 0.2s ease; +} + +.password-toggle:hover { + color: #888; +} + +.submit-button { + width: 100%; + padding: 14px; + background: linear-gradient(135deg, #6a5acd, #483d8b); + border: none; + border-radius: 8px; + color: #ffffff; + font-size: 16px; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; + box-shadow: 0 4px 16px rgba(106, 90, 205, 0.3); + margin-top: 8px; +} + +.submit-button:hover { + background: linear-gradient(135deg, #7b6bd8, #5a4ea0); + transform: translateY(-2px); + box-shadow: 0 6px 20px rgba(106, 90, 205, 0.4); +} + +.submit-button:active { + transform: translateY(0); +} + +.submit-button:disabled { + background: #2a2a2a; + color: #555; + cursor: not-allowed; + transform: none; + box-shadow: none; +} + +.signup-footer { + padding: 20px 40px 30px; + text-align: center; + font-size: 14px; + color: #666; +} + +.signup-footer a { + color: #6a5acd; + text-decoration: none; + font-weight: 600; + transition: color 0.2s ease; +} + +.signup-footer a:hover { + color: #7b6bd8; + text-decoration: underline; +} + +.success-message { + display: none; + padding: 16px; + background: rgba(76, 175, 80, 0.1); + border: 1px solid rgba(76, 175, 80, 0.3); + border-radius: 8px; + color: #4caf50; + font-size: 14px; + margin-bottom: 20px; + text-align: center; +} + +.success-message.show { + display: block; + animation: slideIn 0.3s ease-out; +} + +.loading-spinner { + display: inline-block; + width: 16px; + height: 16px; + border: 2px solid rgba(255, 255, 255, 0.3); + border-top-color: #ffffff; + border-radius: 50%; + animation: spin 0.6s linear infinite; + margin-right: 8px; + vertical-align: middle; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + +.checkbox-group { + display: flex; + align-items: flex-start; + gap: 10px; + margin-bottom: 24px; +} + +.checkbox-group input[type="checkbox"] { + width: 18px; + height: 18px; + margin-top: 2px; + cursor: pointer; + accent-color: #6a5acd; +} + +.checkbox-group label { + font-size: 13px; + color: #888; + line-height: 1.5; + text-transform: none; + letter-spacing: normal; + font-weight: 400; +} + +.checkbox-group a { + color: #6a5acd; + text-decoration: none; +} + +.checkbox-group a:hover { + text-decoration: underline; +} diff --git a/backend/templates/chat.html.tera b/backend/templates/chat.html.tera new file mode 100644 index 0000000..27aa422 --- /dev/null +++ b/backend/templates/chat.html.tera @@ -0,0 +1,231 @@ + + + + + + Discord Clone - Group Chat + + + +
+ + +
+
+ +

Chat title

+
+
+ + +
+
+
+ Map +
+
+
+ Location +
+ +
Live Location
+
+ +
+
+
+
+ + + +
+ + +
+
+ + +
+
+
+ + + + diff --git a/backend/templates/signup.html.tera b/backend/templates/signup.html.tera new file mode 100644 index 0000000..936b7dc --- /dev/null +++ b/backend/templates/signup.html.tera @@ -0,0 +1,275 @@ + + + + + + Discord Clone - Sign Up + + + + + + + +