diff --git a/Cargo.lock b/Cargo.lock index 9bd19d0..f5206b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,1639 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "adler32" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" - -[[package]] -name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "ascii" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" - -[[package]] -name = "askama" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47cbc3cf73fa8d9833727bbee4835ba5c421a0d65b72daf9a7b5d0e0f9cfb57e" -dependencies = [ - "askama_derive", - "askama_escape", - "humansize", - "num-traits", - "percent-encoding", -] - -[[package]] -name = "askama_derive" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c22fbe0413545c098358e56966ff22cdd039e10215ae213cfbd65032b119fc94" -dependencies = [ - "basic-toml", - "mime", - "mime_guess", - "nom", - "proc-macro2", - "quote", - "serde", - "syn 2.0.13", -] - -[[package]] -name = "askama_escape" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "base64" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" - -[[package]] -name = "basic-toml" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c0de75129aa8d0cceaf750b89013f0e08804d6ec61416da787b35ad0d7cddf1" -dependencies = [ - "serde", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c70beb79cbb5ce9c4f8e20849978f34225931f665bb49efa6982875a4d5facb3" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "brotli" -version = "3.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", -] - -[[package]] -name = "brotli-decompressor" -version = "2.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - -[[package]] -name = "buf_redux" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f" -dependencies = [ - "memchr", - "safemem", -] - -[[package]] -name = "bumpalo" -version = "3.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" - -[[package]] -name = "cc" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" -dependencies = [ - "iana-time-zone", - "js-sys", - "num-integer", - "num-traits", - "time 0.1.45", - "wasm-bindgen", - "winapi", -] - -[[package]] -name = "chunked_transfer" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cca491388666e04d7248af3f60f0c40cfb0991c72205595d7c396e3510207d1a" - -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - -[[package]] -name = "commoncrypto" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007" -dependencies = [ - "commoncrypto-sys", -] - -[[package]] -name = "commoncrypto-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fed34f46747aa73dfaa578069fd8279d2818ade2b55f38f22a9401c7f4083e2" -dependencies = [ - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" - -[[package]] -name = "cpufeatures" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "crypto-hash" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a77162240fd97248d19a564a565eb563a3f592b386e4136fb300909e67dddca" -dependencies = [ - "commoncrypto", - "hex", - "openssl", - "winapi", -] - -[[package]] -name = "cxx" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn 2.0.13", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.13", -] - -[[package]] -name = "deflate" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c86f7e25f518f4b81808a2cf1c50996a61f5c2eb394b2393bd87f2a4780a432f" -dependencies = [ - "adler32", - "gzip-header", -] - -[[package]] -name = "digest" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "errno" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "fallible-iterator" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" - -[[package]] -name = "fallible-streaming-iterator" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" - -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - -[[package]] -name = "filetime" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.2.16", - "windows-sys 0.48.0", -] - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "generator" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33a20a288a94683f5f4da0adecdbe095c94a77c295e514cc6484e9394dd8376e" -dependencies = [ - "cc", - "libc", - "log", - "rustversion", - "windows 0.44.0", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", -] - -[[package]] -name = "gzip-header" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95cc527b92e6029a62960ad99aa8a6660faa4555fe5f731aab13aa6a921795a2" -dependencies = [ - "crc32fast", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashlink" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69fe1fcf8b4278d860ad0548329f892a3631fb63f82574df68275f34cdbe0ffa" -dependencies = [ - "hashbrown", -] - -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" - -[[package]] -name = "hex" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" - -[[package]] -name = "humansize" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" -dependencies = [ - "libm", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows 0.48.0", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" -dependencies = [ - "cxx", - "cxx-build", -] - -[[package]] -name = "idna" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" -dependencies = [ - "hermit-abi 0.3.1", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "itoa" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" - -[[package]] -name = "js-sys" -version = "0.3.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.141" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" - -[[package]] -name = "libm" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" - -[[package]] -name = "libsqlite3-sys" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326" -dependencies = [ - "cc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "link-cplusplus" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" -dependencies = [ - "cc", -] - -[[package]] -name = "linux-raw-sys" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "loom" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" -dependencies = [ - "cfg-if", - "generator", - "pin-utils", - "scoped-tls", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "mime_guess" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" -dependencies = [ - "mime", - "unicase", -] - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "multipart" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00dec633863867f29cb39df64a397cdf4a6354708ddd7759f70c7fb51c5f9182" -dependencies = [ - "buf_redux", - "httparse", - "log", - "mime", - "mime_guess", - "quick-error", - "rand", - "safemem", - "tempfile", - "twoway", -] - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" -dependencies = [ - "hermit-abi 0.2.6", - "libc", -] - -[[package]] -name = "num_threads" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" -dependencies = [ - "libc", -] - -[[package]] -name = "once_cell" -version = "1.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" - -[[package]] -name = "oneshot" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc22d22931513428ea6cc089e942d38600e3d00976eef8c86de6b8a3aadec6eb" -dependencies = [ - "loom", -] - -[[package]] -name = "openssl" -version = "0.10.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e30d8bc91859781f0a943411186324d580f2bbeb71b452fe91ae344806af3f1" -dependencies = [ - "bitflags 1.3.2", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.13", -] - -[[package]] -name = "openssl-sys" -version = "0.9.85" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d3d193fb1488ad46ffe3aaabc912cc931d02ee8518fe2959aea8ef52718b0c0" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "percent-encoding" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "proc-macro2" -version = "1.0.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - -[[package]] -name = "quote" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "regex" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" -dependencies = [ - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "rouille" -version = "3.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f86e4c51a773f953f02bbab5fd049f004bfd384341d62da2a079aff812ab176" -dependencies = [ - "base64 0.13.1", - "brotli", - "chrono", - "deflate", - "filetime", - "multipart", - "num_cpus", - "percent-encoding", - "rand", - "serde", - "serde_derive", - "serde_json", - "sha1", - "threadpool", - "time 0.3.20", - "tiny_http", - "url", -] - -[[package]] -name = "rusqlite" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2" -dependencies = [ - "bitflags 2.1.0", - "chrono", - "fallible-iterator", - "fallible-streaming-iterator", - "hashlink", - "libsqlite3-sys", - "smallvec", -] - -[[package]] -name = "rustix" -version = "0.37.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustversion" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" - -[[package]] -name = "ryu" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" - -[[package]] -name = "safemem" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "scratch" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" - -[[package]] -name = "serde" -version = "1.0.159" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.159" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.13", -] - -[[package]] -name = "serde_json" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha1" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sharded-slab" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tempfile" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" -dependencies = [ - "cfg-if", - "fastrand", - "redox_syscall 0.3.5", - "rustix", - "windows-sys 0.45.0", -] - -[[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "thiserror" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.13", -] - -[[package]] -name = "thread_local" -version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "threadpool" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" -dependencies = [ - "num_cpus", -] - -[[package]] -name = "time" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" -dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", -] - -[[package]] -name = "time" -version = "0.3.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" -dependencies = [ - "libc", - "num_threads", - "serde", - "time-core", -] - -[[package]] -name = "time-core" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" - -[[package]] -name = "tiny_http" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389915df6413a2e74fb181895f933386023c71110878cd0825588928e64cdc82" -dependencies = [ - "ascii", - "chunked_transfer", - "httpdate", - "log", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tracing" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" -dependencies = [ - "cfg-if", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "tracing-core" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" -dependencies = [ - "lazy_static", - "log", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - [[package]] name = "tracking_pixel" -version = "0.1.0" -dependencies = [ - "askama", - "base64 0.21.0", - "chrono", - "crypto-hash", - "oneshot", - "rand", - "rouille", - "rusqlite", - "thiserror", -] - -[[package]] -name = "twoway" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1" -dependencies = [ - "memchr", -] - -[[package]] -name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - -[[package]] -name = "unicase" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" - -[[package]] -name = "unicode-ident" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" - -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - -[[package]] -name = "url" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 1.0.109", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows" -version = "0.44.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets 0.48.0", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.0", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" -dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index 8678868..cda4b52 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,17 +1,8 @@ [package] name = "tracking_pixel" -version = "0.1.0" +version = "0.2.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -askama = "0.12.0" -base64 = "0.21.0" -chrono = "0.4.24" -crypto-hash = "0.3.4" -oneshot = "0.1.5" -rand = "0.8.5" -rouille="3.6.1" -rusqlite = { version = "0.29.0", features = ["bundled", "chrono"] } -thiserror = "1.0.40" diff --git a/assets/hello.html b/assets/hello.html deleted file mode 100644 index 819bca9..0000000 --- a/assets/hello.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - Hello - - -

- Hallo -

- - \ No newline at end of file diff --git a/src/db.rs b/src/db.rs deleted file mode 100644 index 5bcc395..0000000 --- a/src/db.rs +++ /dev/null @@ -1,101 +0,0 @@ -use rusqlite::{Connection}; -use std::{sync::mpsc::{Sender, Receiver, channel, SendError}, thread::{self, JoinHandle}, any::Any}; - -enum DBMessage { - HangUp, - Message(T) -} - -#[derive(Debug)] -pub struct DBSender { - sender: Sender> -} - -// #[derive(Clone)] requires MsgT to be Clone, but that's not necessary -impl Clone for DBSender { - fn clone(&self) -> Self { - Self {sender: self.sender.clone()} - } -} - -impl DBSender { - pub fn send(&self, msg: MsgT) -> Result<(), SendError>{ - if let Err(err) = self.sender.send(DBMessage::Message(msg)) { - if let DBMessage::Message(msg) = err.0 { - Err(SendError(msg)) - } else { - unreachable!(); - } - } else { - Ok(()) - } - } - - fn hang_up(&self) -> Result<(), SendError<()>> { - if let Err(_) = self.sender.send(DBMessage::HangUp) { - Err(SendError(())) - } - else { - Ok(()) - } - } -} - - -#[derive(Debug)] -pub struct DBConnection -{ - pub sender: DBSender, - join_handle: Option> -} - - -impl DBConnection - { - pub fn init(connection: Connection, op: F) -> Self { - let (sender, receiver) = channel(); - - let join_handle = thread::spawn(move || Self::db_thread(receiver, connection, op)); - let sender = DBSender { sender }; - - Self {sender, join_handle: Some(join_handle)} - } - - fn db_thread(receiver: Receiver>, connection: Connection, op: F) { - while let Ok(db_msg) = receiver.recv() { - // _ = connection.execute("INSERT INTO hits VALUES(?1, ?2, ?3, ?4);", params![hit.pixel_id, hit.ip, hit.user_agent, hit.date]).unwrap(); - if let DBMessage::Message(msg) = db_msg { - op(msg, &connection); - } - else if let DBMessage::HangUp = db_msg { - break; - } - } - - // execute last messages in buffer - for db_msg in receiver.try_iter() { - if let DBMessage::Message(msg) = db_msg { - op(msg, &connection); - } - } - } - // static is implied, but included for clearness - pub fn finish(&mut self) -> Result<(), Box> { - // let Self{sender, join_handle} = self; - if let Err(err) = self.sender.hang_up() { - return Err(Box::new(err)); - } - if let Some(handle) = self.join_handle.take() { - handle.join() - } - else { - Ok(()) - } - } -} - -impl Drop for DBConnection { - fn drop(&mut self) { - self.finish().unwrap(); - } -} \ No newline at end of file diff --git a/src/helpers.rs b/src/helpers.rs deleted file mode 100644 index a18ff1d..0000000 --- a/src/helpers.rs +++ /dev/null @@ -1,18 +0,0 @@ -use rouille::Response; - -pub fn javascript_redirect(path: &str) -> Response { - Response::html(format!(" - - - - Redirecting... - - - - -

Redirecting...

- - ")) -} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index dc7790c..e71fdf5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,205 +1 @@ -use std::{fs, sync::{Mutex}}; - -use askama::Template; -use rouille::{Response, router, input, Request, try_or_400, post_input}; - - -use pixel::{Hit, PixelManager, PixelManagerDelegate, TrackingPixel, User}; - -mod db; -mod pixel; -mod helpers; - - -fn main() { - let white_1x1_pixel_png = fs::read("assets/white_pixel.png").unwrap(); - - let pixel_manager = PixelManager::build("app.db").unwrap(); - - let pixel_manager_delegate = PixelManagerDelegate::new(&pixel_manager); - // let pixel_id = pixel_manager.create_pixel("Hallo mac").unwrap(); - // print!("{pixel_id}"); - // pixel_manager.register_hit(pixel_id, "ai pie", "joeser eedsjent", chrono::offset::Utc::now()); - - let delegate_mutex = Mutex::new(pixel_manager_delegate); - - rouille::start_server("0.0.0.0:3737", move |request| { - router!(request, - (GET) ["/manage"] => { - let delegate = delegate_mutex.lock().unwrap().clone(); - // panicking on poisoned mutex is acceptable - manage_index(request, &delegate) - }, - (GET) ["/manage/pixel/{pixel_id}", pixel_id: String] => { - let delegate = delegate_mutex.lock().unwrap().clone(); - manage_pixel(&pixel_id, request, &delegate) - }, - (POST) ["/manage/pixel/create"] => { - let delegate = delegate_mutex.lock().unwrap().clone(); - create_pixel(request, &delegate) - }, - (POST) ["/manage/pixel/delete"] => { - let delegate = delegate_mutex.lock().unwrap().clone(); - delete_pixel(request, &delegate) - }, - (GET) ["/img/{id}/white.png", id: String] => { - let delegate = delegate_mutex.lock().unwrap().clone(); - register_hit(&id, request, &delegate); - Response::from_data("image/png", white_1x1_pixel_png.clone()) - }, - _ => { - println!("404: {:#?}", request.url()); - Response::empty_404() - } - ) - }); - -} - -#[derive(Template)] -#[template(path = "index.html")] -struct IndexTemplate<'a> { - username: &'a str, - pixels: Vec<(String, String)> -} - -impl<'a> IndexTemplate<'a> { - fn new(username: &'a str, pixels: &Vec) -> Self { - Self { - username, - pixels: pixels.iter().map(|pix| (pix.name.clone(), pix.url_safe_encode())).collect() - } - } -} - - -#[derive(Template)] -#[template(path = "manage/pixel.html")] -struct PixelTemplate { - pixel_name: String, - hits: Vec<(String, String, String)>, - pixel_url: String, - pixel_id: String -} - -impl PixelTemplate { - fn new(pixel: &TrackingPixel, hits: &Vec) -> Self { - Self { - pixel_name: pixel.name.clone(), - hits: hits.iter().map(|hit| (hit.date.to_string(), hit.ip.clone(), hit.user_agent.clone())).collect(), - pixel_url: get_url_for_pixel(&pixel), - pixel_id: pixel.url_safe_encode() - } - } -} - -fn manage_index(request: &Request, manager_delegate: &PixelManagerDelegate) -> Response { - let user = match auth_user(request, &manager_delegate) { - Ok(user) => user, - Err(response) => return response - }; - - match manager_delegate.get_manager().get_pixels_for_user(&user) { - Ok(pixels) => { - let index_template = IndexTemplate::new(&user.username, &pixels); - match index_template.render() { - Ok(page) => Response::html(page), - Err(_) => Response::text("Page error").with_status_code(500) - } - }, - Err(_) => Response::text("DB error").with_status_code(500) - } -} - -fn auth_user(request: &Request, manager_delegate: &PixelManagerDelegate) -> Result { - let auth = match input::basic_http_auth(request) { - Some(a) => a, - None => return Err(Response::basic_http_auth_login_required("manage")) - }; - match manager_delegate.get_manager().get_user(&auth.login, &auth.password) { - Ok(user) => Ok(user), - Err(_) => return Err(Response::basic_http_auth_login_required("manage")) - } -} - -fn manage_pixel(pixel_id: &str, request: &Request, manager_delegate: &PixelManagerDelegate) -> Response { - let user = match auth_user(request, &manager_delegate) { - Ok(user) => user, - Err(response) => return response - }; - - let pixel = match manager_delegate.get_manager().get_pixel_from_encoded(pixel_id, Some(&user)) { - Ok(pixel_opt) => { - match pixel_opt { - Some(pixel) => pixel, - None => return Response::text("Unknown pixel").with_status_code(500) - } - }, - Err(_) => return Response::text("Encoding error").with_status_code(500) - }; - - let hits = match manager_delegate.get_manager().get_hits_for_pixel(&pixel, Some(&user)) { - Ok(hits) => hits, - Err(_) => return Response::text("DB error").with_status_code(500) - }; - - let pixel_template = PixelTemplate::new(&pixel, &hits); - - match pixel_template.render() { - Ok(page) => Response::html(page), - Err(_) => Response::text("Page error").with_status_code(500) - } -} - -fn create_pixel(request: &Request, manager_delegate: &PixelManagerDelegate) -> Response { - let user = match auth_user(request, &manager_delegate) { - Ok(user) => user, - Err(response) => return response - }; - let input = try_or_400!(post_input!(request, { - pixel_name: String - })); - let _pixel = match manager_delegate.get_manager().create_pixel(&input.pixel_name, &user) { - Ok(pixel) => pixel, - Err(_) => return Response::empty_400() - }; - // Response::redirect_303("/manage") - helpers::javascript_redirect("/manage") -} - -fn delete_pixel(request: &Request, manager_delegate: &PixelManagerDelegate) -> Response { - let user = match auth_user(request, &manager_delegate) { - Ok(user) => user, - Err(response) => return response, - }; - - let input = try_or_400!(post_input!(request, { - pixel_id: String - })); - - let pixel = match manager_delegate.get_manager().get_pixel_from_encoded(&input.pixel_id, Some(&user)) { - Ok(pixel) => pixel, - Err(_) => return Response::text("DB error").with_status_code(500) - }; - if let Some(pixel) = pixel { - if manager_delegate.get_manager().delete_pixel(pixel, Some(&user)).is_err() { - return Response::text("DB error").with_status_code(500); - } - } else { - return Response::empty_400(); // could not find pixel - } - // Response::redirect_303("/manage") - helpers::javascript_redirect("/manage") - -} - -fn register_hit(pixel_id: &str, request: &Request, manager_delegate: &PixelManagerDelegate) { - let ua = request.header("User-Agent").unwrap_or_default(); - let ip = request.header("X-Forwarded-For").unwrap_or_default(); - _ = manager_delegate.get_manager().register_hit_with_encoded_pixel(pixel_id, &ip, ua, chrono::offset::Utc::now()); -} - - -fn get_url_for_pixel(pixel: &TrackingPixel) -> String { - format!("https://track.willem.page/img/{}/white.png", pixel.url_safe_encode()) -} +fn main() {} \ No newline at end of file diff --git a/src/pixel.rs b/src/pixel.rs deleted file mode 100644 index d234dcd..0000000 --- a/src/pixel.rs +++ /dev/null @@ -1,482 +0,0 @@ -use std::sync::mpsc; - -use crate::db::{DBConnection, DBSender}; - -use base64::Engine; -use chrono::{DateTime, Utc}; -use crypto_hash::{Algorithm, hex_digest}; -use rusqlite::{params, Connection, OptionalExtension}; -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum Error { - #[error("Username or password does not exist in database")] - InvalidUserData(), - #[error("Database did not respond")] - RecvError(#[from] oneshot::RecvError), - #[error("Could not send data to database")] - SendError(#[from] mpsc::SendError), - #[error("Timeout receiving data from database")] - TimeoutError(#[from] oneshot::RecvTimeoutError), - #[error("User is not authenticated")] - UserNotAuthed(), - #[error("No user with this username and password")] - InvalidCredentials(), - #[error("Data was not added to database correctly")] - DBError(), - #[error("The username for this user already exists")] - NewUserAlreadyExists(), - #[error("Invalid encoding in ID")] - InvalidEncodedID(#[from] base64::DecodeError), - #[error("Pixel not found in users pixels")] - PixelNotFound() -} - -#[derive(Debug)] -enum DBConnectionMessage { - RegisterHit(Hit), - CreatePixel(TrackingPixel), - DeletePixel(i64), - AuthUser(User, oneshot::Sender), - GetUserFromName(String, oneshot::Sender>), - GetUserFromId(i64, oneshot::Sender>), - CreateUser(User), - DeleteUser(i64), - GetHitsForPixel(TrackingPixel, oneshot::Sender>>, Option), - GetPixelsForUser(User, oneshot::Sender>>), - GetPixel(i64, Option, oneshot::Sender>) -} // messy, there is probably a better way to do this but it works so oh well - -#[derive(Debug, Clone)] -pub struct TrackingPixel { - id: i64, // ID may not be omitted when creating new pixel - pub name: String, - user_id: i64 -} - -impl TrackingPixel { - pub fn url_safe_encode(&self) -> String { - base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(self.id.to_be_bytes()) - } - - fn url_safe_decode_id(encoded_id: &str) -> Result { - let bytes_vec = base64::engine::general_purpose::URL_SAFE_NO_PAD.decode(encoded_id)?; - let mut bytes_arr = [0; 8]; - - for i in 0..8 { - bytes_arr[i] = bytes_vec.get(i).cloned().unwrap_or_default(); - } - - Ok(i64::from_be_bytes(bytes_arr)) - } -} - -#[derive(Debug, Clone)] -pub struct Hit { - id: Option, // ID is omitted when creating new hit - pixel_id: i64, - pub ip: String, - pub user_agent: String, - pub date: DateTime -} - -#[derive(Debug, Clone, PartialEq)] -pub struct User { - id: Option, // ID is omitted when creating new user - pub username: String, - pass_hash: String, -} - - -#[derive(Debug)] -pub struct PixelManager { - db_connection_sender: DBSender, - db_connection: Option> // only original manager holds the connection, clones in delegate do not - } - -impl PixelManager { - pub fn build(db_file: &str) -> Option { - let conn = Connection::open(db_file); - if conn.is_err() { - return None; - } - let db_connection = DBConnection::init(conn.unwrap(), Self::db_delegate); - - Some(Self{ db_connection_sender: db_connection.sender.clone(), db_connection: Some(db_connection) }) - } - - fn db_delegate(msg: DBConnectionMessage, conn: &Connection) { - _ = match msg { // beware, code folding recommended - DBConnectionMessage::CreatePixel(pixel) => - conn.execute("INSERT INTO pixels (id, name, user_id) VALUES (?1, ?2, ?3)", params![pixel.id, pixel.name, pixel.user_id]), - DBConnectionMessage::RegisterHit(hit) => - conn.execute("INSERT INTO hits (pixel_id, ip, user_agent, date) VALUES (?1, ?2, ?3, ?4)", params![hit.pixel_id, hit.ip, hit.user_agent, hit.date]), - DBConnectionMessage::DeletePixel(pixel_id) => - conn.execute("DELETE FROM pixels WHERE id = ?1", [pixel_id]), - DBConnectionMessage::AuthUser(user, response_sender) => { - let result: Result; - if let User{ id: Some(id), username, pass_hash} = user { - result = conn.query_row("SELECT id FROM users WHERE id = ?1 AND username = ?2 AND pass_hash = ?3", params![id, username, pass_hash], - |row| row.get(0)); - match result.optional() { - Ok(id) => { - if let Some(_) = id { - _ = response_sender.send(true); - } else { - _ = response_sender.send(false); - } - Ok(1) // 1 row affected - } - Err(e) => {Err(e)}, - } - } else { // invalid user object - Ok(0) // 0 rows affected - } - }, - DBConnectionMessage::GetUserFromName(username, response_sender) => { - let result = conn.query_row("SELECT id, username, pass_hash FROM users WHERE username = ?1", [username], - |row| Ok( - User{ - id: row.get(0)?, - username: row.get(1)?, - pass_hash: row.get(2)? - })); - match result.optional() { - Ok(user) => { - if let Some(user) = user { - _ = response_sender.send(Some(user)); - Ok(1) // 1 row affected - } - else { - _ = response_sender.send(None); - Ok(0) // no rows affected - } - }, - Err(e) => { - _ = response_sender.send(None); - Err(e) - } - } - }, - DBConnectionMessage::GetUserFromId(id, response_sender) => { - let result = conn.query_row("SELECT id, username, pass_hash FROM users WHERE id = ?1", [id], - |row| Ok( - User{ - id: row.get(0)?, - username: row.get(1)?, - pass_hash: row.get(2)? - })); - match result.optional() { - Ok(user) => { - if let Some(user) = user { - _ = response_sender.send(Some(user)); - Ok(1) // 1 row affected - } - else { - _ = response_sender.send(None); - Ok(0) // no rows affected - } - }, - Err(e) => { - _ = response_sender.send(None); - Err(e) - } - } - }, - DBConnectionMessage::CreateUser(user) => - conn.execute("INSERT INTO users (username, pass_hash) VALUES (?1, ?2)", params![user.username, user.pass_hash]), - DBConnectionMessage::DeleteUser(id) => - conn.execute("DELETE from users WHERE id = ?1", [id]), - DBConnectionMessage::GetHitsForPixel(pixel, response_sender, user) => 'gethitsforpixel: { - let mut stmt = conn.prepare("SELECT id, pixel_id, ip, user_agent, date FROM hits WHERE pixel_id = ?1").unwrap(); - if let Some(user) = user { - if let Some(user_id) = user.id { - // check if pixel belongs to user - let pixel_id: Result = conn.query_row("SELECT id FROM pixels WHERE id = ?1 AND user_id = ?2", [pixel.id, user_id], |row| { - Ok(row.get(0)?) - }); - if !pixel_id.is_ok() { - _ = response_sender.send(None); - break 'gethitsforpixel Ok(0); - } - } - } - // if this fails something is very wrong with the underlying connection, so panicking the thread is perfectly acceptable - let mapped_rows = stmt.query_map([pixel.id], |row| { - Ok(Hit { - id: Some(row.get(0)?), - pixel_id: row.get(1)?, - ip: row.get(2)?, - user_agent: row.get(3)?, - date: row.get(4)?, - }) - }); // processing on the DB thread is a bad idea, but this really isn't very complex and I don't really care - - match mapped_rows { - Ok(hits) => { - let hits: Vec = hits.filter_map(|hit| hit.ok()).collect(); - let rows_affected = hits.len(); - _ = response_sender.send(Some(hits)); - Ok(rows_affected) - }, - Err(e) => { - _ = response_sender.send(None); - Err(e) - } - } - }, - DBConnectionMessage::GetPixelsForUser(user, response_sender) => { - let mut stmt = conn.prepare("SELECT id,name,user_id FROM pixels WHERE user_id = ?1").unwrap(); // should't fail but if it does connection is bad and panicking is acceptable - let mapped_rows = stmt.query_map([user.id], |row| { - Ok(TrackingPixel { - id: row.get(0)?, - name: row.get(1)?, - user_id: row.get(2)? - }) - }); - - match mapped_rows { - Ok(pixels) => { - let pixels: Vec = pixels.filter_map(|pixel| pixel.ok()).collect(); - let rows_affected = pixels.len(); - _ = response_sender.send(Some(pixels)); - Ok(rows_affected) - }, - Err(e) => { - _ = response_sender.send(None); - Err(e) - } - } - - }, - DBConnectionMessage::GetPixel(id, user, response_sender) => { - let mut stmt = conn.prepare("SELECT id, name, user_id FROM pixels WHERE id = ?1").unwrap(); - if let Some(user) = user { - if let Some(user_id) = user.id { - let sql_str = format!("SELECT id,name,user_id FROM pixels WHERE id = ?1 AND user_id = {}", user_id); - stmt = conn.prepare(&sql_str).unwrap(); - } - } - let pixel = stmt.query_row([id], |row| { - Ok(TrackingPixel { - id: row.get(0)?, - name: row.get(1)?, - user_id: row.get(2)? - }) - }).optional(); - match pixel { - Ok(pixel) => { - _ = response_sender.send(pixel); - Ok(1) // 1 row affected - }, - Err(e) => { - _ = response_sender.send(None); - Err(e) - } - } - } - }; - } - - pub fn create_pixel(&self, name: &str, user: &User) -> Result { - let id = rand::random::().abs(); - // yes I don't check for duplicates. but whatever - if user.id.is_none() { - return Err(Error::UserNotAuthed()); - } - - let pixel = TrackingPixel{id, name: name.to_string(), user_id: user.id.unwrap() }; - self.db_connection_sender.send(DBConnectionMessage::CreatePixel(pixel))?; - - Ok(TrackingPixel { id, name: name.to_string(), user_id: user.id.unwrap() }) - } - - pub fn delete_pixel(&self, pixel: TrackingPixel, user: Option<&User>) -> Result<(), Error> { - if let Some(user) = user { - if let Ok(pixel) = self.get_pixel_from_id(pixel.id, Some(user)) { - if pixel.is_none() { // pixel is not withing user's pixels - return Err(Error::PixelNotFound()); - } - } - } - Ok(self.db_connection_sender.send(DBConnectionMessage::DeletePixel(pixel.id))?) - } - - pub fn register_hit_with_encoded_pixel(&self, encoded_pixel: &str, ip: &str, user_agent: &str, date: DateTime) -> Result<(), Error> { - self.register_hit_with_pixel_id(TrackingPixel::url_safe_decode_id(encoded_pixel)?, ip, user_agent, date) - } - - - pub fn register_hit_with_pixel(&self, pixel: &TrackingPixel, ip: &str, user_agent: &str, date: DateTime) -> Result<(), Error> { - self.register_hit_with_pixel_id(pixel.id, ip, user_agent, date) - } - - fn register_hit_with_pixel_id(&self, id: i64, ip: &str, user_agent: &str, date: DateTime) -> Result<(), Error> { - Ok(self.db_connection_sender.send( - DBConnectionMessage::RegisterHit( - Hit { - pixel_id: id, - ip: ip.to_string(), - user_agent: user_agent.to_string(), - date, id: None - }) - )? - ) - } - - fn pass_hash(password: &str) -> String { - hex_digest(Algorithm::SHA256, password.as_bytes()) - } - - fn auth_user(&self, user: &User, password: &str) -> Result { - let (sender, receiver) = oneshot::channel(); - - - let auth_user = User { - pass_hash: Self::pass_hash(password), - ..user.clone() - }; - - self.db_connection_sender.send(DBConnectionMessage::AuthUser(auth_user, sender))?; - - let auth = receiver.recv()?; - - Ok(auth) - } - - fn get_user_from_username(&self, username: &str) -> Result, Error> { - let (sender, receiver) = oneshot::channel(); - - self.db_connection_sender.send( - DBConnectionMessage::GetUserFromName(username.to_string(), sender))?; - - Ok(receiver.recv()?) - } - - fn get_user_from_id(&self, id: i64) -> Result, Error> { - let (sender, receiver) = oneshot::channel(); - - self.db_connection_sender.send(DBConnectionMessage::GetUserFromId(id, sender))?; - - Ok(receiver.recv()?) - } - - pub fn create_user(&self, username: &str, password: &str) -> Result{ - let user = self.get_user_from_username(username)?; - if user.is_some() { - return Err(Error::NewUserAlreadyExists()); - } - - let new_user = User { - username: username.to_string(), - pass_hash: Self::pass_hash(password), - id: None - }; - self.db_connection_sender.send( - DBConnectionMessage::CreateUser(new_user))?; - - let user = self.get_user_from_username(username)?; - // get user struct that has the id - - if let Some(user) = user { - Ok(user) - } else { - Err(Error::DBError()) - } - } - - pub fn delete_user(&self, user: User) -> Result<(), Error> { - let mut id = user.id; - if id.is_none() { - let db_user = self.get_user_from_username(&user.username)?; - - if let Some(db_user) = db_user { - id = db_user.id; // must always be Some because get_user_from_username will always contain an id - } else { - return Err(Error::InvalidUserData()) - } - } - - self.db_connection_sender.send(DBConnectionMessage::DeleteUser(id.unwrap()))?; - - Ok(()) - } - - pub fn get_user(&self, username: &str, password: &str) -> Result { - let user = self.get_user_from_username(username)?; - if let Some(user) = user { - let auth = self.auth_user(&user, password)?; - if auth { - Ok(user) - } else { - Err(Error::InvalidCredentials()) // wrong password - } - } else { - Err(Error::InvalidCredentials()) // username does not exist - } - } - // optionally include a user - pub fn get_hits_for_pixel(&self, pixel: &TrackingPixel, user: Option<&User>) -> Result, Error> { - let (sender, receiver) = oneshot::channel(); - self.db_connection_sender.send(DBConnectionMessage::GetHitsForPixel(pixel.clone(), sender, user.cloned()))?; - - let hits = receiver.recv()? ; - - Ok(hits.unwrap_or_default()) - } - - pub fn get_pixels_for_user(&self, user: &User) -> Result, Error> { - let (sender, receiver) = oneshot::channel(); - - self.db_connection_sender.send(DBConnectionMessage::GetPixelsForUser(user.clone(), sender))?; - - let pixels = receiver.recv()?; - - - Ok(pixels.unwrap_or_default()) - } - - pub fn get_pixel_from_encoded(&self, encoded_id: &str, user: Option<&User>) -> Result, Error> { - let id = TrackingPixel::url_safe_decode_id(encoded_id)?; - - self.get_pixel_from_id(id, user) - } - fn get_pixel_from_id(&self, pixel_id: i64, user: Option<&User>) -> Result, Error> { - let (sender, receiver) = oneshot::channel(); - - self.db_connection_sender.send(DBConnectionMessage::GetPixel(pixel_id, user.cloned(), sender))?; - - Ok(receiver.recv()?) - } - -} - -// stores a version of the pixel manager struct with only a sender, which may be cloned and used in multiple threads -#[derive(Debug)] -pub struct PixelManagerDelegate { - manager: PixelManager -} - -impl PixelManagerDelegate { - pub fn new(pixel_manager: &PixelManager) -> Self { - let internal_pixel_manager = PixelManager { - db_connection_sender: pixel_manager.db_connection_sender.clone(), - db_connection: None - }; - Self {manager: internal_pixel_manager} - } - - pub fn get_manager(&self) -> &PixelManager { - &self.manager - } -} - -impl Clone for PixelManagerDelegate { - fn clone(&self) -> Self { - let internal_pixel_manager = PixelManager { - db_connection_sender: self.manager.db_connection_sender.clone(), - db_connection: None - }; - Self {manager: internal_pixel_manager} - } -}