From a4251a772a34f8ce85340cc872cb2246c5e63dc1 Mon Sep 17 00:00:00 2001 From: realaravinth Date: Mon, 4 Oct 2021 21:21:10 +0530 Subject: [PATCH] init --- .github/FUNDING.yml | 12 + .github/workflows/clippy-fmt.yml | 43 + .github/workflows/coverage.yml | 79 + .github/workflows/linux.yml | 90 + .gitignore | 15 + Cargo.lock | 2914 ++++++++++++++++++++ Cargo.toml | 76 + LICENSE.md | 660 +++++ Makefile | 53 + build.rs | 69 + config/default.toml | 33 + migrations/20211001071311_survey_users.sql | 5 + package.json | 13 + rustfmt.toml | 1 + sailfish.yml | 1 + src/api/mod.rs | 18 + src/api/v1/auth.rs | 92 + src/api/v1/meta.rs | 124 + src/api/v1/mod.rs | 45 + src/api/v1/routes.rs | 34 + src/data.rs | 45 + src/errors.rs | 201 ++ src/main.rs | 143 + src/middleware/auth.rs | 81 + src/middleware/mod.rs | 18 + src/pages/auth/join.rs | 158 ++ src/pages/auth/login.rs | 167 ++ src/pages/auth/mod.rs | 46 + src/pages/auth/sudo.rs | 43 + src/pages/errors.rs | 120 + src/pages/mod.rs | 116 + src/pages/panel/campaigns/delete.rs | 196 ++ src/pages/panel/campaigns/get.rs | 61 + src/pages/panel/campaigns/mod.rs | 93 + src/pages/panel/campaigns/new.rs | 134 + src/pages/panel/mod.rs | 55 + src/pages/routes.rs | 68 + src/settings.rs | 180 ++ src/static_assets/filemap.rs | 46 + src/static_assets/mod.rs | 25 + src/static_assets/static_files.rs | 145 + src/tests-migrate.rs | 92 + src/tests.rs | 261 ++ static/cache/img/logo.png | Bin 0 -> 30215 bytes static/cache/img/logo.svg | 1 + static/cache/img/trash.svg | 1 + static/favicons/android-icon-144x144.png | Bin 0 -> 11158 bytes static/favicons/android-icon-192x192.png | Bin 0 -> 13646 bytes static/favicons/android-icon-36x36.png | Bin 0 -> 2475 bytes static/favicons/android-icon-48x48.png | Bin 0 -> 3337 bytes static/favicons/android-icon-72x72.png | Bin 0 -> 4910 bytes static/favicons/android-icon-96x96.png | Bin 0 -> 6656 bytes static/favicons/apple-icon-114x114.png | Bin 0 -> 8317 bytes static/favicons/apple-icon-120x120.png | Bin 0 -> 8857 bytes static/favicons/apple-icon-144x144.png | Bin 0 -> 11158 bytes static/favicons/apple-icon-152x152.png | Bin 0 -> 11981 bytes static/favicons/apple-icon-180x180.png | Bin 0 -> 15194 bytes static/favicons/apple-icon-57x57.png | Bin 0 -> 3922 bytes static/favicons/apple-icon-60x60.png | Bin 0 -> 4101 bytes static/favicons/apple-icon-72x72.png | Bin 0 -> 4910 bytes static/favicons/apple-icon-76x76.png | Bin 0 -> 5236 bytes static/favicons/apple-icon-precomposed.png | Bin 0 -> 14188 bytes static/favicons/apple-icon.png | Bin 0 -> 14188 bytes static/favicons/browserconfig.xml | 2 + static/favicons/favicon-16x16.png | Bin 0 -> 1295 bytes static/favicons/favicon-32x32.png | Bin 0 -> 2271 bytes static/favicons/favicon-96x96.png | Bin 0 -> 6656 bytes static/favicons/favicon.ico | Bin 0 -> 1150 bytes static/favicons/manifest.json | 41 + static/favicons/ms-icon-144x144.png | Bin 0 -> 11158 bytes static/favicons/ms-icon-150x150.png | Bin 0 -> 11728 bytes static/favicons/ms-icon-310x310.png | Bin 0 -> 32285 bytes static/favicons/ms-icon-70x70.png | Bin 0 -> 4781 bytes 73 files changed, 6916 insertions(+) create mode 100644 .github/FUNDING.yml create mode 100644 .github/workflows/clippy-fmt.yml create mode 100644 .github/workflows/coverage.yml create mode 100644 .github/workflows/linux.yml create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 LICENSE.md create mode 100644 Makefile create mode 100644 build.rs create mode 100644 config/default.toml create mode 100644 migrations/20211001071311_survey_users.sql create mode 100644 package.json create mode 100644 rustfmt.toml create mode 100644 sailfish.yml create mode 100644 src/api/mod.rs create mode 100644 src/api/v1/auth.rs create mode 100644 src/api/v1/meta.rs create mode 100644 src/api/v1/mod.rs create mode 100644 src/api/v1/routes.rs create mode 100644 src/data.rs create mode 100644 src/errors.rs create mode 100644 src/main.rs create mode 100644 src/middleware/auth.rs create mode 100644 src/middleware/mod.rs create mode 100644 src/pages/auth/join.rs create mode 100644 src/pages/auth/login.rs create mode 100644 src/pages/auth/mod.rs create mode 100644 src/pages/auth/sudo.rs create mode 100644 src/pages/errors.rs create mode 100644 src/pages/mod.rs create mode 100644 src/pages/panel/campaigns/delete.rs create mode 100644 src/pages/panel/campaigns/get.rs create mode 100644 src/pages/panel/campaigns/mod.rs create mode 100644 src/pages/panel/campaigns/new.rs create mode 100644 src/pages/panel/mod.rs create mode 100644 src/pages/routes.rs create mode 100644 src/settings.rs create mode 100644 src/static_assets/filemap.rs create mode 100644 src/static_assets/mod.rs create mode 100644 src/static_assets/static_files.rs create mode 100644 src/tests-migrate.rs create mode 100644 src/tests.rs create mode 100644 static/cache/img/logo.png create mode 100644 static/cache/img/logo.svg create mode 100644 static/cache/img/trash.svg create mode 100644 static/favicons/android-icon-144x144.png create mode 100644 static/favicons/android-icon-192x192.png create mode 100644 static/favicons/android-icon-36x36.png create mode 100644 static/favicons/android-icon-48x48.png create mode 100644 static/favicons/android-icon-72x72.png create mode 100644 static/favicons/android-icon-96x96.png create mode 100644 static/favicons/apple-icon-114x114.png create mode 100644 static/favicons/apple-icon-120x120.png create mode 100644 static/favicons/apple-icon-144x144.png create mode 100644 static/favicons/apple-icon-152x152.png create mode 100644 static/favicons/apple-icon-180x180.png create mode 100644 static/favicons/apple-icon-57x57.png create mode 100644 static/favicons/apple-icon-60x60.png create mode 100644 static/favicons/apple-icon-72x72.png create mode 100644 static/favicons/apple-icon-76x76.png create mode 100644 static/favicons/apple-icon-precomposed.png create mode 100644 static/favicons/apple-icon.png create mode 100644 static/favicons/browserconfig.xml create mode 100644 static/favicons/favicon-16x16.png create mode 100644 static/favicons/favicon-32x32.png create mode 100644 static/favicons/favicon-96x96.png create mode 100644 static/favicons/favicon.ico create mode 100644 static/favicons/manifest.json create mode 100644 static/favicons/ms-icon-144x144.png create mode 100644 static/favicons/ms-icon-150x150.png create mode 100644 static/favicons/ms-icon-310x310.png create mode 100644 static/favicons/ms-icon-70x70.png diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..1950079 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +# github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +# patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +# ko_fi: # Replace with a single Ko-fi username +# tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +# community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: mcaptcha +issuehunt: # Replace with a single IssueHunt username +# otechie: # Replace with a single Otechie username +custom: ['https://mcaptcha.org/donate'] diff --git a/.github/workflows/clippy-fmt.yml b/.github/workflows/clippy-fmt.yml new file mode 100644 index 0000000..325e539 --- /dev/null +++ b/.github/workflows/clippy-fmt.yml @@ -0,0 +1,43 @@ +name: Lint + +on: + pull_request: + types: [opened, synchronize, reopened] + push: + branches: + - master + +jobs: + fmt: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + components: rustfmt + - name: Check with rustfmt + uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all -- --check + + clippy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + components: clippy + override: true + + - name: Check with Clippy + uses: actions-rs/clippy-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + args: --workspace --tests --all-features diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 0000000..70accc1 --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,79 @@ +name: Coverage + +on: + pull_request: + types: [opened, synchronize, reopened] + push: + branches: + - master + +jobs: + build_and_test: + strategy: + fail-fast: false + matrix: + version: + # - stable + - 1.51.0 + + name: ${{ matrix.version }} - x86_64-unknown-linux-gnu + runs-on: ubuntu-latest + + services: + postgres: + image: postgres + env: + POSTGRES_PASSWORD: password + POSTGRES_USER: postgres + POSTGRES_DB: postgres + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 + + steps: + - uses: actions/checkout@v2 + - name: ⚡ Cache + uses: actions/cache@v2 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + + - name: Install ${{ matrix.version }} + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.version }}-x86_64-unknown-linux-gnu + profile: minimal + override: true + + - name: build sass + run: make frontend + + - name: Run migrations + run: make migrate + env: + DATABASE_URL: postgres://postgres:password@localhost:5432/postgres + + - name: Generate coverage file + if: matrix.version == '1.51.0' && (github.ref == 'refs/heads/master' || github.event_name == 'pull_request') + uses: actions-rs/tarpaulin@v0.1 + with: + version: '0.15.0' + args: '-t 1200' + env: + DATABASE_URL: postgres://postgres:password@localhost:5432/postgres + # GIT_HASH is dummy value. I guess build.rs is skipped in tarpaulin + # execution so this value is required for preventing meta tests from + # panicking + GIT_HASH: 8e77345f1597e40c2e266cb4e6dee74888918a61 + COMPILED_DATE: "2021-07-21" + + - name: Upload to Codecov + if: matrix.version == '1.51.0' && (github.ref == 'refs/heads/master' || github.event_name == 'pull_request') + uses: codecov/codecov-action@v1 diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml new file mode 100644 index 0000000..4d2d955 --- /dev/null +++ b/.github/workflows/linux.yml @@ -0,0 +1,90 @@ +name: Build + +on: + pull_request: + types: [opened, synchronize, reopened] + push: + branches: + - master + +jobs: + build_and_test: + strategy: + fail-fast: false + matrix: + version: + #- 1.51.0 + - stable + # - nightly + + name: ${{ matrix.version }} - x86_64-unknown-linux-gnu + runs-on: ubuntu-latest + + services: + postgres: + image: postgres + env: + POSTGRES_PASSWORD: password + POSTGRES_USER: postgres + POSTGRES_DB: postgres + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 + + steps: + - uses: actions/checkout@v2 + - name: ⚡ Cache + uses: actions/cache@v2 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + + + - name: Install ${{ matrix.version }} + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.version }}-x86_64-unknown-linux-gnu + profile: minimal + override: true + + - name: build sass + run: make frontend + + - name: Run migrations + run: make migrate + env: + DATABASE_URL: postgres://postgres:password@localhost:5432/postgres + + - name: build + run: make + env: + DATABASE_URL: postgres://postgres:password@localhost:5432/postgres + + - name: run tests + run: make test + env: + DATABASE_URL: postgres://postgres:password@localhost:5432/postgres + + - name: generate documentation + if: matrix.version == 'stable' && (github.repository == 'mcapthca/survey') + run: make doc + env: + DATABASE_URL: postgres://postgres:password@localhost:5432/postgres + GIT_HASH: 8e77345f1597e40c2e266cb4e6dee74888918a61 # dummy value + OPEN_API_DOCS: 8e77345f1597e40c2e266cb4e6dee74888918a61 + COMPILED_DATE: "2021-07-21" + + - name: Deploy to GitHub Pages + if: matrix.version == 'stable' && (github.repository == 'mcapthca/survey') + uses: JamesIves/github-pages-deploy-action@3.7.1 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BRANCH: gh-pages + FOLDER: target/doc diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4aa3436 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +/target +tarpaulin-report.html +.env +cobertura.xml +prod/ +node_modules/ +/static-assets/bundle +static/cache/bundle +./templates/**/*.js +/static-assets/bundle/* +src/cache_buster_data.json +coverage +dist +assets +scripts/creds.py diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..a0a2f74 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,2914 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "actix" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3720d0064a0ce5c0de7bd93bdb0a6caebab2a9b5668746145d7b3b0c5da02914" +dependencies = [ + "actix-rt", + "actix_derive", + "bitflags", + "bytes", + "crossbeam-channel", + "futures-core", + "futures-sink", + "futures-task", + "futures-util", + "log", + "once_cell", + "parking_lot", + "pin-project-lite", + "smallvec", + "tokio", + "tokio-util", +] + +[[package]] +name = "actix-codec" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d5dbeb2d9e51344cb83ca7cc170f1217f9fe25bfc50160e6e200b5c31c1019a" +dependencies = [ + "bitflags", + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "actix-cors" +version = "0.6.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01552b8facccd5d7a4cc5d8e2b07d306160c97a4968181c2db965533389c8725" +dependencies = [ + "actix-service", + "actix-web", + "derive_more", + "futures-util", + "log", + "once_cell", + "smallvec", +] + +[[package]] +name = "actix-http" +version = "3.0.0-beta.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd38a862fa7fead2b47ee55e550982aba583ebc7365ccf0155b49934ad6f16f9" +dependencies = [ + "actix-codec", + "actix-rt", + "actix-service", + "actix-tls", + "actix-utils", + "ahash", + "base64", + "bitflags", + "brotli2", + "bytes", + "bytestring", + "derive_more", + "encoding_rs", + "flate2", + "futures-core", + "futures-util", + "h2", + "http", + "httparse", + "itoa", + "language-tags", + "local-channel", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project", + "pin-project-lite", + "rand", + "regex", + "serde 1.0.130", + "sha-1", + "smallvec", + "time", + "tokio", + "zstd", +] + +[[package]] +name = "actix-identity" +version = "0.4.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50b26f099c3b3bd459a547abf391c3cbecdc077df757f56856e31e8cd5757f28" +dependencies = [ + "actix-service", + "actix-web", + "futures-util", + "serde 1.0.130", + "serde_json", + "time", +] + +[[package]] +name = "actix-macros" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2f86cd6857c135e6e9fe57b1619a88d1f94a7df34c00e11fe13e64fd3438837" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "actix-router" +version = "0.5.0-beta.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36b95ce0d76d1aa2f98b681702807475ade0f99bd4552546a6843a966d42ea3d" +dependencies = [ + "bytestring", + "firestorm", + "http", + "log", + "regex", + "serde 1.0.130", +] + +[[package]] +name = "actix-rt" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d7cd957c9ed92288a7c3c96af81fa5291f65247a76a34dac7b6af74e52ba0" +dependencies = [ + "actix-macros", + "futures-core", + "tokio", +] + +[[package]] +name = "actix-server" +version = "2.0.0-beta.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26369215fcc3b0176018b3b68756a8bcc275bb000e6212e454944913a1f9bf87" +dependencies = [ + "actix-rt", + "actix-service", + "actix-utils", + "futures-core", + "log", + "mio", + "num_cpus", + "slab", + "tokio", +] + +[[package]] +name = "actix-service" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77f5f9d66a8730d0fae62c26f3424f5751e5518086628a40b7ab6fca4a705034" +dependencies = [ + "futures-core", + "paste", + "pin-project-lite", +] + +[[package]] +name = "actix-tls" +version = "3.0.0-beta.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65b7bb60840962ef0332f7ea01a57d73a24d2cb663708511ff800250bbfef569" +dependencies = [ + "actix-codec", + "actix-rt", + "actix-service", + "actix-utils", + "derive_more", + "futures-core", + "http", + "log", + "tokio-util", +] + +[[package]] +name = "actix-utils" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e491cbaac2e7fc788dfff99ff48ef317e23b3cf63dbaf7aaab6418f40f92aa94" +dependencies = [ + "local-waker", + "pin-project-lite", +] + +[[package]] +name = "actix-web" +version = "4.0.0-beta.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34aa2b23ec9c7c9a799b3cf9258f67c91b18ac3f0f5f484e175c7ac46739bb5" +dependencies = [ + "actix-codec", + "actix-http", + "actix-macros", + "actix-router", + "actix-rt", + "actix-server", + "actix-service", + "actix-utils", + "actix-web-codegen 0.5.0-beta.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ahash", + "bytes", + "cfg-if", + "cookie", + "derive_more", + "either", + "encoding_rs", + "futures-core", + "futures-util", + "itoa", + "language-tags", + "log", + "mime", + "once_cell", + "paste", + "pin-project", + "regex", + "serde 1.0.130", + "serde_json", + "serde_urlencoded", + "smallvec", + "socket2", + "time", + "url", +] + +[[package]] +name = "actix-web-codegen" +version = "0.5.0-beta.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a11fd6f322120a74b23327e778ef0a4950b1f44a2b76468a69316a150f5c6dd" +dependencies = [ + "actix-router", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "actix-web-codegen" +version = "0.5.0-beta.4" +source = "git+https://github.com/realaravinth/actix-web#292317ff1eae7db38bd0aa9900ede5fadc9216d1" +dependencies = [ + "actix-router", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "actix_derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d44b8fee1ced9671ba043476deddef739dd0959bf77030b26b738cc591737a7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[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 = "ahash" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98" +dependencies = [ + "getrandom", + "once_cell", + "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 = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "async-trait" +version = "0.1.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atoi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616896e05fc0e2649463a93a15183c6a16bf03413a7af88ef1285ddedfa9cda5" +dependencies = [ + "num-traits 0.2.14", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "base-x" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde 1.0.130", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[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 = "brotli-sys" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4445dea95f4c2b41cde57cc9fee236ae4dbae88d8fcbdb4750fc1bb5d86aaecd" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "brotli2" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cb036c3eade309815c15ddbacec5b22c4d1f3983a774ab2eac2e3e9ea85568e" +dependencies = [ + "brotli-sys", + "libc", +] + +[[package]] +name = "bumpalo" +version = "3.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538" + +[[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 = "bytestring" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90706ba19e97b90786e19dc0d5e2abd80008d99d4c0c5d1ad0b5e72cec7c494d" +dependencies = [ + "bytes", +] + +[[package]] +name = "cache-buster" +version = "0.2.0" +source = "git+https://github.com/realaravinth/cache-buster#e01e7bcc1d0c79b6f51648e42e8c027f894dc514" +dependencies = [ + "data-encoding", + "derive_builder", + "mime", + "mime_guess", + "serde 1.0.130", + "serde_json", + "sha2", + "walkdir", +] + +[[package]] +name = "cc" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cipher" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" +dependencies = [ + "generic-array", +] + +[[package]] +name = "combine" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a909e4d93292cd8e9c42e189f61681eff9d67b6541f96b8a1a737f23737bd001" +dependencies = [ + "bytes", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "config" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1b9d958c2b1368a663f05538fc1b5975adce1e19f435acceae987aceeeb369" +dependencies = [ + "lazy_static", + "nom 5.1.2", + "rust-ini", + "serde 1.0.130", + "serde-hjson", + "serde_json", + "toml", + "yaml-rust", +] + +[[package]] +name = "const_fn" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f92cfa0fd5690b3cf8c1ef2cabbd9b7ef22fa53cf5e1f92b05103f6d5d1cf6e7" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "cookie" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f1c7727e460397e56abc4bddc1d49e07a1ad78fc98eb2e1c8f032a58a2f80d" +dependencies = [ + "aes-gcm", + "base64", + "hkdf", + "hmac", + "percent-encoding", + "rand", + "sha2", + "subtle", + "time", + "version_check", +] + +[[package]] +name = "cpufeatures" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +dependencies = [ + "libc", +] + +[[package]] +name = "cpuid-bool" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" + +[[package]] +name = "crc" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10c2722795460108a7872e1cd933a85d6ec38abc4baecad51028f702da28889f" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" + +[[package]] +name = "crc16" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "338089f42c427b86394a5ee60ff321da23a5c89c9d89514c829687b26359fcff" + +[[package]] +name = "crc32fast" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[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 = "darling" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f2c43f534ea4b0b049015d00269734195e6d3f0f6635cb692251aca6f9f8b3c" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e91455b86830a1c21799d94524df0845183fa55bafd9aa137b01c7d1065fa36" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29b5acf0dea37a7f66f7b25d2c5e93fd46f8f6968b1a5d7a3e02e97768afc95a" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "data-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" + +[[package]] +name = "derive_builder" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d13202debe11181040ae9063d739fa32cfcaaebe2275fe387703460ae2365b30" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66e616858f6187ed828df7c64a6d71720d83767a7f19740b2d1b6fe6327b36e5" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive_builder_macro" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58a94ace95092c5acb1e97a7e846b310cfbd499652f72297da7493f618a98d73" +dependencies = [ + "derive_builder_core", + "syn", +] + +[[package]] +name = "derive_more" +version = "0.99.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40eebddd2156ce1bb37b20bbe5151340a31828b1f2d22ba4141f3531710e38df" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.3.3", + "syn", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "dirs" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "discard" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" + +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + +[[package]] +name = "dtoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +dependencies = [ + "serde 1.0.130", +] + +[[package]] +name = "encoding_rs" +version = "0.8.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80df024fbc5ac80f87dfef0d9f5209a252f2a497f7f42944cff24d8253cac065" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "filetime" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "winapi", +] + +[[package]] +name = "firestorm" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31586bda1b136406162e381a3185a506cdfc1631708dd40cba2f6628d8634499" + +[[package]] +name = "flate2" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" +dependencies = [ + "cfg-if", + "crc32fast", + "libc", + "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 = "futures" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" + +[[package]] +name = "futures-executor" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62007592ac46aa7c2b6416f7deb9a8a8f63a01e0f1d6e1787d5630170db2b63e" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-io" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" + +[[package]] +name = "futures-macro" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" +dependencies = [ + "autocfg", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" + +[[package]] +name = "futures-task" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" + +[[package]] +name = "futures-util" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" +dependencies = [ + "autocfg", + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "proc-macro-hack", + "proc-macro-nested", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[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 = "h2" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c06815895acec637cd6ed6e9662c935b866d20a106f8361892893a7d9234964" +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 = "hashlink" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" +dependencies = [ + "hashbrown", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f" +dependencies = [ + "digest", + "hmac", +] + +[[package]] +name = "hmac" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" +dependencies = [ + "crypto-mac", + "digest", +] + +[[package]] +name = "home" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654" +dependencies = [ + "winapi", +] + +[[package]] +name = "http" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "httparse" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" + +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + +[[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 = "if_chain" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" + +[[package]] +name = "indexmap" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "716d3d89f35ac6a34fd0eed635395f4c3b76fa889338a4632e5231a8684216bd" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "itertools" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + +[[package]] +name = "itoap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9028f49264629065d057f340a86acb84867925865f73bbf8d47b4d149a7e88b8" + +[[package]] +name = "jobserver" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "language-tags" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lexical-core" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" +dependencies = [ + "arrayvec", + "bitflags", + "cfg-if", + "ryu", + "static_assertions", +] + +[[package]] +name = "libc" +version = "0.2.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" + +[[package]] +name = "libmcaptcha" +version = "0.1.4" +source = "git+https://github.com/mCaptcha/libmcaptcha?branch=master#48220d78e706745a5208850c832ee8ba7e704601" +dependencies = [ + "actix", + "derive_builder", + "derive_more", + "log", + "pow_sha256", + "pretty_env_logger", + "rand", + "redis", + "serde 1.0.130", + "serde_json", + "tokio", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" + +[[package]] +name = "local-channel" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6246c68cf195087205a0512559c97e15eaf95198bf0e206d662092cdcb03fe9f" +dependencies = [ + "futures-core", + "futures-sink", + "futures-util", + "local-waker", +] + +[[package]] +name = "local-waker" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84f9a2d3e27ce99ce2c3aad0b09b1a7b916293ea9b2bf624c13fe646fadd8da4" + +[[package]] +name = "lock_api" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "md-5" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15" +dependencies = [ + "block-buffer", + "digest", + "opaque-debug", +] + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "minimal-lexical" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c835948974f68e0bd58636fc6c5b1fbff7b297e3046f11b3b3c18bbac012c6d" + +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + +[[package]] +name = "mio" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + +[[package]] +name = "nom" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" +dependencies = [ + "lexical-core", + "memchr", + "version_check", +] + +[[package]] +name = "nom" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffd9d26838a953b4af82cbeb9f1592c6798916983959be223a7124e992742c1" +dependencies = [ + "memchr", + "minimal-lexical", + "version_check", +] + +[[package]] +name = "ntapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +dependencies = [ + "winapi", +] + +[[package]] +name = "num" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits 0.2.14", +] + +[[package]] +name = "num-bigint" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74e768dff5fb39a41b3bcd30bb25cf989706c90d028d1ad71971987aa309d535" +dependencies = [ + "autocfg", + "num-integer", + "num-traits 0.2.14", + "serde 1.0.130", +] + +[[package]] +name = "num-complex" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26873667bbbb7c5182d4a37c1add32cdf09f841af72da53318fdb81543c15085" +dependencies = [ + "num-traits 0.2.14", + "serde 1.0.130", +] + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits 0.2.14", +] + +[[package]] +name = "num-iter" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" +dependencies = [ + "autocfg", + "num-integer", + "num-traits 0.2.14", +] + +[[package]] +name = "num-rational" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a" +dependencies = [ + "autocfg", + "num-integer", + "num-traits 0.2.14", + "serde 1.0.130", +] + +[[package]] +name = "num-traits" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" +dependencies = [ + "num-traits 0.2.14", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "openssl" +version = "0.10.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d9facdb76fec0b73c406f125d44d86fdad818d66fef0531eec9233ca425ff4a" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-sys", +] + +[[package]] +name = "openssl-src" +version = "111.16.0+1.1.1l" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab2173f69416cf3ec12debb5823d244127d23a9b127d5a5189aa97c5fa2859f" +dependencies = [ + "cc", +] + +[[package]] +name = "openssl-sys" +version = "0.9.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69df2d8dfc6ce3aaf44b40dec6f487d5a886516cf6879c49e98e0710f310a058" +dependencies = [ + "autocfg", + "cc", + "libc", + "openssl-src", + "pkg-config", + "vcpkg", +] + +[[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", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "paste" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58" + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + +[[package]] +name = "pin-project" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" + +[[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.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c9b1041b4387893b91ee6746cddfc28516aff326a3519fb2adf820932c5e6cb" + +[[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 = "pow_sha256" +version = "0.2.1" +source = "git+https://github.com/mcaptcha/pow_sha256#807fa7c75284f6d8d488a6f66a3a1b3301f2f412" +dependencies = [ + "bincode", + "derive_builder", + "num", + "serde 1.0.130", + "sha2", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] +name = "pretty_env_logger" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" +dependencies = [ + "env_logger", + "log", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + +[[package]] +name = "proc-macro-nested" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" + +[[package]] +name = "proc-macro2" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[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 = "rand_hc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redis" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "202c5bf92cad3d57605c366e644a7fbf305a83f19754fc66678c6265dcc9b8b4" +dependencies = [ + "async-trait", + "bytes", + "combine", + "crc16", + "dtoa", + "futures-util", + "itoa", + "percent-encoding", + "pin-project-lite", + "rand", + "sha1", + "tokio", + "tokio-util", + "url", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +dependencies = [ + "getrandom", + "redox_syscall", +] + +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "rust-embed" +version = "6.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1be44a6694859b7cfc955699935944a6844aa9fe416aeda5d40829e3e38dfee6" +dependencies = [ + "rust-embed-impl", + "rust-embed-utils", + "walkdir", +] + +[[package]] +name = "rust-embed-impl" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f567ca01565c50c67b29e535f5f67b8ea8aeadaeed16a88f10792ab57438b957" +dependencies = [ + "proc-macro2", + "quote", + "rust-embed-utils", + "syn", + "walkdir", +] + +[[package]] +name = "rust-embed-utils" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6116e7ab9ea963f60f2f20291d8fcf6c7273192cdd7273b3c80729a9605c97b2" +dependencies = [ + "sha2", + "walkdir", +] + +[[package]] +name = "rust-ini" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + +[[package]] +name = "rustls" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" +dependencies = [ + "base64", + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "sailfish" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "816920a08514d9741242b3efe70c16c350ed548bc4a5ba03426e56faf9d45f77" +dependencies = [ + "itoap", + "ryu", + "sailfish-macros", + "version_check", +] + +[[package]] +name = "sailfish-compiler" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4276e7b848bde8e7813d534f014bc35ce5acd2b9e2b6b075727113fcf478ba63" +dependencies = [ + "filetime", + "home", + "memchr", + "proc-macro2", + "quote", + "syn", + "yaml-rust", +] + +[[package]] +name = "sailfish-macros" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bba2458ef07ae12c9aed2edb866c3db2f9c21cf19a2c3f2613b2982bc1a4a46" +dependencies = [ + "proc-macro2", + "sailfish-compiler", +] + +[[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 = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "sct" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser 0.7.0", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser 0.10.2", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + +[[package]] +name = "serde" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" + +[[package]] +name = "serde" +version = "1.0.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-hjson" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a3a4e0ea8a88553209f6cc6cfe8724ecad22e1acf372793c27d995290fe74f8" +dependencies = [ + "lazy_static", + "num-traits 0.1.43", + "regex", + "serde 0.8.23", +] + +[[package]] +name = "serde_derive" +version = "1.0.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde 1.0.130", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde 1.0.130", +] + +[[package]] +name = "sha-1" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" +dependencies = [ + "block-buffer", + "cfg-if", + "cpufeatures", + "digest", + "opaque-debug", +] + +[[package]] +name = "sha1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" + +[[package]] +name = "sha2" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" +dependencies = [ + "block-buffer", + "cfg-if", + "cpufeatures", + "digest", + "opaque-debug", +] + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" + +[[package]] +name = "smallvec" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" + +[[package]] +name = "socket2" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "sqlformat" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b7922be017ee70900be125523f38bdd644f4f06a1b16e8fa5a8ee8c34bffd4" +dependencies = [ + "itertools", + "nom 7.0.0", + "unicode_categories", +] + +[[package]] +name = "sqlx" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4b94ab0f8c21ee4899b93b06451ef5d965f1a355982ee73684338228498440" +dependencies = [ + "sqlx-core", + "sqlx-macros", +] + +[[package]] +name = "sqlx-core" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec28b91a01e1fe286d6ba66f68289a2286df023fc97444e1fd86c2fd6d5dc026" +dependencies = [ + "ahash", + "atoi", + "base64", + "bitflags", + "byteorder", + "bytes", + "crc", + "crossbeam-channel", + "crossbeam-queue", + "crossbeam-utils", + "dirs", + "either", + "futures-channel", + "futures-core", + "futures-intrusive", + "futures-util", + "hashlink", + "hex", + "hmac", + "itoa", + "libc", + "log", + "md-5", + "memchr", + "once_cell", + "parking_lot", + "percent-encoding", + "rand", + "rustls", + "serde 1.0.130", + "serde_json", + "sha-1", + "sha2", + "smallvec", + "sqlformat", + "sqlx-rt", + "stringprep", + "thiserror", + "time", + "tokio-stream", + "url", + "uuid", + "webpki", + "webpki-roots", + "whoami", +] + +[[package]] +name = "sqlx-macros" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dc33c35d54774eed73d54568d47a6ac099aed8af5e1556a017c131be88217d5" +dependencies = [ + "dotenv", + "either", + "futures", + "heck", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde 1.0.130", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-rt", + "syn", + "url", +] + +[[package]] +name = "sqlx-rt" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14302b678d9c76b28f2e60115211e25e0aabc938269991745a169753dc00e35c" +dependencies = [ + "actix-rt", + "once_cell", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "standback" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" +dependencies = [ + "version_check", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stdweb" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" +dependencies = [ + "discard", + "rustc_version 0.2.3", + "stdweb-derive", + "stdweb-internal-macros", + "stdweb-internal-runtime", + "wasm-bindgen", +] + +[[package]] +name = "stdweb-derive" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" +dependencies = [ + "proc-macro2", + "quote", + "serde 1.0.130", + "serde_derive", + "syn", +] + +[[package]] +name = "stdweb-internal-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +dependencies = [ + "base-x", + "proc-macro2", + "quote", + "serde 1.0.130", + "serde_derive", + "serde_json", + "sha1", + "syn", +] + +[[package]] +name = "stdweb-internal-runtime" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" + +[[package]] +name = "stringprep" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "survey" +version = "0.1.0" +dependencies = [ + "actix", + "actix-cors", + "actix-http", + "actix-identity", + "actix-rt", + "actix-service", + "actix-web", + "actix-web-codegen 0.5.0-beta.4 (git+https://github.com/realaravinth/actix-web)", + "cache-buster", + "config", + "derive_builder", + "derive_more", + "futures", + "lazy_static", + "libmcaptcha", + "log", + "mime", + "mime_guess", + "openssl", + "pretty_env_logger", + "rand", + "rust-embed", + "sailfish", + "serde 1.0.130", + "serde_json", + "sqlx", + "tokio", + "url", + "uuid", + "validator", +] + +[[package]] +name = "syn" +version = "1.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5239bc68e0fef57495900cfea4e8dc75596d9a319d7e16b1e0a440d24e6fe0a0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" +dependencies = [ + "const_fn", + "libc", + "standback", + "stdweb", + "time-macros", + "version_check", + "winapi", +] + +[[package]] +name = "time-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" +dependencies = [ + "proc-macro-hack", + "time-macros-impl", +] + +[[package]] +name = "time-macros-impl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "standback", + "syn", +] + +[[package]] +name = "tinyvec" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83b2a3d4d9091d0abd7eba4dc2710b1718583bd4d8992e2190720ea38f391f7" +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.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2c2416fdedca8443ae44b4527de1ea633af61d8f7169ffa6e72c5b53d24efcc" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "winapi", +] + +[[package]] +name = "tokio-rustls" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" +dependencies = [ + "rustls", + "tokio", + "webpki", +] + +[[package]] +name = "tokio-stream" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2f3f698253f03119ac0102beaa64f67a67e08074d03a22d18784104543727f" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d3725d3efa29485e87311c5b699de63cde14b00ed4d256b8318aa30ca452cd" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde 1.0.130", +] + +[[package]] +name = "tracing" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84f96e095c0c82419687c20ddf5cb3eadb61f4e1405923c9dc8e53a1adacbda8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46125608c26121c81b0c6d693eab5a420e416da7e43c426d2e8f7df8da8a3acf" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "typenum" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" + +[[package]] +name = "ucd-trie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246f4c42e67e7a4e3c6106ff716a5d067d4132a642840b242e357e468a2a0085" + +[[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-segmentation" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + +[[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 = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[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" +dependencies = [ + "getrandom", +] + +[[package]] +name = "validator" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d0f08911ab0fee2c5009580f04615fa868898ee57de10692a45da0c3bcc3e5e" +dependencies = [ + "idna", + "lazy_static", + "regex", + "serde 1.0.130", + "serde_derive", + "serde_json", + "url", + "validator_derive", + "validator_types", +] + +[[package]] +name = "validator_derive" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d85135714dba11a1bd0b3eb1744169266f1a38977bf4e3ff5e2e1acb8c2b7eee" +dependencies = [ + "if_chain", + "lazy_static", + "proc-macro-error", + "proc-macro2", + "quote", + "regex", + "syn", + "validator_types", +] + +[[package]] +name = "validator_types" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded9d97e1d42327632f5f3bae6403c04886e2de3036261ef42deebd931a6a291" +dependencies = [ + "proc-macro2", + "syn", +] + +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + +[[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 = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "wasm-bindgen" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" + +[[package]] +name = "web-sys" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" +dependencies = [ + "webpki", +] + +[[package]] +name = "whoami" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "483a59fee1a93fec90eb08bc2eb4315ef10f4ebc478b3a5fadc969819cb66117" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "zstd" +version = "0.7.0+zstd.1.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9428752481d8372e15b1bf779ea518a179ad6c771cca2d2c60e4fbff3cc2cd52" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "3.1.0+zstd.1.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa1926623ad7fe406e090555387daf73db555b948134b4d73eac5eb08fb666d" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "1.5.0+zstd.1.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e6c094340240369025fc6b731b054ee2a834328fa584310ac96aa4baebdc465" +dependencies = [ + "cc", + "libc", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..cc67599 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,76 @@ +[package] +name = "survey" +version = "0.1.0" +description = "Feedback agregator" +homepage = "https://github.com/mCaptcha/survey" +repository = "https://github.com/mCaptcha/survey" +documentation = "https://github.con/mCaptcha/survey" +readme = "https://github.com/mCaptcha/survey/blob/master/README.md" +license = "AGPLv3 or later version" +authors = ["realaravinth "] +edition = "2018" +default-run = "survey" +build = "build.rs" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[[bin]] +name = "survey" +path = "./src/main.rs" + +[[bin]] +name = "tests-migrate" +path = "./src/tests-migrate.rs" + +[dependencies] +actix-web = "4.0.0-beta.9" +actix-identity = "0.4.0-beta.2" +actix-http = "3.0.0-beta.8" +actix-rt = "2" +actix-cors = "0.6.0-beta.2" +actix-service = "2.0.0" +actix = "0.12" +my-codegen = {package = "actix-web-codegen", git ="https://github.com/realaravinth/actix-web"} + +libmcaptcha = { branch = "master", git = "https://github.com/mCaptcha/libmcaptcha", features = ["full"] } + +futures = "0.3.15" + +sqlx = { version = "0.5.5", features = [ "runtime-actix-rustls", "postgres", "time", "offline" ] } + +derive_builder = "0.10" +validator = { version = "0.14", features = ["derive"]} +derive_more = "0.99" + +config = "0.11" + +serde = "1" +serde_json = "1" + +pretty_env_logger = "0.4" +log = "0.4" + +lazy_static = "1.4" + +url = "2.2" + +rand = "0.8" +uuid = { version="0.8.2", features = ["v4"]} + +mime_guess = "2.0.3" +rust-embed = "6.0.0" +cache-buster = { git = "https://github.com/realaravinth/cache-buster" } +mime = "0.3.16" + +openssl = { version = "0.10.29", features = ["vendored"] } + +sailfish = "0.3.2" + +tokio = "1.11.0" + +[build-dependencies] +sqlx = { version = "0.5.5", features = [ "runtime-actix-rustls", "uuid", "postgres", "time", "offline" ] } +#serde_yaml = "0.8.17" +serde_json = "1" +#yaml-rust = "0.4.5" +cache-buster = { version = "0.2.0", git = "https://github.com/realaravinth/cache-buster" } +mime = "0.3.16" diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..cba6f6a --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,660 @@ +### GNU AFFERO GENERAL PUBLIC LICENSE + +Version 3, 19 November 2007 + +Copyright (C) 2007 Free Software Foundation, Inc. + + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + +### Preamble + +The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + +The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains +free software for all its users. + +When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + +Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + +A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + +The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + +An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing +under this license. + +The precise terms and conditions for copying, distribution and +modification follow. + +### TERMS AND CONDITIONS + +#### 0. Definitions. + +"This License" refers to version 3 of the GNU Affero General Public +License. + +"Copyright" also means copyright-like laws that apply to other kinds +of works, such as semiconductor masks. + +"The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + +To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of +an exact copy. The resulting work is called a "modified version" of +the earlier work or a work "based on" the earlier work. + +A "covered work" means either the unmodified Program or a work based +on the Program. + +To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + +To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user +through a computer network, with no transfer of a copy, is not +conveying. + +An interactive user interface displays "Appropriate Legal Notices" to +the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + +#### 1. Source Code. + +The "source code" for a work means the preferred form of the work for +making modifications to it. "Object code" means any non-source form of +a work. + +A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + +The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + +The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + +The Corresponding Source need not include anything that users can +regenerate automatically from other parts of the Corresponding Source. + +The Corresponding Source for a work in source code form is that same +work. + +#### 2. Basic Permissions. + +All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + +You may make, run and propagate covered works that you do not convey, +without conditions so long as your license otherwise remains in force. +You may convey covered works to others for the sole purpose of having +them make modifications exclusively for you, or provide you with +facilities for running those works, provided that you comply with the +terms of this License in conveying all material for which you do not +control copyright. Those thus making or running the covered works for +you must do so exclusively on your behalf, under your direction and +control, on terms that prohibit them from making any copies of your +copyrighted material outside their relationship with you. + +Conveying under any other circumstances is permitted solely under the +conditions stated below. Sublicensing is not allowed; section 10 makes +it unnecessary. + +#### 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + +No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + +When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such +circumvention is effected by exercising rights under this License with +respect to the covered work, and you disclaim any intention to limit +operation or modification of the work as a means of enforcing, against +the work's users, your or third parties' legal rights to forbid +circumvention of technological measures. + +#### 4. Conveying Verbatim Copies. + +You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + +You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + +#### 5. Conveying Modified Source Versions. + +You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these +conditions: + +- a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. +- b) The work must carry prominent notices stating that it is + released under this License and any conditions added under + section 7. This requirement modifies the requirement in section 4 + to "keep intact all notices". +- c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. +- d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + +A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + +#### 6. Conveying Non-Source Forms. + +You may convey a covered work in object code form under the terms of +sections 4 and 5, provided that you also convey the machine-readable +Corresponding Source under the terms of this License, in one of these +ways: + +- a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. +- b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the Corresponding + Source from a network server at no charge. +- c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. +- d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. +- e) Convey the object code using peer-to-peer transmission, + provided you inform other peers where the object code and + Corresponding Source of the work are being offered to the general + public at no charge under subsection 6d. + +A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + +A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, +family, or household purposes, or (2) anything designed or sold for +incorporation into a dwelling. In determining whether a product is a +consumer product, doubtful cases shall be resolved in favor of +coverage. For a particular product received by a particular user, +"normally used" refers to a typical or common use of that class of +product, regardless of the status of the particular user or of the way +in which the particular user actually uses, or expects or is expected +to use, the product. A product is a consumer product regardless of +whether the product has substantial commercial, industrial or +non-consumer uses, unless such uses represent the only significant +mode of use of the product. + +"Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to +install and execute modified versions of a covered work in that User +Product from a modified version of its Corresponding Source. The +information must suffice to ensure that the continued functioning of +the modified object code is in no case prevented or interfered with +solely because modification has been made. + +If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + +The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or +updates for a work that has been modified or installed by the +recipient, or for the User Product in which it has been modified or +installed. Access to a network may be denied when the modification +itself materially and adversely affects the operation of the network +or violates the rules and protocols for communication across the +network. + +Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + +#### 7. Additional Terms. + +"Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + +Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders +of that material) supplement the terms of this License with terms: + +- a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or +- b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or +- c) Prohibiting misrepresentation of the origin of that material, + or requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or +- d) Limiting the use for publicity purposes of names of licensors + or authors of the material; or +- e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or +- f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions + of it) with contractual assumptions of liability to the recipient, + for any liability that these contractual assumptions directly + impose on those licensors and authors. + +All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + +If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; the +above requirements apply either way. + +#### 8. Termination. + +You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + +However, if you cease all violation of this License, then your license +from a particular copyright holder is reinstated (a) provisionally, +unless and until the copyright holder explicitly and finally +terminates your license, and (b) permanently, if the copyright holder +fails to notify you of the violation by some reasonable means prior to +60 days after the cessation. + +Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + +#### 9. Acceptance Not Required for Having Copies. + +You are not required to accept this License in order to receive or run +a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + +#### 10. Automatic Licensing of Downstream Recipients. + +Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + +An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + +#### 11. Patents. + +A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + +A contributor's "essential patent claims" are all patent claims owned +or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + +In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + +If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + +A patent license is "discriminatory" if it does not include within the +scope of its coverage, prohibits the exercise of, or is conditioned on +the non-exercise of one or more of the rights that are specifically +granted under this License. You may not convey a covered work if you +are a party to an arrangement with a third party that is in the +business of distributing software, under which you make payment to the +third party based on the extent of your activity of conveying the +work, and under which the third party grants, to any of the parties +who would receive the covered work from you, a discriminatory patent +license (a) in connection with copies of the covered work conveyed by +you (or copies made from those copies), or (b) primarily for and in +connection with specific products or compilations that contain the +covered work, unless you entered into that arrangement, or that patent +license was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + +#### 12. No Surrender of Others' Freedom. + +If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under +this License and any other pertinent obligations, then as a +consequence you may not convey it at all. For example, if you agree to +terms that obligate you to collect a royalty for further conveying +from those to whom you convey the Program, the only way you could +satisfy both those terms and this License would be to refrain entirely +from conveying the Program. + +#### 13. Remote Network Interaction; Use with the GNU General Public License. + +Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your +version supports such interaction) an opportunity to receive the +Corresponding Source of your version by providing access to the +Corresponding Source from a network server at no charge, through some +standard or customary means of facilitating copying of software. This +Corresponding Source shall include the Corresponding Source for any +work covered by version 3 of the GNU General Public License that is +incorporated pursuant to the following paragraph. + +Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + +#### 14. Revised Versions of this License. + +The Free Software Foundation may publish revised and/or new versions +of the GNU Affero General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever +published by the Free Software Foundation. + +If the Program specifies that a proxy can decide which future versions +of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + +Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + +#### 15. Disclaimer of Warranty. + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT +WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND +PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR +CORRECTION. + +#### 16. Limitation of Liability. + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR +CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT +NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR +LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM +TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER +PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +#### 17. Interpretation of Sections 15 and 16. + +If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + +END OF TERMS AND CONDITIONS + +### How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these +terms. + +To do so, attach the following notices to the program. It is safest to +attach them to the start of each source file to most effectively state +the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper +mail. + +If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for +the specific requirements. + +You should also get your employer (if you work as a programmer) or +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. For more information on this, and how to apply and follow +the GNU AGPL, see . diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..121a3a8 --- /dev/null +++ b/Makefile @@ -0,0 +1,53 @@ +default: frontend ## Debug build + cargo build + +clean: ## Clean all build artifacts and dependencies + @cargo clean + @yarn cache clean + @-rm -rf browser/pkg + @-rm ./src/cache_buster_data.json + @-rm -rf ./static/cache/bundle + @-rm -rf ./assets + +coverage: migrate ## Generate HTML code coverage + cargo tarpaulin -t 1200 --out Html + +dev-env: ## Download development dependencies + cargo fetch + yarn install + +doc: ## Prepare documentation + cargo doc --no-deps --workspace --all-features + +docker: ## Build docker images + docker build -t mcapthca/survey:master -t mcapthca/survey:latest . + +docker-publish: docker ## Build and publish docker images + docker push mcapthca/survey:master + docker push mcapthca/survey:latest + +frontend: ## Build frontend assets + @yarn install + @-rm -rf ./static/cache/bundle/ + @-mkdir ./static/cache/bundle/css/ + @yarn run dart-sass -s compressed templates/main.scss ./static/cache/bundle/css/main.css + +migrate: ## Run database migrations + cargo run --bin tests-migrate + +release: frontend ## Release build + cargo build --release + +run: default ## Run debug build + cargo run + +test: frontend ## Run tests + echo 'static/' && tree static || true + echo 'tree/' && tree assets || true + cargo test --all-features --no-fail-fast + +xml-test-coverage: migrate ## Generate cobertura.xml test coverage + cargo tarpaulin -t 1200 --out Xml + +help: ## Prints help for targets with comments + @cat $(MAKEFILE_LIST) | grep -E '^[a-zA-Z_-]+:.*?## .*$$' | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..af9b4f7 --- /dev/null +++ b/build.rs @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use std::process::Command; + +use cache_buster::{BusterBuilder, NoHashCategory}; +use sqlx::types::time::OffsetDateTime; + +fn main() { + // note: add error checking yourself. + let output = Command::new("git") + .args(&["rev-parse", "HEAD"]) + .output() + .unwrap(); + let git_hash = String::from_utf8(output.stdout).unwrap(); + println!("cargo:rustc-env=GIT_HASH={}", git_hash); + + // let yml = include_str!("./openapi.yaml"); + // let api_json: serde_json::Value = serde_yaml::from_str(yml).unwrap(); + // println!( + // "cargo:rustc-env=OPEN_API_DOCS={}", + // serde_json::to_string(&api_json).unwrap() + // ); + + let now = OffsetDateTime::now_utc().format("%y-%m-%d"); + println!("cargo:rustc-env=COMPILED_DATE={}", &now); + + cache_bust(); +} + +fn cache_bust() { + // until APPLICATION_WASM gets added to mime crate + // PR: https://github.com/hyperium/mime/pull/138 + // let types = vec![ + // mime::IMAGE_PNG, + // mime::IMAGE_SVG, + // mime::IMAGE_JPEG, + // mime::IMAGE_GIF, + // mime::APPLICATION_JAVASCRIPT, + // mime::TEXT_CSS, + // ]; + + println!("cargo:rerun-if-changed=static/cache"); + let no_hash = vec![NoHashCategory::FileExtentions(vec!["wasm"])]; + + let config = BusterBuilder::default() + .source("./static/cache/") + .result("./assets") + .copy(true) + .no_hash(no_hash) + .follow_links(true) + .build() + .unwrap(); + + config.process().unwrap(); +} diff --git a/config/default.toml b/config/default.toml new file mode 100644 index 0000000..048c7a9 --- /dev/null +++ b/config/default.toml @@ -0,0 +1,33 @@ +debug = true +allow_registration = true +source_code = "https://github.com/mcaptcha/survey" +password = "password" + +[server] +# Please set a unique value, your kaizen instance's security depends on this being +# unique +cookie_secret = "8ce364dab188452ffa76c3e1869be5d40dcb9db4826b7b78a3e6ce1a8ca19d32" +# The port at which you want authentication to listen to +# takes a number, choose from 1000-10000 if you dont know what you are doing +port = 7000 +#IP address. Enter 0.0.0.0 to listen on all availale addresses +ip= "0.0.0.0" +# enter your hostname, eg: example.com +domain = "localhost" +allow_registration = true +proxy_has_tls = false + +[database] +# This section deals with the database location and how to access it +# Please note that at the moment, we have support for only postgresqa. +# Example, if you are Batman, your config would be: +# hostname = "batcave.org" +# port = "5432" +# username = "batman" +# password = "somereallycomplicatedBatmanpassword" +hostname = "localhost" +port = "5432" +username = "postgres" +password = "password" +name = "postgres" +pool = 4 diff --git a/migrations/20211001071311_survey_users.sql b/migrations/20211001071311_survey_users.sql new file mode 100644 index 0000000..0bdc223 --- /dev/null +++ b/migrations/20211001071311_survey_users.sql @@ -0,0 +1,5 @@ +CREATE TABLE IF NOT EXISTS survey_users ( + ID UUID PRIMARY KEY NOT NULL UNIQUE, + created_at TIMESTAMPTZ NOT NULL + device VARCHAR(100) NOT NULL, +) diff --git a/package.json b/package.json new file mode 100644 index 0000000..a863f76 --- /dev/null +++ b/package.json @@ -0,0 +1,13 @@ +{ + "name": "mcaptcha-survey", + "main": "index.js", + "version": "1.0.0", + "scripts": { + "prod": "yarn run dart-sass", + "start": "webpack-dev-server --mode development --progress --color", + "test": "jest" + }, + "devDependencies": { + "dart-sass": "^1.25.0" + } +} diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..038034f --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +max_width = 89 diff --git a/sailfish.yml b/sailfish.yml new file mode 100644 index 0000000..5f64209 --- /dev/null +++ b/sailfish.yml @@ -0,0 +1 @@ +delimiter: "." diff --git a/src/api/mod.rs b/src/api/mod.rs new file mode 100644 index 0000000..cce780a --- /dev/null +++ b/src/api/mod.rs @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +pub mod v1; diff --git a/src/api/v1/auth.rs b/src/api/v1/auth.rs new file mode 100644 index 0000000..d11af04 --- /dev/null +++ b/src/api/v1/auth.rs @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +use actix_identity::Identity; +use actix_web::http::header; +use actix_web::{web, HttpResponse, Responder}; +use serde::{Deserialize, Serialize}; + +use super::get_random; +use super::get_uuid; +use crate::errors::*; +use crate::AppData; + +pub mod routes { + pub struct Auth { + pub register: &'static str, + } + + impl Auth { + pub const fn new() -> Auth { + let register = "/api/v1/signup"; + Auth { register } + } + } +} + +pub mod runners { + // use std::borrow::Cow; + + use super::*; + + pub async fn register_runner() -> ServiceResult { + let mut uuid; + + loop { + uuid = get_uuid(); + + // let res= sqlx::query!( + // "INSERT INTO + // kaizen_feedbacks (helpful , description, uuid, campaign_id, time, page_url) + // VALUES ($1, $2, $3, $4, $5, + // (SELECT ID from kaizen_campaign_pages WHERE page_url = $6))", + // &payload.helpful, + // &payload.description, + // &uuid, + // &campaign_id, + // &now, + // &payload.page_url, + // ) + // .execute(&data.db) + // .await; + // + // if res.is_ok() { + // break; + // } else if let Err(sqlx::Error::Database(err)) = res { + // if err.code() == Some(Cow::from("23505")) + // && err.message().contains("kaizen_campaign_uuid_key") + // { + // continue; + // } else { + // return Err(sqlx::Error::Database(err).into()); + // } + // } + // } + } + Ok(uuid) + } +} + +pub fn services(cfg: &mut web::ServiceConfig) { + cfg.service(register); +} +#[my_codegen::post(path = "crate::V1_API_ROUTES.auth.register")] +async fn register(data: AppData, id: Identity) -> ServiceResult { + let uuid = runners::register_runner().await?; + id.remember(uuid.to_string()); + Ok(HttpResponse::Ok()) +} diff --git a/src/api/v1/meta.rs b/src/api/v1/meta.rs new file mode 100644 index 0000000..fd90971 --- /dev/null +++ b/src/api/v1/meta.rs @@ -0,0 +1,124 @@ +/* +* Copyright (C) 2021 Aravinth Manivannan +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as +* published by the Free Software Foundation, either version 3 of the +* License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ + +use actix_web::{web, HttpResponse, Responder}; +use derive_builder::Builder; +use serde::{Deserialize, Serialize}; + +use crate::AppData; +use crate::{GIT_COMMIT_HASH, VERSION}; + +#[derive(Clone, Debug, Deserialize, Builder, Serialize)] +pub struct BuildDetails { + pub version: &'static str, + pub git_commit_hash: &'static str, +} + +pub mod routes { + pub struct Meta { + pub build_details: &'static str, + pub health: &'static str, + } + + impl Meta { + pub const fn new() -> Self { + Self { + build_details: "/api/v1/meta/build", + health: "/api/v1/meta/health", + } + } + } +} + +/// emmits build details of the bninary +#[my_codegen::get(path = "crate::V1_API_ROUTES.meta.build_details")] +async fn build_details() -> impl Responder { + let build = BuildDetails { + version: VERSION, + git_commit_hash: GIT_COMMIT_HASH, + }; + HttpResponse::Ok().json(build) +} + +#[derive(Clone, Debug, Deserialize, Builder, Serialize)] +/// Health check return datatype +pub struct Health { + db: bool, +} + +/// checks all components of the system +#[my_codegen::get(path = "crate::V1_API_ROUTES.meta.health")] +async fn health(data: AppData) -> impl Responder { + use sqlx::Connection; + + let mut resp_builder = HealthBuilder::default(); + resp_builder.db(false); + + if let Ok(mut con) = data.db.acquire().await { + if con.ping().await.is_ok() { + resp_builder.db(true); + } + }; + HttpResponse::Ok().json(resp_builder.build().unwrap()) +} + +pub fn services(cfg: &mut web::ServiceConfig) { + cfg.service(build_details); + cfg.service(health); +} + +#[cfg(test)] +mod tests { + use actix_web::{http::StatusCode, test, App}; + + use super::*; + use crate::api::v1::services; + use crate::*; + + #[actix_rt::test] + async fn build_details_works() { + let app = test::init_service(App::new().configure(services)).await; + + let resp = test::call_service( + &app, + test::TestRequest::get() + .uri(V1_API_ROUTES.meta.build_details) + .to_request(), + ) + .await; + assert_eq!(resp.status(), StatusCode::OK); + } + + // #[actix_rt::test] + // async fn health_works() { + // println!("{}", V1_API_ROUTES.meta.health); + // let data = Data::new().await; + // let app = get_app!(data).await; + // + // let resp = test::call_service( + // &app, + // test::TestRequest::get() + // .uri(V1_API_ROUTES.meta.health) + // .to_request(), + // ) + // .await; + // assert_eq!(resp.status(), StatusCode::OK); + // + // let health_resp: Health = test::read_body_json(resp).await; + // assert!(health_resp.db); + // } +} diff --git a/src/api/v1/mod.rs b/src/api/v1/mod.rs new file mode 100644 index 0000000..49727a0 --- /dev/null +++ b/src/api/v1/mod.rs @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use actix_web::web::ServiceConfig; +use uuid::Uuid; + +pub mod auth; +mod meta; +pub mod routes; +pub use routes::ROUTES; + +pub fn services(cfg: &mut ServiceConfig) { + meta::services(cfg); + auth::services(cfg); +} + +pub fn get_random(len: usize) -> String { + use rand::{distributions::Alphanumeric, rngs::ThreadRng, thread_rng, Rng}; + use std::iter; + + let mut rng: ThreadRng = thread_rng(); + + iter::repeat(()) + .map(|()| rng.sample(Alphanumeric)) + .map(char::from) + .take(len) + .collect::() +} + +pub fn get_uuid() -> Uuid { + Uuid::new_v4() +} diff --git a/src/api/v1/routes.rs b/src/api/v1/routes.rs new file mode 100644 index 0000000..6cd6471 --- /dev/null +++ b/src/api/v1/routes.rs @@ -0,0 +1,34 @@ +/* +* Copyright (C) 2021 Aravinth Manivannan +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as +* published by the Free Software Foundation, either version 3 of the +* License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ +use super::auth::routes::Auth; +use super::meta::routes::Meta; + +pub const ROUTES: Routes = Routes::new(); + +pub struct Routes { + pub auth: Auth, + pub meta: Meta, +} + +impl Routes { + const fn new() -> Routes { + Routes { + auth: Auth::new(), + meta: Meta::new(), + } + } +} diff --git a/src/data.rs b/src/data.rs new file mode 100644 index 0000000..a86d86e --- /dev/null +++ b/src/data.rs @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +//! App data: database connections, etc. +use std::sync::Arc; + +use sqlx::postgres::PgPoolOptions; +use sqlx::PgPool; + +use crate::SETTINGS; + +/// App data +pub struct Data { + /// databse pool + pub db: PgPool, +} + +impl Data { + #[cfg(not(tarpaulin_include))] + /// create new instance of app data + pub async fn new() -> Arc { + let db = PgPoolOptions::new() + .max_connections(SETTINGS.database.pool) + .connect(&SETTINGS.database.url) + .await + .expect("Unable to form database pool"); + + let data = Data { db }; + + Arc::new(data) + } +} diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000..38ed977 --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,201 @@ +/* +* Copyright (C) 2021 Aravinth Manivannan +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License as +* published by the Free Software Foundation, either version 3 of the +* License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with this program. If not, see . +*/ +use std::convert::From; + +use actix::MailboxError; +use actix_web::{ + error::ResponseError, + http::{header, StatusCode}, + HttpResponse, HttpResponseBuilder, +}; +use derive_more::{Display, Error}; +use libmcaptcha::errors::CaptchaError; +use serde::{Deserialize, Serialize}; +use tokio::sync::oneshot::error::RecvError; +use url::ParseError; +use validator::ValidationErrors; + +#[derive(Debug, Display, PartialEq, Error)] +#[cfg(not(tarpaulin_include))] +pub enum ServiceError { + #[display(fmt = "internal server error")] + InternalServerError, + + /// when the a username is already taken + #[display(fmt = "Username not available")] + UsernameTaken, + + /// email is already taken + #[display(fmt = "Email not available")] + EmailTaken, + + /// when the a token name is already taken + /// token not found + #[display(fmt = "Token not found. Is token registered?")] + TokenNotFound, + + #[display(fmt = "{}", _0)] + CaptchaError(CaptchaError), +} + +#[derive(Serialize, Deserialize)] +#[cfg(not(tarpaulin_include))] +pub struct ErrorToResponse { + pub error: String, +} + +#[cfg(not(tarpaulin_include))] +impl ResponseError for ServiceError { + #[cfg(not(tarpaulin_include))] + fn error_response(&self) -> HttpResponse { + HttpResponseBuilder::new(self.status_code()) + .append_header((header::CONTENT_TYPE, "application/json; charset=UTF-8")) + .body( + serde_json::to_string(&ErrorToResponse { + error: self.to_string(), + }) + .unwrap(), + ) + .into() + } + + #[cfg(not(tarpaulin_include))] + fn status_code(&self) -> StatusCode { + match self { + ServiceError::InternalServerError => StatusCode::INTERNAL_SERVER_ERROR, + + ServiceError::UsernameTaken => StatusCode::BAD_REQUEST, + ServiceError::EmailTaken => StatusCode::BAD_REQUEST, + + ServiceError::TokenNotFound => StatusCode::NOT_FOUND, + ServiceError::CaptchaError(e) => { + log::error!("{}", e); + match e { + CaptchaError::MailboxError => StatusCode::INTERNAL_SERVER_ERROR, + _ => StatusCode::BAD_REQUEST, + } + } + } + } +} + +#[cfg(not(tarpaulin_include))] +impl From for ServiceError { + fn from(e: CaptchaError) -> ServiceError { + ServiceError::CaptchaError(e) + } +} + +#[cfg(not(tarpaulin_include))] +impl From for ServiceError { + #[cfg(not(tarpaulin_include))] + fn from(e: sqlx::Error) -> Self { + // use sqlx::error::Error; + // use std::borrow::Cow; + + ServiceError::InternalServerError + } +} + +#[cfg(not(tarpaulin_include))] +impl From for ServiceError { + #[cfg(not(tarpaulin_include))] + fn from(e: RecvError) -> Self { + log::error!("{:?}", e); + ServiceError::InternalServerError + } +} + +#[cfg(not(tarpaulin_include))] +impl From for ServiceError { + #[cfg(not(tarpaulin_include))] + fn from(e: MailboxError) -> Self { + log::error!("{:?}", e); + ServiceError::InternalServerError + } +} + +#[cfg(not(tarpaulin_include))] +pub type ServiceResult = std::result::Result; + +//#[derive(Debug, Display, PartialEq, Error)] +//#[cfg(not(tarpaulin_include))] +//pub enum PageError { +// #[display(fmt = "Something weng wrong: Internal server error")] +// InternalServerError, +// +// #[display(fmt = "{}", _0)] +// ServiceError(ServiceError), +//} +// +//#[cfg(not(tarpaulin_include))] +//impl From for PageError { +// #[cfg(not(tarpaulin_include))] +// fn from(_: sqlx::Error) -> Self { +// PageError::InternalServerError +// } +//} +// +//#[cfg(not(tarpaulin_include))] +//impl From for PageError { +// #[cfg(not(tarpaulin_include))] +// fn from(e: ServiceError) -> Self { +// PageError::ServiceError(e) +// } +//} +// +//impl ResponseError for PageError { +// fn error_response(&self) -> HttpResponse { +// use crate::PAGES; +// match self.status_code() { +// StatusCode::INTERNAL_SERVER_ERROR => HttpResponse::Found() +// .append_header((header::LOCATION, PAGES.errors.internal_server_error)) +// .finish(), +// _ => HttpResponse::Found() +// .append_header((header::LOCATION, PAGES.errors.unknown_error)) +// .finish(), +// } +// } +// +// #[cfg(not(tarpaulin_include))] +// fn status_code(&self) -> StatusCode { +// match self { +// PageError::InternalServerError => StatusCode::INTERNAL_SERVER_ERROR, +// PageError::ServiceError(e) => e.status_code(), +// } +// } +//} +// +//#[cfg(not(tarpaulin_include))] +//pub type PageResult = std::result::Result; +// +//#[cfg(test)] +//mod tests { +// use super::*; +// use crate::PAGES; +// +// #[test] +// fn error_works() { +// let resp: HttpResponse = PageError::InternalServerError.error_response(); +// assert_eq!(resp.status(), StatusCode::FOUND); +// let headers = resp.headers(); +// assert_eq!( +// headers.get(header::LOCATION).unwrap(), +// PAGES.errors.internal_server_error +// ); +// } +//} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..00d11b5 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use std::env; +use std::sync::Arc; + +use actix_identity::{CookieIdentityPolicy, IdentityService}; +use actix_web::{ + error::InternalError, http::StatusCode, middleware as actix_middleware, + web::JsonConfig, App, HttpServer, +}; +use lazy_static::lazy_static; +use log::info; + +mod api; +mod data; +mod errors; +mod middleware; +//mod pages; +mod settings; +//mod static_assets; +//#[cfg(test)] +//#[macro_use] +//mod tests; + +pub use crate::data::Data; +pub use api::v1::ROUTES as V1_API_ROUTES; +pub use middleware::auth::CheckLogin; +//pub use pages::routes::ROUTES as PAGES; +pub use settings::Settings; +//pub use static_assets::static_files::assets; +// +//use static_assets::FileMap; + +lazy_static! { + pub static ref SETTINGS: Settings = Settings::new().unwrap(); +// pub static ref FILES: FileMap = FileMap::new(); +// +// pub static ref CSS: &'static str = +// FILES.get("./static/cache/bundle/css/main.css").unwrap(); + /// points to source files matching build commit + pub static ref SOURCE_FILES_OF_INSTANCE: String = { + let mut url = SETTINGS.source_code.clone(); + if !url.ends_with('/') { + url.push('/'); + } + let mut base = url::Url::parse(&url).unwrap(); + base = base.join("tree/").unwrap(); + base = base.join(GIT_COMMIT_HASH).unwrap(); + base.into() + }; +} + +pub const CACHE_AGE: u32 = 604800; + +pub const COMPILED_DATE: &str = env!("COMPILED_DATE"); +pub const GIT_COMMIT_HASH: &str = env!("GIT_HASH"); +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); +pub const PKG_NAME: &str = env!("CARGO_PKG_NAME"); +pub const PKG_DESCRIPTION: &str = env!("CARGO_PKG_DESCRIPTION"); +pub const PKG_HOMEPAGE: &str = env!("CARGO_PKG_HOMEPAGE"); + +pub type AppData = actix_web::web::Data>; + +#[cfg(not(tarpaulin_include))] +#[actix_web::main] +async fn main() -> std::io::Result<()> { + env::set_var("RUST_LOG", "info"); + + pretty_env_logger::init(); + + info!( + "{}: {}.\nFor more information, see: {}\nBuild info:\nVersion: {} commit: {}", + PKG_NAME, PKG_DESCRIPTION, PKG_HOMEPAGE, VERSION, GIT_COMMIT_HASH + ); + + let data = Data::new().await; + sqlx::migrate!("./migrations/").run(&data.db).await.unwrap(); + let data = actix_web::web::Data::new(data); + + println!("Starting server on: http://{}", SETTINGS.server.get_ip()); + + HttpServer::new(move || { + App::new() + .wrap(actix_middleware::Logger::default()) + .wrap(actix_middleware::Compress::default()) + .app_data(get_json_err()) + .wrap( + actix_middleware::DefaultHeaders::new() + .header("Permissions-Policy", "interest-cohort=()"), + ) + .wrap(get_identity_service()) + .wrap(actix_middleware::NormalizePath::new( + actix_middleware::TrailingSlash::Trim, + )) + .configure(services) + .app_data(data.clone()) + }) + .bind(SETTINGS.server.get_ip()) + .unwrap() + .run() + .await +} + +#[cfg(not(tarpaulin_include))] +pub fn get_json_err() -> JsonConfig { + JsonConfig::default().error_handler(|err, _| { + //debug!("JSON deserialization error: {:?}", &err); + InternalError::new(err, StatusCode::BAD_REQUEST).into() + }) +} + +#[cfg(not(tarpaulin_include))] +pub fn get_identity_service() -> IdentityService { + let cookie_secret = &SETTINGS.server.cookie_secret; + IdentityService::new( + CookieIdentityPolicy::new(cookie_secret.as_bytes()) + .name("Authorization") + //TODO change cookie age + .max_age_secs(216000) + .domain(&SETTINGS.server.domain) + .secure(false), + ) +} + +pub fn services(cfg: &mut actix_web::web::ServiceConfig) { + //pages::services(cfg); + api::v1::services(cfg); + // static_assets::services(cfg); +} diff --git a/src/middleware/auth.rs b/src/middleware/auth.rs new file mode 100644 index 0000000..ef18902 --- /dev/null +++ b/src/middleware/auth.rs @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +#![allow(clippy::type_complexity)] + +use actix_http::body::AnyBody; +use actix_identity::Identity; +use actix_service::{Service, Transform}; +use actix_web::dev::{ServiceRequest, ServiceResponse}; +use actix_web::{http, Error, FromRequest, HttpResponse}; + +use futures::future::{ok, Either, Ready}; + +pub const AUTH: &str = "/login"; //crate::PAGES.auth.login; + +pub struct CheckLogin; + +impl Transform for CheckLogin +where + S: Service, Error = Error>, + S::Future: 'static, +{ + type Response = ServiceResponse; + type Error = Error; + type Transform = CheckLoginMiddleware; + type InitError = (); + type Future = Ready>; + + fn new_transform(&self, service: S) -> Self::Future { + ok(CheckLoginMiddleware { service }) + } +} +pub struct CheckLoginMiddleware { + service: S, +} + +impl Service for CheckLoginMiddleware +where + S: Service, Error = Error>, + S::Future: 'static, +{ + type Response = ServiceResponse; + type Error = Error; + type Future = Either>>; + + actix_service::forward_ready!(service); + + fn call(&self, req: ServiceRequest) -> Self::Future { + let (r, mut pl) = req.into_parts(); + + // TODO investigate when the bellow statement will + // return error + if let Ok(Some(_)) = Identity::from_request(&r, &mut pl) + .into_inner() + .map(|x| x.identity()) + { + let req = ServiceRequest::from_parts(r, pl); + Either::Left(self.service.call(req)) + } else { + let req = ServiceRequest::from_parts(r, pl); //.ok().unwrap(); + Either::Right(ok(req.into_response( + HttpResponse::Found() + .insert_header((http::header::LOCATION, AUTH)) + .finish(), + ))) + } + } +} diff --git a/src/middleware/mod.rs b/src/middleware/mod.rs new file mode 100644 index 0000000..1f5d11b --- /dev/null +++ b/src/middleware/mod.rs @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +pub mod auth; diff --git a/src/pages/auth/join.rs b/src/pages/auth/join.rs new file mode 100644 index 0000000..19ee487 --- /dev/null +++ b/src/pages/auth/join.rs @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use actix_web::HttpResponseBuilder; +use actix_web::{error::ResponseError, http::header, web, HttpResponse, Responder}; +use lazy_static::lazy_static; +use sailfish::TemplateOnce; + +use crate::api::v1::auth::runners; +use crate::errors::*; +use crate::pages::errors::ErrorPage; +use crate::AppData; +use crate::PAGES; + +#[derive(Clone, TemplateOnce)] +#[template(path = "auth/join/index.html")] +struct IndexPage<'a> { + error: Option>, +} + +const PAGE: &str = "Join"; + +impl<'a> Default for IndexPage<'a> { + fn default() -> Self { + IndexPage { error: None } + } +} + +impl<'a> IndexPage<'a> { + pub fn new(title: &'a str, message: &'a str) -> Self { + Self { + error: Some(ErrorPage::new(title, message)), + } + } +} + +lazy_static! { + static ref INDEX: String = IndexPage::default().render_once().unwrap(); +} + +#[my_codegen::get(path = "crate::PAGES.auth.join")] +pub async fn join() -> impl Responder { + HttpResponse::Ok() + .content_type("text/html; charset=utf-8") + .body(&*INDEX) +} + +#[my_codegen::post(path = "PAGES.auth.join")] +pub async fn join_submit( + payload: web::Form, + data: AppData, +) -> PageResult { + let mut payload = payload.into_inner(); + if payload.email.is_some() && payload.email.as_ref().unwrap().is_empty() { + payload.email = None; + } + + match runners::register_runner(&payload, &data).await { + Ok(()) => Ok(HttpResponse::Found() + .insert_header((header::LOCATION, PAGES.auth.login)) + .finish()), + Err(e) => { + let status = e.status_code(); + let heading = status.canonical_reason().unwrap_or("Error"); + Ok(HttpResponseBuilder::new(status) + .content_type("text/html; charset=utf-8") + .body( + IndexPage::new(heading, &format!("{}", e)) + .render_once() + .unwrap(), + )) + } + } +} + +#[cfg(test)] +mod tests { + use actix_web::test; + + use super::*; + + use crate::api::v1::account::{ + username::runners::username_exists, AccountCheckPayload, + }; + use crate::api::v1::auth::runners::Register; + use crate::data::Data; + use crate::tests::*; + use crate::*; + use actix_web::http::StatusCode; + + #[actix_rt::test] + async fn auth_join_form_works() { + let data = Data::new().await; + const NAME: &str = "testuserformjoin"; + const NAME2: &str = "testuserformjoin2"; + const EMAIL: &str = "testuserformjoin@a.com"; + const PASSWORD: &str = "longpassword"; + + let app = get_app!(data).await; + + delete_user(NAME, &data).await; + + // 1. Register with email == None + let mut msg = Register { + username: NAME.into(), + password: PASSWORD.into(), + confirm_password: PASSWORD.into(), + email: Some(EMAIL.into()), + }; + + let resp = test::call_service( + &app, + post_request!(&msg, PAGES.auth.join, FORM).to_request(), + ) + .await; + assert_eq!(resp.status(), StatusCode::FOUND); + let headers = resp.headers(); + assert_eq!(headers.get(header::LOCATION).unwrap(), PAGES.auth.login,); + + let account_check = AccountCheckPayload { val: NAME.into() }; + assert!( + username_exists(&account_check, &AppData::new(data.clone())) + .await + .unwrap() + .exists + ); + + msg.email = None; + let resp = test::call_service( + &app, + post_request!(&msg, PAGES.auth.join, FORM).to_request(), + ) + .await; + assert_eq!(resp.status(), StatusCode::BAD_REQUEST); + + msg.email = Some(EMAIL.into()); + msg.username = NAME2.into(); + let resp = test::call_service( + &app, + post_request!(&msg, PAGES.auth.join, FORM).to_request(), + ) + .await; + assert_eq!(resp.status(), StatusCode::BAD_REQUEST); + } +} diff --git a/src/pages/auth/login.rs b/src/pages/auth/login.rs new file mode 100644 index 0000000..08be460 --- /dev/null +++ b/src/pages/auth/login.rs @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use actix_identity::Identity; +use actix_web::HttpResponseBuilder; +use actix_web::{error::ResponseError, http::header, web, HttpResponse, Responder}; +use lazy_static::lazy_static; +use my_codegen::{get, post}; +use sailfish::TemplateOnce; + +use crate::api::v1::auth::runners; +use crate::errors::*; +use crate::pages::errors::ErrorPage; +use crate::AppData; +use crate::PAGES; + +#[derive(Clone, TemplateOnce)] +#[template(path = "auth/login/index.html")] +struct IndexPage<'a> { + error: Option>, +} + +const PAGE: &str = "Login"; + +impl<'a> Default for IndexPage<'a> { + fn default() -> Self { + IndexPage { error: None } + } +} + +impl<'a> IndexPage<'a> { + pub fn new(title: &'a str, message: &'a str) -> Self { + Self { + error: Some(ErrorPage::new(title, message)), + } + } +} + +lazy_static! { + static ref INDEX: String = IndexPage::default().render_once().unwrap(); +} + +#[get(path = "PAGES.auth.login")] +pub async fn login() -> impl Responder { + HttpResponse::Ok() + .content_type("text/html; charset=utf-8") + .body(&*INDEX) +} + +#[post(path = "PAGES.auth.login")] +pub async fn login_submit( + id: Identity, + payload: web::Form, + data: AppData, +) -> PageResult { + let payload = payload.into_inner(); + match runners::login_runner(&payload, &data).await { + Ok(username) => { + id.remember(username); + Ok(HttpResponse::Found() + .insert_header((header::LOCATION, PAGES.home)) + .finish()) + } + Err(e) => { + let status = e.status_code(); + let heading = status.canonical_reason().unwrap_or("Error"); + + Ok(HttpResponseBuilder::new(status) + .content_type("text/html; charset=utf-8") + .body( + IndexPage::new(heading, &format!("{}", e)) + .render_once() + .unwrap(), + )) + } + } +} + +#[cfg(test)] +mod tests { + use actix_web::test; + + use super::*; + + use crate::api::v1::auth::runners::{Login, Register}; + use crate::data::Data; + use crate::tests::*; + use crate::*; + use actix_web::http::StatusCode; + + #[actix_rt::test] + async fn auth_form_works() { + let data = Data::new().await; + const NAME: &str = "testuserform"; + const PASSWORD: &str = "longpassword"; + + let app = get_app!(data).await; + + delete_user(NAME, &data).await; + + // 1. Register with email == None + let msg = Register { + username: NAME.into(), + password: PASSWORD.into(), + confirm_password: PASSWORD.into(), + email: None, + }; + let resp = test::call_service( + &app, + post_request!(&msg, V1_API_ROUTES.auth.register).to_request(), + ) + .await; + assert_eq!(resp.status(), StatusCode::OK); + + // correct form login + let msg = Login { + login: NAME.into(), + password: PASSWORD.into(), + }; + + let resp = test::call_service( + &app, + post_request!(&msg, PAGES.auth.login, FORM).to_request(), + ) + .await; + assert_eq!(resp.status(), StatusCode::FOUND); + let headers = resp.headers(); + assert_eq!(headers.get(header::LOCATION).unwrap(), PAGES.home,); + + // incorrect form login + let msg = Login { + login: NAME.into(), + password: NAME.into(), + }; + let resp = test::call_service( + &app, + post_request!(&msg, PAGES.auth.login, FORM).to_request(), + ) + .await; + assert_eq!(resp.status(), StatusCode::UNAUTHORIZED); + + // non-existent form login + let msg = Login { + login: PASSWORD.into(), + password: PASSWORD.into(), + }; + let resp = test::call_service( + &app, + post_request!(&msg, PAGES.auth.login, FORM).to_request(), + ) + .await; + assert_eq!(resp.status(), StatusCode::NOT_FOUND); + } +} diff --git a/src/pages/auth/mod.rs b/src/pages/auth/mod.rs new file mode 100644 index 0000000..ae5025b --- /dev/null +++ b/src/pages/auth/mod.rs @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +pub mod join; +pub mod login; +pub mod sudo; + +pub fn services(cfg: &mut actix_web::web::ServiceConfig) { + cfg.service(login::login); + cfg.service(login::login_submit); + cfg.service(join::join); + cfg.service(join::join_submit); +} + +pub mod routes { + pub struct Auth { + pub login: &'static str, + pub join: &'static str, + } + impl Auth { + pub const fn new() -> Auth { + Auth { + login: "/login", + join: "/join", + } + } + + pub const fn get_sitemap() -> [&'static str; 2] { + const AUTH: Auth = Auth::new(); + [AUTH.login, AUTH.join] + } + } +} diff --git a/src/pages/auth/sudo.rs b/src/pages/auth/sudo.rs new file mode 100644 index 0000000..73b6d64 --- /dev/null +++ b/src/pages/auth/sudo.rs @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use sailfish::TemplateOnce; + +use crate::pages::errors::ErrorPage; + +#[derive(Clone, TemplateOnce)] +#[template(path = "auth/sudo/index.html")] +pub struct SudoPage<'a> { + url: &'a str, + title: &'a str, + error: Option>, +} + +pub const PAGE: &str = "Confirm Access"; + +impl<'a> SudoPage<'a> { + pub fn new(url: &'a str, title: &'a str) -> Self { + Self { + url, + title, + error: None, + } + } + + pub fn set_err(&mut self, err_title: &'a str, message: &'a str) { + self.error = Some(ErrorPage::new(err_title, message)); + } +} diff --git a/src/pages/errors.rs b/src/pages/errors.rs new file mode 100644 index 0000000..657c55f --- /dev/null +++ b/src/pages/errors.rs @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +use actix_web::{web, HttpResponse, Responder}; +use lazy_static::lazy_static; +use sailfish::TemplateOnce; + +use crate::errors::PageError; + +#[derive(Clone, TemplateOnce)] +#[template(path = "errors/index.html")] +pub struct ErrorPage<'a> { + pub title: &'a str, + pub message: &'a str, +} + +const PAGE: &str = "Error"; + +impl<'a> ErrorPage<'a> { + pub fn new(title: &'a str, message: &'a str) -> Self { + ErrorPage { title, message } + } +} + +lazy_static! { + static ref INTERNAL_SERVER_ERROR_BODY: String = ErrorPage::new( + "Internal Server Error", + &format!("{}", PageError::InternalServerError), + ) + .render_once() + .unwrap(); + static ref UNKNOWN_ERROR_BODY: String = ErrorPage::new( + "Something went wrong", + &format!("{}", PageError::InternalServerError), + ) + .render_once() + .unwrap(); +} + +const ERROR_ROUTE: &str = "/error/{id}"; + +#[my_codegen::get(path = "ERROR_ROUTE")] +async fn error(path: web::Path) -> impl Responder { + let resp = match path.into_inner() { + 500 => HttpResponse::InternalServerError() + .content_type("text/html; charset=utf-8") + .body(&*INTERNAL_SERVER_ERROR_BODY), + + _ => HttpResponse::InternalServerError() + .content_type("text/html; charset=utf-8") + .body(&*UNKNOWN_ERROR_BODY), + }; + + resp +} + +pub fn services(cfg: &mut web::ServiceConfig) { + cfg.service(error); +} + +pub mod routes { + pub struct Errors { + pub internal_server_error: &'static str, + pub unknown_error: &'static str, + } + + impl Errors { + pub const fn new() -> Self { + Errors { + internal_server_error: "/error/500", + unknown_error: "/error/007", + } + } + } +} + +#[cfg(test)] +mod tests { + use actix_web::{http::StatusCode, test, App}; + + use super::*; + use crate::PAGES; + + #[actix_rt::test] + async fn error_pages_work() { + let app = test::init_service(App::new().configure(services)).await; + + let resp = test::call_service( + &app, + test::TestRequest::get() + .uri(PAGES.errors.internal_server_error) + .to_request(), + ) + .await; + assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR); + + let resp = test::call_service( + &app, + test::TestRequest::get() + .uri(PAGES.errors.unknown_error) + .to_request(), + ) + .await; + assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR); + } +} diff --git a/src/pages/mod.rs b/src/pages/mod.rs new file mode 100644 index 0000000..276c146 --- /dev/null +++ b/src/pages/mod.rs @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License along with this program. If not, see . + */ + +use actix_web::web::ServiceConfig; + +pub mod auth; +pub mod errors; +mod panel; +pub mod routes; +//mod sitemap; + +pub const NAME: &str = "Kaizen"; + +pub fn services(cfg: &mut ServiceConfig) { + auth::services(cfg); + panel::services(cfg); + errors::services(cfg); +} + +#[cfg(not(tarpaulin_include))] +#[cfg(test)] +mod tests { + use actix_web::http::{header, StatusCode}; + use actix_web::test; + + use crate::tests::*; + use crate::*; + + #[actix_rt::test] + async fn protected_pages_templates_work() { + const NAME: &str = "templateuser"; + const PASSWORD: &str = "longpassword"; + const EMAIL: &str = "templateuser@a.com"; + const CAMPAIGN_NAME: &str = "delcappageusercamaping"; + + let data = Data::new().await; + { + delete_user(NAME, &data).await; + } + + let (_, _, signin_resp) = register_and_signin(NAME, EMAIL, PASSWORD).await; + let cookies = get_cookie!(signin_resp); + + let campaign = + create_new_campaign(CAMPAIGN_NAME, data.clone(), cookies.clone()).await; + + let app = get_app!(data).await; + + let urls = vec![ + PAGES.home.into(), + PAGES.panel.campaigns.home.into(), + PAGES.panel.campaigns.new.into(), + PAGES.panel.campaigns.get_feedback_route(&campaign.uuid), + PAGES.panel.campaigns.get_delete_route(&campaign.uuid), + ]; + + for url in urls.iter() { + let resp = + test::call_service(&app, test::TestRequest::get().uri(url).to_request()) + .await; + if resp.status() != StatusCode::FOUND { + println!("Probably error url: {}", url); + } + assert_eq!(resp.status(), StatusCode::FOUND); + + let authenticated_resp = test::call_service( + &app, + test::TestRequest::get() + .uri(url) + .cookie(cookies.clone()) + .to_request(), + ) + .await; + + if url == &PAGES.home { + assert_eq!(authenticated_resp.status(), StatusCode::FOUND); + let headers = authenticated_resp.headers(); + assert_eq!( + headers.get(header::LOCATION).unwrap(), + PAGES.panel.campaigns.home + ); + } else { + assert_eq!(authenticated_resp.status(), StatusCode::OK); + } + } + + delete_user(NAME, &data).await; + } + + #[actix_rt::test] + async fn public_pages_tempaltes_work() { + let app = test::init_service(App::new().configure(crate::pages::services)).await; + let urls = vec![PAGES.auth.login, PAGES.auth.join]; //, PAGES.sitemap]; + + for url in urls.iter() { + let resp = + test::call_service(&app, test::TestRequest::get().uri(url).to_request()) + .await; + + assert_eq!(resp.status(), StatusCode::OK); + } + } +} diff --git a/src/pages/panel/campaigns/delete.rs b/src/pages/panel/campaigns/delete.rs new file mode 100644 index 0000000..d7199c9 --- /dev/null +++ b/src/pages/panel/campaigns/delete.rs @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use actix_identity::Identity; +use actix_web::HttpResponseBuilder; +use actix_web::{ + error::ResponseError, + http::{header, StatusCode}, + web, HttpResponse, Responder, +}; +use my_codegen::{get, post}; +use sailfish::TemplateOnce; +use uuid::Uuid; + +use crate::api::v1::auth::runners::{login_runner, Login, Password}; +use crate::api::v1::campaign::runners; +use crate::errors::*; +use crate::pages::auth::sudo::SudoPage; +use crate::AppData; +use crate::PAGES; + +async fn get_title( + username: &str, + uuid: &Uuid, + data: &AppData, +) -> ServiceResult { + struct Name { + name: String, + } + let campaign = sqlx::query_as!( + Name, + "SELECT name + FROM kaizen_campaign + WHERE + uuid = $1 + AND + user_id = (SELECT ID from kaizen_users WHERE name = $2)", + &uuid, + &username + ) + .fetch_one(&data.db) + .await?; + + Ok(format!("Delete camapign \"{}\"?", campaign.name)) +} + +#[get(path = "PAGES.panel.campaigns.delete", wrap = "crate::CheckLogin")] +pub async fn delete_campaign( + id: Identity, + path: web::Path, + data: AppData, +) -> PageResult { + let username = id.identity().unwrap(); + let path = path.into_inner(); + let uuid = Uuid::parse_str(&path).map_err(|_| ServiceError::NotAnId)?; + + let title = get_title(&username, &uuid, &data).await?; + + let page = SudoPage::new( + &crate::PAGES.panel.campaigns.get_delete_route(&path), + &title, + ) + .render_once() + .unwrap(); + Ok(HttpResponse::Ok() + .content_type("text/html; charset=utf-8") + .body(page)) +} + +#[post(path = "PAGES.panel.campaigns.delete", wrap = "crate::CheckLogin")] +pub async fn delete_campaign_submit( + id: Identity, + path: web::Path, + payload: web::Form, + data: AppData, +) -> PageResult { + let username = id.identity().unwrap(); + let path = path.into_inner(); + let uuid = Uuid::parse_str(&path).map_err(|_| ServiceError::NotAnId)?; + let payload = payload.into_inner(); + + async fn render_err( + e: ServiceError, + username: &str, + uuid: &Uuid, + path: &str, + data: &AppData, + ) -> ServiceResult<(String, StatusCode)> { + let status = e.status_code(); + let heading = status.canonical_reason().unwrap_or("Error"); + + let form_route = crate::V1_API_ROUTES.campaign.get_delete_route(&path); + let title = get_title(&username, &uuid, &data).await?; + let mut ctx = SudoPage::new(&form_route, &title); + let err = format!("{}", e); + ctx.set_err(heading, &err); + let page = ctx.render_once().unwrap(); + Ok((page, status)) + } + + let creds = Login { + login: username, + password: payload.password, + }; + + match login_runner(&creds, &data).await { + Err(e) => { + let (page, status) = + render_err(e, &creds.login, &uuid, &path, &data).await?; + + Ok(HttpResponseBuilder::new(status) + .content_type("text/html; charset=utf-8") + .body(page)) + } + Ok(_) => { + match runners::delete(&uuid, &creds.login, &data).await { + Ok(_) => Ok(HttpResponse::Found() + //TODO show stats of new campaign + .insert_header((header::LOCATION, PAGES.panel.campaigns.home)) + .finish()), + + Err(e) => { + let (page, status) = + render_err(e, &creds.login, &uuid, &path, &data).await?; + Ok(HttpResponseBuilder::new(status) + .content_type("text/html; charset=utf-8") + .body(page)) + } + } + } + } +} + +#[cfg(test)] +mod tests { + use actix_web::test; + + use super::*; + + use crate::data::Data; + use crate::tests::*; + use crate::*; + use actix_web::http::StatusCode; + + #[actix_rt::test] + async fn new_campaign_form_works() { + let data = Data::new().await; + const NAME: &str = "delcappageuser"; + const EMAIL: &str = "delcappageuser@aaa.com"; + const PASSWORD: &str = "longpassword"; + const CAMPAIGN_NAME: &str = "delcappageusercamaping"; + + let app = get_app!(data).await; + delete_user(NAME, &data).await; + let (_, _, signin_resp) = register_and_signin(NAME, EMAIL, PASSWORD).await; + let cookies = get_cookie!(signin_resp); + + let uuid = + create_new_campaign(CAMPAIGN_NAME, data.clone(), cookies.clone()).await; + + let creds = Password { + password: PASSWORD.into(), + }; + + let new_resp = test::call_service( + &app, + post_request!( + &creds, + &PAGES.panel.campaigns.get_delete_route(&uuid.uuid), + FORM + ) + .cookie(cookies.clone()) + .to_request(), + ) + .await; + assert_eq!(new_resp.status(), StatusCode::FOUND); + let headers = new_resp.headers(); + assert_eq!( + headers.get(header::LOCATION).unwrap(), + PAGES.panel.campaigns.home, + ); + } +} diff --git a/src/pages/panel/campaigns/get.rs b/src/pages/panel/campaigns/get.rs new file mode 100644 index 0000000..0d8085f --- /dev/null +++ b/src/pages/panel/campaigns/get.rs @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use actix_identity::Identity; +use actix_web::{web, HttpResponse, Responder}; +use my_codegen::get; +use sailfish::TemplateOnce; + +use crate::api::v1::campaign::{runners, GetFeedbackResp}; +use crate::AppData; +use crate::PAGES; + +#[derive(TemplateOnce)] +#[template(path = "panel/campaigns/get/index.html")] +struct ViewFeedback<'a> { + campaign: GetFeedbackResp, + uuid: &'a str, +} + +const PAGE: &str = "New Campaign"; + +impl<'a> ViewFeedback<'a> { + pub fn new(campaign: GetFeedbackResp, uuid: &'a str) -> Self { + Self { campaign, uuid } + } +} + +#[get( + path = "PAGES.panel.campaigns.get_feedback", + wrap = "crate::CheckLogin" +)] +pub async fn get_feedback( + id: Identity, + data: AppData, + path: web::Path, +) -> impl Responder { + let username = id.identity().unwrap(); + let path = path.into_inner(); + let feedback_resp = runners::get_feedback(&username, &path, &data) + .await + .unwrap(); + let page = ViewFeedback::new(feedback_resp, &path) + .render_once() + .unwrap(); + HttpResponse::Ok() + .content_type("text/html; charset=utf-8") + .body(page) +} diff --git a/src/pages/panel/campaigns/mod.rs b/src/pages/panel/campaigns/mod.rs new file mode 100644 index 0000000..1fb5541 --- /dev/null +++ b/src/pages/panel/campaigns/mod.rs @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License along with this program. If not, see . + */ +use actix_identity::Identity; +use actix_web::{HttpResponse, Responder}; +use my_codegen::get; +use sailfish::TemplateOnce; + +use crate::api::v1::campaign::{runners::list_campaign_runner, ListCampaignResp}; +use crate::AppData; +use crate::PAGES; + +pub mod delete; +pub mod get; +pub mod new; + +pub mod routes { + pub struct Campaigns { + pub home: &'static str, + pub new: &'static str, + pub get_feedback: &'static str, + pub delete: &'static str, + } + impl Campaigns { + pub const fn new() -> Campaigns { + Campaigns { + home: "/campaigns", + new: "/campaigns/new", + get_feedback: "/campaigns/{uuid}/feedback", + delete: "/campaigns/{uuid}/delete", + } + } + + pub fn get_delete_route(&self, campaign_id: &str) -> String { + self.delete.replace("{uuid}", campaign_id) + } + + pub fn get_feedback_route(&self, campaign_id: &str) -> String { + self.get_feedback.replace("{uuid}", campaign_id) + } + + pub const fn get_sitemap() -> [&'static str; 2] { + const CAMPAIGNS: Campaigns = Campaigns::new(); + [CAMPAIGNS.home, CAMPAIGNS.new] + } + } +} + +pub fn services(cfg: &mut actix_web::web::ServiceConfig) { + cfg.service(home); + cfg.service(new::new_campaign); + cfg.service(new::new_campaign_submit); + cfg.service(get::get_feedback); + cfg.service(delete::delete_campaign); + cfg.service(delete::delete_campaign_submit); +} + +#[derive(TemplateOnce)] +#[template(path = "panel/campaigns/index.html")] +struct HomePage { + data: Vec, +} + +impl HomePage { + fn new(data: Vec) -> Self { + Self { data } + } +} + +const PAGE: &str = "Campaigns"; + +#[get(path = "PAGES.panel.campaigns.home", wrap = "crate::CheckLogin")] +pub async fn home(data: AppData, id: Identity) -> impl Responder { + let username = id.identity().unwrap(); + let campaigns = list_campaign_runner(&username, &data).await.unwrap(); + let page = HomePage::new(campaigns).render_once().unwrap(); + + HttpResponse::Ok() + .content_type("text/html; charset=utf-8") + .body(&page) +} diff --git a/src/pages/panel/campaigns/new.rs b/src/pages/panel/campaigns/new.rs new file mode 100644 index 0000000..d7ab8ed --- /dev/null +++ b/src/pages/panel/campaigns/new.rs @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use actix_identity::Identity; +use actix_web::HttpResponseBuilder; +use actix_web::{error::ResponseError, http::header, web, HttpResponse, Responder}; +use lazy_static::lazy_static; +use my_codegen::{get, post}; +use sailfish::TemplateOnce; + +use crate::api::v1::campaign::{runners, CreateReq}; +use crate::errors::*; +use crate::pages::errors::ErrorPage; +use crate::AppData; +use crate::PAGES; + +#[derive(Clone, TemplateOnce)] +#[template(path = "panel/campaigns/new/index.html")] +struct NewCampaign<'a> { + error: Option>, +} + +const PAGE: &str = "New Campaign"; + +impl<'a> Default for NewCampaign<'a> { + fn default() -> Self { + NewCampaign { error: None } + } +} + +impl<'a> NewCampaign<'a> { + pub fn new(title: &'a str, message: &'a str) -> Self { + Self { + error: Some(ErrorPage::new(title, message)), + } + } +} + +lazy_static! { + static ref INDEX: String = NewCampaign::default().render_once().unwrap(); +} + +#[get(path = "PAGES.panel.campaigns.new", wrap = "crate::CheckLogin")] +pub async fn new_campaign() -> impl Responder { + HttpResponse::Ok() + .content_type("text/html; charset=utf-8") + .body(&*INDEX) +} + +#[post(path = "PAGES.panel.campaigns.new", wrap = "crate::CheckLogin")] +pub async fn new_campaign_submit( + id: Identity, + payload: web::Form, + data: AppData, +) -> PageResult { + match runners::new(&payload.into_inner(), &data, &id).await { + Ok(_) => { + Ok(HttpResponse::Found() + //TODO show stats of new campaign + .insert_header((header::LOCATION, PAGES.panel.campaigns.home)) + .finish()) + } + Err(e) => { + let status = e.status_code(); + let heading = status.canonical_reason().unwrap_or("Error"); + + Ok(HttpResponseBuilder::new(status) + .content_type("text/html; charset=utf-8") + .body( + NewCampaign::new(heading, &format!("{}", e)) + .render_once() + .unwrap(), + )) + } + } +} + +#[cfg(test)] +mod tests { + use actix_web::test; + + use super::*; + + use crate::data::Data; + use crate::tests::*; + use crate::*; + use actix_web::http::StatusCode; + + #[actix_rt::test] + async fn new_campaign_form_works() { + let data = Data::new().await; + const NAME: &str = "testusercampaignform"; + const EMAIL: &str = "testcampaignuser@aaa.com"; + const PASSWORD: &str = "longpassword"; + + const CAMPAIGN_NAME: &str = "testcampaignuser"; + + let app = get_app!(data).await; + delete_user(NAME, &data).await; + let (_, _, signin_resp) = register_and_signin(NAME, EMAIL, PASSWORD).await; + let cookies = get_cookie!(signin_resp); + + let new = CreateReq { + name: CAMPAIGN_NAME.into(), + }; + + let new_resp = test::call_service( + &app, + post_request!(&new, PAGES.panel.campaigns.new, FORM) + .cookie(cookies.clone()) + .to_request(), + ) + .await; + assert_eq!(new_resp.status(), StatusCode::FOUND); + let headers = new_resp.headers(); + assert_eq!( + headers.get(header::LOCATION).unwrap(), + PAGES.panel.campaigns.home, + ); + } +} diff --git a/src/pages/panel/mod.rs b/src/pages/panel/mod.rs new file mode 100644 index 0000000..cc7e626 --- /dev/null +++ b/src/pages/panel/mod.rs @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License along with this program. If not, see . + */ +use actix_web::{http, HttpResponse, Responder}; +use my_codegen::get; + +use crate::PAGES; + +mod campaigns; + +pub mod routes { + use super::campaigns::routes::Campaigns; + + pub struct Panel { + pub home: &'static str, + pub campaigns: Campaigns, + } + impl Panel { + pub const fn new() -> Panel { + Panel { + home: "/", + campaigns: Campaigns::new(), + } + } + + pub const fn get_sitemap() -> [&'static str; 1] { + const PANEL: Panel = Panel::new(); + [PANEL.home] + } + } +} + +pub fn services(cfg: &mut actix_web::web::ServiceConfig) { + cfg.service(home); + campaigns::services(cfg); +} + +#[get(path = "PAGES.panel.home", wrap = "crate::CheckLogin")] +pub async fn home() -> impl Responder { + HttpResponse::Found() + .insert_header((http::header::LOCATION, PAGES.panel.campaigns.home)) + .finish() +} diff --git a/src/pages/routes.rs b/src/pages/routes.rs new file mode 100644 index 0000000..7547947 --- /dev/null +++ b/src/pages/routes.rs @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use super::auth::routes::Auth; +use super::errors::routes::Errors; +use super::panel::routes::Panel; +pub const ROUTES: Routes = Routes::new(); + +pub struct Routes { + pub home: &'static str, + pub auth: Auth, + pub panel: Panel, + pub errors: Errors, + pub about: &'static str, + pub sitemap: &'static str, + pub thanks: &'static str, + pub donate: &'static str, + pub security: &'static str, + pub privacy: &'static str, +} + +impl Routes { + const fn new() -> Routes { + let panel = Panel::new(); + let home = panel.home; + Routes { + auth: Auth::new(), + panel, + home, + errors: Errors::new(), + about: "/about", + sitemap: "/sitemap.xml", + thanks: "/thanks", + donate: "/donate", + security: "/security", + privacy: "/privacy-policy", + } + } + + pub const fn get_sitemap() -> [&'static str; 3] { + let a = Auth::get_sitemap(); + let p = Panel::get_sitemap(); + [a[0], a[1], p[0]] //, p[1], p[2], p[3], p[4]] + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn sitemap_works() { + Routes::get_sitemap(); + } +} diff --git a/src/settings.rs b/src/settings.rs new file mode 100644 index 0000000..20116d5 --- /dev/null +++ b/src/settings.rs @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use std::env; +use std::path::Path; + +use config::{Config, ConfigError, Environment, File}; +use log::{debug, warn}; +use serde::Deserialize; +use url::Url; + +#[derive(Debug, Clone, Deserialize)] +pub struct Server { + pub port: u32, + pub domain: String, + pub cookie_secret: String, + pub ip: String, + pub proxy_has_tls: bool, +} + +impl Server { + #[cfg(not(tarpaulin_include))] + pub fn get_ip(&self) -> String { + format!("{}:{}", self.ip, self.port) + } +} + +#[derive(Debug, Clone, Deserialize)] +struct DatabaseBuilder { + pub port: u32, + pub hostname: String, + pub username: String, + pub password: String, + pub name: String, + pub url: String, +} + +impl DatabaseBuilder { + #[cfg(not(tarpaulin_include))] + fn extract_database_url(url: &Url) -> Self { + debug!("Databse name: {}", url.path()); + let mut path = url.path().split('/'); + path.next(); + let name = path.next().expect("no database name").to_string(); + DatabaseBuilder { + port: url.port().expect("Enter database port").into(), + hostname: url.host().expect("Enter database host").to_string(), + username: url.username().into(), + url: url.to_string(), + password: url.password().expect("Enter database password").into(), + name, + } + } +} + +#[derive(Debug, Clone, Deserialize)] +pub struct Database { + pub url: String, + pub pool: u32, +} + +#[derive(Debug, Clone, Deserialize)] +pub struct Settings { + pub debug: bool, + pub allow_registration: bool, + pub database: Database, + pub server: Server, + pub source_code: String, + pub password: String, +} + +#[cfg(not(tarpaulin_include))] +impl Settings { + pub fn new() -> Result { + let mut s = Config::new(); + + // setting default values + #[cfg(test)] + s.set_default("database.pool", 2.to_string()) + .expect("Couldn't get the number of CPUs"); + + const CURRENT_DIR: &str = "./config/default.toml"; + const ETC: &str = "/etc/athena/config.toml"; + + if let Ok(path) = env::var("ATHENA_CONFIG") { + s.merge(File::with_name(&path))?; + } else if Path::new(CURRENT_DIR).exists() { + // merging default config from file + s.merge(File::with_name(CURRENT_DIR))?; + } else if Path::new(ETC).exists() { + s.merge(File::with_name(ETC))?; + } else { + log::warn!("configuration file not found"); + } + + s.merge(Environment::with_prefix("MCAPTCHA").separator("_"))?; + + check_url(&s); + + match env::var("PORT") { + Ok(val) => { + s.set("server.port", val).unwrap(); + } + Err(e) => warn!("couldn't interpret PORT: {}", e), + } + + match env::var("DATABASE_URL") { + Ok(val) => { + let url = Url::parse(&val).expect("couldn't parse Database URL"); + let database_conf = DatabaseBuilder::extract_database_url(&url); + set_from_database_url(&mut s, &database_conf); + } + Err(e) => warn!("couldn't interpret DATABASE_URL: {}", e), + } + + set_database_url(&mut s); + + match s.try_into() { + Ok(val) => Ok(val), + Err(e) => Err(ConfigError::Message(format!("\n\nError: {}. If it says missing fields, then please refer to https://github.com/mCaptcha/mcaptcha#configuration to learn more about how mcaptcha reads configuration\n\n", e))), + } + } +} + +#[cfg(not(tarpaulin_include))] +fn check_url(s: &Config) { + let url = s + .get::("source_code") + .expect("Couldn't access source_code"); + + Url::parse(&url).expect("Please enter a URL for source_code in settings"); +} + +#[cfg(not(tarpaulin_include))] +fn set_from_database_url(s: &mut Config, database_conf: &DatabaseBuilder) { + s.set("database.username", database_conf.username.clone()) + .expect("Couldn't set database username"); + s.set("database.password", database_conf.password.clone()) + .expect("Couldn't access database password"); + s.set("database.hostname", database_conf.hostname.clone()) + .expect("Couldn't access database hostname"); + s.set("database.port", database_conf.port as i64) + .expect("Couldn't access database port"); + s.set("database.name", database_conf.name.clone()) + .expect("Couldn't access database name"); +} + +#[cfg(not(tarpaulin_include))] +fn set_database_url(s: &mut Config) { + s.set( + "database.url", + format!( + r"postgres://{}:{}@{}:{}/{}", + s.get::("database.username") + .expect("Couldn't access database username"), + s.get::("database.password") + .expect("Couldn't access database password"), + s.get::("database.hostname") + .expect("Couldn't access database hostname"), + s.get::("database.port") + .expect("Couldn't access database port"), + s.get::("database.name") + .expect("Couldn't access database name") + ), + ) + .expect("Couldn't set databse url"); +} diff --git a/src/static_assets/filemap.rs b/src/static_assets/filemap.rs new file mode 100644 index 0000000..4f7a364 --- /dev/null +++ b/src/static_assets/filemap.rs @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use cache_buster::Files; + +pub struct FileMap { + pub files: Files, +} + +impl FileMap { + #[allow(clippy::new_without_default)] + pub fn new() -> Self { + let map = include_str!("../cache_buster_data.json"); + let files = Files::new(map); + Self { files } + } + pub fn get(&self, path: impl AsRef) -> Option<&str> { + let file_path = self.files.get_full_path(path); + file_path.map(|file_path| &file_path[1..]) + } +} + +#[cfg(test)] +mod tests { + + #[test] + fn filemap_works() { + let files = super::FileMap::new(); + let css = files.get("./static/cache/img/logo.svg").unwrap(); + println!("{}", css); + assert!(css.contains("/assets/img/logo")); + } +} diff --git a/src/static_assets/mod.rs b/src/static_assets/mod.rs new file mode 100644 index 0000000..a080139 --- /dev/null +++ b/src/static_assets/mod.rs @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +pub mod filemap; +pub mod static_files; + +pub use filemap::FileMap; + +pub fn services(cfg: &mut actix_web::web::ServiceConfig) { + cfg.service(static_files::static_files); + cfg.service(static_files::favicons); +} diff --git a/src/static_assets/static_files.rs b/src/static_assets/static_files.rs new file mode 100644 index 0000000..38dcdf4 --- /dev/null +++ b/src/static_assets/static_files.rs @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use std::borrow::Cow; + +use actix_web::body::Body; +use actix_web::{get, http::header, web, HttpResponse, Responder}; +use log::debug; +use mime_guess::from_path; +use rust_embed::RustEmbed; + +use crate::CACHE_AGE; + +pub mod assets { + use lazy_static::lazy_static; + + use crate::FILES; + + pub struct Img { + pub path: &'static str, + pub name: &'static str, + } + + lazy_static! { + pub static ref LOGO: Img = Img { + path: FILES.get("./static/cache/img/logo.svg").unwrap(), + name: "Kaizen logo" + }; + pub static ref TRASH: Img = Img { + path: FILES.get("./static/cache/img/trash.svg").unwrap(), + name: "Trash logo" + }; + } +} + +#[derive(RustEmbed)] +#[folder = "assets/"] +struct Asset; + +fn handle_assets(path: &str) -> HttpResponse { + match Asset::get(path) { + Some(content) => { + let body: Body = match content.data { + Cow::Borrowed(bytes) => bytes.into(), + Cow::Owned(bytes) => bytes.into(), + }; + + HttpResponse::Ok() + .insert_header(header::CacheControl(vec![ + header::CacheDirective::Public, + header::CacheDirective::Extension("immutable".into(), None), + header::CacheDirective::MaxAge(CACHE_AGE), + ])) + .content_type(from_path(path).first_or_octet_stream().as_ref()) + .body(body) + } + None => HttpResponse::NotFound().body("404 Not Found"), + } +} + +#[get("/assets/{_:.*}")] +pub async fn static_files(path: web::Path) -> impl Responder { + handle_assets(&path) +} + +#[derive(RustEmbed)] +#[folder = "static/favicons/"] +struct Favicons; + +fn handle_favicons(path: &str) -> HttpResponse { + match Favicons::get(path) { + Some(content) => { + let body: Body = match content.data { + Cow::Borrowed(bytes) => bytes.into(), + Cow::Owned(bytes) => bytes.into(), + }; + + HttpResponse::Ok() + .insert_header(header::CacheControl(vec![ + header::CacheDirective::Public, + header::CacheDirective::Extension("immutable".into(), None), + header::CacheDirective::MaxAge(CACHE_AGE), + ])) + .content_type(from_path(path).first_or_octet_stream().as_ref()) + .body(body) + } + None => HttpResponse::NotFound().body("404 Not Found"), + } +} + +#[get("/{file}")] +pub async fn favicons(path: web::Path) -> impl Responder { + debug!("searching favicons"); + handle_favicons(&path) +} + +#[cfg(test)] +mod tests { + use actix_web::http::StatusCode; + use actix_web::test; + + use super::*; + use crate::*; + + #[actix_rt::test] + async fn static_assets_work() { + let app = get_app!().await; + + for file in [assets::LOGO.path, *crate::CSS].iter() { + let resp = test::call_service( + &app, + test::TestRequest::get().uri(file).to_request(), + ) + .await; + assert_eq!(resp.status(), StatusCode::OK); + } + } + + #[actix_rt::test] + async fn favicons_work() { + assert!(Favicons::get("favicon.ico").is_some()); + + let app = get_app!().await; + + let resp = test::call_service( + &app, + test::TestRequest::get().uri("/favicon.ico").to_request(), + ) + .await; + assert_eq!(resp.status(), StatusCode::OK); + } +} diff --git a/src/tests-migrate.rs b/src/tests-migrate.rs new file mode 100644 index 0000000..569dd50 --- /dev/null +++ b/src/tests-migrate.rs @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2021 Aravinth Manivannan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +use std::env; + +use lazy_static::lazy_static; +use sqlx::postgres::PgPoolOptions; + +mod settings; + +pub use settings::Settings; + +#[cfg(not(tarpaulin_include))] +lazy_static! { + #[cfg(not(tarpaulin_include))] + pub static ref SETTINGS: Settings = Settings::new().unwrap(); +} + +#[cfg(not(tarpaulin_include))] +#[actix_rt::main] +async fn main() { + let db = PgPoolOptions::new() + .max_connections(SETTINGS.database.pool) + .connect(&SETTINGS.database.url) + .await + .expect("Unable to form database pool"); + + for arg in env::args() { + if arg == "--build" { + println!("Building cache buster config"); + build(); + } + } + + sqlx::migrate!("./migrations/").run(&db).await.unwrap(); +} + +fn build() { + use std::process::Command; + + // note: add error checking yourself. + let output = Command::new("git") + .args(&["rev-parse", "HEAD"]) + .output() + .unwrap(); + let git_hash = String::from_utf8(output.stdout).unwrap(); + println!("cargo:rustc-env=GIT_HASH={}", git_hash); + + // let yml = include_str!("../openapi.yaml"); + // let api_json: serde_json::Value = serde_yaml::from_str(yml).unwrap(); + // println!( + // "cargo:rustc-env=OPEN_API_DOCS={}", + // serde_json::to_string(&api_json).unwrap() + // ); + cache_bust(); +} + +fn cache_bust() { + use cache_buster::BusterBuilder; + let types = vec![ + mime::IMAGE_PNG, + mime::IMAGE_SVG, + mime::IMAGE_JPEG, + mime::IMAGE_GIF, + mime::APPLICATION_JAVASCRIPT, + mime::TEXT_CSS, + ]; + + let config = BusterBuilder::default() + .source("./static/cache") + .result("./assets") + .mime_types(types) + .copy(true) + .follow_links(true) + .build() + .unwrap(); + + config.process().unwrap(); +} diff --git a/src/tests.rs b/src/tests.rs new file mode 100644 index 0000000..098af8a --- /dev/null +++ b/src/tests.rs @@ -0,0 +1,261 @@ +use std::sync::Arc; + +use actix_web::cookie::Cookie; +use actix_web::test; +use actix_web::{dev::ServiceResponse, error::ResponseError, http::StatusCode}; +use serde::Serialize; + +use super::*; +use crate::api::v1::feedback::{RatingReq, RatingResp}; +use crate::api::v1::ROUTES; +use crate::data::Data; +use crate::errors::*; + +#[macro_export] +macro_rules! get_cookie { + ($resp:expr) => { + $resp.response().cookies().next().unwrap().to_owned() + }; +} + +pub async fn delete_user(name: &str, data: &Data) { + let r = sqlx::query!("DELETE FROM kaizen_users WHERE name = ($1)", name,) + .execute(&data.db) + .await; + println!(); + println!(); + println!(); + println!("Deleting user: {:?}", &r); +} + +#[allow(dead_code, clippy::upper_case_acronyms)] +pub struct FORM; + +#[macro_export] +macro_rules! post_request { + ($uri:expr) => { + test::TestRequest::post().uri($uri) + }; + + ($serializable:expr, $uri:expr) => { + test::TestRequest::post() + .uri($uri) + .insert_header((actix_web::http::header::CONTENT_TYPE, "application/json")) + .set_payload(serde_json::to_string($serializable).unwrap()) + }; + + ($serializable:expr, $uri:expr, FORM) => { + test::TestRequest::post().uri($uri).set_form($serializable) + }; +} + +#[macro_export] +macro_rules! get_works { + ($app:expr,$route:expr ) => { + let list_sitekey_resp = + test::call_service(&$app, test::TestRequest::get().uri($route).to_request()) + .await; + assert_eq!(list_sitekey_resp.status(), StatusCode::OK); + }; +} + +#[macro_export] +macro_rules! get_app { + ("APP") => { + actix_web::App::new() + .app_data(crate::get_json_err()) + .wrap(crate::get_identity_service()) + .wrap(actix_web::middleware::NormalizePath::new( + actix_web::middleware::TrailingSlash::Trim, + )) + .configure(crate::services) + }; + + () => { + test::init_service(get_app!("APP")) + }; + ($data:expr) => { + test::init_service( + get_app!("APP").app_data(actix_web::web::Data::new($data.clone())), + ) + }; +} + +/// register and signin utility +pub async fn register_and_signin( + name: &str, + email: &str, + password: &str, +) -> (Arc, Login, ServiceResponse) { + register(name, email, password).await; + signin(name, password).await +} + +/// register utility +pub async fn register(name: &str, email: &str, password: &str) { + let data = Data::new().await; + let app = get_app!(data).await; + + // 1. Register + let msg = Register { + username: name.into(), + password: password.into(), + confirm_password: password.into(), + email: Some(email.into()), + }; + let resp = + test::call_service(&app, post_request!(&msg, ROUTES.auth.register).to_request()) + .await; + assert_eq!(resp.status(), StatusCode::OK); +} + +/// signin util +pub async fn signin(name: &str, password: &str) -> (Arc, Login, ServiceResponse) { + let data = Data::new().await; + let app = get_app!(data.clone()).await; + + // 2. signin + let creds = Login { + login: name.into(), + password: password.into(), + }; + let signin_resp = + test::call_service(&app, post_request!(&creds, ROUTES.auth.login).to_request()) + .await; + assert_eq!(signin_resp.status(), StatusCode::OK); + (data, creds, signin_resp) +} + +/// pub duplicate test +pub async fn bad_post_req_test( + name: &str, + password: &str, + url: &str, + payload: &T, + err: ServiceError, +) { + let (data, _, signin_resp) = signin(name, password).await; + let cookies = get_cookie!(signin_resp); + let app = get_app!(data).await; + + let resp = test::call_service( + &app, + post_request!(&payload, url) + .cookie(cookies.clone()) + .to_request(), + ) + .await; + assert_eq!(resp.status(), err.status_code()); + let resp_err: ErrorToResponse = test::read_body_json(resp).await; + //println!("{}", txt.error); + assert_eq!(resp_err.error, format!("{}", err)); +} + +/// bad post req test without payload +pub async fn bad_post_req_test_witout_payload( + name: &str, + password: &str, + url: &str, + err: ServiceError, +) { + let (data, _, signin_resp) = signin(name, password).await; + let cookies = get_cookie!(signin_resp); + let app = get_app!(data).await; + + let resp = test::call_service( + &app, + post_request!(url).cookie(cookies.clone()).to_request(), + ) + .await; + assert_eq!(resp.status(), err.status_code()); + let resp_err: ErrorToResponse = test::read_body_json(resp).await; + //println!("{}", txt.error); + assert_eq!(resp_err.error, format!("{}", err)); +} + +pub async fn create_new_campaign( + campaign_name: &str, + data: Arc, + cookies: Cookie<'_>, +) -> CreateResp { + let new = CreateReq { + name: campaign_name.into(), + }; + + let app = get_app!(data).await; + let new_resp = test::call_service( + &app, + post_request!(&new, crate::V1_API_ROUTES.campaign.new) + .cookie(cookies) + .to_request(), + ) + .await; + assert_eq!(new_resp.status(), StatusCode::OK); + let uuid: CreateResp = test::read_body_json(new_resp).await; + uuid +} + +pub async fn delete_campaign( + camapign: &CreateResp, + data: Arc, + cookies: Cookie<'_>, +) { + let del_route = V1_API_ROUTES.campaign.get_delete_route(&camapign.uuid); + let app = get_app!(data).await; + let del_resp = + test::call_service(&app, post_request!(&del_route).cookie(cookies).to_request()) + .await; + assert_eq!(del_resp.status(), StatusCode::OK); +} + +pub async fn list_campaings( + data: Arc, + cookies: Cookie<'_>, +) -> Vec { + let app = get_app!(data).await; + let list_resp = test::call_service( + &app, + post_request!(crate::V1_API_ROUTES.campaign.list) + .cookie(cookies) + .to_request(), + ) + .await; + assert_eq!(list_resp.status(), StatusCode::OK); + test::read_body_json(list_resp).await +} + +pub async fn add_feedback( + rating: &RatingReq, + campaign: &CreateResp, + data: Arc, +) -> RatingResp { + let add_feedback_route = V1_API_ROUTES.feedback.add_feedback_route(&campaign.uuid); + let app = get_app!(data).await; + let add_feedback_resp = test::call_service( + &app, + post_request!(&rating, &add_feedback_route).to_request(), + ) + .await; + assert_eq!(add_feedback_resp.status(), StatusCode::OK); + + test::read_body_json(add_feedback_resp).await +} + +pub async fn get_feedback( + campaign: &CreateResp, + data: Arc, + cookies: Cookie<'_>, +) -> GetFeedbackResp { + let get_feedback_route = V1_API_ROUTES.campaign.get_feedback_route(&campaign.uuid); + let app = get_app!(data).await; + + let get_feedback_resp = test::call_service( + &app, + post_request!(&get_feedback_route) + .cookie(cookies) + .to_request(), + ) + .await; + assert_eq!(get_feedback_resp.status(), StatusCode::OK); + test::read_body_json(get_feedback_resp).await +} diff --git a/static/cache/img/logo.png b/static/cache/img/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..c92af77b91fc7d8f1613dd1d2728e56b98b1c11e GIT binary patch literal 30215 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 bZ{eSr#$*+E^1<)10)UL9qD1){qrm?IH~JuY literal 0 HcmV?d00001 diff --git a/static/cache/img/logo.svg b/static/cache/img/logo.svg new file mode 100644 index 0000000..eadecdf --- /dev/null +++ b/static/cache/img/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/cache/img/trash.svg b/static/cache/img/trash.svg new file mode 100644 index 0000000..f24d55b --- /dev/null +++ b/static/cache/img/trash.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/favicons/android-icon-144x144.png b/static/favicons/android-icon-144x144.png new file mode 100644 index 0000000000000000000000000000000000000000..9a1cd142fd5636203a8baa362fa65a31c8acf175 GIT binary patch literal 11158 zcmaL71yEd1@GiQz1a}DTw#c$*aCcqYHMo0lcPGK!H4xlg0t9yr5-hkwfVaO_uj>8p zt-80iW~R=ZZ@OoDq^IXQ(W=Ta=%^&900018PF7MKS|dSCFaY2gS`~Bz0C;c!04F8@fItQSKWG%D46IxNPP*zTmS$Qlboa& z#Cz>5*Cx(l*<(BK!J+wLag!@2T_Prp(Ir_iIfYRnrnOI*^phv)=+~|x6f8NuNB5ZJKc5GJq5CjXdr_o_8K)pruk(KcKZ z>W1724?g2cV02a+Eq313yZw62KNui&o8%n*zhoQPs-sW4M!hH~lzmZwC3_-#(Q};a zQ>61dW61kHER1J>wWaUK2JpYA0;gdScVK}#^v?KgRd{5Sjk)}V%G4OSqFV)Q_2xtf zY0p@fxz?{>@dD~3#G1$MuplJ&V9lM=zMHFjCxAm=WP7*(6CW7X#}T&)u@sf@4ne{}dCO^bc3ZLP?_nH|rkh

