diff --git a/Cargo.lock b/Cargo.lock index 6061ba0a59..79caee9f16 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -126,7 +126,7 @@ dependencies = [ "log", "mime", "mime_guess", - "percent-encoding 2.3.0", + "percent-encoding", "pin-project-lite 0.2.9", ] @@ -163,7 +163,7 @@ dependencies = [ "lazy_static", "log", "mime", - "percent-encoding 2.3.0", + "percent-encoding", "pin-project 1.0.7", "rand 0.7.3", "regex", @@ -185,7 +185,7 @@ dependencies = [ "actix-rt 2.9.0", "actix-service 2.0.1", "actix-utils 3.0.0", - "ahash", + "ahash 0.7.6", "base64 0.21.0", "bitflags 1.3.2", "brotli", @@ -203,7 +203,7 @@ dependencies = [ "language-tags 0.3.2", "local-channel", "mime", - "percent-encoding 2.3.0", + "percent-encoding", "pin-project-lite 0.2.9", "rand 0.8.5", "sha1 0.10.4", @@ -471,7 +471,7 @@ dependencies = [ "socket2 0.3.19", "time 0.2.26", "tinyvec", - "url 2.4.1", + "url", ] [[package]] @@ -489,7 +489,7 @@ dependencies = [ "actix-service 2.0.1", "actix-utils 3.0.0", "actix-web-codegen 4.2.0", - "ahash", + "ahash 0.7.6", "bytes 1.3.0", "bytestring", "cfg-if 1.0.0", @@ -511,7 +511,7 @@ dependencies = [ "smallvec 1.10.0", "socket2 0.4.7", "time 0.3.14", - "url 2.4.1", + "url", ] [[package]] @@ -625,6 +625,18 @@ dependencies = [ "version_check", ] +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if 1.0.0", + "getrandom 0.2.8", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "1.1.2" @@ -713,9 +725,9 @@ checksum = "70033777eb8b5124a81a1889416543dddef2de240019b674c81285a2635a7e1e" [[package]] name = "anyhow" -version = "1.0.40" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "archives" @@ -822,7 +834,7 @@ dependencies = [ "native-tls", "serde", "serde_json", - "url 2.4.1", + "url", ] [[package]] @@ -859,7 +871,7 @@ dependencies = [ "futures-core", "log", "mime", - "percent-encoding 2.3.0", + "percent-encoding", "rand 0.7.3", "serde", "serde_json", @@ -880,7 +892,7 @@ dependencies = [ "serde", "thiserror", "time 0.3.14", - "url 2.4.1", + "url", ] [[package]] @@ -1354,7 +1366,7 @@ version = "0.0.1" dependencies = [ "anyhow", "easyenv", - "url 2.4.1", + "url", ] [[package]] @@ -1404,7 +1416,7 @@ version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951" dependencies = [ - "percent-encoding 2.3.0", + "percent-encoding", "time 0.2.26", "version_check", ] @@ -1415,11 +1427,21 @@ version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" dependencies = [ - "percent-encoding 2.3.0", + "percent-encoding", "time 0.3.14", "version_check", ] +[[package]] +name = "cookies" +version = "0.0.1" +dependencies = [ + "errors", + "hmac 0.10.1", + "jwt", + "sha2 0.9.5", +] + [[package]] name = "copyless" version = "0.1.5" @@ -1616,29 +1638,25 @@ dependencies = [ [[package]] name = "cssparser" -version = "0.27.2" +version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" +checksum = "5b3df4f93e5fbbe73ec01ec8d3f68bba73107993a5b1e7519273c32db9b0d5be" dependencies = [ "cssparser-macros", "dtoa-short", - "itoa 0.4.7", - "matches", - "phf 0.8.0", - "proc-macro2", - "quote", + "itoa 1.0.3", + "phf", "smallvec 1.10.0", - "syn 1.0.107", ] [[package]] name = "cssparser-macros" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfae75de57f2b2e85e8768c3ea840fd159c8f33e2b6522c7835b7abac81be16e" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 1.0.107", + "syn 2.0.26", ] [[package]] @@ -1825,25 +1843,37 @@ dependencies = [ [[package]] name = "diesel" -version = "1.4.6" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "047bfc4d5c3bd2ef6ca6f981941046113524b9a9f9a7cbdfdd7ff40f58e6f542" +checksum = "2268a214a6f118fce1838edba3d1561cf0e78d8de785475957a580a7f8c69d33" dependencies = [ + "bitflags 2.4.0", "byteorder", "diesel_derives", "mysqlclient-sys", - "url 1.7.2", + "percent-encoding", + "url", ] [[package]] name = "diesel_derives" -version = "1.4.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3" +checksum = "ef8337737574f55a468005a83499da720f20c65586241ffea339db9ecdfd2b44" dependencies = [ + "diesel_table_macro_syntax", "proc-macro2", "quote", - "syn 1.0.107", + "syn 2.0.26", +] + +[[package]] +name = "diesel_table_macro_syntax" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc5557efc453706fed5e4fa85006fe9817c224c3f480a34c7e5959fd700921c5" +dependencies = [ + "syn 2.0.26", ] [[package]] @@ -2250,7 +2280,7 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ - "percent-encoding 2.3.0", + "percent-encoding", ] [[package]] @@ -2546,7 +2576,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash", + "ahash 0.7.6", ] [[package]] @@ -2708,7 +2738,7 @@ dependencies = [ "serde_json", "serde_qs 0.8.5", "serde_urlencoded", - "url 2.4.1", + "url", ] [[package]] @@ -2844,17 +2874,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -[[package]] -name = "idna" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "idna" version = "0.2.3" @@ -3354,8 +3373,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" dependencies = [ "log", - "phf 0.10.1", - "phf_codegen 0.10.0", + "phf", + "phf_codegen", "string_cache", "string_cache_codegen", "tendril", @@ -3603,9 +3622,9 @@ dependencies = [ [[package]] name = "mysqlclient-sys" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e9637d93448044078aaafea7419aed69d301b4a12bcc4aa0ae856eb169bef85" +checksum = "f61b381528ba293005c42a409dd73d034508e273bf90481f17ec2e964a6e969b" dependencies = [ "pkg-config", "vcpkg", @@ -3679,12 +3698,6 @@ dependencies = [ "uuid 0.8.2", ] -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - [[package]] name = "nom" version = "7.1.2" @@ -4032,46 +4045,21 @@ dependencies = [ "base64ct", ] -[[package]] -name = "percent-encoding" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" - [[package]] name = "percent-encoding" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" -[[package]] -name = "phf" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" -dependencies = [ - "phf_macros", - "phf_shared 0.8.0", - "proc-macro-hack", -] - [[package]] name = "phf" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" dependencies = [ - "phf_shared 0.10.0", -] - -[[package]] -name = "phf_codegen" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" -dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", + "phf_macros", + "phf_shared", + "proc-macro-hack", ] [[package]] @@ -4080,18 +4068,8 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", -] - -[[package]] -name = "phf_generator" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" -dependencies = [ - "phf_shared 0.8.0", - "rand 0.7.3", + "phf_generator", + "phf_shared", ] [[package]] @@ -4100,33 +4078,24 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" dependencies = [ - "phf_shared 0.10.0", + "phf_shared", "rand 0.8.5", ] [[package]] name = "phf_macros" -version = "0.8.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" +checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", + "phf_generator", + "phf_shared", "proc-macro-hack", "proc-macro2", "quote", "syn 1.0.107", ] -[[package]] -name = "phf_shared" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" -dependencies = [ - "siphasher", -] - [[package]] name = "phf_shared" version = "0.10.0" @@ -4393,7 +4362,6 @@ dependencies = [ "rand_chacha 0.2.2", "rand_core 0.5.1", "rand_hc", - "rand_pcg", ] [[package]] @@ -4469,15 +4437,6 @@ dependencies = [ "rand_core 0.5.1", ] -[[package]] -name = "rand_pcg" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -dependencies = [ - "rand_core 0.5.1", -] - [[package]] name = "rayon" version = "1.8.0" @@ -4518,7 +4477,7 @@ dependencies = [ "dtoa", "futures 0.1.31", "itoa 0.4.7", - "percent-encoding 2.3.0", + "percent-encoding", "sha1 0.6.0", "tokio-codec", "tokio-executor", @@ -4526,7 +4485,7 @@ dependencies = [ "tokio-sync", "tokio-tcp", "tokio-uds", - "url 2.4.1", + "url", ] [[package]] @@ -4539,9 +4498,9 @@ dependencies = [ "combine 4.6.3", "dtoa", "itoa 0.4.7", - "percent-encoding 2.3.0", + "percent-encoding", "sha1 0.6.0", - "url 2.4.1", + "url", ] [[package]] @@ -4556,12 +4515,12 @@ dependencies = [ "dtoa", "futures-util", "itoa 0.4.7", - "percent-encoding 2.3.0", + "percent-encoding", "pin-project-lite 0.2.9", "sha1 0.6.0", "tokio 1.25.0", "tokio-util 0.6.9", - "url 2.4.1", + "url", ] [[package]] @@ -4672,7 +4631,7 @@ dependencies = [ "mime", "native-tls", "once_cell", - "percent-encoding 2.3.0", + "percent-encoding", "pin-project-lite 0.2.9", "serde", "serde_json", @@ -4681,7 +4640,7 @@ dependencies = [ "tokio-native-tls", "tokio-util 0.7.4", "tower-service", - "url 2.4.1", + "url", "wasm-bindgen", "wasm-bindgen-futures", "wasm-streams", @@ -4744,11 +4703,12 @@ dependencies = [ [[package]] name = "rpassword" -version = "5.0.1" +version = "7.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc936cf8a7ea60c58f030fd36a612a48f440610214dc54bc36431f9ea0c3efb" +checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322" dependencies = [ "libc", + "rtoolbox", "winapi 0.3.9", ] @@ -4784,6 +4744,16 @@ dependencies = [ "quick-xml 0.27.1", ] +[[package]] +name = "rtoolbox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a" +dependencies = [ + "libc", + "winapi 0.3.9", +] + [[package]] name = "rust-ini" version = "0.18.0" @@ -4814,7 +4784,7 @@ dependencies = [ "maybe-async", "md5", "minidom", - "percent-encoding 2.3.0", + "percent-encoding", "quick-xml 0.26.0", "reqwest", "serde", @@ -4824,7 +4794,7 @@ dependencies = [ "time 0.3.14", "tokio 1.25.0", "tokio-stream", - "url 2.4.1", + "url", ] [[package]] @@ -4949,15 +4919,16 @@ dependencies = [ [[package]] name = "scraper" -version = "0.14.0" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7cb4dae083699a22a65aa9d2699c27f525e35dffaec38b10801e958ed4cf27" +checksum = "c95a930e03325234c18c7071fd2b60118307e025d6fff3e12745ffbf63a3d29c" dependencies = [ + "ahash 0.8.3", "cssparser", "ego-tree", "getopts", "html5ever", - "matches", + "once_cell", "selectors", "smallvec 1.10.0", "tendril", @@ -4998,22 +4969,21 @@ dependencies = [ [[package]] name = "selectors" -version = "0.22.0" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" +checksum = "4eb30575f3638fc8f6815f448d50cb1a2e255b0897985c8c59f4d37b72a07b06" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.0", "cssparser", "derive_more", "fxhash", "log", - "matches", - "phf 0.8.0", - "phf_codegen 0.8.0", + "new_debug_unreachable", + "phf", + "phf_codegen", "precomputed-hash", "servo_arc", "smallvec 1.10.0", - "thin-slice", ] [[package]] @@ -5077,7 +5047,7 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6" dependencies = [ - "percent-encoding 2.3.0", + "percent-encoding", "serde", "thiserror", ] @@ -5088,7 +5058,7 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6af4cee6cd4b23b45e6709150d1e9af5c748131de7e3316a7c2b3008051ed725" dependencies = [ - "percent-encoding 2.3.0", + "percent-encoding", "serde", "thiserror", ] @@ -5153,11 +5123,10 @@ dependencies = [ [[package]] name = "servo_arc" -version = "0.1.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" +checksum = "d036d71a959e00c77a63538b90a6c2390969f9772b096ea837205c6bd0491a44" dependencies = [ - "nodrop", "stable_deref_trait", ] @@ -5368,7 +5337,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcbc16ddba161afc99e14d1713a453747a2b07fc097d2009f4c300ec99286105" dependencies = [ - "ahash", + "ahash 0.7.6", "atoi", "bitflags 1.3.2", "byteorder", @@ -5398,7 +5367,7 @@ dependencies = [ "num-bigint 0.4.3", "once_cell", "paste", - "percent-encoding 2.3.0", + "percent-encoding", "rand 0.8.5", "rsa", "serde", @@ -5410,7 +5379,7 @@ dependencies = [ "stringprep", "thiserror", "tokio-stream", - "url 2.4.1", + "url", ] [[package]] @@ -5432,7 +5401,7 @@ dependencies = [ "sqlx-core", "sqlx-rt", "syn 1.0.107", - "url 2.4.1", + "url", ] [[package]] @@ -5551,6 +5520,7 @@ dependencies = [ "cloud_storage", "config", "container_common", + "cookies", "data-encoding", "datetimes", "derive_more", @@ -5644,7 +5614,7 @@ dependencies = [ "new_debug_unreachable", "once_cell", "parking_lot 0.12.1", - "phf_shared 0.10.0", + "phf_shared", "precomputed-hash", "serde", ] @@ -5655,8 +5625,8 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", + "phf_generator", + "phf_shared", "proc-macro2", "quote", ] @@ -6033,12 +6003,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "thin-slice" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" - [[package]] name = "thiserror" version = "1.0.43" @@ -6486,7 +6450,7 @@ dependencies = [ "smallvec 1.10.0", "thiserror", "tokio 0.2.25", - "url 2.4.1", + "url", ] [[package]] @@ -6612,7 +6576,7 @@ dependencies = [ "rustls-native-certs", "sha-1", "thiserror", - "url 2.4.1", + "url", "utf-8", "webpki", ] @@ -6705,7 +6669,7 @@ dependencies = [ "thiserror", "twitch_oauth2", "typed-builder", - "url 2.4.1", + "url", "version_check", ] @@ -6740,7 +6704,7 @@ dependencies = [ "serde", "serde_json", "thiserror", - "url 2.4.1", + "url", ] [[package]] @@ -6839,17 +6803,6 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" -[[package]] -name = "url" -version = "1.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" -dependencies = [ - "idna 0.1.5", - "matches", - "percent-encoding 1.0.1", -] - [[package]] name = "url" version = "2.4.1" @@ -6858,7 +6811,7 @@ checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ "form_urlencoded", "idna 0.4.0", - "percent-encoding 2.3.0", + "percent-encoding", "serde", ] @@ -6895,6 +6848,7 @@ dependencies = [ "bcrypt", "chrono", "container_common", + "cookies", "dotenv", "enums", "errors", diff --git a/Cargo.toml b/Cargo.toml index 6781c87208..658ef97d41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ members = [ "crates/lib/caching/memory_caching", "crates/lib/caching/redis_caching", "crates/lib/concurrency", + "crates/lib/cookies", "crates/lib/crockford", "crates/lib/datetimes", "crates/lib/deprecated/config", # TODO(bt, 2023-02-13): Deprecate or repurpose diff --git a/crates/_types/reusable_types/Cargo.toml b/crates/_types/reusable_types/Cargo.toml index 0b741a9e88..7c0a03d4ad 100644 --- a/crates/_types/reusable_types/Cargo.toml +++ b/crates/_types/reusable_types/Cargo.toml @@ -18,7 +18,7 @@ path = "src/lib.rs" # (none) # External -anyhow = "1.0.40" +anyhow = "1.0.75" chrono = { version = "0.4.19", features = ["serde"] } # Serialization diff --git a/crates/_types/tokens/src/prefixes.rs b/crates/_types/tokens/src/prefixes.rs index 7333ae801f..ca6deb3425 100644 --- a/crates/_types/tokens/src/prefixes.rs +++ b/crates/_types/tokens/src/prefixes.rs @@ -13,6 +13,8 @@ use strum::EnumIter; #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[cfg_attr(test, derive(EnumIter, EnumCount))] pub(crate) enum EntityType { + /// AVTs are not stored as primary keys in any table, but an index in many tables. + AnonymousVisitorTracking, AuditLog, Comment, DownloadJob, @@ -36,6 +38,7 @@ impl EntityType { pub fn prefix(self) -> &'static str { match self { + Self::AnonymousVisitorTracking => "avt_", Self::AuditLog => "audit_", Self::Comment => "comment_", Self::DownloadJob => "jdown_", // NB: Was "JGUP:" diff --git a/crates/_types/tokens/src/tokens/anonymous_visitor_tracking.rs b/crates/_types/tokens/src/tokens/anonymous_visitor_tracking.rs new file mode 100644 index 0000000000..2d014f9bfc --- /dev/null +++ b/crates/_types/tokens/src/tokens/anonymous_visitor_tracking.rs @@ -0,0 +1,16 @@ +use std::fmt::Debug; + +use serde::Deserialize; +use serde::Serialize; + +use crate::prefixes::EntityType; + +/// A rare instance that is *not* a primary key. +/// These are generated as cookies to track users for a better logged out experience and for analytics. +/// We use these as indices into several columns (ML result types, uploads, etc.) +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, sqlx::Type, Debug, Serialize, Deserialize)] +#[sqlx(transparent)] +pub struct AnonymousVisitorTrackingToken(pub String); + +impl_string_token!(AnonymousVisitorTrackingToken); +impl_crockford_generator!(AnonymousVisitorTrackingToken, 32usize, EntityType::AnonymousVisitorTracking, CrockfordLower); diff --git a/crates/_types/tokens/src/tokens/mod.rs b/crates/_types/tokens/src/tokens/mod.rs index 370fa5023a..2a613164fc 100644 --- a/crates/_types/tokens/src/tokens/mod.rs +++ b/crates/_types/tokens/src/tokens/mod.rs @@ -1,3 +1,4 @@ +pub mod anonymous_visitor_tracking; pub mod audit_logs; pub mod comments; pub mod generic_download_jobs; diff --git a/crates/_types/tokens/src/tokens/users.rs b/crates/_types/tokens/src/tokens/users.rs index 6df5b83905..0dbd4fb8a8 100644 --- a/crates/_types/tokens/src/tokens/users.rs +++ b/crates/_types/tokens/src/tokens/users.rs @@ -5,11 +5,6 @@ use serde::Serialize; use crate::prefixes::EntityType; -// FIXME: I think that this file+module structure is an anti-pattern. -// In the future, we should create two top-level directories: /tokens and /ids, and each token or -// ID type should be in its own file. (NB: single files cannot share token definitions due to the -// macro generating test modules that would conflict.) - /// The primary key for users. #[derive(Clone, PartialEq, Eq, sqlx::Type, Debug, Serialize, Deserialize)] #[sqlx(transparent)] diff --git a/crates/cli/database_backup/Cargo.toml b/crates/cli/database_backup/Cargo.toml index 838169307f..98af5e1216 100644 --- a/crates/cli/database_backup/Cargo.toml +++ b/crates/cli/database_backup/Cargo.toml @@ -20,7 +20,7 @@ container_common = { path = "../../lib/deprecated/container_common" } easyenv = { path = "../../lib/easyenv" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" chrono = { version = "0.4.19", features = ["serde"] } clap = "2.34.0" # TODO: This is really out of date, but has conflicts when updated # TODO/NB: Commenting out clap4 as it prevents windows builds diff --git a/crates/cli/database_cleanup/Cargo.toml b/crates/cli/database_cleanup/Cargo.toml index 94e5ae4e56..58321cf0ca 100644 --- a/crates/cli/database_cleanup/Cargo.toml +++ b/crates/cli/database_cleanup/Cargo.toml @@ -20,7 +20,7 @@ container_common = { path = "../../lib/deprecated/container_common" } easyenv = { path = "../../lib/easyenv" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" chrono = { version = "0.4.19", features = ["serde"] } # TODO/NB: Commenting out clap4 as it prevents windows builds # clap4 = { package = "clap", version = "4.0" } # TODO/NB: We're using an older version of clap elsewhere, hence the naming. diff --git a/crates/lib/api_clients/cloud_storage/Cargo.toml b/crates/lib/api_clients/cloud_storage/Cargo.toml index ccb19653ec..3c9a1261c8 100644 --- a/crates/lib/api_clients/cloud_storage/Cargo.toml +++ b/crates/lib/api_clients/cloud_storage/Cargo.toml @@ -19,7 +19,7 @@ buckets = { path = "../../../_types/buckets" } container_common = { path = "../../deprecated/container_common" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" log = "0.4.14" # The "never-encode-slash" feature seems to have been removed: diff --git a/crates/lib/api_clients/google_drive_common/Cargo.toml b/crates/lib/api_clients/google_drive_common/Cargo.toml index a3650e7893..f9b94cef36 100644 --- a/crates/lib/api_clients/google_drive_common/Cargo.toml +++ b/crates/lib/api_clients/google_drive_common/Cargo.toml @@ -19,7 +19,7 @@ container_common = { path = "../../deprecated/container_common" } subprocess_common = { path = "../../subprocess_common" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" log = "0.4.14" tempdir = "0.3.7" diff --git a/crates/lib/api_clients/twitch_common/Cargo.toml b/crates/lib/api_clients/twitch_common/Cargo.toml index cf1b2bbe5b..20506ccdf5 100644 --- a/crates/lib/api_clients/twitch_common/Cargo.toml +++ b/crates/lib/api_clients/twitch_common/Cargo.toml @@ -19,7 +19,7 @@ container_common = { path = "../../deprecated/container_common" } easyenv = { path = "../../easyenv" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" once_cell = "1.18.0" regex = "1.5.4" diff --git a/crates/lib/caching/memory_caching/Cargo.toml b/crates/lib/caching/memory_caching/Cargo.toml index 10b395b685..3650ac219b 100644 --- a/crates/lib/caching/memory_caching/Cargo.toml +++ b/crates/lib/caching/memory_caching/Cargo.toml @@ -20,7 +20,7 @@ container_common = { path = "../../deprecated/container_common" } errors = { path = "../../errors" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" chrono = { version = "0.4.19", features = ["serde"] } log = "0.4.14" diff --git a/crates/lib/cookies/Cargo.toml b/crates/lib/cookies/Cargo.toml new file mode 100644 index 0000000000..6f9678ec57 --- /dev/null +++ b/crates/lib/cookies/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "cookies" +edition = "2018" +version = "0.0.1" +authors = [ + "Brandon Thomas ", + "Brandon Thomas ", +] +publish = false + +[lib] +# NB: Public "cookies" crate is version 0.0.1 from 10 years ago! +name = "cookies" +path = "src/lib.rs" + +[dependencies] +# Internal +errors = { path = "../errors" } + +# External +hmac = "0.10.0" # jwt signing +jwt = "0.13.0" +sha2 = "0.9.5" # hmac signing + +[dev-dependencies] +# None yet diff --git a/crates/lib/cookies/src/jwt_signer.rs b/crates/lib/cookies/src/jwt_signer.rs new file mode 100644 index 0000000000..c6bf7445ad --- /dev/null +++ b/crates/lib/cookies/src/jwt_signer.rs @@ -0,0 +1,95 @@ +use std::collections::BTreeMap; + +use hmac::Hmac; +use hmac::NewMac; +use jwt::SignWithKey; +use jwt::VerifyWithKey; +use sha2::Sha256; + +use errors::{anyhow, AnyhowResult}; + +#[derive(Clone)] +pub struct JwtSigner { + hmac_key: Hmac, +} + +impl JwtSigner { + + pub fn new(hmac_secret: &str) -> AnyhowResult { + let hmac_key = Hmac::new_varkey(hmac_secret.as_bytes()) + .map_err(|e| anyhow!("invalid hmac: {:?}", e))?; + + Ok(Self { + hmac_key, + }) + } + + /// Turn a map of claims into a signed JWT cookie payload (string) + pub fn claims_to_jwt(&self, claims: &impl Claimable) -> AnyhowResult { + let jwt_string = claims.sign(&self.hmac_key)?; + Ok(jwt_string) + } + + /// Turn a JWT cookie payload (string) into a map of (key, value) claims + pub fn jwt_to_claims(&self, jwt: &str) -> AnyhowResult> { + let claims = jwt.verify_with_key(&self.hmac_key)?; + Ok(claims) + } +} + +pub trait Claimable { + fn sign(&self, hmac_key: &Hmac) -> AnyhowResult; +} + +impl Claimable for BTreeMap { + fn sign(&self, hmac_key: &Hmac) -> AnyhowResult { + let claims = self.sign_with_key(hmac_key)?; + Ok(claims) + } +} + +impl Claimable for BTreeMap<&str, &str> { + fn sign(&self, hmac_key: &Hmac) -> AnyhowResult { + let claims = self.sign_with_key(hmac_key)?; + Ok(claims) + } +} + +#[cfg(test)] +mod tests { + use std::collections::BTreeMap; + + use crate::jwt_signer::JwtSigner; + + #[test] + fn test_round_trip() { + let signer = JwtSigner::new("secret").unwrap(); + + let mut claims = BTreeMap::new(); + claims.insert("foo", "yes"); + claims.insert("bar", "no"); + + let jwt = signer.claims_to_jwt(&claims).unwrap(); + + let output_claims = signer.jwt_to_claims(&jwt).unwrap(); + + assert_eq!(claims.len(), output_claims.len()); + + for (k, v) in output_claims.iter() { + assert_eq!(v, claims[k.as_str()]); + } + } + + #[test] + fn test_stability() { + let signer = JwtSigner::new("secret").unwrap(); + + let mut claims = BTreeMap::new(); + claims.insert("foo", "yes"); + claims.insert("bar", "no"); + + let jwt = signer.claims_to_jwt(&claims).unwrap(); + + assert_eq!("eyJhbGciOiJIUzI1NiJ9.eyJiYXIiOiJubyIsImZvbyI6InllcyJ9.k4eRvIrtw4tuGDtQqSmEDngtGYAaQVRYVMCK5N3JcZA", &jwt); + } +} \ No newline at end of file diff --git a/crates/lib/cookies/src/lib.rs b/crates/lib/cookies/src/lib.rs new file mode 100644 index 0000000000..fe07630639 --- /dev/null +++ b/crates/lib/cookies/src/lib.rs @@ -0,0 +1,20 @@ +//! cookies +//! +//! This library contains reusable, tested, cross-cutting cookie functionality. +//! + +// Never allow these +#![forbid(private_in_public)] +#![forbid(unused_must_use)] // NB: It's unsafe to not close/check some things + +// Okay to toggle +#![forbid(unreachable_patterns)] +#![forbid(unused_imports)] +#![forbid(unused_mut)] +#![forbid(unused_variables)] + +// Always allow +#![allow(dead_code)] +#![allow(non_snake_case)] + +pub mod jwt_signer; \ No newline at end of file diff --git a/crates/lib/deprecated/config/Cargo.toml b/crates/lib/deprecated/config/Cargo.toml index e79b080651..9293ceb0c0 100644 --- a/crates/lib/deprecated/config/Cargo.toml +++ b/crates/lib/deprecated/config/Cargo.toml @@ -19,5 +19,5 @@ path = "src/lib.rs" easyenv = { path = "../../../lib/easyenv" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" url = "2.4.1" diff --git a/crates/lib/deprecated/container_common/Cargo.toml b/crates/lib/deprecated/container_common/Cargo.toml index 8007f20678..7492753e95 100644 --- a/crates/lib/deprecated/container_common/Cargo.toml +++ b/crates/lib/deprecated/container_common/Cargo.toml @@ -18,7 +18,7 @@ errors = { path = "../../errors" } hashing = { path = "../../files/hashing" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" once_cell = "1.18.0" rand = "0.8.3" uuid = { version = "0.8.2", features = ["v4"] } diff --git a/crates/lib/deprecated/http_server_common/Cargo.toml b/crates/lib/deprecated/http_server_common/Cargo.toml index 90ab5b8d07..9df7aea8c7 100644 --- a/crates/lib/deprecated/http_server_common/Cargo.toml +++ b/crates/lib/deprecated/http_server_common/Cargo.toml @@ -20,7 +20,7 @@ errors = { path = "../../errors" } reusable_types = { path = "../../../_types/reusable_types" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" base64 = "0.21.0" chrono = { version = "0.4.19", features = ["serde"] } dotenv = "0.15.0" diff --git a/crates/lib/errors/Cargo.toml b/crates/lib/errors/Cargo.toml index 2e77bf7e75..65cfe584a5 100644 --- a/crates/lib/errors/Cargo.toml +++ b/crates/lib/errors/Cargo.toml @@ -17,7 +17,7 @@ path = "src/lib.rs" # NB: This is one of the most central crates in the monorepo and everything depends on it. # Consider the dependencies here wisely. # Ideally we have almost nothing as a dependency of this crate. -anyhow = "1.0.40" +anyhow = "1.0.75" [dev-dependencies] # None yet diff --git a/crates/lib/jobs_common/Cargo.toml b/crates/lib/jobs_common/Cargo.toml index 5f843597e2..10bad74254 100644 --- a/crates/lib/jobs_common/Cargo.toml +++ b/crates/lib/jobs_common/Cargo.toml @@ -23,7 +23,7 @@ errors = { path = "../errors" } redis_common = { path = "../redis_common" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" chrono = { version = "0.4.19", features = ["serde"] } log = "0.4.14" r2d2_redis = "0.14.0" diff --git a/crates/lib/mysql_queries/Cargo.toml b/crates/lib/mysql_queries/Cargo.toml index d6b09feeda..ff67df7c43 100644 --- a/crates/lib/mysql_queries/Cargo.toml +++ b/crates/lib/mysql_queries/Cargo.toml @@ -25,7 +25,7 @@ sqlx_mysql_helpers = { path = "../sqlx_mysql_helpers" } tokens = { path = "../../_types/tokens" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" base64 = "0.21.0" chrono = { version = "0.4.19", features = ["serde"] } dotenv = "0.15.0" diff --git a/crates/lib/mysql_queries/src/queries/voice_designer/voice_samples/list_dataset_samples.rs b/crates/lib/mysql_queries/src/queries/voice_designer/voice_samples/list_dataset_samples_for_dataset_token.rs similarity index 64% rename from crates/lib/mysql_queries/src/queries/voice_designer/voice_samples/list_dataset_samples.rs rename to crates/lib/mysql_queries/src/queries/voice_designer/voice_samples/list_dataset_samples_for_dataset_token.rs index ae2e29d6ab..7548bea6c6 100644 --- a/crates/lib/mysql_queries/src/queries/voice_designer/voice_samples/list_dataset_samples.rs +++ b/crates/lib/mysql_queries/src/queries/voice_designer/voice_samples/list_dataset_samples_for_dataset_token.rs @@ -4,14 +4,24 @@ use log::warn; use sqlx::{MySql, MySqlPool}; use sqlx::pool::PoolConnection; +use enums::by_table::media_files::media_file_type::MediaFileType; use errors::AnyhowResult; +use tokens::tokens::media_files::MediaFileToken; use tokens::tokens::users::UserToken; use tokens::tokens::zs_voice_dataset_samples::ZsVoiceDatasetSampleToken; use tokens::tokens::zs_voice_datasets::ZsVoiceDatasetToken; pub struct DatasetSampleRecordForList { - pub token: ZsVoiceDatasetSampleToken, - pub dataset_token: ZsVoiceDatasetToken, + pub sample_token: ZsVoiceDatasetSampleToken, + + pub media_file_token: MediaFileToken, + pub media_type: MediaFileType, + + // Bucket path, prefix, and extension are all that are required to construct a path to + // download media from cloud buckets. + pub public_bucket_directory_hash: String, + pub maybe_public_bucket_prefix: Option, + pub maybe_public_bucket_extension: Option, pub maybe_creator_user_token: Option, @@ -21,7 +31,7 @@ pub struct DatasetSampleRecordForList { } -pub async fn list_samples( +pub async fn list_dataset_samples_for_dataset_token( dataset_token: &ZsVoiceDatasetToken, can_see_deleted: bool, mysql_pool: &MySqlPool, @@ -65,8 +75,12 @@ pub async fn list_samples_by_dataset_token_with_connection( Ok(records.into_iter() .map(|record| { DatasetSampleRecordForList { - token: record.token, - dataset_token: record.dataset_token, + sample_token: record.token, + media_file_token: record.media_file_token, + media_type: record.media_type, + public_bucket_directory_hash: record.public_bucket_directory_hash, + maybe_public_bucket_prefix: record.maybe_public_bucket_prefix, + maybe_public_bucket_extension: record.maybe_public_bucket_extension, maybe_creator_user_token: record.maybe_creator_user_token, created_at: record.created_at, updated_at: record.updated_at, @@ -87,11 +101,17 @@ async fn list_samples_by_dataset_token( r#" SELECT zds.token as `token: tokens::tokens::zs_voice_dataset_samples::ZsVoiceDatasetSampleToken`, - zds.dataset_token as `dataset_token: tokens::tokens::zs_voice_datasets::ZsVoiceDatasetToken`, + zds.media_file_token as `media_file_token: tokens::tokens::media_files::MediaFileToken`, + m.media_type as `media_type: enums::by_table::media_files::media_file_type::MediaFileType`, + m.public_bucket_directory_hash, + m.maybe_public_bucket_prefix, + m.maybe_public_bucket_extension, zds.maybe_creator_user_token as `maybe_creator_user_token: tokens::tokens::users::UserToken`, zds.created_at, zds.updated_at FROM zs_voice_dataset_samples as zds + JOIN media_files as m + ON zds.media_file_token = m.token WHERE zds.dataset_token = ? AND zds.user_deleted_at IS NULL AND zds.mod_deleted_at IS NULL @@ -104,11 +124,17 @@ async fn list_samples_by_dataset_token( r#" SELECT zds.token as `token: tokens::tokens::zs_voice_dataset_samples::ZsVoiceDatasetSampleToken`, - zds.dataset_token as `dataset_token: tokens::tokens::zs_voice_datasets::ZsVoiceDatasetToken`, + zds.media_file_token as `media_file_token: tokens::tokens::media_files::MediaFileToken`, + m.media_type as `media_type: enums::by_table::media_files::media_file_type::MediaFileType`, + m.public_bucket_directory_hash, + m.maybe_public_bucket_prefix, + m.maybe_public_bucket_extension, zds.maybe_creator_user_token as `maybe_creator_user_token: tokens::tokens::users::UserToken`, zds.created_at, zds.updated_at FROM zs_voice_dataset_samples as zds + JOIN media_files as m + ON zds.media_file_token = m.token WHERE zds.dataset_token = ? "#, dataset_token @@ -121,7 +147,13 @@ async fn list_samples_by_dataset_token( struct InternalRawDatasetSampleRecordForList { token: ZsVoiceDatasetSampleToken, - dataset_token: ZsVoiceDatasetToken, + + media_file_token: MediaFileToken, + media_type: MediaFileType, + + public_bucket_directory_hash: String, + maybe_public_bucket_prefix: Option, + maybe_public_bucket_extension: Option, maybe_creator_user_token: Option, diff --git a/crates/lib/mysql_queries/src/queries/voice_designer/voice_samples/mod.rs b/crates/lib/mysql_queries/src/queries/voice_designer/voice_samples/mod.rs index e5bce36894..20417f9a48 100644 --- a/crates/lib/mysql_queries/src/queries/voice_designer/voice_samples/mod.rs +++ b/crates/lib/mysql_queries/src/queries/voice_designer/voice_samples/mod.rs @@ -2,4 +2,4 @@ pub mod delete_sample; pub mod get_dataset_sample; pub mod get_dataset_sample_by_uuid; pub mod insert_dataset_sample_and_media_file; -pub mod list_dataset_samples; \ No newline at end of file +pub mod list_dataset_samples_for_dataset_token; \ No newline at end of file diff --git a/crates/lib/redis_common/Cargo.toml b/crates/lib/redis_common/Cargo.toml index bcd90dda5e..cbc9e344b4 100644 --- a/crates/lib/redis_common/Cargo.toml +++ b/crates/lib/redis_common/Cargo.toml @@ -18,7 +18,7 @@ path = "src/lib.rs" container_common = { path = "../deprecated/container_common" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" # Serialization serde = "1.0.125" diff --git a/crates/lib/subprocess_common/Cargo.toml b/crates/lib/subprocess_common/Cargo.toml index a895c15d78..a5897716b5 100644 --- a/crates/lib/subprocess_common/Cargo.toml +++ b/crates/lib/subprocess_common/Cargo.toml @@ -18,7 +18,7 @@ path = "src/lib.rs" container_common = { path = "../deprecated/container_common" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" # Serialization #serde = "1.0.125" diff --git a/crates/lib/tts_common/Cargo.toml b/crates/lib/tts_common/Cargo.toml index a825baa48a..83be11e093 100644 --- a/crates/lib/tts_common/Cargo.toml +++ b/crates/lib/tts_common/Cargo.toml @@ -19,7 +19,7 @@ container_common = { path = "../deprecated/container_common" } user_input_common = { path = "../user_input_common" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" chrono = { version = "0.4.19", features = ["serde"] } log = "0.4.14" once_cell = "1.18.0" diff --git a/crates/lib/url_config/Cargo.toml b/crates/lib/url_config/Cargo.toml index 0d9712e39a..df0ba2edd0 100644 --- a/crates/lib/url_config/Cargo.toml +++ b/crates/lib/url_config/Cargo.toml @@ -20,4 +20,4 @@ reusable_types = { path = "../../_types/reusable_types" } # External actix-web = "4.0.0-beta.10" -anyhow = "1.0.40" \ No newline at end of file +anyhow = "1.0.75" \ No newline at end of file diff --git a/crates/lib/user_input_common/Cargo.toml b/crates/lib/user_input_common/Cargo.toml index dfcda1dfb3..9aa5f3d4bb 100644 --- a/crates/lib/user_input_common/Cargo.toml +++ b/crates/lib/user_input_common/Cargo.toml @@ -18,7 +18,7 @@ path = "src/lib.rs" container_common = { path = "../deprecated/container_common" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" log = "0.4.14" once_cell = "1.18.0" pulldown-cmark = "0.8.0" # Markdown diff --git a/crates/lib/web_scrapers/Cargo.toml b/crates/lib/web_scrapers/Cargo.toml index 9aef7c805b..55e97f1322 100644 --- a/crates/lib/web_scrapers/Cargo.toml +++ b/crates/lib/web_scrapers/Cargo.toml @@ -35,7 +35,7 @@ reqwest = { version = "0.11", features = ["json"] } # HTTP Client # Scraping rss = "2.0.2" -scraper = "0.14.0" +scraper = "0.17.1" [dev-dependencies] # None yet diff --git a/crates/service/job/analytics_job/Cargo.toml b/crates/service/job/analytics_job/Cargo.toml index ef52f762a6..c566499148 100644 --- a/crates/service/job/analytics_job/Cargo.toml +++ b/crates/service/job/analytics_job/Cargo.toml @@ -26,7 +26,7 @@ reusable_types = { path = "../../../_types/reusable_types" } tokens = { path = "../../../_types/tokens" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" chrono = { version = "0.4.19", features = ["serde"] } clap = "2.34.0" # TODO: This is really out of date, but has conflicts when updated dotenv = "0.15.0" diff --git a/crates/service/job/download_job/Cargo.toml b/crates/service/job/download_job/Cargo.toml index aafe4c50f4..826b9a8f6b 100644 --- a/crates/service/job/download_job/Cargo.toml +++ b/crates/service/job/download_job/Cargo.toml @@ -38,7 +38,7 @@ tts_common = { path = "../../../lib/tts_common" } newrelic-telemetry = { path = "../../../vendor/newrelic-telemetry-sdk-rust" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" chrono = { version = "0.4.19", features = ["serde"] } clap = "2.34.0" # TODO: This is really out of date, but has conflicts when updated dotenv = "0.15.0" diff --git a/crates/service/job/inference_job/Cargo.toml b/crates/service/job/inference_job/Cargo.toml index 18dbb60d83..116fd73c04 100644 --- a/crates/service/job/inference_job/Cargo.toml +++ b/crates/service/job/inference_job/Cargo.toml @@ -43,7 +43,7 @@ tts_common = { path = "../../../lib/tts_common" } newrelic-telemetry = { path = "../../../vendor/newrelic-telemetry-sdk-rust" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" chrono = { version = "0.4.19", features = ["serde"] } clap = "2.34.0" # TODO: This is really out of date, but has conflicts when updated dotenv = "0.15.0" diff --git a/crates/service/job/tts_download_job/Cargo.toml b/crates/service/job/tts_download_job/Cargo.toml index 299c5fff7d..ea412ddff9 100644 --- a/crates/service/job/tts_download_job/Cargo.toml +++ b/crates/service/job/tts_download_job/Cargo.toml @@ -30,7 +30,7 @@ tts_common = { path = "../../../lib/tts_common" } newrelic-telemetry = { path = "../../../vendor/newrelic-telemetry-sdk-rust" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" chrono = { version = "0.4.19", features = ["serde"] } clap = "2.34.0" # TODO: This is really out of date, but has conflicts when updated dotenv = "0.15.0" diff --git a/crates/service/job/tts_inference_job/Cargo.toml b/crates/service/job/tts_inference_job/Cargo.toml index 4e6c0c5e49..fb2a1a87ef 100644 --- a/crates/service/job/tts_inference_job/Cargo.toml +++ b/crates/service/job/tts_inference_job/Cargo.toml @@ -29,7 +29,7 @@ tts_common = { path = "../../../lib/tts_common" } newrelic-telemetry = { path = "../../../vendor/newrelic-telemetry-sdk-rust" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" chrono = { version = "0.4.19", features = ["serde"] } clap = "2.34.0" # TODO: This is really out of date, but has conflicts when updated dotenv = "0.15.0" diff --git a/crates/service/job/w2l_download_job/Cargo.toml b/crates/service/job/w2l_download_job/Cargo.toml index 36f4b5b9ee..497b98ef96 100644 --- a/crates/service/job/w2l_download_job/Cargo.toml +++ b/crates/service/job/w2l_download_job/Cargo.toml @@ -30,7 +30,7 @@ tts_common = { path = "../../../lib/tts_common" } newrelic-telemetry = { path = "../../../vendor/newrelic-telemetry-sdk-rust" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" chrono = { version = "0.4.19", features = ["serde"] } clap = "2.34.0" # TODO: This is really out of date, but has conflicts when updated dotenv = "0.15.0" diff --git a/crates/service/job/w2l_inference_job/Cargo.toml b/crates/service/job/w2l_inference_job/Cargo.toml index dc97060141..cdad82ea60 100644 --- a/crates/service/job/w2l_inference_job/Cargo.toml +++ b/crates/service/job/w2l_inference_job/Cargo.toml @@ -28,7 +28,7 @@ tts_common = { path = "../../../lib/tts_common" } newrelic-telemetry = { path = "../../../vendor/newrelic-telemetry-sdk-rust" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" chrono = { version = "0.4.19", features = ["serde"] } clap = "2.34.0" # TODO: This is really out of date, but has conflicts when updated dotenv = "0.15.0" diff --git a/crates/service/other/twitch_pubsub_subscriber/Cargo.toml b/crates/service/other/twitch_pubsub_subscriber/Cargo.toml index 1006b9f69d..727913f2be 100644 --- a/crates/service/other/twitch_pubsub_subscriber/Cargo.toml +++ b/crates/service/other/twitch_pubsub_subscriber/Cargo.toml @@ -25,7 +25,7 @@ tts_common = { path = "../../../lib/tts_common" } twitch_common = { path = "../../../lib/api_clients/twitch_common" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" base64 = "0.21.0" chrono = { version = "0.4.19", features = ["serde"] } derive_more = "0.99.14" @@ -111,8 +111,8 @@ toml = "0.5.8" pulldown-cmark = "0.8.0" # Temporary (just to ask for oauth credentials during dev) -rpassword = "5.0.1" +rpassword = "7.2.0" [build-dependencies] # NB: Only using diesel for migrations support -diesel = { version = "1.4.6", features = ["mysql"] } +diesel = { version = "2.1.3", features = ["mysql"] } diff --git a/crates/service/plugins/billing/Cargo.toml b/crates/service/plugins/billing/Cargo.toml index cabe133406..17020560e8 100644 --- a/crates/service/plugins/billing/Cargo.toml +++ b/crates/service/plugins/billing/Cargo.toml @@ -22,7 +22,7 @@ reusable_types = { path = "../../../_types/reusable_types" } url_config = { path = "../../../lib/url_config" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" base64 = "0.21.0" chrono = { version = "0.4.19", features = ["serde"] } dotenv = "0.15.0" diff --git a/crates/service/plugins/inference_workloads/Cargo.toml b/crates/service/plugins/inference_workloads/Cargo.toml index f53392ac14..69f417fc0d 100644 --- a/crates/service/plugins/inference_workloads/Cargo.toml +++ b/crates/service/plugins/inference_workloads/Cargo.toml @@ -18,7 +18,7 @@ path = "src/lib.rs" container_common = { path = "../../../lib/deprecated/container_common" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" base64 = "0.21.0" chrono = { version = "0.4.19", features = ["serde"] } dotenv = "0.15.0" diff --git a/crates/service/plugins/users/Cargo.toml b/crates/service/plugins/users/Cargo.toml index abe762ccef..8e5d603ea3 100644 --- a/crates/service/plugins/users/Cargo.toml +++ b/crates/service/plugins/users/Cargo.toml @@ -16,6 +16,7 @@ path = "src/lib.rs" # Internal container_common = { path = "../../../lib/deprecated/container_common" } +cookies = { path = "../../../lib/cookies" } enums = { path = "../../../_types/enums" } errors = { path = "../../../lib/errors" } http_server_common = { path = "../../../lib/deprecated/http_server_common" } @@ -28,7 +29,7 @@ tokens = { path = "../../../_types/tokens" } user_input_common = { path = "../../../lib/user_input_common" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" base64 = "0.21.0" chrono = { version = "0.4.19", features = ["serde"] } dotenv = "0.15.0" diff --git a/crates/service/plugins/users/src/cookies/anonymous_visitor_tracking/avt_cookie_manager.rs b/crates/service/plugins/users/src/cookies/anonymous_visitor_tracking/avt_cookie_manager.rs new file mode 100644 index 0000000000..86e046861d --- /dev/null +++ b/crates/service/plugins/users/src/cookies/anonymous_visitor_tracking/avt_cookie_manager.rs @@ -0,0 +1,79 @@ +use actix_web::cookie::Cookie; +use actix_web::HttpRequest; +use anyhow::anyhow; +use log::warn; + +use cookies::jwt_signer::JwtSigner; +use errors::AnyhowResult; + +use crate::cookies::anonymous_visitor_tracking::avt_cookie_payload::AvtCookiePayload; + +const VISITOR_COOKIE_NAME : &str = "visitor"; + +/// Handle "anonymous visitor tracking" cookies. +/// This enables us to associate results with an anonymous user for a better experience, +/// as well as do some form of return visitor tracking. +#[derive(Clone)] +pub struct AvtCookieManager { + cookie_domain: String, + jwt_signer: JwtSigner, +} + +impl AvtCookieManager { + + pub fn new(cookie_domain: &str, hmac_secret: &str) -> AnyhowResult { + Ok(Self { + cookie_domain: cookie_domain.to_string(), + jwt_signer: JwtSigner::new(hmac_secret)?, + }) + } + + pub fn make_new_cookie(&self) -> AnyhowResult { + let payload = AvtCookiePayload::new(); + let claims = payload.to_map(); + let jwt_string = self.jwt_signer.claims_to_jwt(&claims)?; + + let make_secure = !self.cookie_domain.to_lowercase().contains("jungle.horse") + && !self.cookie_domain.to_lowercase().contains("localhost"); + + Ok(Cookie::build(VISITOR_COOKIE_NAME, jwt_string) + .secure(make_secure) // HTTPS-only + .permanent() + .path("/") // NB: Otherwise it'll be set to `/v1` + //.domain(&self.cookie_domain) + //.http_only(true) // Not exposed to Javascript + //.same_site(SameSite::Lax) + .finish()) + } + + pub fn make_delete_cookie(&self) -> Cookie { + let mut cookie = Cookie::build(VISITOR_COOKIE_NAME, "DELETED") + .expires(actix_web::cookie::time::OffsetDateTime::UNIX_EPOCH) + .path("/") // NB: Otherwise it'll be set to `/v1` + .finish(); + cookie.make_removal(); + cookie + } + + pub fn decode_cookie_payload(&self, visitor_cookie: &Cookie) -> AnyhowResult { + let cookie_contents = visitor_cookie.value().to_string(); + let claims = self.jwt_signer.jwt_to_claims(&cookie_contents)?; + let payload = AvtCookiePayload::from_map(claims)?; + Ok(payload) + } + + pub fn decode_cookie_payload_from_request(&self, request: &HttpRequest) -> AnyhowResult> { + let cookie = match request.cookie(VISITOR_COOKIE_NAME) { + None => return Ok(None), + Some(cookie) => cookie, + }; + + match self.decode_cookie_payload(&cookie) { + Err(e) => { + warn!("Visitor cookie decode error: {:?}", e); + Err(anyhow!("Could not decode visitor cookie: {:?}", e)) + }, + Ok(payload) => Ok(Some(payload)), + } + } +} diff --git a/crates/service/plugins/users/src/cookies/anonymous_visitor_tracking/avt_cookie_payload.rs b/crates/service/plugins/users/src/cookies/anonymous_visitor_tracking/avt_cookie_payload.rs new file mode 100644 index 0000000000..8dd1c2a6ad --- /dev/null +++ b/crates/service/plugins/users/src/cookies/anonymous_visitor_tracking/avt_cookie_payload.rs @@ -0,0 +1,94 @@ +use std::collections::BTreeMap; +use std::str::FromStr; + +use anyhow::anyhow; + +use errors::AnyhowResult; +use tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken; + +/** + * Cookie version history + * + * Version 1: Claims include "avt_token" and "cookie_version" + */ +const COOKIE_VERSION : u32 = 1; + +// TODO: Should probably use protobuf or nom for handling +// data-migration sensitive wire formats rather than +// hand-rolling these. + +/// The payload of AVT cookies. +/// +/// Version 1 - only `avt_token` and `version`. +#[derive(Clone, Eq, PartialEq, Debug)] +pub struct AvtCookiePayload { + // TODO: Strongly type + pub avt_token: AnonymousVisitorTrackingToken, + pub cookie_version: u32, +} + +impl AvtCookiePayload { + + pub fn new() -> Self { + let avt_token = AnonymousVisitorTrackingToken::generate(); + + AvtCookiePayload { + avt_token, + cookie_version: COOKIE_VERSION, + } + } + + pub fn from_map(map: BTreeMap) -> AnyhowResult { + let avt_token = map.get("avt_token") + .ok_or(anyhow!("avt_token not present"))? + .to_string(); + + let cookie_version = map + .get("cookie_version") + .ok_or(anyhow!("avt_token not present"))?; + + let avt_token = AnonymousVisitorTrackingToken::new_from_str(&avt_token); + + let cookie_version = u32::from_str(cookie_version)?; + + Ok(AvtCookiePayload { + avt_token, + cookie_version, + }) + } + + pub fn to_map(&self) -> BTreeMap { + let mut map = BTreeMap::new(); + map.insert("avt_token".to_string(), self.avt_token.to_string()); + map.insert("cookie_version".to_string(), self.cookie_version.to_string()); + map + } +} + +#[cfg(test)] +mod tests { + use tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken; + use crate::cookies::anonymous_visitor_tracking::avt_cookie_payload::AvtCookiePayload; + + #[test] + fn test_new() { + let payload = AvtCookiePayload::new(); + + assert_eq!(payload.cookie_version, 1); + assert_eq!(payload.avt_token.0.len(), 32); + assert!(payload.avt_token.to_string().starts_with("avt_")); + } + + #[test] + fn round_trip_test() { + let payload = AvtCookiePayload { + avt_token: AnonymousVisitorTrackingToken::generate(), + cookie_version: 123, + }; + + let round_trip_payload= AvtCookiePayload::from_map(payload.to_map()) + .unwrap(); + + assert_eq!(&payload, &round_trip_payload); + } +} diff --git a/crates/service/plugins/users/src/cookies/anonymous_visitor_tracking/mod.rs b/crates/service/plugins/users/src/cookies/anonymous_visitor_tracking/mod.rs new file mode 100644 index 0000000000..8192e11c00 --- /dev/null +++ b/crates/service/plugins/users/src/cookies/anonymous_visitor_tracking/mod.rs @@ -0,0 +1,2 @@ +pub mod avt_cookie_manager; +pub mod avt_cookie_payload; \ No newline at end of file diff --git a/crates/service/plugins/users/src/cookies/mod.rs b/crates/service/plugins/users/src/cookies/mod.rs new file mode 100644 index 0000000000..b5098c1f8d --- /dev/null +++ b/crates/service/plugins/users/src/cookies/mod.rs @@ -0,0 +1,2 @@ +pub mod anonymous_visitor_tracking; +pub mod session; diff --git a/crates/service/plugins/users/src/cookies/session/mod.rs b/crates/service/plugins/users/src/cookies/session/mod.rs new file mode 100644 index 0000000000..0f135e9168 --- /dev/null +++ b/crates/service/plugins/users/src/cookies/session/mod.rs @@ -0,0 +1,2 @@ +pub mod session_cookie_manager; +pub mod session_cookie_payload; diff --git a/crates/service/plugins/users/src/utils/session_cookie_manager.rs b/crates/service/plugins/users/src/cookies/session/session_cookie_manager.rs similarity index 68% rename from crates/service/plugins/users/src/utils/session_cookie_manager.rs rename to crates/service/plugins/users/src/cookies/session/session_cookie_manager.rs index e0d903cb0e..58ae2b8861 100644 --- a/crates/service/plugins/users/src/utils/session_cookie_manager.rs +++ b/crates/service/plugins/users/src/cookies/session/session_cookie_manager.rs @@ -8,15 +8,13 @@ use std::collections::BTreeMap; use actix_web::cookie::Cookie; use actix_web::HttpRequest; use anyhow::anyhow; -use hmac::Hmac; -use hmac::NewMac; -use jwt::SignWithKey; -use jwt::VerifyWithKey; use log::warn; -use sha2::Sha256; +use cookies::jwt_signer::JwtSigner; use errors::AnyhowResult; +use crate::cookies::session::session_cookie_payload::SessionCookiePayload; + /** * Cookie version history * @@ -34,15 +32,7 @@ const SESSION_COOKIE_NAME : &str = "session"; pub struct SessionCookieManager { cookie_domain: String, hmac_secret: String, -} - -#[derive(Clone)] -pub struct SessionCookiePayload { - /// The database primary key for the session instance. - pub session_token: String, - /// The primary key identifier of the user. - /// Version 1 cookies do not have a user token, hence it is optional. - pub maybe_user_token: Option, + jwt_signer: JwtSigner, } impl SessionCookieManager { @@ -50,13 +40,11 @@ impl SessionCookieManager { Self { cookie_domain: cookie_domain.to_string(), hmac_secret: hmac_secret.to_string(), + jwt_signer: JwtSigner::new(hmac_secret).unwrap(),//TODO FIXME } } pub fn create_cookie(&self, session_token: &str, user_token: &str) -> AnyhowResult { - let key: Hmac = Hmac::new_varkey(self.hmac_secret.as_bytes()) - .map_err(|e| anyhow!("invalid hmac: {:?}", e))?; - let cookie_version = COOKIE_VERSION.to_string(); let mut claims = BTreeMap::new(); @@ -64,24 +52,25 @@ impl SessionCookieManager { claims.insert("user_token", user_token); claims.insert("cookie_version", &cookie_version); - let jwt_string = claims.sign_with_key(&key)?; + let jwt_string = self.jwt_signer.claims_to_jwt(&claims)?; let make_secure = !self.cookie_domain.to_lowercase().contains("jungle.horse") && !self.cookie_domain.to_lowercase().contains("localhost"); Ok(Cookie::build(SESSION_COOKIE_NAME, jwt_string) - //.domain(&self.cookie_domain) .secure(make_secure) // HTTPS-only - //.path("/") + .permanent() + .path("/") // NB: Otherwise it'll be set to `/v1` + //.domain(&self.cookie_domain) //.http_only(true) // Not exposed to Javascript //.expires(OffsetDateTime::now_utc() + time::Duration::days(365)) - .permanent() //.same_site(SameSite::Lax) .finish()) } pub fn delete_cookie(&self) -> Cookie { let mut cookie = Cookie::build(SESSION_COOKIE_NAME, "DELETED") + .path("/") // NB: Otherwise it'll be set to `/v1` .expires(actix_web::cookie::time::OffsetDateTime::UNIX_EPOCH) .finish(); cookie.make_removal(); @@ -91,12 +80,9 @@ impl SessionCookieManager { pub fn decode_session_cookie_payload(&self, session_cookie: &Cookie) -> AnyhowResult { - let key: Hmac = Hmac::new_varkey(self.hmac_secret.as_bytes()) - .map_err(|e| anyhow!("invalid hmac: {:?}", e))?; - let cookie_contents = session_cookie.value().to_string(); - let claims: BTreeMap = cookie_contents.verify_with_key(&key)?; + let claims = self.jwt_signer.jwt_to_claims(&cookie_contents)?; let session_token = claims["session_token"].clone(); let maybe_user_token = claims.get("user_token") @@ -149,3 +135,30 @@ impl SessionCookieManager { } } +#[cfg(test)] +mod tests { + use crate::cookies::session::session_cookie_manager::SessionCookieManager; + + #[test] + fn test_cookie_payload() { + // NB: Let's make extra sure this always works when migrating cookies, else we'll accidentally log out logged-in users. + // (These are version 2 cookies.) + let manager = SessionCookieManager::new("fakeyou.com", "secret"); + let cookie = manager.create_cookie("ex_session_token", "ex_user_token").unwrap(); + + assert_eq!(cookie.value(), "eyJhbGciOiJIUzI1NiJ9.eyJjb29raWVfdmVyc2lvbiI6IjIiLCJzZXNzaW9uX3Rva2VuIjoiZXhfc2Vzc2lvbl90b2tlbiIsInVzZXJfdG9rZW4iOiJleF91c2VyX3Rva2VuIn0.94ly2gHhlPVtnANsNy6cJozFVmId4imwW5v-mei7jD8"); + } + + #[test] + fn test_cookie_round_trip() { + // NB: Let's make extra sure this always works when migrating cookies, else we'll accidentally log out logged-in users. + // (These are version 2 cookies.) + let manager = SessionCookieManager::new("fakeyou.com", "secret"); + let cookie = manager.create_cookie("ex_session_token", "ex_user_token").unwrap(); + + let decoded = manager.decode_session_cookie_payload(&cookie).unwrap(); + + assert_eq!(decoded.session_token, "ex_session_token".to_string()); + assert_eq!(decoded.maybe_user_token, Some("ex_user_token".to_string())); + } +} diff --git a/crates/service/plugins/users/src/cookies/session/session_cookie_payload.rs b/crates/service/plugins/users/src/cookies/session/session_cookie_payload.rs new file mode 100644 index 0000000000..b60da99e0e --- /dev/null +++ b/crates/service/plugins/users/src/cookies/session/session_cookie_payload.rs @@ -0,0 +1,9 @@ + +#[derive(Clone)] +pub struct SessionCookiePayload { + /// The database primary key for the session instance. + pub session_token: String, + /// The primary key identifier of the user. + /// Version 1 cookies do not have a user token, hence it is optional. + pub maybe_user_token: Option, +} diff --git a/crates/service/plugins/users/src/default_routes.rs b/crates/service/plugins/users/src/default_routes.rs index f75d2b79cf..10adedc13d 100644 --- a/crates/service/plugins/users/src/default_routes.rs +++ b/crates/service/plugins/users/src/default_routes.rs @@ -29,6 +29,11 @@ pub fn add_suggested_api_v1_account_creation_and_session_routes (app: App< .route(web::post().to(create_account_handler)) .route(web::head().to(|| HttpResponse::Ok())) ) + .service( + web::resource("/v1/create_account") + .route(web::post().to(create_account_handler)) + .route(web::head().to(|| HttpResponse::Ok())) + ) .service( web::resource("/login") .route(web::post().to(login_handler)) diff --git a/crates/service/plugins/users/src/endpoints/create_account_handler.rs b/crates/service/plugins/users/src/endpoints/create_account_handler.rs index 282f5521bc..834dcf00a7 100644 --- a/crates/service/plugins/users/src/endpoints/create_account_handler.rs +++ b/crates/service/plugins/users/src/endpoints/create_account_handler.rs @@ -21,8 +21,8 @@ use mysql_queries::queries::users::user_sessions::create_user_session::create_us use mysql_queries::tokens::Tokens; use user_input_common::check_for_slurs::contains_slurs; +use crate::cookies::session::session_cookie_manager::SessionCookieManager; use crate::utils::email_to_gravatar::email_to_gravatar; -use crate::utils::session_cookie_manager::SessionCookieManager; use crate::validations::is_reserved_username::is_reserved_username; use crate::validations::validate_passwords::validate_passwords; use crate::validations::validate_username::validate_username; diff --git a/crates/service/plugins/users/src/endpoints/login_handler.rs b/crates/service/plugins/users/src/endpoints/login_handler.rs index 7dd840b4b9..5953d61db5 100644 --- a/crates/service/plugins/users/src/endpoints/login_handler.rs +++ b/crates/service/plugins/users/src/endpoints/login_handler.rs @@ -19,7 +19,7 @@ use mysql_queries::queries::users::user::lookup_user_for_login_by_email::lookup_ use mysql_queries::queries::users::user::lookup_user_for_login_by_username::lookup_user_for_login_by_username; use mysql_queries::queries::users::user_sessions::create_user_session::create_user_session; -use crate::utils::session_cookie_manager::SessionCookieManager; +use crate::cookies::session::session_cookie_manager::SessionCookieManager; #[derive(Deserialize)] pub struct LoginRequest { diff --git a/crates/service/plugins/users/src/endpoints/logout_handler.rs b/crates/service/plugins/users/src/endpoints/logout_handler.rs index 1f94bf9b7d..806b525d48 100644 --- a/crates/service/plugins/users/src/endpoints/logout_handler.rs +++ b/crates/service/plugins/users/src/endpoints/logout_handler.rs @@ -14,7 +14,7 @@ use sqlx::MySqlPool; use http_server_common::response::response_error_helpers::to_simple_json_error; use mysql_queries::queries::users::user_sessions::delete_user_session::delete_user_session; -use crate::utils::session_cookie_manager::SessionCookieManager; +use crate::cookies::session::session_cookie_manager::SessionCookieManager; #[derive(Serialize)] pub struct LogoutSuccessResponse { diff --git a/crates/service/plugins/users/src/endpoints/session_info_handler.rs b/crates/service/plugins/users/src/endpoints/session_info_handler.rs index b1ca39b83d..b671aab036 100644 --- a/crates/service/plugins/users/src/endpoints/session_info_handler.rs +++ b/crates/service/plugins/users/src/endpoints/session_info_handler.rs @@ -13,6 +13,7 @@ use sqlx::MySqlPool; use http_server_common::response::response_error_helpers::to_simple_json_error; +use crate::cookies::anonymous_visitor_tracking::avt_cookie_manager::AvtCookieManager; use crate::utils::session_checker::SessionChecker; #[derive(Serialize, Copy, Clone)] @@ -109,6 +110,7 @@ pub async fn session_info_handler( http_request: HttpRequest, mysql_pool: web::Data, session_checker: web::Data, + avt_manager: web::Data, ) -> Result { let mut mysql_connection = mysql_pool.acquire() @@ -174,6 +176,18 @@ pub async fn session_info_handler( } } + let maybe_avt_cookie = match avt_manager.decode_cookie_payload_from_request(&http_request) { + Ok(Some(_avt_cookie)) => None, + _ => { + let cookie = avt_manager.make_new_cookie() + .map_err(|e| { + warn!("avt cookie creation error: {:?}", e); + SessionInfoError::ServerError + })?; + Some(cookie) + } + }; + let response = SessionInfoSuccessResponse { success: true, logged_in, @@ -183,7 +197,13 @@ pub async fn session_info_handler( let body = serde_json::to_string(&response) .map_err(|_e| SessionInfoError::ServerError)?; - Ok(HttpResponse::Ok() + let mut response_builder = HttpResponse::Ok(); + + if let Some(cookie) = maybe_avt_cookie { + response_builder.cookie(cookie); + } + + Ok(response_builder .content_type("application/json") .body(body)) } diff --git a/crates/service/plugins/users/src/lib.rs b/crates/service/plugins/users/src/lib.rs index 9570a7af35..308f563f5c 100644 --- a/crates/service/plugins/users/src/lib.rs +++ b/crates/service/plugins/users/src/lib.rs @@ -4,6 +4,7 @@ pub const RESERVED_USERNAMES : &str = include_str!("../../../../../includes/binary_includes/reserved_usernames.txt"); pub const RESERVED_SUBSTRINGS : &str = include_str!("../../../../../includes/binary_includes/reserved_usernames_including.txt"); +pub mod cookies; pub mod default_routes; pub mod endpoints; pub mod utils; diff --git a/crates/service/plugins/users/src/utils/mod.rs b/crates/service/plugins/users/src/utils/mod.rs index 0e6f07cc17..0110b80c7c 100644 --- a/crates/service/plugins/users/src/utils/mod.rs +++ b/crates/service/plugins/users/src/utils/mod.rs @@ -2,5 +2,4 @@ pub mod default_avatar_color_from_username; pub mod default_avatar_from_username; pub mod email_to_gravatar; pub mod session_checker; -pub mod session_cookie_manager; pub mod user_session_extended; \ No newline at end of file diff --git a/crates/service/plugins/users/src/utils/session_checker.rs b/crates/service/plugins/users/src/utils/session_checker.rs index 00d6647e6c..e904bc8acb 100644 --- a/crates/service/plugins/users/src/utils/session_checker.rs +++ b/crates/service/plugins/users/src/utils/session_checker.rs @@ -15,7 +15,7 @@ use mysql_queries::queries::users::user_subscriptions::list_active_user_subscrip use redis_caching::redis_ttl_cache::{RedisTtlCache, RedisTtlCacheConnection}; use redis_common::redis_cache_keys::RedisCacheKeys; -use crate::utils::session_cookie_manager::SessionCookieManager; +use crate::cookies::session::session_cookie_manager::SessionCookieManager; use crate::utils::user_session_extended::{UserSessionExtended, UserSessionPreferences, UserSessionPremiumPlanInfo, UserSessionRoleAndPermissions, UserSessionSubscriptionPlan, UserSessionUserDetails}; #[derive(Clone)] diff --git a/crates/service/web/storyteller_web/Cargo.toml b/crates/service/web/storyteller_web/Cargo.toml index dbc5cde46c..7e6edd01ae 100644 --- a/crates/service/web/storyteller_web/Cargo.toml +++ b/crates/service/web/storyteller_web/Cargo.toml @@ -22,6 +22,7 @@ buckets = { path = "../../../_types/buckets" } cloud_storage = { path = "../../../lib/api_clients/cloud_storage" } config = { path = "../../../lib/deprecated/config" } container_common = { path = "../../../lib/deprecated/container_common" } +cookies = { path = "../../../lib/cookies" } datetimes = { path = "../../../lib/datetimes" } easyenv = { path = "../../../lib/easyenv" } enums = { path = "../../../_types/enums" } @@ -51,7 +52,7 @@ users_component = { path = "../../plugins/users" } newrelic-telemetry = { path = "../../../vendor/newrelic-telemetry-sdk-rust" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" base64 = "0.21.0" chrono = { version = "0.4.19", features = ["serde"] } derive_more = "0.99.14" @@ -165,7 +166,7 @@ async-trait = "0.1.58" [build-dependencies] # NB: Only using diesel for migrations support -diesel = { version = "1.4.6", features = ["mysql"] } +diesel = { version = "2.1.3", features = ["mysql"] } [dev-dependencies] speculoos = "0.9.0" # Fluent assertions diff --git a/crates/service/web/storyteller_web/src/cookies/mod.rs b/crates/service/web/storyteller_web/src/cookies/mod.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_dataset_samples/list_samples_by_dataset.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_dataset_samples/list_samples_by_dataset.rs index 69866c64f5..fed08dceec 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_dataset_samples/list_samples_by_dataset.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_dataset_samples/list_samples_by_dataset.rs @@ -4,17 +4,29 @@ use actix_web::{HttpRequest, HttpResponse, web}; use actix_web::error::ResponseError; use actix_web::http::StatusCode; use chrono::{DateTime, Utc}; +use log::warn; -use log::{info, warn}; -use mysql_queries::queries::voice_designer::voice_samples::list_dataset_samples::list_samples; +use enums::by_table::media_files::media_file_type::MediaFileType; +use mysql_queries::queries::voice_designer::voice_samples::list_dataset_samples_for_dataset_token::list_dataset_samples_for_dataset_token; +use tokens::tokens::media_files::MediaFileToken; +use tokens::tokens::users::UserToken; +use tokens::tokens::zs_voice_dataset_samples::ZsVoiceDatasetSampleToken; use tokens::tokens::zs_voice_datasets::ZsVoiceDatasetToken; + use crate::server_state::ServerState; #[derive(Serialize, Clone)] pub struct ZsSampleRecordForResponse { - sample_token: String, - dataset_token: String, - maybe_creator_user_token: Option, + sample_token: ZsVoiceDatasetSampleToken, + + media_file_token: MediaFileToken, + media_type: MediaFileType, + + public_bucket_directory_hash: String, + maybe_public_bucket_prefix: Option, + maybe_public_bucket_extension: Option, + + maybe_creator_user_token: Option, created_at: DateTime, updated_at: DateTime, @@ -76,7 +88,7 @@ pub async fn list_samples_by_dataset_handler( let dataset_token = ZsVoiceDatasetToken(path.dataset_token.clone()); let is_mod = user_session.can_ban_users; - let query_results = list_samples( + let query_results = list_dataset_samples_for_dataset_token( &dataset_token, is_mod, &server_state.mysql_pool @@ -96,12 +108,13 @@ pub async fn list_samples_by_dataset_handler( let samples = samples .into_iter() .map(|sample| ZsSampleRecordForResponse { - sample_token: sample.token.to_string(), - dataset_token: sample.dataset_token.to_string(), - maybe_creator_user_token: match sample.maybe_creator_user_token { - Some(user_token) => Some(user_token.to_string()), - None => None, - }, + sample_token: sample.sample_token, + media_file_token: sample.media_file_token, + media_type: sample.media_type, + public_bucket_directory_hash: sample.public_bucket_directory_hash, + maybe_public_bucket_prefix: sample.maybe_public_bucket_prefix, + maybe_public_bucket_extension: sample.maybe_public_bucket_extension, + maybe_creator_user_token: sample.maybe_creator_user_token, created_at: sample.created_at, updated_at: sample.updated_at, }) diff --git a/crates/service/web/storyteller_web/src/main.rs b/crates/service/web/storyteller_web/src/main.rs index a9de5d79c9..b4cd7b4ad8 100644 --- a/crates/service/web/storyteller_web/src/main.rs +++ b/crates/service/web/storyteller_web/src/main.rs @@ -64,8 +64,9 @@ use redis_caching::redis_ttl_cache::RedisTtlCache; use reusable_types::server_environment::ServerEnvironment; use twitch_common::twitch_secrets::TwitchSecrets; use url_config::third_party_url_redirector::ThirdPartyUrlRedirector; +use users_component::cookies::anonymous_visitor_tracking::avt_cookie_manager::AvtCookieManager; +use users_component::cookies::session::session_cookie_manager::SessionCookieManager; use users_component::utils::session_checker::SessionChecker; -use users_component::utils::session_cookie_manager::SessionCookieManager; use crate::billing::internal_product_to_stripe_lookup_impl::InternalProductToStripeLookupImpl; use crate::billing::internal_session_cache_purge_impl::InternalSessionCachePurgeImpl; @@ -90,6 +91,7 @@ pub const RESERVED_SUBSTRINGS : &str = include_str!("../../../../../includes/bin pub mod billing; pub mod configs; +pub mod cookies; pub mod http_server; pub mod memory_cache; pub mod model; @@ -239,9 +241,11 @@ async fn main() -> AnyhowResult<()> { let website_homepage_redirect = easyenv::get_env_string_or_default("WEBSITE_HOMEPAGE_REDIRECT", "https://vo.codes/"); - let cookie_manager = SessionCookieManager::new(&cookie_domain, &hmac_secret); + let session_cookie_manager = SessionCookieManager::new(&cookie_domain, &hmac_secret); + let avt_cookie_manager = AvtCookieManager::new(&cookie_domain, &hmac_secret)?; + let session_checker = SessionChecker::new_with_cache( - &cookie_manager, + &session_cookie_manager, redis_ttl_cache.clone(), ); @@ -456,7 +460,8 @@ async fn main() -> AnyhowResult<()> { }, firehose_publisher, badge_granter, - cookie_manager, + avt_cookie_manager, + session_cookie_manager, session_checker, private_bucket_client, public_bucket_client, @@ -633,7 +638,8 @@ pub async fn serve(server_state: ServerState) -> AnyhowResult<()> .app_data(web::Data::new(server_state_arc.redis_pool.clone())) .app_data(web::Data::new(server_state_arc.redis_ttl_cache.clone())) .app_data(web::Data::new(server_state_arc.session_checker.clone())) - .app_data(web::Data::new(server_state_arc.cookie_manager.clone())) + .app_data(web::Data::new(server_state_arc.avt_cookie_manager.clone())) + .app_data(web::Data::new(server_state_arc.session_cookie_manager.clone())) .app_data(web::Data::new(server_state_arc.stripe.clone().config.clone())) .app_data(web::Data::new(server_state_arc.stripe.clone().client.clone())) .app_data(web::Data::new(server_state_arc.third_party_url_redirector.clone())) diff --git a/crates/service/web/storyteller_web/src/server_state.rs b/crates/service/web/storyteller_web/src/server_state.rs index 2fe1a156e9..fc372e4146 100644 --- a/crates/service/web/storyteller_web/src/server_state.rs +++ b/crates/service/web/storyteller_web/src/server_state.rs @@ -15,8 +15,9 @@ use mysql_queries::queries::w2l::w2l_templates::list_w2l_templates::W2lTemplateR use redis_caching::redis_ttl_cache::RedisTtlCache; use reusable_types::server_environment::ServerEnvironment; use url_config::third_party_url_redirector::ThirdPartyUrlRedirector; +use users_component::cookies::anonymous_visitor_tracking::avt_cookie_manager::AvtCookieManager; +use users_component::cookies::session::session_cookie_manager::SessionCookieManager; use users_component::utils::session_checker::SessionChecker; -use users_component::utils::session_cookie_manager::SessionCookieManager; use crate::http_server::endpoints::categories::tts::list_fully_computed_assigned_tts_categories::list_fully_computed_assigned_tts_categories::ModelTokensByCategoryToken; use crate::http_server::endpoints::leaderboard::get_leaderboard::LeaderboardInfo; @@ -58,7 +59,8 @@ pub struct ServerState { pub redis_rate_limiters: RedisRateLimiters, - pub cookie_manager: SessionCookieManager, + pub session_cookie_manager: SessionCookieManager, + pub avt_cookie_manager: AvtCookieManager, pub session_checker: SessionChecker, diff --git a/crates/service/web/websocket_gateway/Cargo.toml b/crates/service/web/websocket_gateway/Cargo.toml index ed55de1b74..13db988ecb 100644 --- a/crates/service/web/websocket_gateway/Cargo.toml +++ b/crates/service/web/websocket_gateway/Cargo.toml @@ -25,7 +25,7 @@ redis_common = { path = "../../../lib/redis_common" } twitch_common = { path = "../../../lib/api_clients/twitch_common" } # External -anyhow = "1.0.40" +anyhow = "1.0.75" base64 = "0.21.0" chrono = { version = "0.4.19", features = ["serde"] } derive_more = "0.99.14" @@ -112,8 +112,8 @@ toml = "0.5.8" pulldown-cmark = "0.8.0" # Temporary (just to ask for oauth credentials during dev) -rpassword = "5.0.1" +rpassword = "7.2.0" [build-dependencies] # NB: Only using diesel for migrations support -diesel = { version = "1.4.6", features = ["mysql"] } +diesel = { version = "2.1.3", features = ["mysql"] }