From e78be1f39347874c13c8ff1c08025ec375b5e928 Mon Sep 17 00:00:00 2001 From: Jonni Liljamo Date: Tue, 27 Sep 2022 13:24:56 +0300 Subject: [PATCH] I lost the old commit history... --- README.md | 6 + ulairi-api/Cargo.lock | 1678 +++++++++ ulairi-api/Cargo.toml | 26 + ulairi-api/Dockerfile.debian | 45 + ulairi-api/README.md | 12 + ulairi-api/diesel.toml | 5 + .../down.sql | 6 + .../up.sql | 36 + .../2022-04-27-190554_users/down.sql | 3 + .../migrations/2022-04-27-190554_users/up.sql | 8 + .../2022-04-28-071220_roles/down.sql | 3 + .../migrations/2022-04-28-071220_roles/up.sql | 6 + .../2022-04-28-071249_users_roles/down.sql | 3 + .../2022-04-28-071249_users_roles/up.sql | 8 + .../2022-04-29-115235_basic_roles/down.sql | 5 + .../2022-04-29-115235_basic_roles/up.sql | 6 + .../2022-05-01-115036_hour_entries/down.sql | 3 + .../2022-05-01-115036_hour_entries/up.sql | 9 + ulairi-api/scripts/deploy.sh | 8 + ulairi-api/src/db.rs | 41 + ulairi-api/src/hour_entries/mod.rs | 137 + ulairi-api/src/hour_entries/model.rs | 81 + ulairi-api/src/main.rs | 30 + ulairi-api/src/roles/mod.rs | 17 + ulairi-api/src/roles/model.rs | 20 + ulairi-api/src/schema.rs | 44 + ulairi-api/src/users/auth.rs | 40 + ulairi-api/src/users/mod.rs | 113 + ulairi-api/src/users/model.rs | 123 + ulairi-client/Cargo.lock | 3030 +++++++++++++++++ ulairi-client/Cargo.toml | 23 + ulairi-client/Projektisuunnitelma.odt | Bin 0 -> 11731 bytes ulairi-client/README.md | 5 + ulairi-client/src/app.rs | 491 +++ ulairi-client/src/app/api.rs | 465 +++ ulairi-client/src/app/widget/mod.rs | 2 + ulairi-client/src/app/widget/password.rs | 53 + ulairi-client/src/main.rs | 23 + 38 files changed, 6614 insertions(+) create mode 100644 README.md create mode 100644 ulairi-api/Cargo.lock create mode 100644 ulairi-api/Cargo.toml create mode 100644 ulairi-api/Dockerfile.debian create mode 100644 ulairi-api/README.md create mode 100644 ulairi-api/diesel.toml create mode 100644 ulairi-api/migrations/00000000000000_diesel_initial_setup/down.sql create mode 100644 ulairi-api/migrations/00000000000000_diesel_initial_setup/up.sql create mode 100644 ulairi-api/migrations/2022-04-27-190554_users/down.sql create mode 100644 ulairi-api/migrations/2022-04-27-190554_users/up.sql create mode 100644 ulairi-api/migrations/2022-04-28-071220_roles/down.sql create mode 100644 ulairi-api/migrations/2022-04-28-071220_roles/up.sql create mode 100644 ulairi-api/migrations/2022-04-28-071249_users_roles/down.sql create mode 100644 ulairi-api/migrations/2022-04-28-071249_users_roles/up.sql create mode 100644 ulairi-api/migrations/2022-04-29-115235_basic_roles/down.sql create mode 100644 ulairi-api/migrations/2022-04-29-115235_basic_roles/up.sql create mode 100644 ulairi-api/migrations/2022-05-01-115036_hour_entries/down.sql create mode 100644 ulairi-api/migrations/2022-05-01-115036_hour_entries/up.sql create mode 100644 ulairi-api/scripts/deploy.sh create mode 100644 ulairi-api/src/db.rs create mode 100644 ulairi-api/src/hour_entries/mod.rs create mode 100644 ulairi-api/src/hour_entries/model.rs create mode 100644 ulairi-api/src/main.rs create mode 100644 ulairi-api/src/roles/mod.rs create mode 100644 ulairi-api/src/roles/model.rs create mode 100644 ulairi-api/src/schema.rs create mode 100644 ulairi-api/src/users/auth.rs create mode 100644 ulairi-api/src/users/mod.rs create mode 100644 ulairi-api/src/users/model.rs create mode 100644 ulairi-client/Cargo.lock create mode 100644 ulairi-client/Cargo.toml create mode 100644 ulairi-client/Projektisuunnitelma.odt create mode 100644 ulairi-client/README.md create mode 100644 ulairi-client/src/app.rs create mode 100644 ulairi-client/src/app/api.rs create mode 100644 ulairi-client/src/app/widget/mod.rs create mode 100644 ulairi-client/src/app/widget/password.rs create mode 100644 ulairi-client/src/main.rs diff --git a/README.md b/README.md new file mode 100644 index 0000000..12840cb --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# Úlairi + +A simple time-tracking API and client. + +See the READMEs in ulairi-api/ and ulairi-client/ for their setups. + diff --git a/ulairi-api/Cargo.lock b/ulairi-api/Cargo.lock new file mode 100644 index 0000000..fe9932e --- /dev/null +++ b/ulairi-api/Cargo.lock @@ -0,0 +1,1678 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aead" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" +dependencies = [ + "generic-array", +] + +[[package]] +name = "aes" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" +dependencies = [ + "aes-soft", + "aesni", + "cipher", +] + +[[package]] +name = "aes-gcm" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5278b5fabbb9bd46e24aa69b2fdea62c99088e0a950a9be40e3e0101298f88da" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "aes-soft" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" +dependencies = [ + "cipher", + "opaque-debug", +] + +[[package]] +name = "aesni" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" +dependencies = [ + "cipher", + "opaque-debug", +] + +[[package]] +name = "argon2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a27e27b63e4a34caee411ade944981136fdfa535522dc9944d6700196cbd899f" +dependencies = [ + "base64ct", + "blake2", + "password-hash", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi 0.3.9", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" +dependencies = [ + "byteorder", + "safemem", +] + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "base64ct" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea908e7347a8c64e378c17e30ef880ad73e3b4498346b055c2c00ea342f3179" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "blake2" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9cf849ee05b2ee5fba5e36f97ff8ec2533916700fc0758d40d92136a42f3388" +dependencies = [ + "digest 0.10.3", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array", +] + +[[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 = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[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.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "serde", + "time", + "winapi 0.3.9", +] + +[[package]] +name = "cipher" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cookie" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80f6044740a4a516b8aac14c140cdf35c1a640b1bd6b98b6224e49143b2f1566" +dependencies = [ + "aes-gcm", + "base64 0.13.0", + "hkdf", + "hmac", + "percent-encoding 2.1.0", + "rand 0.8.5", + "sha2", + "time", +] + +[[package]] +name = "cpufeatures" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +dependencies = [ + "libc", +] + +[[package]] +name = "cpuid-bool" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" + +[[package]] +name = "crypto-common" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "ctr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" +dependencies = [ + "cipher", +] + +[[package]] +name = "devise" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd716c4a507adc5a2aa7c2a372d06c7497727e0892b243d3036bc7478a13e526" +dependencies = [ + "devise_codegen", + "devise_core", +] + +[[package]] +name = "devise_codegen" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea7b8290d118127c08e3669da20b331bed56b09f20be5945b7da6c116d8fab53" +dependencies = [ + "devise_core", + "quote 0.6.13", +] + +[[package]] +name = "devise_core" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1053e9d5d5aade9bcedb5ab53b78df2b56ff9408a3138ce77eaaef87f932373" +dependencies = [ + "bitflags", + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", +] + +[[package]] +name = "diesel" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b28135ecf6b7d446b43e27e225622a038cc4e2930a1022f51cdb97ada19b8e4d" +dependencies = [ + "bitflags", + "byteorder", + "chrono", + "diesel_derives", + "pq-sys", +] + +[[package]] +name = "diesel_derives" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3" +dependencies = [ + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn 1.0.95", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer 0.10.2", + "crypto-common", + "subtle", +] + +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + +[[package]] +name = "dotenv_codegen" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56966279c10e4f8ee8c22123a15ed74e7c8150b658b26c619c53f4a56eb4a8aa" +dependencies = [ + "dotenv_codegen_implementation", + "proc-macro-hack", +] + +[[package]] +name = "dotenv_codegen_implementation" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e737a3522cd45f6adc19b644ce43ef53e1e9045f2d2de425c1f468abd4cf33" +dependencies = [ + "dotenv", + "proc-macro-hack", + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn 1.0.95", +] + +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + +[[package]] +name = "filetime" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0408e2626025178a6a7f7ffc05a25bc47103229f19c113755de7bf63816290c" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "winapi 0.3.9", +] + +[[package]] +name = "fsevent" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6" +dependencies = [ + "bitflags", + "fsevent-sys", +] + +[[package]] +name = "fsevent-sys" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0" +dependencies = [ + "libc", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +dependencies = [ + "bitflags", + "fuchsia-zircon-sys", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" + +[[package]] +name = "gcc" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check 0.9.4", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", +] + +[[package]] +name = "ghash" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97304e4cd182c3846f7575ced3890c53012ce534ad9114046b0a9e00bb30a375" +dependencies = [ + "opaque-debug", + "polyval", +] + +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hkdf" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f" +dependencies = [ + "digest 0.9.0", + "hmac", +] + +[[package]] +name = "hmac" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "httparse" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" + +[[package]] +name = "hyper" +version = "0.10.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a0652d9a2609a968c14be1a9ea00bf4b1d64e2e1f53a1b51b6fff3a6e829273" +dependencies = [ + "base64 0.9.3", + "httparse", + "language-tags", + "log 0.3.9", + "mime 0.2.6", + "num_cpus", + "time", + "traitobject", + "typeable", + "unicase 1.4.2", + "url", +] + +[[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 = "indexmap" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "inotify" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4816c66d2c8ae673df83366c18341538f234a26d65a9ecea5c348b453ac1d02f" +dependencies = [ + "bitflags", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "iovec" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +dependencies = [ + "libc", +] + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "jwt" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa2b51232f4dba9bcbdc082f4ea5bee58d5c2866770b4dc80c868d09bd82569" +dependencies = [ + "rust-crypto", + "rustc-serialize", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + +[[package]] +name = "language-tags" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" +dependencies = [ + "log 0.4.17", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "mime" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" +dependencies = [ + "log 0.3.9", +] + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime 0.3.16", + "unicase 2.6.0", +] + +[[package]] +name = "mio" +version = "0.6.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +dependencies = [ + "cfg-if 0.1.10", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", + "libc", + "log 0.4.17", + "miow", + "net2", + "slab", + "winapi 0.2.8", +] + +[[package]] +name = "mio-extras" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" +dependencies = [ + "lazycell", + "log 0.4.17", + "mio", + "slab", +] + +[[package]] +name = "miow" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" +dependencies = [ + "kernel32-sys", + "net2", + "winapi 0.2.8", + "ws2_32-sys", +] + +[[package]] +name = "multipart" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050aeedc89243f5347c3e237e3e13dc76fbe4ae3742a57b94dc14f69acf76d4" +dependencies = [ + "buf_redux", + "httparse", + "log 0.4.17", + "mime 0.3.16", + "mime_guess", + "quick-error", + "rand 0.7.3", + "safemem", + "tempfile", + "twoway", +] + +[[package]] +name = "net2" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "winapi 0.3.9", +] + +[[package]] +name = "notify" +version = "4.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae03c8c853dba7bfd23e571ff0cff7bc9dceb40a4cd684cd1681824183f45257" +dependencies = [ + "bitflags", + "filetime", + "fsevent", + "fsevent-sys", + "inotify", + "libc", + "mio", + "mio-extras", + "walkdir", + "winapi 0.3.9", +] + +[[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.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.5", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.3", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi 0.3.9", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "password-hash" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e029e94abc8fb0065241c308f1ac6bc8d20f450e8f7c5f0b25cd9b8d526ba294" +dependencies = [ + "base64ct", + "rand_core 0.6.3", + "subtle", +] + +[[package]] +name = "pear" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32dfa7458144c6af7f9ce6a137ef975466aa68ffa44d4d816ee5934018ba960a" +dependencies = [ + "pear_codegen", +] + +[[package]] +name = "pear_codegen" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0288ba5d581afbc93e2bbd931c1013584c15ecf46b1cdb927edc7abddbc8ca6" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", + "version_check 0.9.4", + "yansi", +] + +[[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.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "polyval" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd" +dependencies = [ + "cpuid-bool", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "pq-sys" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac25eee5a0582f45a67e837e350d784e7003bd29a5f460796772061ca49ffda" +dependencies = [ + "vcpkg", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "proc-macro2" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +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 = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +dependencies = [ + "proc-macro2 0.4.30", +] + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2 1.0.39", +] + +[[package]] +name = "r2d2" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "545c5bc2b880973c9c10e4067418407a0ccaa3091781d1671d46eb35107cb26f" +dependencies = [ + "log 0.4.17", + "parking_lot 0.11.2", + "scheduled-thread-pool", +] + +[[package]] +name = "r2d2-diesel" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9c29bad92da76d02bc2c020452ebc3a3fe6fa74cfab91e711c43116e4fb1a3" +dependencies = [ + "diesel", + "r2d2", +] + +[[package]] +name = "rand" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" +dependencies = [ + "libc", + "rand 0.4.6", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi 0.3.9", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.3", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[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 0.6.3", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom 0.2.6", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi 0.3.9", +] + +[[package]] +name = "rocket" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83b9d9dc08c5dcc1d8126a9dd615545e6a358f8c13c883c8dfed8c0376fa355e" +dependencies = [ + "atty", + "base64 0.13.0", + "log 0.4.17", + "memchr", + "num_cpus", + "pear", + "rocket_codegen", + "rocket_http", + "state", + "time", + "toml", + "version_check 0.9.4", + "yansi", +] + +[[package]] +name = "rocket-multipart-form-data" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73d29a55443ad045eea2121f6047f25dc2f10eda1adc13ed0f00c12af182831f" +dependencies = [ + "mime 0.3.16", + "multipart", + "rocket", +] + +[[package]] +name = "rocket_codegen" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2810037b5820098af97bd4fdd309e76a8101ceb178147de775c835a2537284fe" +dependencies = [ + "devise", + "glob", + "indexmap", + "quote 0.6.13", + "rocket_http", + "version_check 0.9.4", + "yansi", +] + +[[package]] +name = "rocket_contrib" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e20efbc6a211cb3df5375accf532d4186f224b623f39eca650b19b96240c596b" +dependencies = [ + "log 0.4.17", + "notify", + "rocket", + "serde", + "serde_json", +] + +[[package]] +name = "rocket_http" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf9cbd128e1f321a2d0bebd2b7cf0aafd89ca43edf69e49b56a5c46e48eb19f" +dependencies = [ + "cookie", + "hyper", + "indexmap", + "pear", + "percent-encoding 1.0.1", + "smallvec", + "state", + "time", + "unicode-xid", +] + +[[package]] +name = "rust-crypto" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" +dependencies = [ + "gcc", + "libc", + "rand 0.3.23", + "rustc-serialize", + "time", +] + +[[package]] +name = "rustc-serialize" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" + +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[package]] +name = "safemem" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scheduled-thread-pool" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "977a7519bff143a44f842fd07e80ad1329295bd71686457f18e496736f4bf9bf" +dependencies = [ + "parking_lot 0.12.1", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +dependencies = [ + "proc-macro2 1.0.39", + "quote 1.0.18", + "syn 1.0.95", +] + +[[package]] +name = "serde_json" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "slab" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" + +[[package]] +name = "smallvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" + +[[package]] +name = "state" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3015a7d0a5fd5105c91c3710d42f9ccf0abfb287d62206484dcc67f9569a6483" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "unicode-xid", +] + +[[package]] +name = "syn" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +dependencies = [ + "proc-macro2 1.0.39", + "quote 1.0.18", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if 1.0.0", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi 0.3.9", +] + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi 0.3.9", +] + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "toml" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" +dependencies = [ + "serde", +] + +[[package]] +name = "traitobject" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" + +[[package]] +name = "twoway" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1" +dependencies = [ + "memchr", +] + +[[package]] +name = "typeable" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "ulairi-api" +version = "0.1.0" +dependencies = [ + "argon2", + "chrono", + "diesel", + "dotenv", + "dotenv_codegen", + "jwt", + "r2d2", + "r2d2-diesel", + "rand_core 0.6.3", + "rocket", + "rocket-multipart-form-data", + "rocket_codegen", + "rocket_contrib", + "rust-crypto", + "rustc-serialize", + "serde", +] + +[[package]] +name = "unicase" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" +dependencies = [ + "version_check 0.1.5", +] + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check 0.9.4", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" + +[[package]] +name = "unicode-normalization" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + +[[package]] +name = "universal-hash" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "url" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" +dependencies = [ + "idna", + "matches", + "percent-encoding 1.0.1", +] + +[[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.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi 0.3.9", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + +[[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-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" + +[[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 0.3.9", +] + +[[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-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" diff --git a/ulairi-api/Cargo.toml b/ulairi-api/Cargo.toml new file mode 100644 index 0000000..00f1a82 --- /dev/null +++ b/ulairi-api/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "ulairi-api" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +# TODO: Update dependencies to latest versions +[dependencies] +rocket = "0.4.5" +rocket_codegen = "0.4.5" +rocket_contrib = "0.4.5" +diesel = { version = "1.4.5", features = ["postgres", "chrono"] } +chrono = { version = "0.4.19", features = ["serde"] } +dotenv = "0.15.0" +dotenv_codegen = "0.15.0" +rocket-multipart-form-data = "0.9.5" +serde = { version = "1.0", features = ["derive"] } +r2d2-diesel = "1.0.0" +r2d2 = "0.8.3" +jwt = "0.4.0" +rust-crypto = "0.2" +rustc-serialize = "0.3" + +argon2 = "0.4.0" +rand_core = { version = "0.6.0", features = ["std"] } diff --git a/ulairi-api/Dockerfile.debian b/ulairi-api/Dockerfile.debian new file mode 100644 index 0000000..1571ff4 --- /dev/null +++ b/ulairi-api/Dockerfile.debian @@ -0,0 +1,45 @@ +## Buiilder +FROM rust:latest AS builder + +RUN rustup default nightly +RUN update-ca-certificates + +# Create appuser +ENV USER=ulairi +ENV UID=10001 + +RUN adduser \ + --disabled-password \ + --gecos "" \ + --home "/nonexistent" \ + --shell "/sbin/nologin" \ + --no-create-home \ + --uid "${UID}" \ + "${USER}" + +WORKDIR /ulairi-api + +COPY ./ . + +RUN cargo build --release + +## Final image +FROM debian:buster-slim + +RUN apt update +RUN apt install -y libpq5 libpq-dev + +# Import from builder +COPY --from=builder /etc/passwd /etc/passwd +COPY --from=builder /etc/group /etc/group + +WORKDIR /ulairi-api + +# Copy our build +COPY --from=builder /ulairi-api/target/release/ulairi-api ./ + +# Use an unprivileged user +USER ulairi:ulairi + +CMD ["/ulairi-api/ulairi-api"] + diff --git a/ulairi-api/README.md b/ulairi-api/README.md new file mode 100644 index 0000000..7e69c13 --- /dev/null +++ b/ulairi-api/README.md @@ -0,0 +1,12 @@ +# Template + +Install diesel: + * cargo install diesel_cli --no-default-features --features "postgres" + +Run migrations: + * diesel migration run + +Edit .env: + * JWT_KEY = tr -dc A-Za-z0-9 >; + +pub fn init_pool() -> Pool { + let manager = ConnectionManager::::new(database_url()); + Pool::new(manager).expect("db pool") +} + +fn database_url() -> String { + // Read the DATABASE_URL environment variable from the .env file + dotenv!("DATABASE_URL").to_string() +} + +pub struct DbConn(pub r2d2::PooledConnection>); + +impl<'a, 'r> FromRequest<'a, 'r> for DbConn { + type Error = (); + + fn from_request(request: &'a Request<'r>) -> request::Outcome { + let pool = request.guard::>()?; + match pool.get() { + Ok(conn) => Outcome::Success(DbConn(conn)), + Err(_) => Outcome::Failure((Status::ServiceUnavailable, ())), + } + } +} + +impl Deref for DbConn { + type Target = PgConnection; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/ulairi-api/src/hour_entries/mod.rs b/ulairi-api/src/hour_entries/mod.rs new file mode 100644 index 0000000..c1c4f8e --- /dev/null +++ b/ulairi-api/src/hour_entries/mod.rs @@ -0,0 +1,137 @@ +pub mod model; + +use self::model::HourEntry; +use rocket::{self, http::Status}; +use rocket_contrib::json::{Json, JsonValue}; +use serde::{Deserialize, Serialize}; + +use crate::users::auth::ApiKey; +use crate::users::model::User; + +use crate::db; + +#[derive(Serialize, Deserialize)] +struct RequestDetails { + email: String, +} + +#[post("/all", format = "application/json", data = "")] +fn all_entries( + request_details: Json, + key: ApiKey, + connection: db::DbConn, +) -> Result, Status> { + let email = request_details.email.to_string(); + match User::get_by_email(email.clone(), &connection) { + Some(user) => { + // Check if the key is owned by the email given + if key.0 == email { + let entries = HourEntry::get_all(user.id, &connection); + match entries { + Ok(entries) => Ok(Json(json!(entries))), + Err(_) => Err(Status::InternalServerError), + } + } else { + // Key is not owned by the email given + Err(Status::Unauthorized) + } + } + // User not found + None => Err(Status::NotFound), + } +} + +#[derive(Serialize, Deserialize)] +struct InsertDetails { + email: String, + hours: i32, + date_worked: String, +} + +#[post("/insert", format = "application/json", data = "")] +fn insert_entry( + insert_details: Json, + key: ApiKey, + connection: db::DbConn, +) -> Result, Status> { + let email = insert_details.email.to_string(); + let hours = insert_details.hours; + let date_worked = insert_details.date_worked.to_string(); + + match User::get_by_email(email.clone(), &connection) { + Some(user) => { + if key.0 == email { + let entry = HourEntry::create(user.id, hours, date_worked, &connection); + + // Return entry + match entry { + Ok(entry) => Ok(Json(json!(entry))), + Err(_) => Err(Status::InternalServerError), + } + } else { + Err(Status::Unauthorized) + } + } + None => Err(Status::NotFound), + } +} + +#[derive(Serialize, Deserialize)] +struct DeleteDetails { + email: String, + id: i32, +} + +#[post("/delete", format = "application/json", data = "")] +fn delete_entry( + delete_details: Json, + key: ApiKey, + connection: db::DbConn, +) -> Json { + let email = delete_details.email.to_string(); + let id = delete_details.id; + + match User::get_by_email(email.clone(), &connection) { + Some(_) => { + if key.0 == email { + match HourEntry::get_by_id(id, &connection) { + Ok(_) => match HourEntry::delete(id, &connection) { + Ok(_) => Json(json!( + { + "success": false, + "message": "Entry deletion failed" + })), + Err(_) => Json(json!( + { + "success": true, + "message": "Entry deleted succesfully" + })), + }, + Err(_) => Json(json!( + { + "success": false, + "message": "Entry not found" + })), + } + } else { + Json(json!( + { + "success": false, + "message": "You are not authorized to delete this entry" + })) + } + } + None => Json(json!( + { + "success": false, + "message": "User not found" + })), + } +} + +pub fn mount(rocket: rocket::Rocket) -> rocket::Rocket { + rocket.mount( + "/api/hours", + routes![all_entries, insert_entry, delete_entry], + ) +} diff --git a/ulairi-api/src/hour_entries/model.rs b/ulairi-api/src/hour_entries/model.rs new file mode 100644 index 0000000..ed4f812 --- /dev/null +++ b/ulairi-api/src/hour_entries/model.rs @@ -0,0 +1,81 @@ +use crate::schema::hour_entries; + +use diesel; +use diesel::pg::PgConnection; +use diesel::prelude::*; + +use serde::{Deserialize, Serialize}; + +use chrono::NaiveDate; + +#[derive(Serialize, Deserialize, Queryable, AsChangeset)] +#[table_name = "hour_entries"] +pub struct HourEntry { + pub id: i32, + pub user_id: i32, + pub hours: i32, + pub date_worked: NaiveDate, + pub date_entered: NaiveDate, +} + +#[derive(Serialize, Deserialize, Insertable)] +#[table_name = "hour_entries"] +pub struct InsertableHourEntry { + pub user_id: i32, + pub hours: i32, + pub date_worked: NaiveDate, + pub date_entered: NaiveDate, +} + +impl HourEntry { + pub fn create( + user_id: i32, + hours: i32, + date_worked: String, + connection: &PgConnection, + ) -> QueryResult { + let date_worked = NaiveDate::parse_from_str(&date_worked, "%Y-%m-%d").unwrap(); + let date_entered = chrono::Utc::now().naive_utc().date(); + + // Create a new hour entry + let hour_entry = InsertableHourEntry { + user_id, + hours, + date_worked, + date_entered, + }; + + // Insert the new hour entry + diesel::insert_into(hour_entries::table) + .values(hour_entry) + .execute(connection)?; + + // Return the new hour entry + hour_entries::table + .order(hour_entries::id.desc()) + .first(connection) + } + + pub fn delete(id: i32, connection: &PgConnection) -> QueryResult { + // Delete the hour entry + diesel::delete(hour_entries::table.find(id)).execute(connection)?; + + // Find entry with id, returns an error if not found, which we want + hour_entries::table + .filter(hour_entries::id.eq(id)) + .first(connection) + } + + pub fn get_all(user_id: i32, connection: &PgConnection) -> QueryResult> { + hour_entries::table + .filter(hour_entries::user_id.eq(user_id)) + .order(hour_entries::date_worked.desc()) + .load(connection) + } + + pub fn get_by_id(id: i32, connection: &PgConnection) -> QueryResult { + hour_entries::table + .filter(hour_entries::id.eq(id)) + .first(connection) + } +} diff --git a/ulairi-api/src/main.rs b/ulairi-api/src/main.rs new file mode 100644 index 0000000..e889ec3 --- /dev/null +++ b/ulairi-api/src/main.rs @@ -0,0 +1,30 @@ +#![feature(decl_macro)] + +#[macro_use] +extern crate diesel; +#[macro_use] +extern crate rocket; +#[macro_use] +extern crate rocket_contrib; +#[macro_use] +extern crate dotenv_codegen; + +mod db; + +mod hour_entries; +mod roles; +mod users; + +pub mod schema; + +fn main() { + println!("Starting server..."); + + let mut rocket = rocket::ignite().manage(db::init_pool()); + + rocket = users::mount(rocket); + rocket = roles::mount(rocket); + rocket = hour_entries::mount(rocket); + + rocket.launch(); +} diff --git a/ulairi-api/src/roles/mod.rs b/ulairi-api/src/roles/mod.rs new file mode 100644 index 0000000..b71db39 --- /dev/null +++ b/ulairi-api/src/roles/mod.rs @@ -0,0 +1,17 @@ +pub mod model; + +use self::model::Role; +use rocket::{self, http::Status}; +use rocket_contrib::json::{Json, JsonValue}; + +use crate::db; + +#[get("/all")] +pub fn get_all(connection: db::DbConn) -> Json { + // Return all roles as an array of objects + Json(json!({ "roles": Role::get_all(&connection) })) +} + +pub fn mount(rocket: rocket::Rocket) -> rocket::Rocket { + rocket.mount("/api/roles", routes![get_all]) +} diff --git a/ulairi-api/src/roles/model.rs b/ulairi-api/src/roles/model.rs new file mode 100644 index 0000000..bafa39e --- /dev/null +++ b/ulairi-api/src/roles/model.rs @@ -0,0 +1,20 @@ +use crate::schema::roles; + +use diesel; +use diesel::pg::PgConnection; +use diesel::prelude::*; + +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Queryable, AsChangeset)] +#[table_name = "roles"] +pub struct Role { + pub id: i32, + pub name: String, +} + +impl Role { + pub fn get_all(conn: &PgConnection) -> Vec { + roles::table.load::(conn).unwrap() + } +} diff --git a/ulairi-api/src/schema.rs b/ulairi-api/src/schema.rs new file mode 100644 index 0000000..492bb7a --- /dev/null +++ b/ulairi-api/src/schema.rs @@ -0,0 +1,44 @@ +table! { + hour_entries (id) { + id -> Int4, + user_id -> Int4, + hours -> Int4, + date_worked -> Date, + date_entered -> Date, + } +} + +table! { + roles (id) { + id -> Int4, + name -> Varchar, + } +} + +table! { + users (id) { + id -> Int4, + username -> Varchar, + email -> Varchar, + password -> Varchar, + } +} + +table! { + users_roles (id) { + id -> Int4, + user_id -> Int4, + role_id -> Int4, + } +} + +joinable!(hour_entries -> users (user_id)); +joinable!(users_roles -> roles (role_id)); +joinable!(users_roles -> users (user_id)); + +allow_tables_to_appear_in_same_query!( + hour_entries, + roles, + users, + users_roles, +); diff --git a/ulairi-api/src/users/auth.rs b/ulairi-api/src/users/auth.rs new file mode 100644 index 0000000..0feda7f --- /dev/null +++ b/ulairi-api/src/users/auth.rs @@ -0,0 +1,40 @@ +use rocket::request::{self, FromRequest, Request}; +use rocket::Outcome; + +pub extern crate crypto; +pub extern crate jwt; +pub extern crate rustc_serialize; + +use self::jwt::{Header, Registered, Token}; +use crypto::sha2::Sha256; + +pub struct ApiKey(pub String); + +pub fn read_token(key: &str) -> Result { + let token = + Token::::parse(key).map_err(|_| "Unable to parse key".to_string())?; + + // Check if the key is valid + if token.verify(dotenv!("JWT_KEY").as_bytes(), Sha256::new()) { + token.claims.sub.ok_or("Claims not valid".to_string()) + } else { + Err("Token not valid".to_string()) + } +} + +impl<'a, 'r> FromRequest<'a, 'r> for ApiKey { + type Error = (); + + fn from_request(request: &'a Request<'r>) -> request::Outcome { + // Get the key(s) from the authorization header + let keys: Vec<_> = request.headers().get("Authentication").collect(); + if keys.len() != 1 { + return Outcome::Forward(()); + } + // Check if the key is valid + match read_token(keys[0]) { + Ok(claim) => Outcome::Success(ApiKey(claim)), + Err(_) => Outcome::Forward(()), + } + } +} diff --git a/ulairi-api/src/users/mod.rs b/ulairi-api/src/users/mod.rs new file mode 100644 index 0000000..ead78e3 --- /dev/null +++ b/ulairi-api/src/users/mod.rs @@ -0,0 +1,113 @@ +pub mod auth; +pub mod model; + +use self::auth::crypto::sha2::Sha256; +use self::auth::jwt::{Header, Registered, Token}; +use self::auth::ApiKey; +use self::model::{InsertableUser, User}; +use rocket; +use rocket_contrib::json::{Json, JsonValue}; + +use crate::db; +use serde::{Deserialize, Serialize}; + +#[post("/register", format = "application/json", data = "")] +fn register(user: Json, connection: db::DbConn) -> Json { + if User::email_is_taken(user.email.clone(), &connection) { + return Json(json!( + { + "success": false, + "message": "Email is already taken" + })); + } else if User::username_is_taken(user.username.clone(), &connection) { + return Json(json!( + { + "success": false, + "message": "Username is already taken" + })); + } + + match User::create(user.into_inner(), &connection) { + Ok(_) => { + return Json(json!( + { + "success": true, + "message": "User created" + })); + } + Err(_) => { + return Json(json!( + { + "success": false, + "message": "Internal server error, please try again or contact support" + })); + } + } +} + +#[get("/info")] +fn info(key: ApiKey) -> Json { + Json(json!( + { + "success": true, + "message": key.0 + } + )) +} + +#[get("/info", rank = 2)] +fn info_forbidden() -> Json { + Json(json!( + { + "success": false, + "message": "Forbidden" + } + )) +} + +#[derive(Serialize, Deserialize)] +struct Login { + username: String, + password: String, +} + +#[post("/login", format = "application/json", data = "")] +fn login(login: Json, connection: db::DbConn) -> Json { + let header: Header = Default::default(); + let username = login.username.to_string(); + let password = login.password.to_string(); + + match User::get_by_username_and_password(username, password, &connection) { + None => Json(json!( + { + "success": false, + "message": "Username or password is incorrect" + })), + Some(user) => { + let claims = Registered { + sub: Some(user.email.into()), + ..Default::default() + }; + let token = Token::new(header, claims); + + match token.signed(dotenv!("JWT_KEY").as_bytes(), Sha256::new()) { + Ok(token) => Json(json!( + { + "success": true, + "message": token + })), + Err(_) => Json(json!( + { + "success": false, + "message": "Internal server error, please try again or contact support" + })), + } + } + } +} + +pub fn mount(rocket: rocket::Rocket) -> rocket::Rocket { + rocket + .mount("/api/user", routes![info, info_forbidden]) + .mount("/api/auth", routes![register, login]) +} diff --git a/ulairi-api/src/users/model.rs b/ulairi-api/src/users/model.rs new file mode 100644 index 0000000..5d14c17 --- /dev/null +++ b/ulairi-api/src/users/model.rs @@ -0,0 +1,123 @@ +use crate::schema::users; + +use diesel; +use diesel::pg::PgConnection; +use diesel::prelude::*; + +use serde::{Deserialize, Serialize}; + +use argon2::{ + password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString}, + Argon2, +}; + +#[derive(Serialize, Deserialize, Queryable, AsChangeset)] +#[table_name = "users"] +pub struct User { + pub id: i32, + pub username: String, + pub email: String, + pub password: String, +} + +#[derive(Serialize, Deserialize, Insertable)] +#[table_name = "users"] +pub struct InsertableUser { + pub username: String, + pub email: String, + pub password: String, +} + +impl User { + pub fn create(user: InsertableUser, connection: &PgConnection) -> QueryResult { + // Generate a salt + let salt = SaltString::generate(&mut OsRng); + + // Hash the password to PHC string + let password_hash = Argon2::default() + .hash_password(user.password.as_bytes(), &salt) + .unwrap() + .to_string(); + + let encrypted_user = InsertableUser { + password: password_hash, + ..user + }; + + // Insert the user into the database + diesel::insert_into(users::table) + .values(encrypted_user) + .execute(connection)?; + + // Query the database for the encrypted user + users::table.order(users::id.desc()).first(connection) + } + + pub fn get_by_username_and_password( + username: String, + password: String, + connection: &PgConnection, + ) -> Option { + // Query the database for the user + let res = users::table + .filter(users::username.eq(username)) + .get_result::(connection); + + // Check if the user exists + match res { + Ok(user) => { + let parsed_hash = PasswordHash::new(&user.password).unwrap(); + + // Check if the password is correct + if Argon2::default() + .verify_password(password.as_bytes(), &parsed_hash) + .is_ok() + { + Some(user) + } else { + None + } + } + Err(_) => None, + } + } + + pub fn get_by_email(email: String, connection: &PgConnection) -> Option { + // Query the database for the user + let res = users::table + .filter(users::email.eq(email)) + .get_result::(connection); + + // Check if the user exists + match res { + Ok(user) => Some(user), + Err(_) => None, + } + } + + pub fn email_is_taken(email: String, connection: &PgConnection) -> bool { + // Query the database for the user + let res = users::table + .filter(users::email.eq(email)) + .get_result::(connection); + + // Check if the user exists + match res { + Ok(_) => true, + Err(_) => false, + } + } + + pub fn username_is_taken(username: String, connection: &PgConnection) -> bool { + // Query the database for the user + let res = users::table + .filter(users::username.eq(username)) + .get_result::(connection); + + // Check if the user exists + match res { + Ok(_) => true, + Err(_) => false, + } + } +} diff --git a/ulairi-client/Cargo.lock b/ulairi-client/Cargo.lock new file mode 100644 index 0000000..f3fdbd5 --- /dev/null +++ b/ulairi-client/Cargo.lock @@ -0,0 +1,3030 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ab_glyph" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24606928a235e73cdef55a0c909719cadd72fce573e5713d58cb2952d8f5794c" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13739d7177fbd22bb0ed28badfff9f372f8bef46c863db4e1c6248f6b223b6e" + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "serde", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "android_glue" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407" + +[[package]] +name = "arboard" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc120354d1b5ec6d7aaf4876b602def75595937b5e15d356eb554ab5177e08bb" +dependencies = [ + "clipboard-win", + "log", + "objc", + "objc-foundation", + "objc_id", + "parking_lot 0.12.0", + "thiserror", + "winapi", + "x11rb", +] + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "atomic_refcell" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b5e5f48b927f04e952dedc932f31995a65a0bf65ec971c74436e51bf6e970d" + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bigdecimal" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aaf33151a6429fe9211d1b276eafdf70cdff28b071e76c0b0e1503221ea3744" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "bindgen" +version = "0.59.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitvec" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5237f00a8c86130a0cc317830e558b966dd7850d48a953d998c813f01a41b527" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bufstream" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40e38929add23cdf8a366df9b0e088953150724bcbe5fc330b0d8eb3b328eec8" + +[[package]] +name = "bumpalo" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" + +[[package]] +name = "bytemuck" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdead85bdec19c194affaeeb670c0e41fe23de31459efd1c174d049269cf02cc" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562e382481975bc61d11275ac5e62a19abd00b0547d99516a415336f183dcd0e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "calloop" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf2eec61efe56aa1e813f5126959296933cf0700030e4314786c48779a66ab82" +dependencies = [ + "log", + "nix 0.22.3", +] + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cgl" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff" +dependencies = [ + "libc", +] + +[[package]] +name = "clang-sys" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf6b561dcf059c85bbe388e0a7b0a1469acb3934cc0cfa148613a830629e3049" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clipboard-win" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f3e1238132dc01f081e1cbb9dace14e5ef4c3a51ee244bd982275fb514605db" +dependencies = [ + "error-code", + "str-buf", + "winapi", +] + +[[package]] +name = "cmake" +version = "0.1.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" +dependencies = [ + "cc", +] + +[[package]] +name = "cocoa" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63902e9223530efb4e26ccd0cf55ec30d592d3b42e21a28defc42a9586e832" +dependencies = [ + "bitflags", + "block", + "cocoa-foundation", + "core-foundation 0.9.3", + "core-graphics 0.22.3", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" +dependencies = [ + "bitflags", + "block", + "core-foundation 0.9.3", + "core-graphics-types", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "combine" +version = "4.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a604e93b79d1808327a6fca85a6f2d69de66461e7620f5a4cbf5fb4d1d7c948" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "core-foundation" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" +dependencies = [ + "core-foundation-sys 0.7.0", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys 0.8.3", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "core-graphics" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3889374e6ea6ab25dba90bb5d96202f61108058361f6dc72e8b03e6f8bbe923" +dependencies = [ + "bitflags", + "core-foundation 0.7.0", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" +dependencies = [ + "bitflags", + "core-foundation 0.9.3", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" +dependencies = [ + "bitflags", + "core-foundation 0.9.3", + "foreign-types", + "libc", +] + +[[package]] +name = "core-video-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34ecad23610ad9757664d644e369246edde1803fcb43ed72876565098a5d3828" +dependencies = [ + "cfg-if 0.1.10", + "core-foundation-sys 0.7.0", + "core-graphics 0.19.2", + "libc", + "objc", +] + +[[package]] +name = "cpufeatures" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "crossbeam" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" +dependencies = [ + "autocfg", + "cfg-if 1.0.0", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +dependencies = [ + "cfg-if 1.0.0", + "lazy_static", +] + +[[package]] +name = "crypto-common" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "cty" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" + +[[package]] +name = "darling" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "derive_utils" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "532b4c15dccee12c7044f1fcad956e98410860b22231e44a3b827464797ca7bf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "directories-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" +dependencies = [ + "cfg-if 1.0.0", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dlib" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794" +dependencies = [ + "libloading", +] + +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + +[[package]] +name = "downcast-rs" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" + +[[package]] +name = "eframe" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fa97a8188c36261ea162e625dbb23599f67b60777b462b834fe38161b81dce" +dependencies = [ + "bytemuck", + "directories-next", + "egui", + "egui-winit", + "egui_glow", + "glow", + "glutin", + "js-sys", + "percent-encoding", + "ron", + "serde", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winit", +] + +[[package]] +name = "egui" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb095a8b9feb9b7ff8f00b6776dffcef059538a3f4a91238e03c900e9c9ad9a2" +dependencies = [ + "ahash", + "epaint", + "nohash-hasher", + "ron", + "serde", + "tracing", +] + +[[package]] +name = "egui-winit" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b040afd583fd95a9b9578d4399214a13d948ed26bc0ff7cc0104502501f34e68" +dependencies = [ + "arboard", + "egui", + "instant", + "serde", + "tracing", + "webbrowser", + "winit", +] + +[[package]] +name = "egui_extras" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877bfcce06463cdbcfd7f4efd57608b1384d6d9ae03b33e503fbba1d1a899a52" +dependencies = [ + "egui", +] + +[[package]] +name = "egui_glow" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af43ed7ec7199907ab5853c3bb3883ae1e741ab540aa127a798a60b7bdb906f1" +dependencies = [ + "bytemuck", + "egui", + "glow", + "memoffset", + "tracing", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "emath" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c223f58c7e38abe1770f367b969f1b3fbd4704b67666bcb65dbb1adb0980ba72" +dependencies = [ + "bytemuck", + "serde", +] + +[[package]] +name = "encoding_rs" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "epaint" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c29567088888e8ac3e8f61bbb2ddc820207ebb8d69eefde5bcefa06d65e4e89" +dependencies = [ + "ab_glyph", + "ahash", + "atomic_refcell", + "bytemuck", + "emath", + "nohash-hasher", + "parking_lot 0.12.0", + "serde", +] + +[[package]] +name = "error-code" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64f18991e7bf11e7ffee451b5318b5c1a73c52d0d0ada6e5a3017c8c1ced6a21" +dependencies = [ + "libc", + "str-buf", +] + +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + +[[package]] +name = "flate2" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39522e96686d38f4bc984b9198e3a0613264abaebaff2c5c918bfa6b6da09af" +dependencies = [ + "cfg-if 1.0.0", + "crc32fast", + "libc", + "libz-sys", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[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.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "frunk" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cd67cf7d54b7e72d0ea76f3985c3747d74aee43e0218ad993b7903ba7a5395e" +dependencies = [ + "frunk_core", + "frunk_derives", + "frunk_proc_macros", +] + +[[package]] +name = "frunk_core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1246cf43ec80bf8b2505b5c360b8fb999c97dabd17dbb604d85558d5cbc25482" + +[[package]] +name = "frunk_derives" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dbc4f084ec5a3f031d24ccedeb87ab2c3189a2f33b8d070889073837d5ea09e" +dependencies = [ + "frunk_proc_macro_helpers", + "quote", + "syn", +] + +[[package]] +name = "frunk_proc_macro_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99f11257f106c6753f5ffcb8e601fb39c390a088017aaa55b70c526bff15f63e" +dependencies = [ + "frunk_core", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "frunk_proc_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a078bd8459eccbb85e0b007b8f756585762a72a9efc53f359b371c3b6351dbcc" +dependencies = [ + "frunk_core", + "frunk_proc_macros_impl", + "proc-macro-hack", +] + +[[package]] +name = "frunk_proc_macros_impl" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ffba99f0fa4f57e42f57388fbb9a0ca863bc2b4261f3c5570fed579d5df6c32" +dependencies = [ + "frunk_core", + "frunk_proc_macro_helpers", + "proc-macro-hack", + "quote", + "syn", +] + +[[package]] +name = "funty" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1847abb9cb65d566acd5942e94aea9c8f547ad02c98e1649326fc0e8910b8b1e" + +[[package]] +name = "futures-channel" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" + +[[package]] +name = "futures-sink" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" + +[[package]] +name = "futures-task" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" + +[[package]] +name = "futures-util" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "gethostname" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "getrandom" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.10.2+wasi-snapshot-preview1", +] + +[[package]] +name = "gl_generator" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" +dependencies = [ + "khronos_api", + "log", + "xml-rs", +] + +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + +[[package]] +name = "glow" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8bd5877156a19b8ac83a29b2306fe20537429d318f3ff0a1a2119f8d9c61919" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "glutin" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00ea9dbe544bc8a657c4c4a798c2d16cd01b549820e47657297549d28371f6d2" +dependencies = [ + "android_glue", + "cgl", + "cocoa", + "core-foundation 0.9.3", + "glutin_egl_sys", + "glutin_emscripten_sys", + "glutin_gles2_sys", + "glutin_glx_sys", + "glutin_wgl_sys", + "lazy_static", + "libloading", + "log", + "objc", + "osmesa-sys", + "parking_lot 0.11.2", + "wayland-client", + "wayland-egl", + "winapi", + "winit", +] + +[[package]] +name = "glutin_egl_sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2abb6aa55523480c4adc5a56bbaa249992e2dddb2fc63dc96e04a3355364c211" +dependencies = [ + "gl_generator", + "winapi", +] + +[[package]] +name = "glutin_emscripten_sys" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80de4146df76e8a6c32b03007bc764ff3249dcaeb4f675d68a06caf1bac363f1" + +[[package]] +name = "glutin_gles2_sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094e708b730a7c8a1954f4f8a31880af00eb8a1c5b5bf85d28a0a3c6d69103" +dependencies = [ + "gl_generator", + "objc", +] + +[[package]] +name = "glutin_glx_sys" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e393c8fc02b807459410429150e9c4faffdb312d59b8c038566173c81991351" +dependencies = [ + "gl_generator", + "x11-dl", +] + +[[package]] +name = "glutin_wgl_sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3da5951a1569dbab865c6f2a863efafff193a93caf05538d193e9e3816d21696" +dependencies = [ + "gl_generator", +] + +[[package]] +name = "h2" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "http" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff8670570af52249509a86f5e3e18a08c60b177071826898fde8997cf5f6bfbb" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b26ae0a80afebe130861d90abf98e3814a4f28a4c6ffeb5ab8ebb2be311e0ef2" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "io-enum" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03e3306b0f260aad2872563eb0d5d1a59f2420fad270a661dce59a01e92d806b" +dependencies = [ + "autocfg", + "derive_utils", + "quote", + "syn", +] + +[[package]] +name = "ipnet" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "js-sys" +version = "0.3.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "lexical" +version = "6.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7aefb36fd43fef7003334742cbf77b243fcd36418a1d1bdd480d613a67968f6" +dependencies = [ + "lexical-core", +] + +[[package]] +name = "lexical-core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cde5de06e8d4c2faabc400238f9ae1c74d5412d03a7bd067645ccbc47070e46" +dependencies = [ + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", +] + +[[package]] +name = "lexical-parse-float" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683b3a5ebd0130b8fb52ba0bdc718cc56815b6a097e28ae5a6997d0ad17dc05f" +dependencies = [ + "lexical-parse-integer", + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-parse-integer" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "125e1f93e5003d4bd89758c2ca2771bfae13632df633cde581efe07c87d354e5" +dependencies = [ + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-util" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5255b9ff16ff898710eb9eb63cb39248ea8a5bb036bea8085b1a767ff6c4e3fc" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "lexical-write-float" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accabaa1c4581f05a3923d1b4cfd124c329352288b7b9da09e766b0668116862" +dependencies = [ + "lexical-util", + "lexical-write-integer", + "static_assertions", +] + +[[package]] +name = "lexical-write-integer" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1b6f3d1f4422866b68192d62f77bc5c700bee84f3069f2469d7bc8c77852446" +dependencies = [ + "lexical-util", + "static_assertions", +] + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "libloading" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" +dependencies = [ + "cfg-if 1.0.0", + "winapi", +] + +[[package]] +name = "libz-sys" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e7e15d7610cce1d9752e137625f14e61a28cd45929b6e12e47b50fe154ee2e" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "load-dotenv" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71abcf6d8da2a6c163554a61cdbca2438bbe9e687a9c5ebeee12e9af42864b54" +dependencies = [ + "dotenv", +] + +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "lru" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32613e41de4c47ab04970c348ca7ae7382cf116625755af070b008a15516a889" +dependencies = [ + "hashbrown", +] + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memmap2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b6c2ebff6180198788f5db08d7ce3bc1d0b617176678831a7510825973e357" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713d550d9b44d89174e066b7a6217ae06234c10cb47819a88290d2b353c31799" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys", +] + +[[package]] +name = "mysql" +version = "22.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e6f8658d54e3c294d94a741a5f414c21431f56f253b5dc2e2582941d834b3a9" +dependencies = [ + "bufstream", + "bytes", + "crossbeam", + "flate2", + "io-enum", + "libc", + "lru", + "mysql_common", + "named_pipe", + "native-tls", + "nix 0.23.1", + "once_cell", + "pem", + "percent-encoding", + "serde", + "serde_json", + "socket2", + "twox-hash", + "url", +] + +[[package]] +name = "mysql_common" +version = "0.28.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4140827f2d12750de1e8755442577e4292a835f26ff2f659f0a380d1d71020b0" +dependencies = [ + "base64", + "bigdecimal", + "bindgen", + "bitflags", + "bitvec", + "byteorder", + "bytes", + "cc", + "cmake", + "crc32fast", + "flate2", + "frunk", + "lazy_static", + "lexical", + "num-bigint", + "num-traits", + "rand", + "regex", + "rust_decimal", + "saturating", + "serde", + "serde_json", + "sha-1", + "sha2", + "smallvec", + "subprocess", + "thiserror", + "time", + "uuid", +] + +[[package]] +name = "named_pipe" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad9c443cce91fc3e12f017290db75dde490d685cdaaf508d7159d7cf41f0eb2b" +dependencies = [ + "winapi", +] + +[[package]] +name = "native-tls" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd7e2f3618557f980e0b17e8856252eee3c97fa12c54dff0ca290fb6266ca4a9" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "ndk" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d868f654c72e75f8687572699cdabe755f03effbb62542768e995d5b8d699d" +dependencies = [ + "bitflags", + "jni-sys", + "ndk-sys 0.2.2", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" +dependencies = [ + "bitflags", + "jni-sys", + "ndk-sys 0.3.0", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-glue" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71bee8ea72d685477e28bd004cfe1bf99c754d688cd78cad139eae4089484d4" +dependencies = [ + "lazy_static", + "libc", + "log", + "ndk 0.5.0", + "ndk-context", + "ndk-macro", + "ndk-sys 0.2.2", +] + +[[package]] +name = "ndk-glue" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d0c4a7b83860226e6b4183edac21851f05d5a51756e97a1144b7f5a6b63e65f" +dependencies = [ + "lazy_static", + "libc", + "log", + "ndk 0.6.0", + "ndk-context", + "ndk-macro", + "ndk-sys 0.3.0", +] + +[[package]] +name = "ndk-macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c" +dependencies = [ + "darling", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ndk-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121" + +[[package]] +name = "ndk-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "nix" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf" +dependencies = [ + "bitflags", + "cc", + "cfg-if 1.0.0", + "libc", + "memoffset", +] + +[[package]] +name = "nix" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" +dependencies = [ + "bitflags", + "cc", + "cfg-if 1.0.0", + "libc", + "memoffset", +] + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + +[[package]] +name = "nom" +version = "7.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "objc-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +dependencies = [ + "block", + "objc", + "objc_id", +] + +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + +[[package]] +name = "once_cell" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" + +[[package]] +name = "openssl" +version = "0.10.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb81a6430ac911acb25fe5ac8f1d2af1b4ea8a4fdfda0f1ee4292af2e2d8eb0e" +dependencies = [ + "bitflags", + "cfg-if 1.0.0", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5fd19fb3e0a8191c1e34935718976a3e70c112ab9a24af6d7cadccd9d90bc0" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "osmesa-sys" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88cfece6e95d2e717e0872a7f53a8684712ad13822a7979bc760b9c77ec0013b" +dependencies = [ + "shared_library", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb1e509cfe7a12db2a90bfa057dfcdbc55a347f5da677c506b53dd099cfec9d" +dependencies = [ + "ttf-parser", +] + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.5", +] + +[[package]] +name = "parking_lot" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.3", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "pem" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9a3b09a20e374558580a4914d3b7d89bd61b954a5a5e1dcbea98753addb1947" +dependencies = [ + "base64", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[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.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" + +[[package]] +name = "poll-promise" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "260817b339544e5b23d4bb66d4522d89dd64af88d16b6dcd7b2a2409ee2e095d" +dependencies = [ + "static_assertions", + "tokio", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro-crate" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" +dependencies = [ + "thiserror", + "toml", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + +[[package]] +name = "proc-macro2" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" + +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "raw-window-handle" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41" +dependencies = [ + "cty", +] + +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "reqwest" +version = "0.11.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a1f7aa4f35e5e8b4160449f51afc758f0ce6454315a9fa7d0d113e958c41eb" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "lazy_static", + "log", + "mime", + "native-tls", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "ron" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b861ecaade43ac97886a512b360d01d66be9f41f3c61088b42cedf92e03d678" +dependencies = [ + "base64", + "bitflags", + "serde", +] + +[[package]] +name = "rust_decimal" +version = "1.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22dc69eadbf0ee2110b8d20418c0c6edbaefec2811c4963dc17b6344e11fe0f8" +dependencies = [ + "arrayvec", + "num-traits", + "serde", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "saturating" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ece8e78b2f38ec51c51f5d475df0a7187ba5111b2a28bdc761ee05b075d40a71" + +[[package]] +name = "schannel" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +dependencies = [ + "lazy_static", + "windows-sys", +] + +[[package]] +name = "scoped-tls" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "security-framework" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" +dependencies = [ + "bitflags", + "core-foundation 0.9.3", + "core-foundation-sys 0.8.3", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +dependencies = [ + "core-foundation-sys 0.8.3", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha-1" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest", +] + +[[package]] +name = "shared_library" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11" +dependencies = [ + "lazy_static", + "libc", +] + +[[package]] +name = "shlex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" + +[[package]] +name = "slotmap" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" + +[[package]] +name = "smithay-client-toolkit" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a28f16a97fa0e8ce563b2774d1e732dd5d4025d2772c5dba0a41a0f90a29da3" +dependencies = [ + "bitflags", + "calloop", + "dlib", + "lazy_static", + "log", + "memmap2", + "nix 0.22.3", + "pkg-config", + "wayland-client", + "wayland-cursor", + "wayland-protocols", +] + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "str-buf" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d44a3643b4ff9caf57abcee9c2c621d6c03d9135e0d8b589bd9afb5992cb176a" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subprocess" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2e86926081dda636c546d8c5e641661049d7562a68f5488be4a1f7f66f6086" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "syn" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if 1.0.0", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" +dependencies = [ + "libc", + "num_threads", +] + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4903bf0427cf68dddd5aa6a93220756f8be0c34fcfa9f5e6191e103e15a31395" +dependencies = [ + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "parking_lot 0.12.0", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f988a1a1adc2fb21f9c12aa96441da33a1728193ae0b95d2be22dbd17fcb4e5c" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + +[[package]] +name = "tower-service" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" + +[[package]] +name = "tracing" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09" +dependencies = [ + "cfg-if 1.0.0", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "ttf-parser" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c74c96594835e10fa545e2a51e8709f30b173a092bfd6036ef2cec53376244f3" + +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if 1.0.0", + "rand", + "static_assertions", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "ulairi-client" +version = "0.1.0" +dependencies = [ + "eframe", + "egui_extras", + "load-dotenv", + "mysql", + "poll-promise", + "regex", + "reqwest", + "serde", + "tokio", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" + +[[package]] +name = "unicode-normalization" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" + +[[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 = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[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.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" +dependencies = [ + "cfg-if 1.0.0", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f741de44b75e14c35df886aff5f1eb73aa114fa5d4d00dcd37b5e01259bf3b2" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" + +[[package]] +name = "wayland-client" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91223460e73257f697d9e23d401279123d36039a3f7a449e983f123292d4458f" +dependencies = [ + "bitflags", + "downcast-rs", + "libc", + "nix 0.22.3", + "scoped-tls", + "wayland-commons", + "wayland-scanner", + "wayland-sys", +] + +[[package]] +name = "wayland-commons" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f6e5e340d7c13490eca867898c4cec5af56c27a5ffe5c80c6fc4708e22d33e" +dependencies = [ + "nix 0.22.3", + "once_cell", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-cursor" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c52758f13d5e7861fc83d942d3d99bf270c83269575e52ac29e5b73cb956a6bd" +dependencies = [ + "nix 0.22.3", + "wayland-client", + "xcursor", +] + +[[package]] +name = "wayland-egl" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83281d69ee162b59031c666385e93bde4039ec553b90c4191cdb128ceea29a3a" +dependencies = [ + "wayland-client", + "wayland-sys", +] + +[[package]] +name = "wayland-protocols" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60147ae23303402e41fe034f74fb2c35ad0780ee88a1c40ac09a3be1e7465741" +dependencies = [ + "bitflags", + "wayland-client", + "wayland-commons", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39a1ed3143f7a143187156a2ab52742e89dac33245ba505c17224df48939f9e0" +dependencies = [ + "proc-macro2", + "quote", + "xml-rs", +] + +[[package]] +name = "wayland-sys" +version = "0.29.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9341df79a8975679188e37dab3889bfa57c44ac2cb6da166f519a81cbe452d4" +dependencies = [ + "dlib", + "lazy_static", + "pkg-config", +] + +[[package]] +name = "web-sys" +version = "0.3.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webbrowser" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a3cffdb686fbb24d9fb8f03a213803277ed2300f11026a3afe1f108dc021b" +dependencies = [ + "jni", + "ndk-glue 0.6.2", + "url", + "web-sys", + "widestring", + "winapi", +] + +[[package]] +name = "widestring" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983" + +[[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-wsapoll" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c17110f57155602a80dca10be03852116403c9ff3cd25b079d666f2aa3df6e" +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-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "winit" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b43cc931d58b99461188607efd7acb2a093e65fc621f54cad78517a6063e73a" +dependencies = [ + "bitflags", + "cocoa", + "core-foundation 0.9.3", + "core-graphics 0.22.3", + "core-video-sys", + "dispatch", + "instant", + "lazy_static", + "libc", + "log", + "mio", + "ndk 0.5.0", + "ndk-glue 0.5.2", + "ndk-sys 0.2.2", + "objc", + "parking_lot 0.11.2", + "percent-encoding", + "raw-window-handle", + "smithay-client-toolkit", + "wasm-bindgen", + "wayland-client", + "wayland-protocols", + "web-sys", + "winapi", + "x11-dl", +] + +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + +[[package]] +name = "wyz" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "129e027ad65ce1453680623c3fb5163cbf7107bfe1aa32257e7d0e63f9ced188" +dependencies = [ + "tap", +] + +[[package]] +name = "x11-dl" +version = "2.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea26926b4ce81a6f5d9d0f3a0bc401e5a37c6ae14a1bfaa8ff6099ca80038c59" +dependencies = [ + "lazy_static", + "libc", + "pkg-config", +] + +[[package]] +name = "x11rb" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e99be55648b3ae2a52342f9a870c0e138709a3493261ce9b469afe6e4df6d8a" +dependencies = [ + "gethostname", + "nix 0.22.3", + "winapi", + "winapi-wsapoll", +] + +[[package]] +name = "xcursor" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7" +dependencies = [ + "nom", +] + +[[package]] +name = "xml-rs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" diff --git a/ulairi-client/Cargo.toml b/ulairi-client/Cargo.toml new file mode 100644 index 0000000..563a538 --- /dev/null +++ b/ulairi-client/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "ulairi-client" +version = "0.1.0" +authors = ["Jonni Liljamo "] +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +eframe = { version = "0.18.0", features = ["persistence"] } +egui_extras = "0.18.0" + +serde = { version = "1", features = ["derive"], optional = false } + +mysql = "22.1.0" + +regex = "1" + +reqwest = { version = "0.11", features = ["json"] } +tokio = { version = "1", features = ["full"] } +poll-promise = { version = "0.1.0", features = ["tokio"] } + +load-dotenv = "0.1.2" diff --git a/ulairi-client/Projektisuunnitelma.odt b/ulairi-client/Projektisuunnitelma.odt new file mode 100644 index 0000000000000000000000000000000000000000..f24129cd4e5b6cdf93b77752131d2cfb79b7bbda GIT binary patch literal 11731 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 k{^~t`_~f6m{Yc0DTMw-y3kUzB7{=qz, + register: Promise, + user_info: Promise, + hour_entries: Promise>, + insert_hour_entry: Promise, +} + +struct PromisesStates { + login_waiting: bool, + register_waiting: bool, + user_info_waiting: bool, + hour_entries_waiting: bool, + insert_hour_entry_waiting: bool, +} + +/// We derive Deserialize/Serialize so we can persist app state on shutdown. +#[derive(serde::Deserialize, serde::Serialize)] +#[serde(default)] // if we add new fields, give them default values when deserializing old state +pub struct App { + #[serde(skip)] + api_address: String, + + #[serde(skip)] + user: UserDetails, + + #[serde(skip)] + login_state: LoginState, + + #[serde(skip)] + popup_details: PopupDetails, + + #[serde(skip)] + input: InputFields, + + #[serde(skip)] + promise: Promises, + + #[serde(skip)] + promise_state: PromisesStates, + + #[serde(skip)] + logged_in: bool, + + #[serde(skip)] + hour_entries: Vec, + + #[serde(skip)] + adding_hour_entry: bool, +} + +impl Default for App { + fn default() -> Self { + Self { + api_address: env!("WEB_API_ADDRESS").to_string(), + user: UserDetails { + api_key: String::new(), + email: String::new(), + }, + login_state: LoginState::LoggedOut, + popup_details: PopupDetails { + visible: false, + title: String::new(), + message: String::new(), + }, + input: InputFields { + username: String::new(), + email: String::new(), + password: String::new(), + hours: 0, + date: String::new(), + }, + promise: Promises { + login: Promise::from_ready(api::AuthResponse::default()), + register: Promise::from_ready(api::AuthResponse::default()), + user_info: Promise::from_ready(api::UserInfoResponse::default()), + hour_entries: Promise::from_ready(vec![]), + insert_hour_entry: Promise::from_ready(api::HourEntry::default()), + }, + promise_state: PromisesStates { + login_waiting: false, + register_waiting: false, + user_info_waiting: false, + hour_entries_waiting: false, + insert_hour_entry_waiting: false, + }, + logged_in: false, + hour_entries: Vec::new(), + adding_hour_entry: false, + } + } +} + +impl App { + // Called once before the first frame. + pub fn new(cc: &eframe::CreationContext<'_>) -> Self { + // Load previous app state (if any). + if let Some(storage) = cc.storage { + return eframe::get_value(storage, eframe::APP_KEY).unwrap_or_default(); + } + + Default::default() + } +} + +impl eframe::App for App { + /// Called by the frame work to save state before shutdown. + fn save(&mut self, storage: &mut dyn eframe::Storage) { + eframe::set_value(storage, eframe::APP_KEY, self); + } + + /// Called each time the UI needs repainting, which may be many times per second. + fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { + let Self { + api_address, + user, + login_state, + popup_details, + input, + promise, + promise_state, + logged_in, + hour_entries, + adding_hour_entry, + } = self; + + egui::TopBottomPanel::top("top_panel").show(ctx, |ui| { + // The top panel is often a good place for a menu bar: + egui::menu::bar(ui, |ui| { + ui.menu_button("File", |ui| { + if ui.button("Quit").clicked() { + frame.quit(); + } + }); + }); + }); + + egui::SidePanel::left("side_panel").show(ctx, |ui| { + if *logged_in { + if promise_state.user_info_waiting { + ui.label("Loading user info..."); + + if let Some(result) = promise.user_info.ready() { + user.email = result.message.clone(); + + promise_state.user_info_waiting = false; + } + } else { + ui.heading(format!("Logged in as: {}", user.email)); + } + + if ui.button("New hour entry").clicked() { + *adding_hour_entry = true; + } + + ui.with_layout(egui::Layout::bottom_up(egui::Align::Center), |ui| { + if ui.button("Logout").clicked() { + *logged_in = false; + user.api_key = String::new(); + *hour_entries = Vec::new(); + } + }); + } else { + ui.heading("Not logged in"); + } + }); + + egui::CentralPanel::default().show(ctx, |ui| { + // The central panel the region left after adding TopPanel's and SidePanel's + + if *logged_in { + if promise_state.hour_entries_waiting { + ui.heading("Loading..."); + + // Repaint + ctx.request_repaint(); + + if let Some(result) = promise.hour_entries.ready() { + *hour_entries = result.to_vec(); + promise_state.hour_entries_waiting = false; + } + } else { + egui::ScrollArea::vertical().show(ui, |ui| { + TableBuilder::new(ui) + .striped(true) + .cell_layout( + egui::Layout::left_to_right().with_cross_align(egui::Align::Center), + ) + .column(Size::initial(60.0).at_least(40.0)) + .column(Size::initial(60.0).at_least(40.0)) + .column(Size::initial(60.0).at_least(40.0)) + .column(Size::remainder().at_least(60.0)) + .resizable(true) + .header(20.0, |mut header| { + header.col(|ui| { + ui.heading("Hours"); + }); + header.col(|ui| { + ui.heading("Date Worked"); + }); + header.col(|ui| { + ui.heading("Date Entered"); + }); + header.col(|ui| { + ui.heading("Actions"); + }); + }) + .body(|mut body| { + for entry in hour_entries.clone() { + body.row(15.0, |mut row| { + row.col(|ui| { + ui.label(entry.hours.to_string()); + }); + row.col(|ui| { + ui.label(entry.date_worked.to_string()); + }); + row.col(|ui| { + ui.label(entry.date_entered.to_string()); + }); + row.col(|ui| { + if ui.button("Delete").clicked() { + let id = entry.id.clone(); + let api_key = user.api_key.clone(); + let api_addr = api_address.clone(); + + let _delete_promise = + Promise::spawn_async(async move { + api::delete_hour_entry( + id, api_key, api_addr, + ) + .await + }); + + hour_entries.remove( + hour_entries + .clone() + .iter() + .position(|x| x.id == id) + .unwrap(), + ); + } + }); + }); + } + }); + }); + } + } + }); + + if *adding_hour_entry && *logged_in { + egui::Window::new("New time entry").show(ctx, |ui| { + ui.label("Hours worked:"); + ui.add(egui::Slider::new(&mut input.hours, 0..=24).suffix("h")); + ui.label("Date worked in YYYY-MM-DD format:"); + ui.text_edit_singleline(&mut input.date); + + if ui.button("Save").clicked() { + if Regex::new(r"^\d{4}\-(0?[1-9]|1[012])\-(0?[1-9]|[12][0-9]|3[01])$") + .unwrap() + .is_match(&mut input.date) + { + promise_state.insert_hour_entry_waiting = true; + + let hours = input.hours.clone(); + let date_worked = input.date.clone(); + let api_key = user.api_key.clone(); + let api_addr = api_address.clone(); + + promise.insert_hour_entry = Promise::spawn_async(async move { + api::insert_hour_entry(hours, date_worked, api_key, api_addr).await + }); + + *adding_hour_entry = false; + } else { + popup_details.visible = true; + popup_details.title = "Invalid date".to_owned(); + popup_details.message = "Date format is YYYY-MM-DD".to_owned(); + } + } + + if ui.button("Cancel").clicked() { + *adding_hour_entry = false; + } + }); + } else if promise_state.insert_hour_entry_waiting && *logged_in { + // Repaint + ctx.request_repaint(); + + if let Some(result) = promise.insert_hour_entry.ready() { + self.hour_entries.push(result.clone()); + promise_state.insert_hour_entry_waiting = false; + } + } + + if !*logged_in { + egui::Window::new("Login / Register") + .title_bar(false) + .resizable(false) + .show(ctx, |ui| match *login_state { + LoginState::LoggedOut => { + ui.label("Welcome! Please, login or register."); + + ui.horizontal(|ui| { + if ui.button("Register").clicked() { + *login_state = LoginState::Registering; + } + + if ui.button("Login").clicked() { + *login_state = LoginState::LoggingIn; + } + }); + } + LoginState::LoggingIn => { + ui.horizontal(|ui| { + ui.label("Username:"); + ui.text_edit_singleline(&mut input.username); + }); + + ui.horizontal(|ui| { + ui.label("Password:"); + ui.add(widget::password::password(&mut input.password)); + }); + + ui.add_enabled_ui(!promise_state.login_waiting, |ui| { + ui.horizontal(|ui| { + if ui.button("Back").clicked() { + *login_state = LoginState::LoggedOut; + } + + if ui.button("Login").clicked() { + promise_state.login_waiting = true; + + let username = input.username.clone(); + let password = input.password.clone(); + let api_addr = api_address.clone(); + + promise.login = Promise::spawn_async(async { + api::auth(username, password, api_addr).await + }); + + input.password = String::new(); + } + }); + }); + + if promise_state.login_waiting { + // Repaint + ctx.request_repaint(); + + if let Some(result) = promise.login.ready() { + if result.success { + user.api_key = result.message.clone(); + + // TODO: There has to be another way to do this, right? Here I have to make the temporary values twice... + // NOTE: It's a problem with the lifetime of the variables when using them in async functions, while the main program is not async. + let api_key = user.api_key.clone(); + let api_addr = api_address.clone(); + promise.hour_entries = Promise::spawn_async(async { + api::get_hour_entries(api_key, api_addr).await + }); + promise_state.hour_entries_waiting = true; + + let api_key = user.api_key.clone(); + let api_addr = api_address.clone(); + promise.user_info = Promise::spawn_async(async { + api::get_user_info(api_key, api_addr).await + }); + promise_state.user_info_waiting = true; + + *logged_in = true; + } else { + popup_details.visible = true; + popup_details.title = "Login failed".to_owned(); + popup_details.message = result.message.clone(); + } + + promise_state.login_waiting = false; + } + } + } + LoginState::Registering => { + ui.horizontal(|ui| { + ui.label("Username:"); + ui.text_edit_singleline(&mut input.username); + }); + + ui.horizontal(|ui| { + ui.label("Email:"); + ui.text_edit_singleline(&mut input.email); + }); + + ui.horizontal(|ui| { + ui.label("Password:"); + ui.add(widget::password::password(&mut input.password)); + }); + + ui.add_enabled_ui(!promise_state.register_waiting, |ui| { + ui.horizontal(|ui| { + if ui.button("Back").clicked() { + *login_state = LoginState::LoggedOut; + } + + if ui.button("Register").clicked() { + promise_state.register_waiting = true; + + let username = input.username.clone(); + let email = input.email.clone(); + let password = input.password.clone(); + let api_addr = api_address.clone(); + + promise.register = Promise::spawn_async(async { + api::register(username, email, password, api_addr).await + }); + + input.password = String::new(); + } + }); + }); + + if promise_state.register_waiting { + // Repaint + ctx.request_repaint(); + + if let Some(result) = promise.register.ready() { + if result.success { + popup_details.visible = true; + popup_details.title = "Successfully registered!".to_owned(); + popup_details.message = result.message.clone(); + } else { + popup_details.visible = true; + popup_details.title = "Registration failed".to_owned(); + popup_details.message = result.message.clone(); + } + + promise_state.register_waiting = false; + } + } + } + }); + } + + if popup_details.visible { + egui::Window::new(popup_details.title.to_string()).show(ctx, |ui| { + ui.vertical_centered(|ui| { + ui.label(popup_details.message.to_string()); + if ui.button("Ok").clicked() { + popup_details.visible = false; + } + }); + }); + } + } +} diff --git a/ulairi-client/src/app/api.rs b/ulairi-client/src/app/api.rs new file mode 100644 index 0000000..b578ec5 --- /dev/null +++ b/ulairi-client/src/app/api.rs @@ -0,0 +1,465 @@ +use reqwest; + +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub struct AuthInput { + pub username: String, + pub password: String, +} + +#[derive(Serialize, Deserialize)] +pub struct RegisterInput { + pub username: String, + pub email: String, + pub password: String, +} + +#[derive(Serialize, Deserialize)] +pub struct AuthResponse { + pub success: bool, + pub message: String, +} + +impl Default for AuthResponse { + fn default() -> Self { + AuthResponse { + success: false, + message: String::new(), + } + } +} + +#[derive(Serialize, Deserialize)] +pub struct HourEntryInsertInput { + pub email: String, + pub hours: i32, + pub date_worked: String, +} + +#[derive(Serialize, Deserialize)] +pub struct HourEntryDeleteInput { + pub email: String, + pub id: i32, +} + +#[derive(Serialize, Deserialize, Clone)] +pub struct HourEntry { + pub id: i32, + pub user_id: i32, + pub hours: i32, + pub date_worked: String, + pub date_entered: String, +} + +impl Default for HourEntry { + fn default() -> Self { + HourEntry { + id: 0, + user_id: 0, + hours: 0, + date_worked: String::new(), + date_entered: String::new(), + } + } +} + +#[derive(Serialize, Deserialize, Clone)] +pub struct UserInfoInput { + pub email: String, +} + +#[derive(Serialize, Deserialize, Clone)] +pub struct UserInfoResponse { + pub success: bool, + pub message: String, +} + +impl Default for UserInfoResponse { + fn default() -> Self { + UserInfoResponse { + success: false, + message: String::new(), + } + } +} + +pub async fn auth(username: String, password: String, api_address: String) -> AuthResponse { + // Connect to env!("WEB_API_ADDRESS")/api/auth/login and return AuthResponse + let client = reqwest::Client::new(); + let response = client + .post(&format!("{}/api/auth/login", api_address)) + .json(&AuthInput { + username: username.to_string(), + password: password.to_string(), + }) + .send() + .await + .unwrap(); + response.json().await.unwrap() +} + +pub async fn register( + username: String, + email: String, + password: String, + api_address: String, +) -> AuthResponse { + // Connect to env!("WEB_API_ADDRESS")/api/auth/register and return AuthResponse + let client = reqwest::Client::new(); + let response = client + .post(&format!("{}/api/auth/register", api_address)) + .json(&RegisterInput { + username: username.to_string(), + email: email.to_string(), + password: password.to_string(), + }) + .send() + .await + .unwrap(); + response.json().await.unwrap() +} + +pub async fn get_user_info(api_key: String, api_address: String) -> UserInfoResponse { + // Connect to env!("WEB_API_ADDRESS")/api/user/info and return UserInfo + let client = reqwest::Client::new(); + let response = client + .get(&format!("{}/api/user/info", api_address)) + .header("Authentication", api_key) + .send() + .await + .unwrap(); + response.json().await.unwrap() +} + +pub async fn get_hour_entries(api_key: String, api_address: String) -> Vec { + // Connect to env!("WEB_API_ADDRESS")/api/hours/all and return Vec + let email = get_user_info(api_key.clone(), api_address.clone()) + .await + .message; + + let client = reqwest::Client::new(); + + let response = client + .post(&format!("{}/api/hours/all", api_address)) + .header("Authentication", api_key) + .json(&UserInfoInput { + email: email.to_string(), + }) + .send() + .await + .unwrap(); + response.json().await.unwrap() +} + +pub async fn insert_hour_entry( + hours: i32, + date_worked: String, + api_key: String, + api_address: String, +) -> HourEntry { + // Connect to env!("WEB_API_ADDRESS")/api/hours/insert and return HourEntry + let email = get_user_info(api_key.clone(), api_address.clone()) + .await + .message; + + let client = reqwest::Client::new(); + + let response = client + .post(&format!("{}/api/hours/insert", api_address)) + .header("Authentication", api_key) + .json(&HourEntryInsertInput { + email: email.to_string(), + hours: hours, + date_worked: date_worked.to_string(), + }) + .send() + .await + .unwrap(); + response.json().await.unwrap() +} + +pub async fn delete_hour_entry(id: i32, api_key: String, api_address: String) { + // Connect to env!("WEB_API_ADDRESS")/api/hours/delete and return () + let email = get_user_info(api_key.clone(), api_address.clone()) + .await + .message; + + let client = reqwest::Client::new(); + + client + .post(&format!("{}/api/hours/delete", api_address)) + .header("Authentication", api_key) + .json(&HourEntryDeleteInput { + email: email.to_string(), + id: id, + }) + .send() + .await + .unwrap(); +} +/* All the nice old things! +use mysql::prelude::*; +use mysql::*; + +use argon2::{ + password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString}, + Argon2, +}; + +// Different exit contituons for verify_user +#[derive(Debug, PartialEq, Eq)] +pub enum VerifyExit { + EmptyArg, + Success, + WrongPassword, + UserNotFound, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct User { + pub id: i32, + pub username: String, + pub password: String, +} + +impl User { + pub fn new() -> User { + User { + id: 0, + username: "".to_owned(), + password: "".to_owned(), + } + } +} + +// Time entry struct +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct TimeEntry { + pub id: i32, + pub user_id: i32, + pub hours: i32, + pub date_worked: String, + pub date_entered: String, +} + +// Role struct +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct Role { + pub id: i32, + pub name: String, +} + +#[derive(Debug, PartialEq, Eq)] +pub enum Roles { + Member, + Leader, +} + +// UserRole struct +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct UserRole { + pub user_id: i32, + pub role_id: i32, +} + +pub struct DatabaseManager { + pub pool: Pool, +} + +impl DatabaseManager { + pub fn new() -> DatabaseManager { + DatabaseManager { + pool: Pool::new(Opts::from_url("mysql://root:QXSrgXhclUKrC6jl37qQ5ytRVbthtyJSCvFR23ZhYvlbAGwysvqecSsg1eeLPkLP3J9YrSinM192JmcgjrIPdLAhDc5wpU1im1ocNV7oU01CWL4GYgfNdMFx9mMlKZOc@172.104.253.237:3306/tuntikirjanpito").unwrap()).unwrap(), + } + } + + pub fn init_connection(&mut self) { + println!("Connected to mysql"); + } + + pub fn register_user(&mut self, username: &str, password: &str) -> bool { + if username.is_empty() || password.is_empty() { + println!("Username or password is empty"); + return false; + } + + let password = password.as_bytes(); + let salt = SaltString::generate(&mut OsRng); + + // Argon2 with default params (Argon2id v19) + let argon2 = Argon2::default(); + + // Hash password to PHC string + let password_hash = argon2.hash_password(password, &salt).unwrap().to_string(); + + self.pool + .get_conn() + .ok() + .unwrap() + .exec_drop( + "INSERT INTO users (username, password) values (:username, :password)", + params! { + "username" => username, + "password" => password_hash, + }, + ) + .unwrap(); + + println!("User {} registered", username); + return true; + } + + pub fn verify_user(&mut self, username: &str, password: &str) -> VerifyExit { + if username.is_empty() || password.is_empty() { + println!("Username or password is empty"); + return VerifyExit::EmptyArg; + } + + let res = self + .pool + .get_conn() + .ok() + .unwrap() + .query_first(format!( + "SELECT id, username, password FROM users WHERE username='{un}'", + un = username + )) + //Unpack Result + .map(|row| { + //Unpack Option + row.map(|(id, username, password)| User { + id: id, + username: username, + password: password, + }) + }); + + match res.unwrap() { + Some(user) => { + let parsed_hash = PasswordHash::new(&user.password); + + if Argon2::default() + .verify_password(password.as_bytes(), &parsed_hash.unwrap()) + .is_ok() + { + println!("Password verified"); + return VerifyExit::Success; + } else { + println!("Password not verified"); + return VerifyExit::WrongPassword; + } + } + None => return VerifyExit::UserNotFound, + } + } + + pub fn get_user(&mut self, username: &str) -> User { + let res = self + .pool + .get_conn() + .ok() + .unwrap() + .query_first(format!( + "SELECT id, username, password FROM users WHERE username='{un}'", + un = username + )) + //Unpack Result + .map(|row| { + //Unpack Option + row.map(|(id, username, password)| User { + id: id, + username: username, + password: password, + }) + }); + + match res.unwrap() { + Some(mut user) => { + println!("User {} found", user.username); + user.password = "".to_owned(); + return user.clone(); + } + None => { + return User { + id: -1, + username: "".to_owned(), + password: "".to_owned(), + } + } + } + } + + pub fn add_time_entry(&mut self, user_id: i32, hours: i32, date_worked: &str) { + self.pool + .get_conn() + .ok() + .unwrap() + .exec_drop( + "INSERT INTO entries (user_id, hours, date_worked, date_entered) values (:user_id, :hours, :date_worked, CURDATE())", + params! { + "user_id" => user_id, + "hours" => hours, + "date_worked" => date_worked, + }, + ) + .unwrap(); + } + + pub fn delete_time_entry(&mut self, id: i32) { + self.pool + .get_conn() + .ok() + .unwrap() + .exec_drop( + "DELETE FROM entries WHERE id=:id", + params! { + "id" => id, + }, + ) + .unwrap(); + } + + pub fn get_time_entries(&mut self, user_id: i32) -> Vec { + self.pool + .get_conn() + .ok() + .unwrap() + .query_map( + format!( + "SELECT id, user_id, hours, date_worked, date_entered FROM entries WHERE user_id={uid}", + uid = user_id + ), + |(id, user_id, hours, date_worked, date_entered)| TimeEntry { + id, + user_id, + hours, + date_worked, + date_entered, + }, + ) + .unwrap() + } + + pub fn get_roles(&mut self) -> Vec { + self.pool + .get_conn() + .ok() + .unwrap() + .query_map("SELECT id, name FROM roles", |(id, name)| Role { id, name }) + .unwrap() + } + + pub fn get_user_role_pairs(&mut self) -> Vec { + self.pool + .get_conn() + .ok() + .unwrap() + .query_map( + "SELECT user_id, role_id FROM users_roles", + |(user_id, role_id)| UserRole { user_id, role_id }, + ) + .unwrap() + } +} +*/ diff --git a/ulairi-client/src/app/widget/mod.rs b/ulairi-client/src/app/widget/mod.rs new file mode 100644 index 0000000..2468791 --- /dev/null +++ b/ulairi-client/src/app/widget/mod.rs @@ -0,0 +1,2 @@ +pub mod password; + diff --git a/ulairi-client/src/app/widget/password.rs b/ulairi-client/src/app/widget/password.rs new file mode 100644 index 0000000..004af42 --- /dev/null +++ b/ulairi-client/src/app/widget/password.rs @@ -0,0 +1,53 @@ +use eframe::egui; + +pub fn password_ui(ui: &mut egui::Ui, password: &mut String) -> egui::Response { + // This widget has its own state — show or hide password characters (`show_plaintext`). + // In this case we use a simple `bool`, but you can also declare your own type. + // It must implement at least `Clone` and be `'static`. + // If you use the `persistence` feature, it also must implement `serde::{Deserialize, Serialize}`. + + // Generate an id for the state + let state_id = ui.id().with("show_plaintext"); + + // Get state for this widget. + // You should get state by value, not by reference to avoid borrowing of [`Memory`]. + let mut show_plaintext = ui.data().get_temp::(state_id).unwrap_or(false); + + // Process ui, change a local copy of the state + // We want TextEdit to fill entire space, and have button after that, so in that case we can + // change direction to right_to_left. + let result = ui.with_layout(egui::Layout::right_to_left(), |ui| { + // Toggle the `show_plaintext` bool with a button: + let response = ui + .add(egui::SelectableLabel::new(show_plaintext, "👁")) + .on_hover_text("Show/hide password"); + + if response.clicked() { + show_plaintext = !show_plaintext; + } + + // Show the password field: + ui.add_sized( + ui.available_size(), + egui::TextEdit::singleline(password).password(!show_plaintext), + ); + }); + + // Store the (possibly changed) state: + ui.data().insert_temp(state_id, show_plaintext); + + // All done! Return the interaction response so the user can check what happened + // (hovered, clicked, …) and maybe show a tooltip: + result.response +} + +// A wrapper that allows the more idiomatic usage pattern: `ui.add(…)` +/// Password entry field with ability to toggle character hiding. +/// +/// ## Example: +/// ``` ignore +/// ui.add(password(&mut my_password)); +/// ``` +pub fn password(password: &mut String) -> impl egui::Widget + '_ { + move |ui: &mut egui::Ui| password_ui(ui, password) +} diff --git a/ulairi-client/src/main.rs b/ulairi-client/src/main.rs new file mode 100644 index 0000000..6988d43 --- /dev/null +++ b/ulairi-client/src/main.rs @@ -0,0 +1,23 @@ +#![forbid(unsafe_code)] +#![cfg_attr(not(debug_assertions), deny(warnings))] // Forbid warnings in release builds +#![warn(clippy::all, rust_2018_idioms)] +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] //Hide console window in release builds on Windows, this blocks stdout. + +mod app; + +use load_dotenv::load_dotenv; + +load_dotenv!(); + +#[tokio::main] +async fn main() { + println!("Starting tuntikirjanpito..."); + println!("Using {} as web api address.", env!("WEB_API_ADDRESS")); + + let native_options = eframe::NativeOptions::default(); + eframe::run_native( + "Tuntikirjanpito", + native_options, + Box::new(|cc| Box::new(app::App::new(cc))), + ); +} -- 2.44.1