V@NvW zfw2sJqpb*x#}FYl^q)f6ehfUicZj0q0796Np6KFE5EcfcAf|F-7J7TJXZE?`1t?u` zT_HNv`Jh0Q!2A0&GcQP z!W~;vAilv_q{@{%y*em2r46MlI@iEL=7C~ruk5z=p8$ISZ#f84Q~>|N0U*neMk zJ_A0K&P-*)8$T-Dt}!!)pZYF*1YWnJt=d~X#Hyr>H>r)2R(X>&dy7aPknR(xjoXv* zGR@37YNG{VToT~0`(r<%X4zS<1$nBwfu=%UamO4�#I0`U1tm!~jK3-J+Ls?;(B0 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 n$p_}=U literal 0 HcmV?d00001 diff --git a/static/favicons/android-icon-192x192.png b/static/favicons/android-icon-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..18aa76b927a95e05b7255e2ee6c1a5819b78a9ae GIT binary patch literal 13646 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 iT0V|Kv|#w08nVCt2`ul^}j|& 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

Z=w&8my=W>y@U9^ z5WA)=Ntrz%HUC(5{N2S4rbq1@$k-UE6`c9t-sG5sr`vF9W1H4!*LR$1u}0f?iEORO zjdJb*wqc$RNvS&Fy-A>a;)-bKDAU^%Jo9xIxiE)r6jjROHJr%fC&mJ&jfS7S6D^~z zB=HqeS)Ofj|J>-QHRHBV@VXF2Qa!6)$SQkA8A#K#TPyGRkO?#h(gt?BGnbU{CLtHe z%}N|tTwH@V^G3BPf2=HF-avkEQ~TUxEbN$w78>TyA*UDFu~#1#?=zXN?t#n)cs z5Ad{0Tx)0VGNC$tro(MT;a6!U-rk6`LsY%L9vpp{5{R4UBvazQ7paALN+OjQueOp6SZie-4-d(w{JYss}D;RV%B3V^ANB8)>Yf~`jPL^j zOAw?#+~Rad(9G@WI0#7Y2cP-iIqH;)PjizPNiA^MRxFQ<{d_p8d_Z>Sl&(~zQN^wM zKMs&0@vxWbzsdkqI9M;&-=O^PVQSl^A9C%Hm{+0?S>a+5Bzu^1=3H9Sg{QF zje{B}jKWS^e&DKP%8tR}%JXr>@-EmLdVOM0WJa~c!tp+z$`#WI2&K_$H@JS?kCjIf1q_`N&EA9K;peoTv6#k zGN28jdb^V|{5$s%36`4Fkmi)C{Y&we^y(M4c22w6q=eDgB{gQ0{AM1|8=_ewMM44Q zIZhX=s{s;1Oc>K*yT2VY^v3ON7H;NfEH>0{}R z0qi|JT|H2uq7GO~I}E`btQ|#M-0j*&*mDUi(_dE4-V1AmLaDe|dtouoo+y+q0rddH z%Ko&8{s*J+R|SPq$2i#8djew8aI~45K7nEUm(Kq%h7LBK_J5J_DlRet!u&5p%K?k= z^mD}k|J{|StFxU#oq_g$=xFH?C_qe7Tue#~0fWIJ_bwd?2-UxI9y$190GN_eYLWa; zLdxJ@DgB2UfUScQhH&YkSZ7Zs7duf~OK%5j7iSOA|Gnj+;?_1uxD`SSiNr|TBCV|9 o(zX~RLK-QFgu|pP#iT_D6(WTGHY^z02r~d0cePcjl`O*k3%Oz1O#lD@ literal 0 HcmV?d00001 diff --git a/static/favicons/android-icon-96x96.png b/static/favicons/android-icon-96x96.png new file mode 100644 index 0000000000000000000000000000000000000000..dd034f13deaaadbc32d6af7cc34d687f51c47f82 GIT binary patch literal 6656 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 L^iSNH3v?6s3ru5CjE5rAP+_ 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 gBL56ckkWHe*| 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

188o^~na7 z0eHE2c{sR5ICuo~dH6&H_(XZR*|@nyxw!{o2qga-fs329gRTGnpP=b?Z8(g8=081n zy4ia9T7I$t*n4@odx~;#Ik;Hb*}#&6l@q7iC%c|m$^sacfJcN^+RVcMh9UkheEt{4$idpn{y&g~ zT3S>Xg!I2aG#p%Py!_p50RMATT<)%RQq6{%{}&$(eHaSBBgn@i#KX_c%^i95;sk@> z{1-lY4god*Zduuk63H`Ili`19GSF24*g81dz+Rop#nsE%&5p~~(#OHd&DE3Z|A?H6 z&&pbu_ai@#u&|AYt?)-HUJ+XxVSW)|L1A8QAxj<+P8bCzY<$NSMBT6+04fTa^7XP7 G;r|2OoY{Z? literal 0 HcmV?d00001 diff --git a/static/favicons/apple-icon-144x144.png b/static/favicons/apple-icon-144x144.png new file mode 100644 index 0000000000000000000000000000000000000000..9a1cd142fd5636203a8baa362fa65a31c8acf175 GIT binary patch literal 11158 zcmaL71yEd1@GiQz1a}DTw#c$*aCcqYHMo0lcPGK!H4xlg0t9yr5-hkwfVaO_uj>8p zt-80iW~R=ZZ@OoDq^IXQ(W=Ta=%^&900018PF7MKS|dSCFaY2gS`~Bz0C;c!04F8@fItQSKWG%D46IxNPP*zTmS$Qlboa& z#Cz>5*Cx(l*<(BK!J+wLag!@2T_Prp(Ir_iIfYRnrnOI*^phv)=+~|x6f8NuNB5ZJKc5GJq5CjXdr_o_8K)pruk(KcKZ z>W1724?g2cV02a+Eq313yZw62KNui&o8%n*zhoQPs-sW4M!hH~lzmZwC3_-#(Q};a zQ>61dW61kHER1J>wWaUK2JpYA0;gdScVK}#^v?KgRd{5Sjk)}V%G4OSqFV)Q_2xtf zY0p@fxz?{>@dD~3#G1$MuplJ&V9lM=zMHFjCxAm=WP7*(6CW7X#}T&)u@sf@4ne{}dCO^bc3ZLP?_nH|rkh

V@NvW zfw2sJqpb*x#}FYl^q)f6ehfUicZj0q0796Np6KFE5EcfcAf|F-7J7TJXZE?`1t?u` zT_HNv`Jh0Q!2A0&GcQP z!W~;vAilv_q{@{%y*em2r46MlI@iEL=7C~ruk5z=p8$ISZ#f84Q~>|N0U*neMk zJ_A0K&P-*)8$T-Dt}!!)pZYF*1YWnJt=d~X#Hyr>H>r)2R(X>&dy7aPknR(xjoXv* zGR@37YNG{VToT~0`(r<%X4zS<1$nBwfu=%UamO4�#I0`U1tm!~jK3-J+Ls?;(B0 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 n$p_}=U literal 0 HcmV?d00001 diff --git a/static/favicons/apple-icon-152x152.png b/static/favicons/apple-icon-152x152.png new file mode 100644 index 0000000000000000000000000000000000000000..7461929d62915c8535ef9e0e6a47291f425d3847 GIT binary patch literal 11981 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�~a0syJlv zP#~@yPK5IpWi3;qi=KHuy&92_P+`6 z9-GZy5$gE*uGTx}XBi+bc`g4CJidE8EVeQz`|GLsbgQ6q;LOlB(GxQu;zG9RI9&3^ zPim^!LJ{(t-K74=xs<{uR?xK+qIjAop#rW(wX-!rNS({CVbc*1Apdi!D%|w`i`XcS zjI=qjPDj0%85yE0{X3$k0R(ec%>K0Gjq&nFIox#@tT zjmiQV(v+C51xvC(Q#Y!ZtSk%)3T%N>Rib#K^BegbE+lIOkVw`hOZ!VlO7DK-Tbf`7 zlky`y_7*N(OkgkHLst20N}n{Y2nbJi7sq{PCRquX269sQ;bO|eViT_y~wGFH8Yo=Z#+XfzP? zRE+S(KWiLm=5fL?XGwc`8q4zhukVwj1*UC;bad1Nk@fxX$>@7u?Dd+m)7H4t*7U(0 zLx%Zf{d8yQhaMtu*QzXcP,y2C*06 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 S?u6|Crzoo?QzvB>{=WbL88poR literal 0 HcmV?d00001 diff --git a/static/favicons/apple-icon-180x180.png b/static/favicons/apple-icon-180x180.png new file mode 100644 index 0000000000000000000000000000000000000000..215398cf111b7fd5d99765932faebaa2de8d71e3 GIT binary patch literal 15194 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 literal 0 HcmV?d00001 diff --git a/static/favicons/apple-icon-57x57.png b/static/favicons/apple-icon-57x57.png new file mode 100644 index 0000000000000000000000000000000000000000..37e11411ef10845cff003b73a5c2d8866d36d840 GIT binary patch literal 3922 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 literal 0 HcmV?d00001 diff --git a/static/favicons/apple-icon-60x60.png b/static/favicons/apple-icon-60x60.png new file mode 100644 index 0000000000000000000000000000000000000000..82be2efbce8f6cf57037ad9f52c3fd514d4b55eb GIT binary patch literal 4101 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 M^v&Sa*W6?N3nRdGUH||9 literal 0 HcmV?d00001 diff --git a/static/favicons/apple-icon-72x72.png b/static/favicons/apple-icon-72x72.png new file mode 100644 index 0000000000000000000000000000000000000000..41d610d4078cbc9298693cddfed2678a286be59f GIT binary patch literal 4910 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

Z=w&8my=W>y@U9^ z5WA)=Ntrz%HUC(5{N2S4rbq1@$k-UE6`c9t-sG5sr`vF9W1H4!*LR$1u}0f?iEORO zjdJb*wqc$RNvS&Fy-A>a;)-bKDAU^%Jo9xIxiE)r6jjROHJr%fC&mJ&jfS7S6D^~z zB=HqeS)Ofj|J>-QHRHBV@VXF2Qa!6)$SQkA8A#K#TPyGRkO?#h(gt?BGnbU{CLtHe z%}N|tTwH@V^G3BPf2=HF-avkEQ~TUxEbN$w78>TyA*UDFu~#1#?=zXN?t#n)cs z5Ad{0Tx)0VGNC$tro(MT;a6!U-rk6`LsY%L9vpp{5{R4UBvazQ7paALN+OjQueOp6SZie-4-d(w{JYss}D;RV%B3V^ANB8)>Yf~`jPL^j zOAw?#+~Rad(9G@WI0#7Y2cP-iIqH;)PjizPNiA^MRxFQ<{d_p8d_Z>Sl&(~zQN^wM zKMs&0@vxWbzsdkqI9M;&-=O^PVQSl^A9C%Hm{+0?S>a+5Bzu^1=3H9Sg{QF zje{B}jKWS^e&DKP%8tR}%JXr>@-EmLdVOM0WJa~c!tp+z$`#WI2&K_$H@JS?kCjIf1q_`N&EA9K;peoTv6#k zGN28jdb^V|{5$s%36`4Fkmi)C{Y&we^y(M4c22w6q=eDgB{gQ0{AM1|8=_ewMM44Q zIZhX=s{s;1Oc>K*yT2VY^v3ON7H;NfEH>0{}R z0qi|JT|H2uq7GO~I}E`btQ|#M-0j*&*mDUi(_dE4-V1AmLaDe|dtouoo+y+q0rddH z%Ko&8{s*J+R|SPq$2i#8djew8aI~45K7nEUm(Kq%h7LBK_J5J_DlRet!u&5p%K?k= z^mD}k|J{|StFxU#oq_g$=xFH?C_qe7Tue#~0fWIJ_bwd?2-UxI9y$190GN_eYLWa; zLdxJ@DgB2UfUScQhH&YkSZ7Zs7duf~OK%5j7iSOA|Gnj+;?_1uxD`SSiNr|TBCV|9 o(zX~RLK-QFgu|pP#iT_D6(WTGHY^z02r~d0cePcjl`O*k3%Oz1O#lD@ literal 0 HcmV?d00001 diff --git a/static/favicons/apple-icon-76x76.png b/static/favicons/apple-icon-76x76.png new file mode 100644 index 0000000000000000000000000000000000000000..b0b6f9902485306ca2d26ac61edfd797088e1a87 GIT binary patch literal 5236 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 F{sW|kkm>*c literal 0 HcmV?d00001 diff --git a/static/favicons/apple-icon-precomposed.png b/static/favicons/apple-icon-precomposed.png new file mode 100644 index 0000000000000000000000000000000000000000..7b5e161aab3a319e69f2cf7f2c1db2ce07afc03d GIT binary patch literal 14188 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 literal 0 HcmV?d00001 diff --git a/static/favicons/apple-icon.png b/static/favicons/apple-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..7b5e161aab3a319e69f2cf7f2c1db2ce07afc03d GIT binary patch literal 14188 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 literal 0 HcmV?d00001 diff --git a/static/favicons/browserconfig.xml b/static/favicons/browserconfig.xml new file mode 100644 index 0000000..c554148 --- /dev/null +++ b/static/favicons/browserconfig.xml @@ -0,0 +1,2 @@ + +#ffffff \ No newline at end of file diff --git a/static/favicons/favicon-16x16.png b/static/favicons/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..bbeb5aef75f822d53011c86750572d58e3277571 GIT binary patch literal 1295 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 L^iPWL37bVsULU|QLLt4X)3KE z1%(!(&^ETDy#y&0gr;f*6>2TCyPNDUyV)ig=WR?8iZ@M|&1QDqZ{EzjS)zb^8yiWk zN9f{iqJu>7d$E|qBzFD6B_M_XGUUr(#$Ma-* z-VO%LRfz|#yw~3HPOWT|u4Y!;)U&Mf<8De-Iz}vh@vfL*-fF7jnJW@s4Tx{QQSyRI z>!n-MId^Vo-Z8o-RJDE7=GH-*L-9@4`Ye7hRV=L+y>qJtkIG!$x30W1?^jEYQXkyK z_-s+#c%}H#(;6l!IAFEjO^)w?pV zfHeebvhNc=;w0CC@ICZoMmgbLlf&R9Ia>N8cEI9jkK9KVSnJGjByMbDaRzb-&w|u? zdMf9B@wtk>b+Euu!2++vK5^*8IEPM7aO6skTN8!tGf)p|ls-L%;T~t!`RPf;Egef7 z4o{ z$d4FJdVxBS&p*rWU*6}~Hf%HcFFkkBd!k9gEa0opDf)X(E&akn@?97%@b#ApJyV!5 zX8lunXEA$d09t@1Fb7QxJlaQW?jBdw#C*|^I_IQMw++_|3f}`YtyO&OLWAOKf+jDI zS`3YjW}UUnXZN*e_Zl=TT5hOmy1GN}z+)HE%WiX8cH^sA(q&hUV`rEhe;0Ou{-Hxw djrb;!8z7nylb6U}KV9;qYnRwzqFLa?egV*VU>^Vg literal 0 HcmV?d00001 diff --git a/static/favicons/manifest.json b/static/favicons/manifest.json new file mode 100644 index 0000000..013d4a6 --- /dev/null +++ b/static/favicons/manifest.json @@ -0,0 +1,41 @@ +{ + "name": "App", + "icons": [ + { + "src": "\/android-icon-36x36.png", + "sizes": "36x36", + "type": "image\/png", + "density": "0.75" + }, + { + "src": "\/android-icon-48x48.png", + "sizes": "48x48", + "type": "image\/png", + "density": "1.0" + }, + { + "src": "\/android-icon-72x72.png", + "sizes": "72x72", + "type": "image\/png", + "density": "1.5" + }, + { + "src": "\/android-icon-96x96.png", + "sizes": "96x96", + "type": "image\/png", + "density": "2.0" + }, + { + "src": "\/android-icon-144x144.png", + "sizes": "144x144", + "type": "image\/png", + "density": "3.0" + }, + { + "src": "\/android-icon-192x192.png", + "sizes": "192x192", + "type": "image\/png", + "density": "4.0" + } + ] +} \ No newline at end of file diff --git a/static/favicons/ms-icon-144x144.png b/static/favicons/ms-icon-144x144.png new file mode 100644 index 0000000000000000000000000000000000000000..9a1cd142fd5636203a8baa362fa65a31c8acf175 GIT binary patch literal 11158 zcmaL71yEd1@GiQz1a}DTw#c$*aCcqYHMo0lcPGK!H4xlg0t9yr5-hkwfVaO_uj>8p zt-80iW~R=ZZ@OoDq^IXQ(W=Ta=%^&900018PF7MKS|dSCFaY2gS`~Bz0C;c!04F8@fItQSKWG%D46IxNPP*zTmS$Qlboa& z#Cz>5*Cx(l*<(BK!J+wLag!@2T_Prp(Ir_iIfYRnrnOI*^phv)=+~|x6f8NuNB5ZJKc5GJq5CjXdr_o_8K)pruk(KcKZ z>W1724?g2cV02a+Eq313yZw62KNui&o8%n*zhoQPs-sW4M!hH~lzmZwC3_-#(Q};a zQ>61dW61kHER1J>wWaUK2JpYA0;gdScVK}#^v?KgRd{5Sjk)}V%G4OSqFV)Q_2xtf zY0p@fxz?{>@dD~3#G1$MuplJ&V9lM=zMHFjCxAm=WP7*(6CW7X#}T&)u@sf@4ne{}dCO^bc3ZLP?_nH|rkh

V@NvW zfw2sJqpb*x#}FYl^q)f6ehfUicZj0q0796Np6KFE5EcfcAf|F-7J7TJXZE?`1t?u` zT_HNv`Jh0Q!2A0&GcQP z!W~;vAilv_q{@{%y*em2r46MlI@iEL=7C~ruk5z=p8$ISZ#f84Q~>|N0U*neMk zJ_A0K&P-*)8$T-Dt}!!)pZYF*1YWnJt=d~X#Hyr>H>r)2R(X>&dy7aPknR(xjoXv* zGR@37YNG{VToT~0`(r<%X4zS<1$nBwfu=%UamO4�#I0`U1tm!~jK3-J+Ls?;(B0 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 n$p_}=U literal 0 HcmV?d00001 diff --git a/static/favicons/ms-icon-150x150.png b/static/favicons/ms-icon-150x150.png new file mode 100644 index 0000000000000000000000000000000000000000..6b8d2a9bcea68a3d782dcefdaf799e936f3f8f9c GIT binary patch literal 11728 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 SRx5D?fTpUhN|lm%$bSH#P{}6% literal 0 HcmV?d00001