├── .github └── workflows │ └── ci.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── Makefile ├── README.md ├── config-example.sh ├── flake.lock ├── flake.nix ├── formie ├── __init__.py ├── auth.py ├── forms.py ├── models.py ├── static │ ├── new_form.js │ └── style.css └── templates │ ├── auth │ ├── login.html │ └── register.html │ ├── base.html │ ├── forms │ ├── creation_successful.html │ ├── form.html │ ├── forms.html │ ├── new.html │ ├── results.html │ └── submission_successful.html │ └── index.html ├── requirements.txt ├── setup-db.py └── src ├── main.rs └── proxy.rs /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: 4 | pull_request: 5 | branches-ignore: 6 | - 'master' 7 | push: 8 | 9 | jobs: 10 | lint: 11 | name: Lint 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | - uses: cachix/install-nix-action@v25 16 | with: 17 | nix_path: nixpkgs=channel:nixos-unstable 18 | - name: setup 19 | run: | 20 | pip install mypy 21 | pip install -r requirements.txt 22 | mypy *.py formie > /dev/null || true 23 | yes | mypy --install-types 24 | - name: run black (formatter) 25 | run: | 26 | nix develop --command bash -c "black --diff --check formie/" 27 | #- name: run mypy 28 | # run: | 29 | # mypy --strict *.py formie 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | # Formie specific 132 | formie/test.db 133 | 134 | 135 | # Added by cargo 136 | 137 | /target 138 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.22.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "ahash" 22 | version = "0.8.11" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" 25 | dependencies = [ 26 | "cfg-if", 27 | "getrandom", 28 | "once_cell", 29 | "version_check", 30 | "zerocopy", 31 | ] 32 | 33 | [[package]] 34 | name = "aho-corasick" 35 | version = "1.1.3" 36 | source = "registry+https://github.com/rust-lang/crates.io-index" 37 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 38 | dependencies = [ 39 | "memchr", 40 | ] 41 | 42 | [[package]] 43 | name = "allocator-api2" 44 | version = "0.2.18" 45 | source = "registry+https://github.com/rust-lang/crates.io-index" 46 | checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" 47 | 48 | [[package]] 49 | name = "async-stream" 50 | version = "0.3.5" 51 | source = "registry+https://github.com/rust-lang/crates.io-index" 52 | checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" 53 | dependencies = [ 54 | "async-stream-impl", 55 | "futures-core", 56 | "pin-project-lite", 57 | ] 58 | 59 | [[package]] 60 | name = "async-stream-impl" 61 | version = "0.3.5" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" 64 | dependencies = [ 65 | "proc-macro2", 66 | "quote", 67 | "syn 2.0.69", 68 | ] 69 | 70 | [[package]] 71 | name = "async-trait" 72 | version = "0.1.81" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" 75 | dependencies = [ 76 | "proc-macro2", 77 | "quote", 78 | "syn 2.0.69", 79 | ] 80 | 81 | [[package]] 82 | name = "atoi" 83 | version = "2.0.0" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" 86 | dependencies = [ 87 | "num-traits", 88 | ] 89 | 90 | [[package]] 91 | name = "atomic" 92 | version = "0.5.3" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" 95 | 96 | [[package]] 97 | name = "atomic" 98 | version = "0.6.0" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994" 101 | dependencies = [ 102 | "bytemuck", 103 | ] 104 | 105 | [[package]] 106 | name = "autocfg" 107 | version = "1.3.0" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" 110 | 111 | [[package]] 112 | name = "backtrace" 113 | version = "0.3.73" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" 116 | dependencies = [ 117 | "addr2line", 118 | "cc", 119 | "cfg-if", 120 | "libc", 121 | "miniz_oxide", 122 | "object", 123 | "rustc-demangle", 124 | ] 125 | 126 | [[package]] 127 | name = "base64" 128 | version = "0.21.7" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" 131 | 132 | [[package]] 133 | name = "base64" 134 | version = "0.22.1" 135 | source = "registry+https://github.com/rust-lang/crates.io-index" 136 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 137 | 138 | [[package]] 139 | name = "base64ct" 140 | version = "1.6.0" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" 143 | 144 | [[package]] 145 | name = "binascii" 146 | version = "0.1.4" 147 | source = "registry+https://github.com/rust-lang/crates.io-index" 148 | checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72" 149 | 150 | [[package]] 151 | name = "bitflags" 152 | version = "1.3.2" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 155 | 156 | [[package]] 157 | name = "bitflags" 158 | version = "2.6.0" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 161 | dependencies = [ 162 | "serde", 163 | ] 164 | 165 | [[package]] 166 | name = "block-buffer" 167 | version = "0.10.4" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 170 | dependencies = [ 171 | "generic-array", 172 | ] 173 | 174 | [[package]] 175 | name = "bumpalo" 176 | version = "3.16.0" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 179 | 180 | [[package]] 181 | name = "bytemuck" 182 | version = "1.16.1" 183 | source = "registry+https://github.com/rust-lang/crates.io-index" 184 | checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" 185 | 186 | [[package]] 187 | name = "byteorder" 188 | version = "1.5.0" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 191 | 192 | [[package]] 193 | name = "bytes" 194 | version = "1.6.0" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" 197 | 198 | [[package]] 199 | name = "cc" 200 | version = "1.0.105" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "5208975e568d83b6b05cc0a063c8e7e9acc2b43bee6da15616a5b73e109d7437" 203 | 204 | [[package]] 205 | name = "cfg-if" 206 | version = "1.0.0" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 209 | 210 | [[package]] 211 | name = "const-oid" 212 | version = "0.9.6" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" 215 | 216 | [[package]] 217 | name = "cookie" 218 | version = "0.18.1" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" 221 | dependencies = [ 222 | "percent-encoding", 223 | "time", 224 | "version_check", 225 | ] 226 | 227 | [[package]] 228 | name = "cpufeatures" 229 | version = "0.2.12" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" 232 | dependencies = [ 233 | "libc", 234 | ] 235 | 236 | [[package]] 237 | name = "crc" 238 | version = "3.2.1" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" 241 | dependencies = [ 242 | "crc-catalog", 243 | ] 244 | 245 | [[package]] 246 | name = "crc-catalog" 247 | version = "2.4.0" 248 | source = "registry+https://github.com/rust-lang/crates.io-index" 249 | checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" 250 | 251 | [[package]] 252 | name = "crossbeam-queue" 253 | version = "0.3.11" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" 256 | dependencies = [ 257 | "crossbeam-utils", 258 | ] 259 | 260 | [[package]] 261 | name = "crossbeam-utils" 262 | version = "0.8.20" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" 265 | 266 | [[package]] 267 | name = "crypto-common" 268 | version = "0.1.6" 269 | source = "registry+https://github.com/rust-lang/crates.io-index" 270 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 271 | dependencies = [ 272 | "generic-array", 273 | "typenum", 274 | ] 275 | 276 | [[package]] 277 | name = "der" 278 | version = "0.7.9" 279 | source = "registry+https://github.com/rust-lang/crates.io-index" 280 | checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" 281 | dependencies = [ 282 | "const-oid", 283 | "pem-rfc7468", 284 | "zeroize", 285 | ] 286 | 287 | [[package]] 288 | name = "deranged" 289 | version = "0.3.11" 290 | source = "registry+https://github.com/rust-lang/crates.io-index" 291 | checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" 292 | dependencies = [ 293 | "powerfmt", 294 | ] 295 | 296 | [[package]] 297 | name = "devise" 298 | version = "0.4.1" 299 | source = "registry+https://github.com/rust-lang/crates.io-index" 300 | checksum = "d6eacefd3f541c66fc61433d65e54e0e46e0a029a819a7dbbc7a7b489e8a85f8" 301 | dependencies = [ 302 | "devise_codegen", 303 | "devise_core", 304 | ] 305 | 306 | [[package]] 307 | name = "devise_codegen" 308 | version = "0.4.1" 309 | source = "registry+https://github.com/rust-lang/crates.io-index" 310 | checksum = "9c8cf4b8dd484ede80fd5c547592c46c3745a617c8af278e2b72bea86b2dfed6" 311 | dependencies = [ 312 | "devise_core", 313 | "quote", 314 | ] 315 | 316 | [[package]] 317 | name = "devise_core" 318 | version = "0.4.1" 319 | source = "registry+https://github.com/rust-lang/crates.io-index" 320 | checksum = "35b50dba0afdca80b187392b24f2499a88c336d5a8493e4b4ccfb608708be56a" 321 | dependencies = [ 322 | "bitflags 2.6.0", 323 | "proc-macro2", 324 | "proc-macro2-diagnostics", 325 | "quote", 326 | "syn 2.0.69", 327 | ] 328 | 329 | [[package]] 330 | name = "digest" 331 | version = "0.10.7" 332 | source = "registry+https://github.com/rust-lang/crates.io-index" 333 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 334 | dependencies = [ 335 | "block-buffer", 336 | "const-oid", 337 | "crypto-common", 338 | "subtle", 339 | ] 340 | 341 | [[package]] 342 | name = "dotenvy" 343 | version = "0.15.7" 344 | source = "registry+https://github.com/rust-lang/crates.io-index" 345 | checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" 346 | 347 | [[package]] 348 | name = "either" 349 | version = "1.13.0" 350 | source = "registry+https://github.com/rust-lang/crates.io-index" 351 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 352 | dependencies = [ 353 | "serde", 354 | ] 355 | 356 | [[package]] 357 | name = "encoding_rs" 358 | version = "0.8.34" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" 361 | dependencies = [ 362 | "cfg-if", 363 | ] 364 | 365 | [[package]] 366 | name = "equivalent" 367 | version = "1.0.1" 368 | source = "registry+https://github.com/rust-lang/crates.io-index" 369 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 370 | 371 | [[package]] 372 | name = "errno" 373 | version = "0.3.9" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" 376 | dependencies = [ 377 | "libc", 378 | "windows-sys 0.52.0", 379 | ] 380 | 381 | [[package]] 382 | name = "etcetera" 383 | version = "0.8.0" 384 | source = "registry+https://github.com/rust-lang/crates.io-index" 385 | checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" 386 | dependencies = [ 387 | "cfg-if", 388 | "home", 389 | "windows-sys 0.48.0", 390 | ] 391 | 392 | [[package]] 393 | name = "event-listener" 394 | version = "2.5.3" 395 | source = "registry+https://github.com/rust-lang/crates.io-index" 396 | checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" 397 | 398 | [[package]] 399 | name = "fastrand" 400 | version = "2.1.0" 401 | source = "registry+https://github.com/rust-lang/crates.io-index" 402 | checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" 403 | 404 | [[package]] 405 | name = "figment" 406 | version = "0.10.19" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "8cb01cd46b0cf372153850f4c6c272d9cbea2da513e07538405148f95bd789f3" 409 | dependencies = [ 410 | "atomic 0.6.0", 411 | "pear", 412 | "serde", 413 | "toml", 414 | "uncased", 415 | "version_check", 416 | ] 417 | 418 | [[package]] 419 | name = "flume" 420 | version = "0.11.0" 421 | source = "registry+https://github.com/rust-lang/crates.io-index" 422 | checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" 423 | dependencies = [ 424 | "futures-core", 425 | "futures-sink", 426 | "spin", 427 | ] 428 | 429 | [[package]] 430 | name = "fnv" 431 | version = "1.0.7" 432 | source = "registry+https://github.com/rust-lang/crates.io-index" 433 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 434 | 435 | [[package]] 436 | name = "form_urlencoded" 437 | version = "1.2.1" 438 | source = "registry+https://github.com/rust-lang/crates.io-index" 439 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 440 | dependencies = [ 441 | "percent-encoding", 442 | ] 443 | 444 | [[package]] 445 | name = "formie" 446 | version = "1.3.2" 447 | dependencies = [ 448 | "libc", 449 | "reqwest", 450 | "rocket", 451 | "rocket_db_pools", 452 | "sqlx", 453 | ] 454 | 455 | [[package]] 456 | name = "futures" 457 | version = "0.3.30" 458 | source = "registry+https://github.com/rust-lang/crates.io-index" 459 | checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" 460 | dependencies = [ 461 | "futures-channel", 462 | "futures-core", 463 | "futures-io", 464 | "futures-sink", 465 | "futures-task", 466 | "futures-util", 467 | ] 468 | 469 | [[package]] 470 | name = "futures-channel" 471 | version = "0.3.30" 472 | source = "registry+https://github.com/rust-lang/crates.io-index" 473 | checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" 474 | dependencies = [ 475 | "futures-core", 476 | "futures-sink", 477 | ] 478 | 479 | [[package]] 480 | name = "futures-core" 481 | version = "0.3.30" 482 | source = "registry+https://github.com/rust-lang/crates.io-index" 483 | checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" 484 | 485 | [[package]] 486 | name = "futures-executor" 487 | version = "0.3.30" 488 | source = "registry+https://github.com/rust-lang/crates.io-index" 489 | checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" 490 | dependencies = [ 491 | "futures-core", 492 | "futures-task", 493 | "futures-util", 494 | ] 495 | 496 | [[package]] 497 | name = "futures-intrusive" 498 | version = "0.5.0" 499 | source = "registry+https://github.com/rust-lang/crates.io-index" 500 | checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" 501 | dependencies = [ 502 | "futures-core", 503 | "lock_api", 504 | "parking_lot", 505 | ] 506 | 507 | [[package]] 508 | name = "futures-io" 509 | version = "0.3.30" 510 | source = "registry+https://github.com/rust-lang/crates.io-index" 511 | checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" 512 | 513 | [[package]] 514 | name = "futures-macro" 515 | version = "0.3.30" 516 | source = "registry+https://github.com/rust-lang/crates.io-index" 517 | checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" 518 | dependencies = [ 519 | "proc-macro2", 520 | "quote", 521 | "syn 2.0.69", 522 | ] 523 | 524 | [[package]] 525 | name = "futures-sink" 526 | version = "0.3.30" 527 | source = "registry+https://github.com/rust-lang/crates.io-index" 528 | checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" 529 | 530 | [[package]] 531 | name = "futures-task" 532 | version = "0.3.30" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" 535 | 536 | [[package]] 537 | name = "futures-util" 538 | version = "0.3.30" 539 | source = "registry+https://github.com/rust-lang/crates.io-index" 540 | checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" 541 | dependencies = [ 542 | "futures-channel", 543 | "futures-core", 544 | "futures-io", 545 | "futures-macro", 546 | "futures-sink", 547 | "futures-task", 548 | "memchr", 549 | "pin-project-lite", 550 | "pin-utils", 551 | "slab", 552 | ] 553 | 554 | [[package]] 555 | name = "generator" 556 | version = "0.7.5" 557 | source = "registry+https://github.com/rust-lang/crates.io-index" 558 | checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" 559 | dependencies = [ 560 | "cc", 561 | "libc", 562 | "log", 563 | "rustversion", 564 | "windows", 565 | ] 566 | 567 | [[package]] 568 | name = "generic-array" 569 | version = "0.14.7" 570 | source = "registry+https://github.com/rust-lang/crates.io-index" 571 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 572 | dependencies = [ 573 | "typenum", 574 | "version_check", 575 | ] 576 | 577 | [[package]] 578 | name = "getrandom" 579 | version = "0.2.15" 580 | source = "registry+https://github.com/rust-lang/crates.io-index" 581 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 582 | dependencies = [ 583 | "cfg-if", 584 | "libc", 585 | "wasi", 586 | ] 587 | 588 | [[package]] 589 | name = "gimli" 590 | version = "0.29.0" 591 | source = "registry+https://github.com/rust-lang/crates.io-index" 592 | checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" 593 | 594 | [[package]] 595 | name = "glob" 596 | version = "0.3.1" 597 | source = "registry+https://github.com/rust-lang/crates.io-index" 598 | checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" 599 | 600 | [[package]] 601 | name = "h2" 602 | version = "0.3.26" 603 | source = "registry+https://github.com/rust-lang/crates.io-index" 604 | checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" 605 | dependencies = [ 606 | "bytes", 607 | "fnv", 608 | "futures-core", 609 | "futures-sink", 610 | "futures-util", 611 | "http 0.2.12", 612 | "indexmap", 613 | "slab", 614 | "tokio", 615 | "tokio-util", 616 | "tracing", 617 | ] 618 | 619 | [[package]] 620 | name = "hashbrown" 621 | version = "0.14.5" 622 | source = "registry+https://github.com/rust-lang/crates.io-index" 623 | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 624 | dependencies = [ 625 | "ahash", 626 | "allocator-api2", 627 | ] 628 | 629 | [[package]] 630 | name = "hashlink" 631 | version = "0.8.4" 632 | source = "registry+https://github.com/rust-lang/crates.io-index" 633 | checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" 634 | dependencies = [ 635 | "hashbrown", 636 | ] 637 | 638 | [[package]] 639 | name = "heck" 640 | version = "0.4.1" 641 | source = "registry+https://github.com/rust-lang/crates.io-index" 642 | checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" 643 | dependencies = [ 644 | "unicode-segmentation", 645 | ] 646 | 647 | [[package]] 648 | name = "hermit-abi" 649 | version = "0.3.9" 650 | source = "registry+https://github.com/rust-lang/crates.io-index" 651 | checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" 652 | 653 | [[package]] 654 | name = "hex" 655 | version = "0.4.3" 656 | source = "registry+https://github.com/rust-lang/crates.io-index" 657 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 658 | 659 | [[package]] 660 | name = "hkdf" 661 | version = "0.12.4" 662 | source = "registry+https://github.com/rust-lang/crates.io-index" 663 | checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" 664 | dependencies = [ 665 | "hmac", 666 | ] 667 | 668 | [[package]] 669 | name = "hmac" 670 | version = "0.12.1" 671 | source = "registry+https://github.com/rust-lang/crates.io-index" 672 | checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" 673 | dependencies = [ 674 | "digest", 675 | ] 676 | 677 | [[package]] 678 | name = "home" 679 | version = "0.5.9" 680 | source = "registry+https://github.com/rust-lang/crates.io-index" 681 | checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" 682 | dependencies = [ 683 | "windows-sys 0.52.0", 684 | ] 685 | 686 | [[package]] 687 | name = "http" 688 | version = "0.2.12" 689 | source = "registry+https://github.com/rust-lang/crates.io-index" 690 | checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" 691 | dependencies = [ 692 | "bytes", 693 | "fnv", 694 | "itoa", 695 | ] 696 | 697 | [[package]] 698 | name = "http" 699 | version = "1.1.0" 700 | source = "registry+https://github.com/rust-lang/crates.io-index" 701 | checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" 702 | dependencies = [ 703 | "bytes", 704 | "fnv", 705 | "itoa", 706 | ] 707 | 708 | [[package]] 709 | name = "http-body" 710 | version = "0.4.6" 711 | source = "registry+https://github.com/rust-lang/crates.io-index" 712 | checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" 713 | dependencies = [ 714 | "bytes", 715 | "http 0.2.12", 716 | "pin-project-lite", 717 | ] 718 | 719 | [[package]] 720 | name = "http-body" 721 | version = "1.0.0" 722 | source = "registry+https://github.com/rust-lang/crates.io-index" 723 | checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" 724 | dependencies = [ 725 | "bytes", 726 | "http 1.1.0", 727 | ] 728 | 729 | [[package]] 730 | name = "http-body-util" 731 | version = "0.1.2" 732 | source = "registry+https://github.com/rust-lang/crates.io-index" 733 | checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" 734 | dependencies = [ 735 | "bytes", 736 | "futures-util", 737 | "http 1.1.0", 738 | "http-body 1.0.0", 739 | "pin-project-lite", 740 | ] 741 | 742 | [[package]] 743 | name = "httparse" 744 | version = "1.9.4" 745 | source = "registry+https://github.com/rust-lang/crates.io-index" 746 | checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" 747 | 748 | [[package]] 749 | name = "httpdate" 750 | version = "1.0.3" 751 | source = "registry+https://github.com/rust-lang/crates.io-index" 752 | checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" 753 | 754 | [[package]] 755 | name = "hyper" 756 | version = "0.14.29" 757 | source = "registry+https://github.com/rust-lang/crates.io-index" 758 | checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33" 759 | dependencies = [ 760 | "bytes", 761 | "futures-channel", 762 | "futures-core", 763 | "futures-util", 764 | "h2", 765 | "http 0.2.12", 766 | "http-body 0.4.6", 767 | "httparse", 768 | "httpdate", 769 | "itoa", 770 | "pin-project-lite", 771 | "socket2", 772 | "tokio", 773 | "tower-service", 774 | "tracing", 775 | "want", 776 | ] 777 | 778 | [[package]] 779 | name = "hyper" 780 | version = "1.4.0" 781 | source = "registry+https://github.com/rust-lang/crates.io-index" 782 | checksum = "c4fe55fb7a772d59a5ff1dfbff4fe0258d19b89fec4b233e75d35d5d2316badc" 783 | dependencies = [ 784 | "bytes", 785 | "futures-channel", 786 | "futures-util", 787 | "http 1.1.0", 788 | "http-body 1.0.0", 789 | "httparse", 790 | "itoa", 791 | "pin-project-lite", 792 | "smallvec", 793 | "tokio", 794 | "want", 795 | ] 796 | 797 | [[package]] 798 | name = "hyper-util" 799 | version = "0.1.6" 800 | source = "registry+https://github.com/rust-lang/crates.io-index" 801 | checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" 802 | dependencies = [ 803 | "bytes", 804 | "futures-channel", 805 | "futures-util", 806 | "http 1.1.0", 807 | "http-body 1.0.0", 808 | "hyper 1.4.0", 809 | "pin-project-lite", 810 | "socket2", 811 | "tokio", 812 | "tower", 813 | "tower-service", 814 | "tracing", 815 | ] 816 | 817 | [[package]] 818 | name = "idna" 819 | version = "0.5.0" 820 | source = "registry+https://github.com/rust-lang/crates.io-index" 821 | checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" 822 | dependencies = [ 823 | "unicode-bidi", 824 | "unicode-normalization", 825 | ] 826 | 827 | [[package]] 828 | name = "indexmap" 829 | version = "2.2.6" 830 | source = "registry+https://github.com/rust-lang/crates.io-index" 831 | checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" 832 | dependencies = [ 833 | "equivalent", 834 | "hashbrown", 835 | "serde", 836 | ] 837 | 838 | [[package]] 839 | name = "inlinable_string" 840 | version = "0.1.15" 841 | source = "registry+https://github.com/rust-lang/crates.io-index" 842 | checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" 843 | 844 | [[package]] 845 | name = "ipnet" 846 | version = "2.9.0" 847 | source = "registry+https://github.com/rust-lang/crates.io-index" 848 | checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" 849 | 850 | [[package]] 851 | name = "is-terminal" 852 | version = "0.4.12" 853 | source = "registry+https://github.com/rust-lang/crates.io-index" 854 | checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" 855 | dependencies = [ 856 | "hermit-abi", 857 | "libc", 858 | "windows-sys 0.52.0", 859 | ] 860 | 861 | [[package]] 862 | name = "itoa" 863 | version = "1.0.11" 864 | source = "registry+https://github.com/rust-lang/crates.io-index" 865 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 866 | 867 | [[package]] 868 | name = "js-sys" 869 | version = "0.3.69" 870 | source = "registry+https://github.com/rust-lang/crates.io-index" 871 | checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" 872 | dependencies = [ 873 | "wasm-bindgen", 874 | ] 875 | 876 | [[package]] 877 | name = "lazy_static" 878 | version = "1.5.0" 879 | source = "registry+https://github.com/rust-lang/crates.io-index" 880 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 881 | dependencies = [ 882 | "spin", 883 | ] 884 | 885 | [[package]] 886 | name = "libc" 887 | version = "0.2.155" 888 | source = "registry+https://github.com/rust-lang/crates.io-index" 889 | checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" 890 | 891 | [[package]] 892 | name = "libm" 893 | version = "0.2.8" 894 | source = "registry+https://github.com/rust-lang/crates.io-index" 895 | checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" 896 | 897 | [[package]] 898 | name = "libsqlite3-sys" 899 | version = "0.27.0" 900 | source = "registry+https://github.com/rust-lang/crates.io-index" 901 | checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" 902 | dependencies = [ 903 | "cc", 904 | "pkg-config", 905 | "vcpkg", 906 | ] 907 | 908 | [[package]] 909 | name = "linux-raw-sys" 910 | version = "0.4.14" 911 | source = "registry+https://github.com/rust-lang/crates.io-index" 912 | checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" 913 | 914 | [[package]] 915 | name = "lock_api" 916 | version = "0.4.12" 917 | source = "registry+https://github.com/rust-lang/crates.io-index" 918 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 919 | dependencies = [ 920 | "autocfg", 921 | "scopeguard", 922 | ] 923 | 924 | [[package]] 925 | name = "log" 926 | version = "0.4.22" 927 | source = "registry+https://github.com/rust-lang/crates.io-index" 928 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 929 | 930 | [[package]] 931 | name = "loom" 932 | version = "0.5.6" 933 | source = "registry+https://github.com/rust-lang/crates.io-index" 934 | checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" 935 | dependencies = [ 936 | "cfg-if", 937 | "generator", 938 | "scoped-tls", 939 | "serde", 940 | "serde_json", 941 | "tracing", 942 | "tracing-subscriber", 943 | ] 944 | 945 | [[package]] 946 | name = "matchers" 947 | version = "0.1.0" 948 | source = "registry+https://github.com/rust-lang/crates.io-index" 949 | checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" 950 | dependencies = [ 951 | "regex-automata 0.1.10", 952 | ] 953 | 954 | [[package]] 955 | name = "md-5" 956 | version = "0.10.6" 957 | source = "registry+https://github.com/rust-lang/crates.io-index" 958 | checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" 959 | dependencies = [ 960 | "cfg-if", 961 | "digest", 962 | ] 963 | 964 | [[package]] 965 | name = "memchr" 966 | version = "2.7.4" 967 | source = "registry+https://github.com/rust-lang/crates.io-index" 968 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 969 | 970 | [[package]] 971 | name = "mime" 972 | version = "0.3.17" 973 | source = "registry+https://github.com/rust-lang/crates.io-index" 974 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 975 | 976 | [[package]] 977 | name = "minimal-lexical" 978 | version = "0.2.1" 979 | source = "registry+https://github.com/rust-lang/crates.io-index" 980 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 981 | 982 | [[package]] 983 | name = "miniz_oxide" 984 | version = "0.7.4" 985 | source = "registry+https://github.com/rust-lang/crates.io-index" 986 | checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" 987 | dependencies = [ 988 | "adler", 989 | ] 990 | 991 | [[package]] 992 | name = "mio" 993 | version = "0.8.11" 994 | source = "registry+https://github.com/rust-lang/crates.io-index" 995 | checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" 996 | dependencies = [ 997 | "libc", 998 | "wasi", 999 | "windows-sys 0.48.0", 1000 | ] 1001 | 1002 | [[package]] 1003 | name = "multer" 1004 | version = "3.1.0" 1005 | source = "registry+https://github.com/rust-lang/crates.io-index" 1006 | checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" 1007 | dependencies = [ 1008 | "bytes", 1009 | "encoding_rs", 1010 | "futures-util", 1011 | "http 1.1.0", 1012 | "httparse", 1013 | "memchr", 1014 | "mime", 1015 | "spin", 1016 | "tokio", 1017 | "tokio-util", 1018 | "version_check", 1019 | ] 1020 | 1021 | [[package]] 1022 | name = "nom" 1023 | version = "7.1.3" 1024 | source = "registry+https://github.com/rust-lang/crates.io-index" 1025 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 1026 | dependencies = [ 1027 | "memchr", 1028 | "minimal-lexical", 1029 | ] 1030 | 1031 | [[package]] 1032 | name = "nu-ansi-term" 1033 | version = "0.46.0" 1034 | source = "registry+https://github.com/rust-lang/crates.io-index" 1035 | checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" 1036 | dependencies = [ 1037 | "overload", 1038 | "winapi", 1039 | ] 1040 | 1041 | [[package]] 1042 | name = "num-bigint-dig" 1043 | version = "0.8.4" 1044 | source = "registry+https://github.com/rust-lang/crates.io-index" 1045 | checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" 1046 | dependencies = [ 1047 | "byteorder", 1048 | "lazy_static", 1049 | "libm", 1050 | "num-integer", 1051 | "num-iter", 1052 | "num-traits", 1053 | "rand", 1054 | "smallvec", 1055 | "zeroize", 1056 | ] 1057 | 1058 | [[package]] 1059 | name = "num-conv" 1060 | version = "0.1.0" 1061 | source = "registry+https://github.com/rust-lang/crates.io-index" 1062 | checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 1063 | 1064 | [[package]] 1065 | name = "num-integer" 1066 | version = "0.1.46" 1067 | source = "registry+https://github.com/rust-lang/crates.io-index" 1068 | checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" 1069 | dependencies = [ 1070 | "num-traits", 1071 | ] 1072 | 1073 | [[package]] 1074 | name = "num-iter" 1075 | version = "0.1.45" 1076 | source = "registry+https://github.com/rust-lang/crates.io-index" 1077 | checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" 1078 | dependencies = [ 1079 | "autocfg", 1080 | "num-integer", 1081 | "num-traits", 1082 | ] 1083 | 1084 | [[package]] 1085 | name = "num-traits" 1086 | version = "0.2.19" 1087 | source = "registry+https://github.com/rust-lang/crates.io-index" 1088 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 1089 | dependencies = [ 1090 | "autocfg", 1091 | "libm", 1092 | ] 1093 | 1094 | [[package]] 1095 | name = "num_cpus" 1096 | version = "1.16.0" 1097 | source = "registry+https://github.com/rust-lang/crates.io-index" 1098 | checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" 1099 | dependencies = [ 1100 | "hermit-abi", 1101 | "libc", 1102 | ] 1103 | 1104 | [[package]] 1105 | name = "object" 1106 | version = "0.36.1" 1107 | source = "registry+https://github.com/rust-lang/crates.io-index" 1108 | checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" 1109 | dependencies = [ 1110 | "memchr", 1111 | ] 1112 | 1113 | [[package]] 1114 | name = "once_cell" 1115 | version = "1.19.0" 1116 | source = "registry+https://github.com/rust-lang/crates.io-index" 1117 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 1118 | 1119 | [[package]] 1120 | name = "overload" 1121 | version = "0.1.1" 1122 | source = "registry+https://github.com/rust-lang/crates.io-index" 1123 | checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" 1124 | 1125 | [[package]] 1126 | name = "parking_lot" 1127 | version = "0.12.3" 1128 | source = "registry+https://github.com/rust-lang/crates.io-index" 1129 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 1130 | dependencies = [ 1131 | "lock_api", 1132 | "parking_lot_core", 1133 | ] 1134 | 1135 | [[package]] 1136 | name = "parking_lot_core" 1137 | version = "0.9.10" 1138 | source = "registry+https://github.com/rust-lang/crates.io-index" 1139 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 1140 | dependencies = [ 1141 | "cfg-if", 1142 | "libc", 1143 | "redox_syscall 0.5.2", 1144 | "smallvec", 1145 | "windows-targets 0.52.6", 1146 | ] 1147 | 1148 | [[package]] 1149 | name = "paste" 1150 | version = "1.0.15" 1151 | source = "registry+https://github.com/rust-lang/crates.io-index" 1152 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 1153 | 1154 | [[package]] 1155 | name = "pear" 1156 | version = "0.2.9" 1157 | source = "registry+https://github.com/rust-lang/crates.io-index" 1158 | checksum = "bdeeaa00ce488657faba8ebf44ab9361f9365a97bd39ffb8a60663f57ff4b467" 1159 | dependencies = [ 1160 | "inlinable_string", 1161 | "pear_codegen", 1162 | "yansi", 1163 | ] 1164 | 1165 | [[package]] 1166 | name = "pear_codegen" 1167 | version = "0.2.9" 1168 | source = "registry+https://github.com/rust-lang/crates.io-index" 1169 | checksum = "4bab5b985dc082b345f812b7df84e1bef27e7207b39e448439ba8bd69c93f147" 1170 | dependencies = [ 1171 | "proc-macro2", 1172 | "proc-macro2-diagnostics", 1173 | "quote", 1174 | "syn 2.0.69", 1175 | ] 1176 | 1177 | [[package]] 1178 | name = "pem-rfc7468" 1179 | version = "0.7.0" 1180 | source = "registry+https://github.com/rust-lang/crates.io-index" 1181 | checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" 1182 | dependencies = [ 1183 | "base64ct", 1184 | ] 1185 | 1186 | [[package]] 1187 | name = "percent-encoding" 1188 | version = "2.3.1" 1189 | source = "registry+https://github.com/rust-lang/crates.io-index" 1190 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 1191 | 1192 | [[package]] 1193 | name = "pin-project" 1194 | version = "1.1.5" 1195 | source = "registry+https://github.com/rust-lang/crates.io-index" 1196 | checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" 1197 | dependencies = [ 1198 | "pin-project-internal", 1199 | ] 1200 | 1201 | [[package]] 1202 | name = "pin-project-internal" 1203 | version = "1.1.5" 1204 | source = "registry+https://github.com/rust-lang/crates.io-index" 1205 | checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" 1206 | dependencies = [ 1207 | "proc-macro2", 1208 | "quote", 1209 | "syn 2.0.69", 1210 | ] 1211 | 1212 | [[package]] 1213 | name = "pin-project-lite" 1214 | version = "0.2.14" 1215 | source = "registry+https://github.com/rust-lang/crates.io-index" 1216 | checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" 1217 | 1218 | [[package]] 1219 | name = "pin-utils" 1220 | version = "0.1.0" 1221 | source = "registry+https://github.com/rust-lang/crates.io-index" 1222 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1223 | 1224 | [[package]] 1225 | name = "pkcs1" 1226 | version = "0.7.5" 1227 | source = "registry+https://github.com/rust-lang/crates.io-index" 1228 | checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" 1229 | dependencies = [ 1230 | "der", 1231 | "pkcs8", 1232 | "spki", 1233 | ] 1234 | 1235 | [[package]] 1236 | name = "pkcs8" 1237 | version = "0.10.2" 1238 | source = "registry+https://github.com/rust-lang/crates.io-index" 1239 | checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" 1240 | dependencies = [ 1241 | "der", 1242 | "spki", 1243 | ] 1244 | 1245 | [[package]] 1246 | name = "pkg-config" 1247 | version = "0.3.30" 1248 | source = "registry+https://github.com/rust-lang/crates.io-index" 1249 | checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" 1250 | 1251 | [[package]] 1252 | name = "powerfmt" 1253 | version = "0.2.0" 1254 | source = "registry+https://github.com/rust-lang/crates.io-index" 1255 | checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 1256 | 1257 | [[package]] 1258 | name = "ppv-lite86" 1259 | version = "0.2.17" 1260 | source = "registry+https://github.com/rust-lang/crates.io-index" 1261 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 1262 | 1263 | [[package]] 1264 | name = "proc-macro2" 1265 | version = "1.0.86" 1266 | source = "registry+https://github.com/rust-lang/crates.io-index" 1267 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" 1268 | dependencies = [ 1269 | "unicode-ident", 1270 | ] 1271 | 1272 | [[package]] 1273 | name = "proc-macro2-diagnostics" 1274 | version = "0.10.1" 1275 | source = "registry+https://github.com/rust-lang/crates.io-index" 1276 | checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" 1277 | dependencies = [ 1278 | "proc-macro2", 1279 | "quote", 1280 | "syn 2.0.69", 1281 | "version_check", 1282 | "yansi", 1283 | ] 1284 | 1285 | [[package]] 1286 | name = "quote" 1287 | version = "1.0.36" 1288 | source = "registry+https://github.com/rust-lang/crates.io-index" 1289 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 1290 | dependencies = [ 1291 | "proc-macro2", 1292 | ] 1293 | 1294 | [[package]] 1295 | name = "rand" 1296 | version = "0.8.5" 1297 | source = "registry+https://github.com/rust-lang/crates.io-index" 1298 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1299 | dependencies = [ 1300 | "libc", 1301 | "rand_chacha", 1302 | "rand_core", 1303 | ] 1304 | 1305 | [[package]] 1306 | name = "rand_chacha" 1307 | version = "0.3.1" 1308 | source = "registry+https://github.com/rust-lang/crates.io-index" 1309 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1310 | dependencies = [ 1311 | "ppv-lite86", 1312 | "rand_core", 1313 | ] 1314 | 1315 | [[package]] 1316 | name = "rand_core" 1317 | version = "0.6.4" 1318 | source = "registry+https://github.com/rust-lang/crates.io-index" 1319 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1320 | dependencies = [ 1321 | "getrandom", 1322 | ] 1323 | 1324 | [[package]] 1325 | name = "redox_syscall" 1326 | version = "0.4.1" 1327 | source = "registry+https://github.com/rust-lang/crates.io-index" 1328 | checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" 1329 | dependencies = [ 1330 | "bitflags 1.3.2", 1331 | ] 1332 | 1333 | [[package]] 1334 | name = "redox_syscall" 1335 | version = "0.5.2" 1336 | source = "registry+https://github.com/rust-lang/crates.io-index" 1337 | checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" 1338 | dependencies = [ 1339 | "bitflags 2.6.0", 1340 | ] 1341 | 1342 | [[package]] 1343 | name = "ref-cast" 1344 | version = "1.0.23" 1345 | source = "registry+https://github.com/rust-lang/crates.io-index" 1346 | checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931" 1347 | dependencies = [ 1348 | "ref-cast-impl", 1349 | ] 1350 | 1351 | [[package]] 1352 | name = "ref-cast-impl" 1353 | version = "1.0.23" 1354 | source = "registry+https://github.com/rust-lang/crates.io-index" 1355 | checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" 1356 | dependencies = [ 1357 | "proc-macro2", 1358 | "quote", 1359 | "syn 2.0.69", 1360 | ] 1361 | 1362 | [[package]] 1363 | name = "regex" 1364 | version = "1.10.5" 1365 | source = "registry+https://github.com/rust-lang/crates.io-index" 1366 | checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" 1367 | dependencies = [ 1368 | "aho-corasick", 1369 | "memchr", 1370 | "regex-automata 0.4.7", 1371 | "regex-syntax 0.8.4", 1372 | ] 1373 | 1374 | [[package]] 1375 | name = "regex-automata" 1376 | version = "0.1.10" 1377 | source = "registry+https://github.com/rust-lang/crates.io-index" 1378 | checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" 1379 | dependencies = [ 1380 | "regex-syntax 0.6.29", 1381 | ] 1382 | 1383 | [[package]] 1384 | name = "regex-automata" 1385 | version = "0.4.7" 1386 | source = "registry+https://github.com/rust-lang/crates.io-index" 1387 | checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" 1388 | dependencies = [ 1389 | "aho-corasick", 1390 | "memchr", 1391 | "regex-syntax 0.8.4", 1392 | ] 1393 | 1394 | [[package]] 1395 | name = "regex-syntax" 1396 | version = "0.6.29" 1397 | source = "registry+https://github.com/rust-lang/crates.io-index" 1398 | checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" 1399 | 1400 | [[package]] 1401 | name = "regex-syntax" 1402 | version = "0.8.4" 1403 | source = "registry+https://github.com/rust-lang/crates.io-index" 1404 | checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" 1405 | 1406 | [[package]] 1407 | name = "reqwest" 1408 | version = "0.12.5" 1409 | source = "registry+https://github.com/rust-lang/crates.io-index" 1410 | checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" 1411 | dependencies = [ 1412 | "base64 0.22.1", 1413 | "bytes", 1414 | "futures-core", 1415 | "futures-util", 1416 | "http 1.1.0", 1417 | "http-body 1.0.0", 1418 | "http-body-util", 1419 | "hyper 1.4.0", 1420 | "hyper-util", 1421 | "ipnet", 1422 | "js-sys", 1423 | "log", 1424 | "mime", 1425 | "once_cell", 1426 | "percent-encoding", 1427 | "pin-project-lite", 1428 | "serde", 1429 | "serde_json", 1430 | "serde_urlencoded", 1431 | "sync_wrapper", 1432 | "tokio", 1433 | "tokio-util", 1434 | "tower-service", 1435 | "url", 1436 | "wasm-bindgen", 1437 | "wasm-bindgen-futures", 1438 | "wasm-streams", 1439 | "web-sys", 1440 | "winreg", 1441 | ] 1442 | 1443 | [[package]] 1444 | name = "ring" 1445 | version = "0.17.8" 1446 | source = "registry+https://github.com/rust-lang/crates.io-index" 1447 | checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" 1448 | dependencies = [ 1449 | "cc", 1450 | "cfg-if", 1451 | "getrandom", 1452 | "libc", 1453 | "spin", 1454 | "untrusted", 1455 | "windows-sys 0.52.0", 1456 | ] 1457 | 1458 | [[package]] 1459 | name = "rocket" 1460 | version = "0.5.1" 1461 | source = "registry+https://github.com/rust-lang/crates.io-index" 1462 | checksum = "a516907296a31df7dc04310e7043b61d71954d703b603cc6867a026d7e72d73f" 1463 | dependencies = [ 1464 | "async-stream", 1465 | "async-trait", 1466 | "atomic 0.5.3", 1467 | "binascii", 1468 | "bytes", 1469 | "either", 1470 | "figment", 1471 | "futures", 1472 | "indexmap", 1473 | "log", 1474 | "memchr", 1475 | "multer", 1476 | "num_cpus", 1477 | "parking_lot", 1478 | "pin-project-lite", 1479 | "rand", 1480 | "ref-cast", 1481 | "rocket_codegen", 1482 | "rocket_http", 1483 | "serde", 1484 | "state", 1485 | "tempfile", 1486 | "time", 1487 | "tokio", 1488 | "tokio-stream", 1489 | "tokio-util", 1490 | "ubyte", 1491 | "version_check", 1492 | "yansi", 1493 | ] 1494 | 1495 | [[package]] 1496 | name = "rocket_codegen" 1497 | version = "0.5.1" 1498 | source = "registry+https://github.com/rust-lang/crates.io-index" 1499 | checksum = "575d32d7ec1a9770108c879fc7c47815a80073f96ca07ff9525a94fcede1dd46" 1500 | dependencies = [ 1501 | "devise", 1502 | "glob", 1503 | "indexmap", 1504 | "proc-macro2", 1505 | "quote", 1506 | "rocket_http", 1507 | "syn 2.0.69", 1508 | "unicode-xid", 1509 | "version_check", 1510 | ] 1511 | 1512 | [[package]] 1513 | name = "rocket_db_pools" 1514 | version = "0.2.0" 1515 | source = "registry+https://github.com/rust-lang/crates.io-index" 1516 | checksum = "c6578b2740ceee3e78bff63fe9299d964b7e68318446cdcb9af3b9cab46e1e9d" 1517 | dependencies = [ 1518 | "rocket", 1519 | "rocket_db_pools_codegen", 1520 | "sqlx", 1521 | "version_check", 1522 | ] 1523 | 1524 | [[package]] 1525 | name = "rocket_db_pools_codegen" 1526 | version = "0.2.0" 1527 | source = "registry+https://github.com/rust-lang/crates.io-index" 1528 | checksum = "842e859f2e87a23efc0f81e25756c0fb43f18726e62daf99da7ea19fbc56cebd" 1529 | dependencies = [ 1530 | "devise", 1531 | "quote", 1532 | ] 1533 | 1534 | [[package]] 1535 | name = "rocket_http" 1536 | version = "0.5.1" 1537 | source = "registry+https://github.com/rust-lang/crates.io-index" 1538 | checksum = "e274915a20ee3065f611c044bd63c40757396b6dbc057d6046aec27f14f882b9" 1539 | dependencies = [ 1540 | "cookie", 1541 | "either", 1542 | "futures", 1543 | "http 0.2.12", 1544 | "hyper 0.14.29", 1545 | "indexmap", 1546 | "log", 1547 | "memchr", 1548 | "pear", 1549 | "percent-encoding", 1550 | "pin-project-lite", 1551 | "ref-cast", 1552 | "serde", 1553 | "smallvec", 1554 | "stable-pattern", 1555 | "state", 1556 | "time", 1557 | "tokio", 1558 | "uncased", 1559 | ] 1560 | 1561 | [[package]] 1562 | name = "rsa" 1563 | version = "0.9.6" 1564 | source = "registry+https://github.com/rust-lang/crates.io-index" 1565 | checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" 1566 | dependencies = [ 1567 | "const-oid", 1568 | "digest", 1569 | "num-bigint-dig", 1570 | "num-integer", 1571 | "num-traits", 1572 | "pkcs1", 1573 | "pkcs8", 1574 | "rand_core", 1575 | "signature", 1576 | "spki", 1577 | "subtle", 1578 | "zeroize", 1579 | ] 1580 | 1581 | [[package]] 1582 | name = "rustc-demangle" 1583 | version = "0.1.24" 1584 | source = "registry+https://github.com/rust-lang/crates.io-index" 1585 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 1586 | 1587 | [[package]] 1588 | name = "rustix" 1589 | version = "0.38.34" 1590 | source = "registry+https://github.com/rust-lang/crates.io-index" 1591 | checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" 1592 | dependencies = [ 1593 | "bitflags 2.6.0", 1594 | "errno", 1595 | "libc", 1596 | "linux-raw-sys", 1597 | "windows-sys 0.52.0", 1598 | ] 1599 | 1600 | [[package]] 1601 | name = "rustls" 1602 | version = "0.21.12" 1603 | source = "registry+https://github.com/rust-lang/crates.io-index" 1604 | checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" 1605 | dependencies = [ 1606 | "ring", 1607 | "rustls-webpki", 1608 | "sct", 1609 | ] 1610 | 1611 | [[package]] 1612 | name = "rustls-pemfile" 1613 | version = "1.0.4" 1614 | source = "registry+https://github.com/rust-lang/crates.io-index" 1615 | checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" 1616 | dependencies = [ 1617 | "base64 0.21.7", 1618 | ] 1619 | 1620 | [[package]] 1621 | name = "rustls-webpki" 1622 | version = "0.101.7" 1623 | source = "registry+https://github.com/rust-lang/crates.io-index" 1624 | checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" 1625 | dependencies = [ 1626 | "ring", 1627 | "untrusted", 1628 | ] 1629 | 1630 | [[package]] 1631 | name = "rustversion" 1632 | version = "1.0.17" 1633 | source = "registry+https://github.com/rust-lang/crates.io-index" 1634 | checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" 1635 | 1636 | [[package]] 1637 | name = "ryu" 1638 | version = "1.0.18" 1639 | source = "registry+https://github.com/rust-lang/crates.io-index" 1640 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 1641 | 1642 | [[package]] 1643 | name = "scoped-tls" 1644 | version = "1.0.1" 1645 | source = "registry+https://github.com/rust-lang/crates.io-index" 1646 | checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" 1647 | 1648 | [[package]] 1649 | name = "scopeguard" 1650 | version = "1.2.0" 1651 | source = "registry+https://github.com/rust-lang/crates.io-index" 1652 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1653 | 1654 | [[package]] 1655 | name = "sct" 1656 | version = "0.7.1" 1657 | source = "registry+https://github.com/rust-lang/crates.io-index" 1658 | checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" 1659 | dependencies = [ 1660 | "ring", 1661 | "untrusted", 1662 | ] 1663 | 1664 | [[package]] 1665 | name = "serde" 1666 | version = "1.0.204" 1667 | source = "registry+https://github.com/rust-lang/crates.io-index" 1668 | checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" 1669 | dependencies = [ 1670 | "serde_derive", 1671 | ] 1672 | 1673 | [[package]] 1674 | name = "serde_derive" 1675 | version = "1.0.204" 1676 | source = "registry+https://github.com/rust-lang/crates.io-index" 1677 | checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" 1678 | dependencies = [ 1679 | "proc-macro2", 1680 | "quote", 1681 | "syn 2.0.69", 1682 | ] 1683 | 1684 | [[package]] 1685 | name = "serde_json" 1686 | version = "1.0.120" 1687 | source = "registry+https://github.com/rust-lang/crates.io-index" 1688 | checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" 1689 | dependencies = [ 1690 | "itoa", 1691 | "ryu", 1692 | "serde", 1693 | ] 1694 | 1695 | [[package]] 1696 | name = "serde_spanned" 1697 | version = "0.6.6" 1698 | source = "registry+https://github.com/rust-lang/crates.io-index" 1699 | checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" 1700 | dependencies = [ 1701 | "serde", 1702 | ] 1703 | 1704 | [[package]] 1705 | name = "serde_urlencoded" 1706 | version = "0.7.1" 1707 | source = "registry+https://github.com/rust-lang/crates.io-index" 1708 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1709 | dependencies = [ 1710 | "form_urlencoded", 1711 | "itoa", 1712 | "ryu", 1713 | "serde", 1714 | ] 1715 | 1716 | [[package]] 1717 | name = "sha1" 1718 | version = "0.10.6" 1719 | source = "registry+https://github.com/rust-lang/crates.io-index" 1720 | checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" 1721 | dependencies = [ 1722 | "cfg-if", 1723 | "cpufeatures", 1724 | "digest", 1725 | ] 1726 | 1727 | [[package]] 1728 | name = "sha2" 1729 | version = "0.10.8" 1730 | source = "registry+https://github.com/rust-lang/crates.io-index" 1731 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 1732 | dependencies = [ 1733 | "cfg-if", 1734 | "cpufeatures", 1735 | "digest", 1736 | ] 1737 | 1738 | [[package]] 1739 | name = "sharded-slab" 1740 | version = "0.1.7" 1741 | source = "registry+https://github.com/rust-lang/crates.io-index" 1742 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 1743 | dependencies = [ 1744 | "lazy_static", 1745 | ] 1746 | 1747 | [[package]] 1748 | name = "signal-hook-registry" 1749 | version = "1.4.2" 1750 | source = "registry+https://github.com/rust-lang/crates.io-index" 1751 | checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" 1752 | dependencies = [ 1753 | "libc", 1754 | ] 1755 | 1756 | [[package]] 1757 | name = "signature" 1758 | version = "2.2.0" 1759 | source = "registry+https://github.com/rust-lang/crates.io-index" 1760 | checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" 1761 | dependencies = [ 1762 | "digest", 1763 | "rand_core", 1764 | ] 1765 | 1766 | [[package]] 1767 | name = "slab" 1768 | version = "0.4.9" 1769 | source = "registry+https://github.com/rust-lang/crates.io-index" 1770 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 1771 | dependencies = [ 1772 | "autocfg", 1773 | ] 1774 | 1775 | [[package]] 1776 | name = "smallvec" 1777 | version = "1.13.2" 1778 | source = "registry+https://github.com/rust-lang/crates.io-index" 1779 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 1780 | 1781 | [[package]] 1782 | name = "socket2" 1783 | version = "0.5.7" 1784 | source = "registry+https://github.com/rust-lang/crates.io-index" 1785 | checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" 1786 | dependencies = [ 1787 | "libc", 1788 | "windows-sys 0.52.0", 1789 | ] 1790 | 1791 | [[package]] 1792 | name = "spin" 1793 | version = "0.9.8" 1794 | source = "registry+https://github.com/rust-lang/crates.io-index" 1795 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 1796 | dependencies = [ 1797 | "lock_api", 1798 | ] 1799 | 1800 | [[package]] 1801 | name = "spki" 1802 | version = "0.7.3" 1803 | source = "registry+https://github.com/rust-lang/crates.io-index" 1804 | checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" 1805 | dependencies = [ 1806 | "base64ct", 1807 | "der", 1808 | ] 1809 | 1810 | [[package]] 1811 | name = "sqlformat" 1812 | version = "0.2.4" 1813 | source = "registry+https://github.com/rust-lang/crates.io-index" 1814 | checksum = "f895e3734318cc55f1fe66258926c9b910c124d47520339efecbb6c59cec7c1f" 1815 | dependencies = [ 1816 | "nom", 1817 | "unicode_categories", 1818 | ] 1819 | 1820 | [[package]] 1821 | name = "sqlx" 1822 | version = "0.7.4" 1823 | source = "registry+https://github.com/rust-lang/crates.io-index" 1824 | checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa" 1825 | dependencies = [ 1826 | "sqlx-core", 1827 | "sqlx-macros", 1828 | "sqlx-mysql", 1829 | "sqlx-postgres", 1830 | "sqlx-sqlite", 1831 | ] 1832 | 1833 | [[package]] 1834 | name = "sqlx-core" 1835 | version = "0.7.4" 1836 | source = "registry+https://github.com/rust-lang/crates.io-index" 1837 | checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6" 1838 | dependencies = [ 1839 | "ahash", 1840 | "atoi", 1841 | "byteorder", 1842 | "bytes", 1843 | "crc", 1844 | "crossbeam-queue", 1845 | "either", 1846 | "event-listener", 1847 | "futures-channel", 1848 | "futures-core", 1849 | "futures-intrusive", 1850 | "futures-io", 1851 | "futures-util", 1852 | "hashlink", 1853 | "hex", 1854 | "indexmap", 1855 | "log", 1856 | "memchr", 1857 | "once_cell", 1858 | "paste", 1859 | "percent-encoding", 1860 | "rustls", 1861 | "rustls-pemfile", 1862 | "serde", 1863 | "serde_json", 1864 | "sha2", 1865 | "smallvec", 1866 | "sqlformat", 1867 | "thiserror", 1868 | "tokio", 1869 | "tokio-stream", 1870 | "tracing", 1871 | "url", 1872 | "webpki-roots", 1873 | ] 1874 | 1875 | [[package]] 1876 | name = "sqlx-macros" 1877 | version = "0.7.4" 1878 | source = "registry+https://github.com/rust-lang/crates.io-index" 1879 | checksum = "4ea40e2345eb2faa9e1e5e326db8c34711317d2b5e08d0d5741619048a803127" 1880 | dependencies = [ 1881 | "proc-macro2", 1882 | "quote", 1883 | "sqlx-core", 1884 | "sqlx-macros-core", 1885 | "syn 1.0.109", 1886 | ] 1887 | 1888 | [[package]] 1889 | name = "sqlx-macros-core" 1890 | version = "0.7.4" 1891 | source = "registry+https://github.com/rust-lang/crates.io-index" 1892 | checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8" 1893 | dependencies = [ 1894 | "dotenvy", 1895 | "either", 1896 | "heck", 1897 | "hex", 1898 | "once_cell", 1899 | "proc-macro2", 1900 | "quote", 1901 | "serde", 1902 | "serde_json", 1903 | "sha2", 1904 | "sqlx-core", 1905 | "sqlx-mysql", 1906 | "sqlx-sqlite", 1907 | "syn 1.0.109", 1908 | "tempfile", 1909 | "tokio", 1910 | "url", 1911 | ] 1912 | 1913 | [[package]] 1914 | name = "sqlx-mysql" 1915 | version = "0.7.4" 1916 | source = "registry+https://github.com/rust-lang/crates.io-index" 1917 | checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" 1918 | dependencies = [ 1919 | "atoi", 1920 | "base64 0.21.7", 1921 | "bitflags 2.6.0", 1922 | "byteorder", 1923 | "bytes", 1924 | "crc", 1925 | "digest", 1926 | "dotenvy", 1927 | "either", 1928 | "futures-channel", 1929 | "futures-core", 1930 | "futures-io", 1931 | "futures-util", 1932 | "generic-array", 1933 | "hex", 1934 | "hkdf", 1935 | "hmac", 1936 | "itoa", 1937 | "log", 1938 | "md-5", 1939 | "memchr", 1940 | "once_cell", 1941 | "percent-encoding", 1942 | "rand", 1943 | "rsa", 1944 | "serde", 1945 | "sha1", 1946 | "sha2", 1947 | "smallvec", 1948 | "sqlx-core", 1949 | "stringprep", 1950 | "thiserror", 1951 | "tracing", 1952 | "whoami", 1953 | ] 1954 | 1955 | [[package]] 1956 | name = "sqlx-postgres" 1957 | version = "0.7.4" 1958 | source = "registry+https://github.com/rust-lang/crates.io-index" 1959 | checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" 1960 | dependencies = [ 1961 | "atoi", 1962 | "base64 0.21.7", 1963 | "bitflags 2.6.0", 1964 | "byteorder", 1965 | "crc", 1966 | "dotenvy", 1967 | "etcetera", 1968 | "futures-channel", 1969 | "futures-core", 1970 | "futures-io", 1971 | "futures-util", 1972 | "hex", 1973 | "hkdf", 1974 | "hmac", 1975 | "home", 1976 | "itoa", 1977 | "log", 1978 | "md-5", 1979 | "memchr", 1980 | "once_cell", 1981 | "rand", 1982 | "serde", 1983 | "serde_json", 1984 | "sha2", 1985 | "smallvec", 1986 | "sqlx-core", 1987 | "stringprep", 1988 | "thiserror", 1989 | "tracing", 1990 | "whoami", 1991 | ] 1992 | 1993 | [[package]] 1994 | name = "sqlx-sqlite" 1995 | version = "0.7.4" 1996 | source = "registry+https://github.com/rust-lang/crates.io-index" 1997 | checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa" 1998 | dependencies = [ 1999 | "atoi", 2000 | "flume", 2001 | "futures-channel", 2002 | "futures-core", 2003 | "futures-executor", 2004 | "futures-intrusive", 2005 | "futures-util", 2006 | "libsqlite3-sys", 2007 | "log", 2008 | "percent-encoding", 2009 | "serde", 2010 | "sqlx-core", 2011 | "tracing", 2012 | "url", 2013 | "urlencoding", 2014 | ] 2015 | 2016 | [[package]] 2017 | name = "stable-pattern" 2018 | version = "0.1.0" 2019 | source = "registry+https://github.com/rust-lang/crates.io-index" 2020 | checksum = "4564168c00635f88eaed410d5efa8131afa8d8699a612c80c455a0ba05c21045" 2021 | dependencies = [ 2022 | "memchr", 2023 | ] 2024 | 2025 | [[package]] 2026 | name = "state" 2027 | version = "0.6.0" 2028 | source = "registry+https://github.com/rust-lang/crates.io-index" 2029 | checksum = "2b8c4a4445d81357df8b1a650d0d0d6fbbbfe99d064aa5e02f3e4022061476d8" 2030 | dependencies = [ 2031 | "loom", 2032 | ] 2033 | 2034 | [[package]] 2035 | name = "stringprep" 2036 | version = "0.1.5" 2037 | source = "registry+https://github.com/rust-lang/crates.io-index" 2038 | checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" 2039 | dependencies = [ 2040 | "unicode-bidi", 2041 | "unicode-normalization", 2042 | "unicode-properties", 2043 | ] 2044 | 2045 | [[package]] 2046 | name = "subtle" 2047 | version = "2.6.1" 2048 | source = "registry+https://github.com/rust-lang/crates.io-index" 2049 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 2050 | 2051 | [[package]] 2052 | name = "syn" 2053 | version = "1.0.109" 2054 | source = "registry+https://github.com/rust-lang/crates.io-index" 2055 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 2056 | dependencies = [ 2057 | "proc-macro2", 2058 | "quote", 2059 | "unicode-ident", 2060 | ] 2061 | 2062 | [[package]] 2063 | name = "syn" 2064 | version = "2.0.69" 2065 | source = "registry+https://github.com/rust-lang/crates.io-index" 2066 | checksum = "201fcda3845c23e8212cd466bfebf0bd20694490fc0356ae8e428e0824a915a6" 2067 | dependencies = [ 2068 | "proc-macro2", 2069 | "quote", 2070 | "unicode-ident", 2071 | ] 2072 | 2073 | [[package]] 2074 | name = "sync_wrapper" 2075 | version = "1.0.1" 2076 | source = "registry+https://github.com/rust-lang/crates.io-index" 2077 | checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" 2078 | 2079 | [[package]] 2080 | name = "tempfile" 2081 | version = "3.10.1" 2082 | source = "registry+https://github.com/rust-lang/crates.io-index" 2083 | checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" 2084 | dependencies = [ 2085 | "cfg-if", 2086 | "fastrand", 2087 | "rustix", 2088 | "windows-sys 0.52.0", 2089 | ] 2090 | 2091 | [[package]] 2092 | name = "thiserror" 2093 | version = "1.0.61" 2094 | source = "registry+https://github.com/rust-lang/crates.io-index" 2095 | checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" 2096 | dependencies = [ 2097 | "thiserror-impl", 2098 | ] 2099 | 2100 | [[package]] 2101 | name = "thiserror-impl" 2102 | version = "1.0.61" 2103 | source = "registry+https://github.com/rust-lang/crates.io-index" 2104 | checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" 2105 | dependencies = [ 2106 | "proc-macro2", 2107 | "quote", 2108 | "syn 2.0.69", 2109 | ] 2110 | 2111 | [[package]] 2112 | name = "thread_local" 2113 | version = "1.1.8" 2114 | source = "registry+https://github.com/rust-lang/crates.io-index" 2115 | checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" 2116 | dependencies = [ 2117 | "cfg-if", 2118 | "once_cell", 2119 | ] 2120 | 2121 | [[package]] 2122 | name = "time" 2123 | version = "0.3.36" 2124 | source = "registry+https://github.com/rust-lang/crates.io-index" 2125 | checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" 2126 | dependencies = [ 2127 | "deranged", 2128 | "itoa", 2129 | "num-conv", 2130 | "powerfmt", 2131 | "serde", 2132 | "time-core", 2133 | "time-macros", 2134 | ] 2135 | 2136 | [[package]] 2137 | name = "time-core" 2138 | version = "0.1.2" 2139 | source = "registry+https://github.com/rust-lang/crates.io-index" 2140 | checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" 2141 | 2142 | [[package]] 2143 | name = "time-macros" 2144 | version = "0.2.18" 2145 | source = "registry+https://github.com/rust-lang/crates.io-index" 2146 | checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" 2147 | dependencies = [ 2148 | "num-conv", 2149 | "time-core", 2150 | ] 2151 | 2152 | [[package]] 2153 | name = "tinyvec" 2154 | version = "1.7.0" 2155 | source = "registry+https://github.com/rust-lang/crates.io-index" 2156 | checksum = "ce6b6a2fb3a985e99cebfaefa9faa3024743da73304ca1c683a36429613d3d22" 2157 | dependencies = [ 2158 | "tinyvec_macros", 2159 | ] 2160 | 2161 | [[package]] 2162 | name = "tinyvec_macros" 2163 | version = "0.1.1" 2164 | source = "registry+https://github.com/rust-lang/crates.io-index" 2165 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 2166 | 2167 | [[package]] 2168 | name = "tokio" 2169 | version = "1.38.0" 2170 | source = "registry+https://github.com/rust-lang/crates.io-index" 2171 | checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" 2172 | dependencies = [ 2173 | "backtrace", 2174 | "bytes", 2175 | "libc", 2176 | "mio", 2177 | "num_cpus", 2178 | "pin-project-lite", 2179 | "signal-hook-registry", 2180 | "socket2", 2181 | "tokio-macros", 2182 | "windows-sys 0.48.0", 2183 | ] 2184 | 2185 | [[package]] 2186 | name = "tokio-macros" 2187 | version = "2.3.0" 2188 | source = "registry+https://github.com/rust-lang/crates.io-index" 2189 | checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" 2190 | dependencies = [ 2191 | "proc-macro2", 2192 | "quote", 2193 | "syn 2.0.69", 2194 | ] 2195 | 2196 | [[package]] 2197 | name = "tokio-stream" 2198 | version = "0.1.15" 2199 | source = "registry+https://github.com/rust-lang/crates.io-index" 2200 | checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" 2201 | dependencies = [ 2202 | "futures-core", 2203 | "pin-project-lite", 2204 | "tokio", 2205 | ] 2206 | 2207 | [[package]] 2208 | name = "tokio-util" 2209 | version = "0.7.11" 2210 | source = "registry+https://github.com/rust-lang/crates.io-index" 2211 | checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" 2212 | dependencies = [ 2213 | "bytes", 2214 | "futures-core", 2215 | "futures-sink", 2216 | "pin-project-lite", 2217 | "tokio", 2218 | ] 2219 | 2220 | [[package]] 2221 | name = "toml" 2222 | version = "0.8.14" 2223 | source = "registry+https://github.com/rust-lang/crates.io-index" 2224 | checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" 2225 | dependencies = [ 2226 | "serde", 2227 | "serde_spanned", 2228 | "toml_datetime", 2229 | "toml_edit", 2230 | ] 2231 | 2232 | [[package]] 2233 | name = "toml_datetime" 2234 | version = "0.6.6" 2235 | source = "registry+https://github.com/rust-lang/crates.io-index" 2236 | checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" 2237 | dependencies = [ 2238 | "serde", 2239 | ] 2240 | 2241 | [[package]] 2242 | name = "toml_edit" 2243 | version = "0.22.14" 2244 | source = "registry+https://github.com/rust-lang/crates.io-index" 2245 | checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" 2246 | dependencies = [ 2247 | "indexmap", 2248 | "serde", 2249 | "serde_spanned", 2250 | "toml_datetime", 2251 | "winnow", 2252 | ] 2253 | 2254 | [[package]] 2255 | name = "tower" 2256 | version = "0.4.13" 2257 | source = "registry+https://github.com/rust-lang/crates.io-index" 2258 | checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" 2259 | dependencies = [ 2260 | "futures-core", 2261 | "futures-util", 2262 | "pin-project", 2263 | "pin-project-lite", 2264 | "tokio", 2265 | "tower-layer", 2266 | "tower-service", 2267 | ] 2268 | 2269 | [[package]] 2270 | name = "tower-layer" 2271 | version = "0.3.2" 2272 | source = "registry+https://github.com/rust-lang/crates.io-index" 2273 | checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" 2274 | 2275 | [[package]] 2276 | name = "tower-service" 2277 | version = "0.3.2" 2278 | source = "registry+https://github.com/rust-lang/crates.io-index" 2279 | checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" 2280 | 2281 | [[package]] 2282 | name = "tracing" 2283 | version = "0.1.40" 2284 | source = "registry+https://github.com/rust-lang/crates.io-index" 2285 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 2286 | dependencies = [ 2287 | "log", 2288 | "pin-project-lite", 2289 | "tracing-attributes", 2290 | "tracing-core", 2291 | ] 2292 | 2293 | [[package]] 2294 | name = "tracing-attributes" 2295 | version = "0.1.27" 2296 | source = "registry+https://github.com/rust-lang/crates.io-index" 2297 | checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" 2298 | dependencies = [ 2299 | "proc-macro2", 2300 | "quote", 2301 | "syn 2.0.69", 2302 | ] 2303 | 2304 | [[package]] 2305 | name = "tracing-core" 2306 | version = "0.1.32" 2307 | source = "registry+https://github.com/rust-lang/crates.io-index" 2308 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 2309 | dependencies = [ 2310 | "once_cell", 2311 | "valuable", 2312 | ] 2313 | 2314 | [[package]] 2315 | name = "tracing-log" 2316 | version = "0.2.0" 2317 | source = "registry+https://github.com/rust-lang/crates.io-index" 2318 | checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" 2319 | dependencies = [ 2320 | "log", 2321 | "once_cell", 2322 | "tracing-core", 2323 | ] 2324 | 2325 | [[package]] 2326 | name = "tracing-subscriber" 2327 | version = "0.3.18" 2328 | source = "registry+https://github.com/rust-lang/crates.io-index" 2329 | checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" 2330 | dependencies = [ 2331 | "matchers", 2332 | "nu-ansi-term", 2333 | "once_cell", 2334 | "regex", 2335 | "sharded-slab", 2336 | "smallvec", 2337 | "thread_local", 2338 | "tracing", 2339 | "tracing-core", 2340 | "tracing-log", 2341 | ] 2342 | 2343 | [[package]] 2344 | name = "try-lock" 2345 | version = "0.2.5" 2346 | source = "registry+https://github.com/rust-lang/crates.io-index" 2347 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 2348 | 2349 | [[package]] 2350 | name = "typenum" 2351 | version = "1.17.0" 2352 | source = "registry+https://github.com/rust-lang/crates.io-index" 2353 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 2354 | 2355 | [[package]] 2356 | name = "ubyte" 2357 | version = "0.10.4" 2358 | source = "registry+https://github.com/rust-lang/crates.io-index" 2359 | checksum = "f720def6ce1ee2fc44d40ac9ed6d3a59c361c80a75a7aa8e75bb9baed31cf2ea" 2360 | dependencies = [ 2361 | "serde", 2362 | ] 2363 | 2364 | [[package]] 2365 | name = "uncased" 2366 | version = "0.9.10" 2367 | source = "registry+https://github.com/rust-lang/crates.io-index" 2368 | checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697" 2369 | dependencies = [ 2370 | "serde", 2371 | "version_check", 2372 | ] 2373 | 2374 | [[package]] 2375 | name = "unicode-bidi" 2376 | version = "0.3.15" 2377 | source = "registry+https://github.com/rust-lang/crates.io-index" 2378 | checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" 2379 | 2380 | [[package]] 2381 | name = "unicode-ident" 2382 | version = "1.0.12" 2383 | source = "registry+https://github.com/rust-lang/crates.io-index" 2384 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 2385 | 2386 | [[package]] 2387 | name = "unicode-normalization" 2388 | version = "0.1.23" 2389 | source = "registry+https://github.com/rust-lang/crates.io-index" 2390 | checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" 2391 | dependencies = [ 2392 | "tinyvec", 2393 | ] 2394 | 2395 | [[package]] 2396 | name = "unicode-properties" 2397 | version = "0.1.1" 2398 | source = "registry+https://github.com/rust-lang/crates.io-index" 2399 | checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" 2400 | 2401 | [[package]] 2402 | name = "unicode-segmentation" 2403 | version = "1.11.0" 2404 | source = "registry+https://github.com/rust-lang/crates.io-index" 2405 | checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" 2406 | 2407 | [[package]] 2408 | name = "unicode-xid" 2409 | version = "0.2.4" 2410 | source = "registry+https://github.com/rust-lang/crates.io-index" 2411 | checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" 2412 | 2413 | [[package]] 2414 | name = "unicode_categories" 2415 | version = "0.1.1" 2416 | source = "registry+https://github.com/rust-lang/crates.io-index" 2417 | checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" 2418 | 2419 | [[package]] 2420 | name = "untrusted" 2421 | version = "0.9.0" 2422 | source = "registry+https://github.com/rust-lang/crates.io-index" 2423 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 2424 | 2425 | [[package]] 2426 | name = "url" 2427 | version = "2.5.2" 2428 | source = "registry+https://github.com/rust-lang/crates.io-index" 2429 | checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" 2430 | dependencies = [ 2431 | "form_urlencoded", 2432 | "idna", 2433 | "percent-encoding", 2434 | ] 2435 | 2436 | [[package]] 2437 | name = "urlencoding" 2438 | version = "2.1.3" 2439 | source = "registry+https://github.com/rust-lang/crates.io-index" 2440 | checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" 2441 | 2442 | [[package]] 2443 | name = "valuable" 2444 | version = "0.1.0" 2445 | source = "registry+https://github.com/rust-lang/crates.io-index" 2446 | checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" 2447 | 2448 | [[package]] 2449 | name = "vcpkg" 2450 | version = "0.2.15" 2451 | source = "registry+https://github.com/rust-lang/crates.io-index" 2452 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 2453 | 2454 | [[package]] 2455 | name = "version_check" 2456 | version = "0.9.4" 2457 | source = "registry+https://github.com/rust-lang/crates.io-index" 2458 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 2459 | 2460 | [[package]] 2461 | name = "want" 2462 | version = "0.3.1" 2463 | source = "registry+https://github.com/rust-lang/crates.io-index" 2464 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 2465 | dependencies = [ 2466 | "try-lock", 2467 | ] 2468 | 2469 | [[package]] 2470 | name = "wasi" 2471 | version = "0.11.0+wasi-snapshot-preview1" 2472 | source = "registry+https://github.com/rust-lang/crates.io-index" 2473 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 2474 | 2475 | [[package]] 2476 | name = "wasite" 2477 | version = "0.1.0" 2478 | source = "registry+https://github.com/rust-lang/crates.io-index" 2479 | checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" 2480 | 2481 | [[package]] 2482 | name = "wasm-bindgen" 2483 | version = "0.2.92" 2484 | source = "registry+https://github.com/rust-lang/crates.io-index" 2485 | checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" 2486 | dependencies = [ 2487 | "cfg-if", 2488 | "wasm-bindgen-macro", 2489 | ] 2490 | 2491 | [[package]] 2492 | name = "wasm-bindgen-backend" 2493 | version = "0.2.92" 2494 | source = "registry+https://github.com/rust-lang/crates.io-index" 2495 | checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" 2496 | dependencies = [ 2497 | "bumpalo", 2498 | "log", 2499 | "once_cell", 2500 | "proc-macro2", 2501 | "quote", 2502 | "syn 2.0.69", 2503 | "wasm-bindgen-shared", 2504 | ] 2505 | 2506 | [[package]] 2507 | name = "wasm-bindgen-futures" 2508 | version = "0.4.42" 2509 | source = "registry+https://github.com/rust-lang/crates.io-index" 2510 | checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" 2511 | dependencies = [ 2512 | "cfg-if", 2513 | "js-sys", 2514 | "wasm-bindgen", 2515 | "web-sys", 2516 | ] 2517 | 2518 | [[package]] 2519 | name = "wasm-bindgen-macro" 2520 | version = "0.2.92" 2521 | source = "registry+https://github.com/rust-lang/crates.io-index" 2522 | checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" 2523 | dependencies = [ 2524 | "quote", 2525 | "wasm-bindgen-macro-support", 2526 | ] 2527 | 2528 | [[package]] 2529 | name = "wasm-bindgen-macro-support" 2530 | version = "0.2.92" 2531 | source = "registry+https://github.com/rust-lang/crates.io-index" 2532 | checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" 2533 | dependencies = [ 2534 | "proc-macro2", 2535 | "quote", 2536 | "syn 2.0.69", 2537 | "wasm-bindgen-backend", 2538 | "wasm-bindgen-shared", 2539 | ] 2540 | 2541 | [[package]] 2542 | name = "wasm-bindgen-shared" 2543 | version = "0.2.92" 2544 | source = "registry+https://github.com/rust-lang/crates.io-index" 2545 | checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" 2546 | 2547 | [[package]] 2548 | name = "wasm-streams" 2549 | version = "0.4.0" 2550 | source = "registry+https://github.com/rust-lang/crates.io-index" 2551 | checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" 2552 | dependencies = [ 2553 | "futures-util", 2554 | "js-sys", 2555 | "wasm-bindgen", 2556 | "wasm-bindgen-futures", 2557 | "web-sys", 2558 | ] 2559 | 2560 | [[package]] 2561 | name = "web-sys" 2562 | version = "0.3.69" 2563 | source = "registry+https://github.com/rust-lang/crates.io-index" 2564 | checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" 2565 | dependencies = [ 2566 | "js-sys", 2567 | "wasm-bindgen", 2568 | ] 2569 | 2570 | [[package]] 2571 | name = "webpki-roots" 2572 | version = "0.25.4" 2573 | source = "registry+https://github.com/rust-lang/crates.io-index" 2574 | checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" 2575 | 2576 | [[package]] 2577 | name = "whoami" 2578 | version = "1.5.1" 2579 | source = "registry+https://github.com/rust-lang/crates.io-index" 2580 | checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" 2581 | dependencies = [ 2582 | "redox_syscall 0.4.1", 2583 | "wasite", 2584 | ] 2585 | 2586 | [[package]] 2587 | name = "winapi" 2588 | version = "0.3.9" 2589 | source = "registry+https://github.com/rust-lang/crates.io-index" 2590 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 2591 | dependencies = [ 2592 | "winapi-i686-pc-windows-gnu", 2593 | "winapi-x86_64-pc-windows-gnu", 2594 | ] 2595 | 2596 | [[package]] 2597 | name = "winapi-i686-pc-windows-gnu" 2598 | version = "0.4.0" 2599 | source = "registry+https://github.com/rust-lang/crates.io-index" 2600 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2601 | 2602 | [[package]] 2603 | name = "winapi-x86_64-pc-windows-gnu" 2604 | version = "0.4.0" 2605 | source = "registry+https://github.com/rust-lang/crates.io-index" 2606 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2607 | 2608 | [[package]] 2609 | name = "windows" 2610 | version = "0.48.0" 2611 | source = "registry+https://github.com/rust-lang/crates.io-index" 2612 | checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" 2613 | dependencies = [ 2614 | "windows-targets 0.48.5", 2615 | ] 2616 | 2617 | [[package]] 2618 | name = "windows-sys" 2619 | version = "0.48.0" 2620 | source = "registry+https://github.com/rust-lang/crates.io-index" 2621 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 2622 | dependencies = [ 2623 | "windows-targets 0.48.5", 2624 | ] 2625 | 2626 | [[package]] 2627 | name = "windows-sys" 2628 | version = "0.52.0" 2629 | source = "registry+https://github.com/rust-lang/crates.io-index" 2630 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 2631 | dependencies = [ 2632 | "windows-targets 0.52.6", 2633 | ] 2634 | 2635 | [[package]] 2636 | name = "windows-targets" 2637 | version = "0.48.5" 2638 | source = "registry+https://github.com/rust-lang/crates.io-index" 2639 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 2640 | dependencies = [ 2641 | "windows_aarch64_gnullvm 0.48.5", 2642 | "windows_aarch64_msvc 0.48.5", 2643 | "windows_i686_gnu 0.48.5", 2644 | "windows_i686_msvc 0.48.5", 2645 | "windows_x86_64_gnu 0.48.5", 2646 | "windows_x86_64_gnullvm 0.48.5", 2647 | "windows_x86_64_msvc 0.48.5", 2648 | ] 2649 | 2650 | [[package]] 2651 | name = "windows-targets" 2652 | version = "0.52.6" 2653 | source = "registry+https://github.com/rust-lang/crates.io-index" 2654 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 2655 | dependencies = [ 2656 | "windows_aarch64_gnullvm 0.52.6", 2657 | "windows_aarch64_msvc 0.52.6", 2658 | "windows_i686_gnu 0.52.6", 2659 | "windows_i686_gnullvm", 2660 | "windows_i686_msvc 0.52.6", 2661 | "windows_x86_64_gnu 0.52.6", 2662 | "windows_x86_64_gnullvm 0.52.6", 2663 | "windows_x86_64_msvc 0.52.6", 2664 | ] 2665 | 2666 | [[package]] 2667 | name = "windows_aarch64_gnullvm" 2668 | version = "0.48.5" 2669 | source = "registry+https://github.com/rust-lang/crates.io-index" 2670 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 2671 | 2672 | [[package]] 2673 | name = "windows_aarch64_gnullvm" 2674 | version = "0.52.6" 2675 | source = "registry+https://github.com/rust-lang/crates.io-index" 2676 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 2677 | 2678 | [[package]] 2679 | name = "windows_aarch64_msvc" 2680 | version = "0.48.5" 2681 | source = "registry+https://github.com/rust-lang/crates.io-index" 2682 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 2683 | 2684 | [[package]] 2685 | name = "windows_aarch64_msvc" 2686 | version = "0.52.6" 2687 | source = "registry+https://github.com/rust-lang/crates.io-index" 2688 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 2689 | 2690 | [[package]] 2691 | name = "windows_i686_gnu" 2692 | version = "0.48.5" 2693 | source = "registry+https://github.com/rust-lang/crates.io-index" 2694 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 2695 | 2696 | [[package]] 2697 | name = "windows_i686_gnu" 2698 | version = "0.52.6" 2699 | source = "registry+https://github.com/rust-lang/crates.io-index" 2700 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 2701 | 2702 | [[package]] 2703 | name = "windows_i686_gnullvm" 2704 | version = "0.52.6" 2705 | source = "registry+https://github.com/rust-lang/crates.io-index" 2706 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 2707 | 2708 | [[package]] 2709 | name = "windows_i686_msvc" 2710 | version = "0.48.5" 2711 | source = "registry+https://github.com/rust-lang/crates.io-index" 2712 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 2713 | 2714 | [[package]] 2715 | name = "windows_i686_msvc" 2716 | version = "0.52.6" 2717 | source = "registry+https://github.com/rust-lang/crates.io-index" 2718 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 2719 | 2720 | [[package]] 2721 | name = "windows_x86_64_gnu" 2722 | version = "0.48.5" 2723 | source = "registry+https://github.com/rust-lang/crates.io-index" 2724 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 2725 | 2726 | [[package]] 2727 | name = "windows_x86_64_gnu" 2728 | version = "0.52.6" 2729 | source = "registry+https://github.com/rust-lang/crates.io-index" 2730 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 2731 | 2732 | [[package]] 2733 | name = "windows_x86_64_gnullvm" 2734 | version = "0.48.5" 2735 | source = "registry+https://github.com/rust-lang/crates.io-index" 2736 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 2737 | 2738 | [[package]] 2739 | name = "windows_x86_64_gnullvm" 2740 | version = "0.52.6" 2741 | source = "registry+https://github.com/rust-lang/crates.io-index" 2742 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 2743 | 2744 | [[package]] 2745 | name = "windows_x86_64_msvc" 2746 | version = "0.48.5" 2747 | source = "registry+https://github.com/rust-lang/crates.io-index" 2748 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 2749 | 2750 | [[package]] 2751 | name = "windows_x86_64_msvc" 2752 | version = "0.52.6" 2753 | source = "registry+https://github.com/rust-lang/crates.io-index" 2754 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 2755 | 2756 | [[package]] 2757 | name = "winnow" 2758 | version = "0.6.13" 2759 | source = "registry+https://github.com/rust-lang/crates.io-index" 2760 | checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" 2761 | dependencies = [ 2762 | "memchr", 2763 | ] 2764 | 2765 | [[package]] 2766 | name = "winreg" 2767 | version = "0.52.0" 2768 | source = "registry+https://github.com/rust-lang/crates.io-index" 2769 | checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" 2770 | dependencies = [ 2771 | "cfg-if", 2772 | "windows-sys 0.48.0", 2773 | ] 2774 | 2775 | [[package]] 2776 | name = "yansi" 2777 | version = "1.0.1" 2778 | source = "registry+https://github.com/rust-lang/crates.io-index" 2779 | checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" 2780 | dependencies = [ 2781 | "is-terminal", 2782 | ] 2783 | 2784 | [[package]] 2785 | name = "zerocopy" 2786 | version = "0.7.35" 2787 | source = "registry+https://github.com/rust-lang/crates.io-index" 2788 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 2789 | dependencies = [ 2790 | "zerocopy-derive", 2791 | ] 2792 | 2793 | [[package]] 2794 | name = "zerocopy-derive" 2795 | version = "0.7.35" 2796 | source = "registry+https://github.com/rust-lang/crates.io-index" 2797 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 2798 | dependencies = [ 2799 | "proc-macro2", 2800 | "quote", 2801 | "syn 2.0.69", 2802 | ] 2803 | 2804 | [[package]] 2805 | name = "zeroize" 2806 | version = "1.8.1" 2807 | source = "registry+https://github.com/rust-lang/crates.io-index" 2808 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 2809 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "formie" 3 | version = "1.3.2" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | libc = "0.2.155" 8 | reqwest = { version = "0.12.5", features = [ "stream" ], default-features = false } 9 | rocket = "0.5.1" 10 | rocket_db_pools = { version = "0.2.0", features = ["sqlx_sqlite"] } 11 | sqlx = { version = "0.7.4", features = ["macros"] } 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU AFFERO GENERAL PUBLIC LICENSE 2 | Version 3, 19 November 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU Affero General Public License is a free, copyleft license for 11 | software and other kinds of works, specifically designed to ensure 12 | cooperation with the community in the case of network server software. 13 | 14 | The licenses for most software and other practical works are designed 15 | to take away your freedom to share and change the works. By contrast, 16 | our General Public Licenses are intended to guarantee your freedom to 17 | share and change all versions of a program--to make sure it remains free 18 | software for all its users. 19 | 20 | When we speak of free software, we are referring to freedom, not 21 | price. Our General Public Licenses are designed to make sure that you 22 | have the freedom to distribute copies of free software (and charge for 23 | them if you wish), that you receive source code or can get it if you 24 | want it, that you can change the software or use pieces of it in new 25 | free programs, and that you know you can do these things. 26 | 27 | Developers that use our General Public Licenses protect your rights 28 | with two steps: (1) assert copyright on the software, and (2) offer 29 | you this License which gives you legal permission to copy, distribute 30 | and/or modify the software. 31 | 32 | A secondary benefit of defending all users' freedom is that 33 | improvements made in alternate versions of the program, if they 34 | receive widespread use, become available for other developers to 35 | incorporate. Many developers of free software are heartened and 36 | encouraged by the resulting cooperation. However, in the case of 37 | software used on network servers, this result may fail to come about. 38 | The GNU General Public License permits making a modified version and 39 | letting the public access it on a server without ever releasing its 40 | source code to the public. 41 | 42 | The GNU Affero General Public License is designed specifically to 43 | ensure that, in such cases, the modified source code becomes available 44 | to the community. It requires the operator of a network server to 45 | provide the source code of the modified version running there to the 46 | users of that server. Therefore, public use of a modified version, on 47 | a publicly accessible server, gives the public access to the source 48 | code of the modified version. 49 | 50 | An older license, called the Affero General Public License and 51 | published by Affero, was designed to accomplish similar goals. This is 52 | a different license, not a version of the Affero GPL, but Affero has 53 | released a new version of the Affero GPL which permits relicensing under 54 | this license. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | TERMS AND CONDITIONS 60 | 61 | 0. Definitions. 62 | 63 | "This License" refers to version 3 of the GNU Affero General Public License. 64 | 65 | "Copyright" also means copyright-like laws that apply to other kinds of 66 | works, such as semiconductor masks. 67 | 68 | "The Program" refers to any copyrightable work licensed under this 69 | License. Each licensee is addressed as "you". "Licensees" and 70 | "recipients" may be individuals or organizations. 71 | 72 | To "modify" a work means to copy from or adapt all or part of the work 73 | in a fashion requiring copyright permission, other than the making of an 74 | exact copy. The resulting work is called a "modified version" of the 75 | earlier work or a work "based on" the earlier work. 76 | 77 | A "covered work" means either the unmodified Program or a work based 78 | on the Program. 79 | 80 | To "propagate" a work means to do anything with it that, without 81 | permission, would make you directly or secondarily liable for 82 | infringement under applicable copyright law, except executing it on a 83 | computer or modifying a private copy. Propagation includes copying, 84 | distribution (with or without modification), making available to the 85 | public, and in some countries other activities as well. 86 | 87 | To "convey" a work means any kind of propagation that enables other 88 | parties to make or receive copies. Mere interaction with a user through 89 | a computer network, with no transfer of a copy, is not conveying. 90 | 91 | An interactive user interface displays "Appropriate Legal Notices" 92 | to the extent that it includes a convenient and prominently visible 93 | feature that (1) displays an appropriate copyright notice, and (2) 94 | tells the user that there is no warranty for the work (except to the 95 | extent that warranties are provided), that licensees may convey the 96 | work under this License, and how to view a copy of this License. If 97 | the interface presents a list of user commands or options, such as a 98 | menu, a prominent item in the list meets this criterion. 99 | 100 | 1. Source Code. 101 | 102 | The "source code" for a work means the preferred form of the work 103 | for making modifications to it. "Object code" means any non-source 104 | form of a work. 105 | 106 | A "Standard Interface" means an interface that either is an official 107 | standard defined by a recognized standards body, or, in the case of 108 | interfaces specified for a particular programming language, one that 109 | is widely used among developers working in that language. 110 | 111 | The "System Libraries" of an executable work include anything, other 112 | than the work as a whole, that (a) is included in the normal form of 113 | packaging a Major Component, but which is not part of that Major 114 | Component, and (b) serves only to enable use of the work with that 115 | Major Component, or to implement a Standard Interface for which an 116 | implementation is available to the public in source code form. A 117 | "Major Component", in this context, means a major essential component 118 | (kernel, window system, and so on) of the specific operating system 119 | (if any) on which the executable work runs, or a compiler used to 120 | produce the work, or an object code interpreter used to run it. 121 | 122 | The "Corresponding Source" for a work in object code form means all 123 | the source code needed to generate, install, and (for an executable 124 | work) run the object code and to modify the work, including scripts to 125 | control those activities. However, it does not include the work's 126 | System Libraries, or general-purpose tools or generally available free 127 | programs which are used unmodified in performing those activities but 128 | which are not part of the work. For example, Corresponding Source 129 | includes interface definition files associated with source files for 130 | the work, and the source code for shared libraries and dynamically 131 | linked subprograms that the work is specifically designed to require, 132 | such as by intimate data communication or control flow between those 133 | subprograms and other parts of the work. 134 | 135 | The Corresponding Source need not include anything that users 136 | can regenerate automatically from other parts of the Corresponding 137 | Source. 138 | 139 | The Corresponding Source for a work in source code form is that 140 | same work. 141 | 142 | 2. Basic Permissions. 143 | 144 | All rights granted under this License are granted for the term of 145 | copyright on the Program, and are irrevocable provided the stated 146 | conditions are met. This License explicitly affirms your unlimited 147 | permission to run the unmodified Program. The output from running a 148 | covered work is covered by this License only if the output, given its 149 | content, constitutes a covered work. This License acknowledges your 150 | rights of fair use or other equivalent, as provided by copyright law. 151 | 152 | You may make, run and propagate covered works that you do not 153 | convey, without conditions so long as your license otherwise remains 154 | in force. You may convey covered works to others for the sole purpose 155 | of having them make modifications exclusively for you, or provide you 156 | with facilities for running those works, provided that you comply with 157 | the terms of this License in conveying all material for which you do 158 | not control copyright. Those thus making or running the covered works 159 | for you must do so exclusively on your behalf, under your direction 160 | and control, on terms that prohibit them from making any copies of 161 | your copyrighted material outside their relationship with you. 162 | 163 | Conveying under any other circumstances is permitted solely under 164 | the conditions stated below. Sublicensing is not allowed; section 10 165 | makes it unnecessary. 166 | 167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 168 | 169 | No covered work shall be deemed part of an effective technological 170 | measure under any applicable law fulfilling obligations under article 171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 172 | similar laws prohibiting or restricting circumvention of such 173 | measures. 174 | 175 | When you convey a covered work, you waive any legal power to forbid 176 | circumvention of technological measures to the extent such circumvention 177 | is effected by exercising rights under this License with respect to 178 | the covered work, and you disclaim any intention to limit operation or 179 | modification of the work as a means of enforcing, against the work's 180 | users, your or third parties' legal rights to forbid circumvention of 181 | technological measures. 182 | 183 | 4. Conveying Verbatim Copies. 184 | 185 | You may convey verbatim copies of the Program's source code as you 186 | receive it, in any medium, provided that you conspicuously and 187 | appropriately publish on each copy an appropriate copyright notice; 188 | keep intact all notices stating that this License and any 189 | non-permissive terms added in accord with section 7 apply to the code; 190 | keep intact all notices of the absence of any warranty; and give all 191 | recipients a copy of this License along with the Program. 192 | 193 | You may charge any price or no price for each copy that you convey, 194 | and you may offer support or warranty protection for a fee. 195 | 196 | 5. Conveying Modified Source Versions. 197 | 198 | You may convey a work based on the Program, or the modifications to 199 | produce it from the Program, in the form of source code under the 200 | terms of section 4, provided that you also meet all of these conditions: 201 | 202 | a) The work must carry prominent notices stating that you modified 203 | it, and giving a relevant date. 204 | 205 | b) The work must carry prominent notices stating that it is 206 | released under this License and any conditions added under section 207 | 7. This requirement modifies the requirement in section 4 to 208 | "keep intact all notices". 209 | 210 | c) You must license the entire work, as a whole, under this 211 | License to anyone who comes into possession of a copy. This 212 | License will therefore apply, along with any applicable section 7 213 | additional terms, to the whole of the work, and all its parts, 214 | regardless of how they are packaged. This License gives no 215 | permission to license the work in any other way, but it does not 216 | invalidate such permission if you have separately received it. 217 | 218 | d) If the work has interactive user interfaces, each must display 219 | Appropriate Legal Notices; however, if the Program has interactive 220 | interfaces that do not display Appropriate Legal Notices, your 221 | work need not make them do so. 222 | 223 | A compilation of a covered work with other separate and independent 224 | works, which are not by their nature extensions of the covered work, 225 | and which are not combined with it such as to form a larger program, 226 | in or on a volume of a storage or distribution medium, is called an 227 | "aggregate" if the compilation and its resulting copyright are not 228 | used to limit the access or legal rights of the compilation's users 229 | beyond what the individual works permit. Inclusion of a covered work 230 | in an aggregate does not cause this License to apply to the other 231 | parts of the aggregate. 232 | 233 | 6. Conveying Non-Source Forms. 234 | 235 | You may convey a covered work in object code form under the terms 236 | of sections 4 and 5, provided that you also convey the 237 | machine-readable Corresponding Source under the terms of this License, 238 | in one of these ways: 239 | 240 | a) Convey the object code in, or embodied in, a physical product 241 | (including a physical distribution medium), accompanied by the 242 | Corresponding Source fixed on a durable physical medium 243 | customarily used for software interchange. 244 | 245 | b) Convey the object code in, or embodied in, a physical product 246 | (including a physical distribution medium), accompanied by a 247 | written offer, valid for at least three years and valid for as 248 | long as you offer spare parts or customer support for that product 249 | model, to give anyone who possesses the object code either (1) a 250 | copy of the Corresponding Source for all the software in the 251 | product that is covered by this License, on a durable physical 252 | medium customarily used for software interchange, for a price no 253 | more than your reasonable cost of physically performing this 254 | conveying of source, or (2) access to copy the 255 | Corresponding Source from a network server at no charge. 256 | 257 | c) Convey individual copies of the object code with a copy of the 258 | written offer to provide the Corresponding Source. This 259 | alternative is allowed only occasionally and noncommercially, and 260 | only if you received the object code with such an offer, in accord 261 | with subsection 6b. 262 | 263 | d) Convey the object code by offering access from a designated 264 | place (gratis or for a charge), and offer equivalent access to the 265 | Corresponding Source in the same way through the same place at no 266 | further charge. You need not require recipients to copy the 267 | Corresponding Source along with the object code. If the place to 268 | copy the object code is a network server, the Corresponding Source 269 | may be on a different server (operated by you or a third party) 270 | that supports equivalent copying facilities, provided you maintain 271 | clear directions next to the object code saying where to find the 272 | Corresponding Source. Regardless of what server hosts the 273 | Corresponding Source, you remain obligated to ensure that it is 274 | available for as long as needed to satisfy these requirements. 275 | 276 | e) Convey the object code using peer-to-peer transmission, provided 277 | you inform other peers where the object code and Corresponding 278 | Source of the work are being offered to the general public at no 279 | charge under subsection 6d. 280 | 281 | A separable portion of the object code, whose source code is excluded 282 | from the Corresponding Source as a System Library, need not be 283 | included in conveying the object code work. 284 | 285 | A "User Product" is either (1) a "consumer product", which means any 286 | tangible personal property which is normally used for personal, family, 287 | or household purposes, or (2) anything designed or sold for incorporation 288 | into a dwelling. In determining whether a product is a consumer product, 289 | doubtful cases shall be resolved in favor of coverage. For a particular 290 | product received by a particular user, "normally used" refers to a 291 | typical or common use of that class of product, regardless of the status 292 | of the particular user or of the way in which the particular user 293 | actually uses, or expects or is expected to use, the product. A product 294 | is a consumer product regardless of whether the product has substantial 295 | commercial, industrial or non-consumer uses, unless such uses represent 296 | the only significant mode of use of the product. 297 | 298 | "Installation Information" for a User Product means any methods, 299 | procedures, authorization keys, or other information required to install 300 | and execute modified versions of a covered work in that User Product from 301 | a modified version of its Corresponding Source. The information must 302 | suffice to ensure that the continued functioning of the modified object 303 | code is in no case prevented or interfered with solely because 304 | modification has been made. 305 | 306 | If you convey an object code work under this section in, or with, or 307 | specifically for use in, a User Product, and the conveying occurs as 308 | part of a transaction in which the right of possession and use of the 309 | User Product is transferred to the recipient in perpetuity or for a 310 | fixed term (regardless of how the transaction is characterized), the 311 | Corresponding Source conveyed under this section must be accompanied 312 | by the Installation Information. But this requirement does not apply 313 | if neither you nor any third party retains the ability to install 314 | modified object code on the User Product (for example, the work has 315 | been installed in ROM). 316 | 317 | The requirement to provide Installation Information does not include a 318 | requirement to continue to provide support service, warranty, or updates 319 | for a work that has been modified or installed by the recipient, or for 320 | the User Product in which it has been modified or installed. Access to a 321 | network may be denied when the modification itself materially and 322 | adversely affects the operation of the network or violates the rules and 323 | protocols for communication across the network. 324 | 325 | Corresponding Source conveyed, and Installation Information provided, 326 | in accord with this section must be in a format that is publicly 327 | documented (and with an implementation available to the public in 328 | source code form), and must require no special password or key for 329 | unpacking, reading or copying. 330 | 331 | 7. Additional Terms. 332 | 333 | "Additional permissions" are terms that supplement the terms of this 334 | License by making exceptions from one or more of its conditions. 335 | Additional permissions that are applicable to the entire Program shall 336 | be treated as though they were included in this License, to the extent 337 | that they are valid under applicable law. If additional permissions 338 | apply only to part of the Program, that part may be used separately 339 | under those permissions, but the entire Program remains governed by 340 | this License without regard to the additional permissions. 341 | 342 | When you convey a copy of a covered work, you may at your option 343 | remove any additional permissions from that copy, or from any part of 344 | it. (Additional permissions may be written to require their own 345 | removal in certain cases when you modify the work.) You may place 346 | additional permissions on material, added by you to a covered work, 347 | for which you have or can give appropriate copyright permission. 348 | 349 | Notwithstanding any other provision of this License, for material you 350 | add to a covered work, you may (if authorized by the copyright holders of 351 | that material) supplement the terms of this License with terms: 352 | 353 | a) Disclaiming warranty or limiting liability differently from the 354 | terms of sections 15 and 16 of this License; or 355 | 356 | b) Requiring preservation of specified reasonable legal notices or 357 | author attributions in that material or in the Appropriate Legal 358 | Notices displayed by works containing it; or 359 | 360 | c) Prohibiting misrepresentation of the origin of that material, or 361 | requiring that modified versions of such material be marked in 362 | reasonable ways as different from the original version; or 363 | 364 | d) Limiting the use for publicity purposes of names of licensors or 365 | authors of the material; or 366 | 367 | e) Declining to grant rights under trademark law for use of some 368 | trade names, trademarks, or service marks; or 369 | 370 | f) Requiring indemnification of licensors and authors of that 371 | material by anyone who conveys the material (or modified versions of 372 | it) with contractual assumptions of liability to the recipient, for 373 | any liability that these contractual assumptions directly impose on 374 | those licensors and authors. 375 | 376 | All other non-permissive additional terms are considered "further 377 | restrictions" within the meaning of section 10. If the Program as you 378 | received it, or any part of it, contains a notice stating that it is 379 | governed by this License along with a term that is a further 380 | restriction, you may remove that term. If a license document contains 381 | a further restriction but permits relicensing or conveying under this 382 | License, you may add to a covered work material governed by the terms 383 | of that license document, provided that the further restriction does 384 | not survive such relicensing or conveying. 385 | 386 | If you add terms to a covered work in accord with this section, you 387 | must place, in the relevant source files, a statement of the 388 | additional terms that apply to those files, or a notice indicating 389 | where to find the applicable terms. 390 | 391 | Additional terms, permissive or non-permissive, may be stated in the 392 | form of a separately written license, or stated as exceptions; 393 | the above requirements apply either way. 394 | 395 | 8. Termination. 396 | 397 | You may not propagate or modify a covered work except as expressly 398 | provided under this License. Any attempt otherwise to propagate or 399 | modify it is void, and will automatically terminate your rights under 400 | this License (including any patent licenses granted under the third 401 | paragraph of section 11). 402 | 403 | However, if you cease all violation of this License, then your 404 | license from a particular copyright holder is reinstated (a) 405 | provisionally, unless and until the copyright holder explicitly and 406 | finally terminates your license, and (b) permanently, if the copyright 407 | holder fails to notify you of the violation by some reasonable means 408 | prior to 60 days after the cessation. 409 | 410 | Moreover, your license from a particular copyright holder is 411 | reinstated permanently if the copyright holder notifies you of the 412 | violation by some reasonable means, this is the first time you have 413 | received notice of violation of this License (for any work) from that 414 | copyright holder, and you cure the violation prior to 30 days after 415 | your receipt of the notice. 416 | 417 | Termination of your rights under this section does not terminate the 418 | licenses of parties who have received copies or rights from you under 419 | this License. If your rights have been terminated and not permanently 420 | reinstated, you do not qualify to receive new licenses for the same 421 | material under section 10. 422 | 423 | 9. Acceptance Not Required for Having Copies. 424 | 425 | You are not required to accept this License in order to receive or 426 | run a copy of the Program. Ancillary propagation of a covered work 427 | occurring solely as a consequence of using peer-to-peer transmission 428 | to receive a copy likewise does not require acceptance. However, 429 | nothing other than this License grants you permission to propagate or 430 | modify any covered work. These actions infringe copyright if you do 431 | not accept this License. Therefore, by modifying or propagating a 432 | covered work, you indicate your acceptance of this License to do so. 433 | 434 | 10. Automatic Licensing of Downstream Recipients. 435 | 436 | Each time you convey a covered work, the recipient automatically 437 | receives a license from the original licensors, to run, modify and 438 | propagate that work, subject to this License. You are not responsible 439 | for enforcing compliance by third parties with this License. 440 | 441 | An "entity transaction" is a transaction transferring control of an 442 | organization, or substantially all assets of one, or subdividing an 443 | organization, or merging organizations. If propagation of a covered 444 | work results from an entity transaction, each party to that 445 | transaction who receives a copy of the work also receives whatever 446 | licenses to the work the party's predecessor in interest had or could 447 | give under the previous paragraph, plus a right to possession of the 448 | Corresponding Source of the work from the predecessor in interest, if 449 | the predecessor has it or can get it with reasonable efforts. 450 | 451 | You may not impose any further restrictions on the exercise of the 452 | rights granted or affirmed under this License. For example, you may 453 | not impose a license fee, royalty, or other charge for exercise of 454 | rights granted under this License, and you may not initiate litigation 455 | (including a cross-claim or counterclaim in a lawsuit) alleging that 456 | any patent claim is infringed by making, using, selling, offering for 457 | sale, or importing the Program or any portion of it. 458 | 459 | 11. Patents. 460 | 461 | A "contributor" is a copyright holder who authorizes use under this 462 | License of the Program or a work on which the Program is based. The 463 | work thus licensed is called the contributor's "contributor version". 464 | 465 | A contributor's "essential patent claims" are all patent claims 466 | owned or controlled by the contributor, whether already acquired or 467 | hereafter acquired, that would be infringed by some manner, permitted 468 | by this License, of making, using, or selling its contributor version, 469 | but do not include claims that would be infringed only as a 470 | consequence of further modification of the contributor version. For 471 | purposes of this definition, "control" includes the right to grant 472 | patent sublicenses in a manner consistent with the requirements of 473 | this License. 474 | 475 | Each contributor grants you a non-exclusive, worldwide, royalty-free 476 | patent license under the contributor's essential patent claims, to 477 | make, use, sell, offer for sale, import and otherwise run, modify and 478 | propagate the contents of its contributor version. 479 | 480 | In the following three paragraphs, a "patent license" is any express 481 | agreement or commitment, however denominated, not to enforce a patent 482 | (such as an express permission to practice a patent or covenant not to 483 | sue for patent infringement). To "grant" such a patent license to a 484 | party means to make such an agreement or commitment not to enforce a 485 | patent against the party. 486 | 487 | If you convey a covered work, knowingly relying on a patent license, 488 | and the Corresponding Source of the work is not available for anyone 489 | to copy, free of charge and under the terms of this License, through a 490 | publicly available network server or other readily accessible means, 491 | then you must either (1) cause the Corresponding Source to be so 492 | available, or (2) arrange to deprive yourself of the benefit of the 493 | patent license for this particular work, or (3) arrange, in a manner 494 | consistent with the requirements of this License, to extend the patent 495 | license to downstream recipients. "Knowingly relying" means you have 496 | actual knowledge that, but for the patent license, your conveying the 497 | covered work in a country, or your recipient's use of the covered work 498 | in a country, would infringe one or more identifiable patents in that 499 | country that you have reason to believe are valid. 500 | 501 | If, pursuant to or in connection with a single transaction or 502 | arrangement, you convey, or propagate by procuring conveyance of, a 503 | covered work, and grant a patent license to some of the parties 504 | receiving the covered work authorizing them to use, propagate, modify 505 | or convey a specific copy of the covered work, then the patent license 506 | you grant is automatically extended to all recipients of the covered 507 | work and works based on it. 508 | 509 | A patent license is "discriminatory" if it does not include within 510 | the scope of its coverage, prohibits the exercise of, or is 511 | conditioned on the non-exercise of one or more of the rights that are 512 | specifically granted under this License. You may not convey a covered 513 | work if you are a party to an arrangement with a third party that is 514 | in the business of distributing software, under which you make payment 515 | to the third party based on the extent of your activity of conveying 516 | the work, and under which the third party grants, to any of the 517 | parties who would receive the covered work from you, a discriminatory 518 | patent license (a) in connection with copies of the covered work 519 | conveyed by you (or copies made from those copies), or (b) primarily 520 | for and in connection with specific products or compilations that 521 | contain the covered work, unless you entered into that arrangement, 522 | or that patent license was granted, prior to 28 March 2007. 523 | 524 | Nothing in this License shall be construed as excluding or limiting 525 | any implied license or other defenses to infringement that may 526 | otherwise be available to you under applicable patent law. 527 | 528 | 12. No Surrender of Others' Freedom. 529 | 530 | If conditions are imposed on you (whether by court order, agreement or 531 | otherwise) that contradict the conditions of this License, they do not 532 | excuse you from the conditions of this License. If you cannot convey a 533 | covered work so as to satisfy simultaneously your obligations under this 534 | License and any other pertinent obligations, then as a consequence you may 535 | not convey it at all. For example, if you agree to terms that obligate you 536 | to collect a royalty for further conveying from those to whom you convey 537 | the Program, the only way you could satisfy both those terms and this 538 | License would be to refrain entirely from conveying the Program. 539 | 540 | 13. Remote Network Interaction; Use with the GNU General Public License. 541 | 542 | Notwithstanding any other provision of this License, if you modify the 543 | Program, your modified version must prominently offer all users 544 | interacting with it remotely through a computer network (if your version 545 | supports such interaction) an opportunity to receive the Corresponding 546 | Source of your version by providing access to the Corresponding Source 547 | from a network server at no charge, through some standard or customary 548 | means of facilitating copying of software. This Corresponding Source 549 | shall include the Corresponding Source for any work covered by version 3 550 | of the GNU General Public License that is incorporated pursuant to the 551 | following paragraph. 552 | 553 | Notwithstanding any other provision of this License, you have 554 | permission to link or combine any covered work with a work licensed 555 | under version 3 of the GNU General Public License into a single 556 | combined work, and to convey the resulting work. The terms of this 557 | License will continue to apply to the part which is the covered work, 558 | but the work with which it is combined will remain governed by version 559 | 3 of the GNU General Public License. 560 | 561 | 14. Revised Versions of this License. 562 | 563 | The Free Software Foundation may publish revised and/or new versions of 564 | the GNU Affero General Public License from time to time. Such new versions 565 | will be similar in spirit to the present version, but may differ in detail to 566 | address new problems or concerns. 567 | 568 | Each version is given a distinguishing version number. If the 569 | Program specifies that a certain numbered version of the GNU Affero General 570 | Public License "or any later version" applies to it, you have the 571 | option of following the terms and conditions either of that numbered 572 | version or of any later version published by the Free Software 573 | Foundation. If the Program does not specify a version number of the 574 | GNU Affero General Public License, you may choose any version ever published 575 | by the Free Software Foundation. 576 | 577 | If the Program specifies that a proxy can decide which future 578 | versions of the GNU Affero General Public License can be used, that proxy's 579 | public statement of acceptance of a version permanently authorizes you 580 | to choose that version for the Program. 581 | 582 | Later license versions may give you additional or different 583 | permissions. However, no additional obligations are imposed on any 584 | author or copyright holder as a result of your choosing to follow a 585 | later version. 586 | 587 | 15. Disclaimer of Warranty. 588 | 589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 597 | 598 | 16. Limitation of Liability. 599 | 600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 608 | SUCH DAMAGES. 609 | 610 | 17. Interpretation of Sections 15 and 16. 611 | 612 | If the disclaimer of warranty and limitation of liability provided 613 | above cannot be given local legal effect according to their terms, 614 | reviewing courts shall apply local law that most closely approximates 615 | an absolute waiver of all civil liability in connection with the 616 | Program, unless a warranty or assumption of liability accompanies a 617 | copy of the Program in return for a fee. 618 | 619 | END OF TERMS AND CONDITIONS 620 | 621 | How to Apply These Terms to Your New Programs 622 | 623 | If you develop a new program, and you want it to be of the greatest 624 | possible use to the public, the best way to achieve this is to make it 625 | free software which everyone can redistribute and change under these terms. 626 | 627 | To do so, attach the following notices to the program. It is safest 628 | to attach them to the start of each source file to most effectively 629 | state the exclusion of warranty; and each file should have at least 630 | the "copyright" line and a pointer to where the full notice is found. 631 | 632 | 633 | Copyright (C) 634 | 635 | This program is free software: you can redistribute it and/or modify 636 | it under the terms of the GNU Affero General Public License as published 637 | by the Free Software Foundation, either version 3 of the License, or 638 | (at your option) any later version. 639 | 640 | This program is distributed in the hope that it will be useful, 641 | but WITHOUT ANY WARRANTY; without even the implied warranty of 642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 643 | GNU Affero General Public License for more details. 644 | 645 | You should have received a copy of the GNU Affero General Public License 646 | along with this program. If not, see . 647 | 648 | Also add information on how to contact you by electronic and paper mail. 649 | 650 | If your software can interact with users remotely through a computer 651 | network, you should also make sure that it provides a way for users to 652 | get its source. For example, if your program is a web application, its 653 | interface could display a "Source" link that leads users to an archive 654 | of the code. There are many ways you could offer source, and different 655 | solutions will be better for different programs; see section 13 for the 656 | specific requirements. 657 | 658 | You should also get your employer (if you work as a programmer) or school, 659 | if any, to sign a "copyright disclaimer" for the program, if necessary. 660 | For more information on this, and how to apply and follow the GNU AGPL, see 661 | . 662 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: run clean 2 | 3 | run: .venv .formie-secret-key formie.db 4 | . .venv/bin/activate && \ 5 | SECRET_KEY="$$(cat .formie-secret-key)" SQLALCHEMY_DATABASE_URI="sqlite:///$(PWD)/formie.db" FLASK_APP="formie" FLASK_DEBUG=1 cargo run 6 | 7 | clean: 8 | rm -rf .venv .formie-secret-key formie.db 9 | 10 | .venv: requirements.txt 11 | -rm -rf .venv 12 | python3 -m venv .venv 13 | . .venv/bin/activate && pip install -U -r requirements.txt 14 | 15 | .formie-secret-key: 16 | head -c 32 /dev/urandom | base64 > .formie-secret-key 17 | 18 | %.db: .venv .formie-secret-key 19 | . .venv/bin/activate && \ 20 | SECRET_KEY="$$(cat .formie-secret-key)" SQLALCHEMY_DATABASE_URI="sqlite:///$(PWD)/$@" python setup-db.py 0 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # formie 2 | 3 | Open source form application made with pure HTML/CSS/JS. Needs minimal client-side JS for form creation. 4 | 5 | ## Setup 6 | 7 | Python 3.9+ is required to run Formie. If you are running Formie for a development build, you can just run `make run`. 8 | 9 | If you are planning on running Formie on production, I'd advise looking at my [PKGBUILDs](https://github.com/div72/PKGBUILDs/tree/development/formie) repo. 10 | -------------------------------------------------------------------------------- /config-example.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export SQLALCHEMY_DATABASE_URI="sqlite:////var/lib/formie/formie.db" 4 | export SECRET_KEY="" 5 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "nixpkgs": { 4 | "locked": { 5 | "lastModified": 1707092692, 6 | "narHash": "sha256-ZbHsm+mGk/izkWtT4xwwqz38fdlwu7nUUKXTOmm4SyE=", 7 | "owner": "NixOS", 8 | "repo": "nixpkgs", 9 | "rev": "faf912b086576fd1a15fca610166c98d47bc667e", 10 | "type": "github" 11 | }, 12 | "original": { 13 | "id": "nixpkgs", 14 | "ref": "nixos-unstable", 15 | "type": "indirect" 16 | } 17 | }, 18 | "root": { 19 | "inputs": { 20 | "nixpkgs": "nixpkgs" 21 | } 22 | } 23 | }, 24 | "root": "root", 25 | "version": 7 26 | } 27 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Nix flake for Formie."; 3 | 4 | inputs.nixpkgs.url = "nixpkgs/nixos-unstable"; 5 | 6 | outputs = { self, nixpkgs }: let 7 | supportedSystems = [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin" ]; 8 | 9 | forAllSystems = nixpkgs.lib.genAttrs supportedSystems; 10 | nixpkgsFor = forAllSystems (system: import nixpkgs { inherit system; }); 11 | 12 | in rec { 13 | packages = forAllSystems (system: let 14 | pkgs = nixpkgsFor.${system}; 15 | in { 16 | default = pkgs.stdenv.mkDerivation { 17 | pname = "formie"; 18 | version = "v3.2"; 19 | 20 | src = ./.; 21 | buildInputs = with pkgs.python312Packages; [ 22 | flask 23 | flask_sqlalchemy 24 | passlib 25 | argon2-cffi 26 | ]; 27 | }; 28 | }); 29 | 30 | devShells = forAllSystems (system: { 31 | default = packages.${system}.default.overrideAttrs (finalAttrs: previousAttrs: { 32 | nativeBuildInputs = [ nixpkgsFor.${system}.black ]; 33 | }); 34 | }); 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /formie/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | from typing import TYPE_CHECKING 3 | 4 | import sqlalchemy 5 | from flask import redirect, render_template, session, url_for, Flask 6 | 7 | from formie import auth, forms, models 8 | 9 | if TYPE_CHECKING: 10 | from flask.typing import ResponseReturnValue 11 | else: 12 | ResponseReturnValue = "ResponseReturnValue" 13 | 14 | 15 | def create_app() -> Flask: 16 | app = Flask(__name__, instance_relative_config=True) 17 | app.config["SQLALCHEMY_DATABASE_URI"] = os.environ["SQLALCHEMY_DATABASE_URI"] 18 | app.config["SECRET_KEY"] = os.environ["SECRET_KEY"] 19 | models.db.init_app(app) # type: ignore[no-untyped-call] 20 | 21 | app.register_blueprint(auth.bp) 22 | app.register_blueprint(forms.bp) 23 | 24 | if app.config["ENV"] == "production": 25 | from werkzeug.middleware.proxy_fix import ProxyFix 26 | 27 | app.wsgi_app = ProxyFix( # type: ignore[assignment] 28 | app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1 29 | ) 30 | 31 | with app.app_context(): 32 | try: 33 | models.Form.query.all() 34 | except sqlalchemy.exc.OperationalError: 35 | models.db.create_all() 36 | 37 | @app.route("/") 38 | def index() -> ResponseReturnValue: 39 | return redirect(url_for("forms.all_forms")) # render_template("index.html") 40 | 41 | @app.route("/session/") 42 | def get_session_var(key: str) -> str: 43 | return str(session.get(key)) 44 | 45 | return app 46 | -------------------------------------------------------------------------------- /formie/auth.py: -------------------------------------------------------------------------------- 1 | import functools 2 | from typing import Any, Callable 3 | 4 | from flask import ( 5 | g, 6 | flash, 7 | redirect, 8 | render_template, 9 | request, 10 | session, 11 | url_for, 12 | Blueprint, 13 | ) 14 | from flask.typing import ResponseReturnValue 15 | from passlib.hash import argon2 16 | from sqlalchemy.exc import IntegrityError 17 | 18 | from formie.models import db, User 19 | 20 | bp = Blueprint("auth", __name__, url_prefix="/auth") 21 | 22 | 23 | def login_required( 24 | view: Callable[..., ResponseReturnValue] 25 | ) -> Callable[..., ResponseReturnValue]: 26 | """View decorator that redirects anonymous users to the login page.""" 27 | 28 | @functools.wraps(view) 29 | def wrapped_view(**kwargs: Any) -> ResponseReturnValue: 30 | if g.user is None: 31 | return redirect(url_for("auth.login")) 32 | 33 | return view(**kwargs) 34 | 35 | return wrapped_view 36 | 37 | 38 | @bp.before_app_request 39 | def load_logged_in_user() -> None: 40 | """If a user id is stored in the session, load the user object from 41 | the database into ``g.user``.""" 42 | user_id = session.get("user_id") 43 | 44 | if user_id is None: 45 | g.user = None 46 | else: 47 | g.user = User.query.filter_by(id=user_id).first() 48 | 49 | 50 | @bp.route("/register", methods=("GET", "POST")) 51 | def register() -> ResponseReturnValue: 52 | """Register a new user. 53 | Validates that the username is not already taken. Hashes the 54 | password for security. 55 | """ 56 | if request.method == "POST": 57 | username = request.form["username"] 58 | password = request.form["password"] 59 | error = None 60 | 61 | if not username: 62 | error = "An username is required." 63 | elif not password: 64 | error = "A password is required." 65 | elif len(username) > 32: 66 | error = "Username cannot be longer than 32 characters." 67 | elif len(password) > 256: 68 | error = "Password cannot be longer than 256 characters." 69 | 70 | if error is None: 71 | try: 72 | db.session.add(User(username=username, password=argon2.hash(password))) # type: ignore[no-untyped-call] 73 | db.session.commit() 74 | 75 | return redirect(url_for("auth.login")) 76 | except IntegrityError: 77 | error = "Username is already in use." 78 | 79 | flash(error) 80 | 81 | return render_template("auth/register.html") 82 | 83 | 84 | @bp.route("/login", methods=("GET", "POST")) 85 | def login() -> ResponseReturnValue: 86 | """Log in a registered user by adding the user id to the session.""" 87 | if request.method == "POST": 88 | username = request.form["username"] 89 | password = request.form["password"] 90 | error = None 91 | user = User.query.filter_by(username=username).first() 92 | 93 | if user is None or not argon2.verify(password, user.password): # type: ignore[no-untyped-call] 94 | error = "Incorrect username/password." 95 | 96 | if error is None: 97 | # store the user id in a new session and return to the index 98 | session.clear() 99 | session["user_id"] = user.id 100 | return redirect(url_for("index")) 101 | 102 | flash(error) 103 | 104 | return render_template("auth/login.html") 105 | 106 | 107 | @bp.route("/logout") 108 | def logout() -> ResponseReturnValue: 109 | """Clear the current session, including the stored user id.""" 110 | session.clear() 111 | return redirect(url_for("index")) 112 | -------------------------------------------------------------------------------- /formie/forms.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import datetime 3 | import io 4 | import json 5 | from collections import defaultdict 6 | from dataclasses import dataclass 7 | from enum import Flag 8 | from typing import cast, Type, TYPE_CHECKING, Union 9 | 10 | from flask import ( 11 | abort, 12 | g, 13 | redirect, 14 | render_template, 15 | request, 16 | url_for, 17 | Blueprint, 18 | Response, 19 | ) 20 | 21 | if TYPE_CHECKING: 22 | from flask.typing import ResponseReturnValue 23 | else: 24 | ResponseReturnValue = "ResponseReturnValue" 25 | 26 | from formie import auth 27 | from formie.models import ( 28 | db, 29 | Field, 30 | ChoiceField, 31 | Form, 32 | InfoField, 33 | Model, 34 | TextField, 35 | RangeField, 36 | ) 37 | 38 | bp = Blueprint("forms", __name__, url_prefix="/forms") 39 | 40 | 41 | JSONData = Union[str, int, bool, float, list["JSONData"], dict[str, "JSONData"]] 42 | 43 | 44 | class ACF(Flag): 45 | """Access control flags for forms. Can be used to limit viewing results/answering for other users.""" 46 | 47 | HIDE_RESULTS = 0x1 48 | DISALLOW_ANON_ANSWER = 0x2 49 | 50 | 51 | def validate_schema(data: JSONData) -> str: 52 | """Validates the given schema. Returns a string with the error on fail.""" 53 | if not isinstance(data, list): 54 | return "Invalid schema root type." 55 | 56 | if len(data) == 0: 57 | # Disallow empty schemas. 58 | return "Cannot make an empty form." 59 | 60 | if len(data) > 64: 61 | return f"Cannot have more than 64 fields." 62 | 63 | for i, field in enumerate(data): 64 | if not isinstance(field, dict): 65 | return f"Invalid type for field #{i}" 66 | 67 | if TYPE_CHECKING: 68 | field = cast(dict[str, JSONData], field) 69 | 70 | if "type" not in field: 71 | return f"Field #{i} needs a type." 72 | 73 | if field["type"] == "info": 74 | if "text" not in field: 75 | return f"Field #{i} needs information text." 76 | 77 | if len(field) != 2: 78 | return f"Field #{i} cannot have more than 2 attributes." 79 | 80 | if not isinstance(field["text"], str): 81 | return f"Field #{i} has invalid text type." 82 | 83 | if len(field["text"]) > 512: 84 | return f"Field #{i}'s information text cannot have more than 512 characters." 85 | 86 | continue 87 | 88 | if ( 89 | "name" not in field 90 | or not isinstance(field["name"], str) 91 | or len(field["name"]) == 0 92 | ): 93 | return f"Field #{i} requires a question." 94 | 95 | if len(field["name"]) > 256: 96 | return f"Field #{i}'s question cannot be longer than 256 characters." 97 | 98 | if field["type"] == "text": 99 | if "default" not in field: 100 | return f"Field #{i} needs a default attribute." 101 | 102 | if not isinstance(field["default"], str): 103 | return f"Field #{i}'s default must be a string." 104 | 105 | if len(field["default"]) > 1023: 106 | return f"Field #{i}'s default cannot be longer than 1023 characters." 107 | 108 | if "multiline" in field: 109 | if not isinstance(field["multiline"], bool): 110 | return f"Field #{i} has invalid multline attribute" 111 | 112 | if len(field) != 4: 113 | return f"Field #{i} cannot have more than 4 attributes." 114 | else: 115 | if len(field) != 3: 116 | return f"Field #{i} cannot have more than 3 attributes." 117 | elif field["type"] == "choice": 118 | if "default" not in field: 119 | return f"Field #{i} needs a default attribute." 120 | 121 | if not isinstance(field["default"], int): 122 | return f"Field #{i}'s default must be an integer." 123 | 124 | if "single" not in field: 125 | return f"Field #{i} needs a single attribute." 126 | 127 | if not isinstance(field["single"], bool): 128 | return f"Field #{i}'s single must be a boolean." 129 | 130 | if "choices" not in field: 131 | return f"Field #{i} needs a choices attribute" 132 | 133 | if not isinstance(field["choices"], list): 134 | return f"Field #{i}'s choices must be a list." 135 | 136 | if len(field["choices"]) > 64: 137 | return f"Field #{i} cannot have more than 64 choices." 138 | 139 | if len(field["choices"]) == 0: 140 | return f"Field #{i} needs at least one choice." 141 | 142 | for ci, choice in enumerate(field["choices"]): 143 | if not isinstance(choice, str): 144 | return f"Field #{i} choice #{ci} must be a string." 145 | 146 | if len(choice) > 64: 147 | return ( 148 | f"Field #{i} choice #{ci} cannot have more than 64 characters." 149 | ) 150 | 151 | if len(field) != 5: 152 | return f"Field #{i} cannot have more than 5 attributes." 153 | elif field["type"] == "range": 154 | for attr in ("default", "min", "max"): 155 | if attr not in field: 156 | return f"Field #{i} needs a {attr} attribute." 157 | 158 | if not isinstance(field[attr], int): 159 | return f"Field #{i} must be an integer." 160 | 161 | if field["default"] < field["min"]: 162 | return f"Field #{i}'s default cannot be lower than minimum." 163 | 164 | if field["default"] > field["max"]: 165 | return f"Field #{i}'s default cannot be higher than maximum." 166 | 167 | if len(field) != 5: 168 | return f"Field #{i} cannot have more than 5 attributes." 169 | else: 170 | return f"Field #{i} has an invalid type." 171 | 172 | return "" 173 | 174 | 175 | def validate_answer(schema: list[Field], form: dict[str, str]) -> str: 176 | """Validates an answer against the given schema. Returns an error string on failure.""" 177 | 178 | for i, field in enumerate(schema): 179 | if isinstance(field, InfoField): 180 | continue 181 | 182 | if not isinstance(field, ChoiceField) or field.single: 183 | if f"col{i}" not in form: 184 | return f"Question #{i + 1} is missing an answer." 185 | 186 | if isinstance(field, TextField) and len(form[f"col{i}"]) > 1023: 187 | return ( 188 | f"Question #{i + 1}'s answer cannot be longer than 1023 characters." 189 | ) 190 | elif isinstance(field, (ChoiceField, RangeField)): 191 | # log10(2 ** 64) ~= 19 so 20 characters should be more than enough. 192 | if len(form[f"col{i}"]) > 20: 193 | return f"Question #{i + 1} answer is out of bounds." 194 | 195 | try: 196 | answer = int(form[f"col{i}"]) 197 | except ValueError: 198 | return f"Question #{i + 1} has an invalid answer." 199 | 200 | if isinstance(field, ChoiceField) and answer >= len(field.choices): 201 | return f"Question #{i + 1} has an invalid answer." 202 | elif isinstance(field, RangeField) and ( 203 | answer < field.min or answer > field.max 204 | ): 205 | return f"Question #{i + 1}'s answer is out of bounds." 206 | else: 207 | if f"col{i}" in form: 208 | try: 209 | answer = int(answer) 210 | except ValueError: 211 | return f"Question #{i + 1} has an invalid answer." 212 | else: 213 | answer = 0 214 | for part in form: 215 | try: 216 | if part.startswith(f"col{i}"): 217 | answer |= 1 << int(part.split("_")[1]) 218 | except ValueError: 219 | pass 220 | 221 | if answer < 0 or answer >= (1 << len(field.choices)): 222 | return f"Question #{i + 1}'s answer is out of bounds." 223 | 224 | return "" 225 | 226 | 227 | def decode_fields(data: list[dict[str, JSONData]]) -> list[Field]: 228 | fields: list[Field] = [] 229 | for elem in data: 230 | assert isinstance(elem["type"], str) 231 | 232 | if elem["type"] == "text": 233 | del elem["type"] 234 | 235 | assert isinstance(elem["default"], str) 236 | 237 | fields.append(TextField(name=elem["name"], default=elem["default"], multiline=elem.get("multiline", False))) 238 | 239 | elem["type"] = "text" 240 | elif elem["type"] == "choice": 241 | del elem["type"] 242 | 243 | assert isinstance(elem["single"], bool) 244 | assert isinstance(elem["default"], int) 245 | assert isinstance(elem["choices"], list) 246 | 247 | fields.append(ChoiceField(name=elem["name"], single=elem["single"], default=elem["default"], choices=elem["choices"])) # type: ignore[arg-type] 248 | elem["type"] = "choice" 249 | elif elem["type"] == "range": 250 | del elem["type"] 251 | 252 | assert isinstance(elem["default"], int) 253 | assert isinstance(elem["min"], int) 254 | assert isinstance(elem["max"], int) 255 | 256 | fields.append( 257 | RangeField( 258 | name=elem["name"], 259 | default=elem["default"], 260 | min=elem["min"], 261 | max=elem["max"], 262 | ) 263 | ) 264 | elem["type"] = "range" 265 | elif elem["type"] == "info": 266 | assert isinstance(elem["text"], str) 267 | 268 | fields.append(InfoField(text=elem["text"])) 269 | 270 | return fields 271 | 272 | 273 | MODELS: dict[str, Type[Model]] = {} 274 | 275 | 276 | def create_model(name: str, fields: list[Field]) -> Type[Model]: 277 | if name in MODELS: 278 | return MODELS[name] 279 | 280 | cols = {"id": db.Column(db.Integer, primary_key=True)} 281 | for i, field in enumerate(fields): 282 | if isinstance(field, InfoField): 283 | continue 284 | 285 | if isinstance(field, TextField): 286 | col = db.Column(db.Text, default=field.default) 287 | elif isinstance(field, ChoiceField): 288 | col = db.Column(db.Integer, default=field.default) 289 | elif isinstance(field, RangeField): 290 | col = db.Column(db.Integer, default=field.default) 291 | cols[f"col{i}"] = col 292 | cls = type(name, (db.Model,), cols) # type: ignore[arg-type] 293 | MODELS[name] = cls 294 | return cls 295 | 296 | 297 | @bp.route("/") 298 | def all_forms() -> ResponseReturnValue: 299 | forms = [] 300 | for form in Form.query.all(): 301 | form_dict = {} 302 | form_dict["id"] = form.id 303 | form_dict["creator"] = "anon" 304 | if form.creator: 305 | form_dict["creator"] = form.creator.username 306 | forms.append(form_dict) 307 | return render_template("forms/forms.html", forms=forms) 308 | 309 | 310 | @bp.route("/new", methods=("GET", "POST")) 311 | @auth.login_required 312 | def new_form() -> ResponseReturnValue: 313 | if request.method == "POST": 314 | acf: ACF = ACF(0) 315 | if request.args.get("hide_results", "false") == "true": 316 | acf |= ACF.HIDE_RESULTS 317 | if request.args.get("disallow_anon_answer", "false") == "true": 318 | acf |= ACF.DISALLOW_ANON_ANSWER 319 | 320 | schema = request.json 321 | if schema is None: 322 | return "A JSON Body is required", 400 323 | 324 | error = validate_schema(cast(JSONData, schema)) 325 | 326 | if error: 327 | return error, 400 328 | 329 | try: 330 | schema_str = json.dumps(schema) # TODO: fetch original instead 331 | fields = decode_fields(cast(list[dict[str, JSONData]], schema)) 332 | form = Form( 333 | schema=schema_str, 334 | created_at=datetime.datetime.now(), 335 | creator_id=g.user.id, 336 | access_control_flags=acf.value, 337 | ) 338 | db.session.add(form) 339 | db.session.commit() 340 | create_model(str(form.id), fields).__table__.create(db.engine) 341 | except Exception as e: 342 | raise e 343 | abort(401) 344 | db.session.commit() 345 | 346 | return url_for("forms.form", form_id=form.id), 200 347 | return render_template("forms/new.html") 348 | 349 | 350 | @bp.route("/", methods=("GET", "POST")) 351 | def form(form_id: int) -> ResponseReturnValue: 352 | form = Form.query.filter_by(id=form_id).first() 353 | if form is None: 354 | abort(404) 355 | schema = json.loads(form.schema) 356 | 357 | model = create_model(str(form.id), decode_fields(schema.copy())) 358 | 359 | if request.method == "POST": 360 | if ( 361 | ACF.DISALLOW_ANON_ANSWER in ACF(form.access_control_flags) 362 | and g.user is None 363 | ): 364 | abort(403) # TODO: Better pages for aborts 365 | 366 | error = validate_answer(decode_fields(schema), request.form) 367 | if error: 368 | return error, 400 369 | 370 | values: dict[str, Union[int, str]] = defaultdict(int) 371 | for key in request.form: 372 | try: 373 | if not key.startswith("col"): 374 | continue 375 | 376 | parts = key.split("_") 377 | key = parts[0] 378 | 379 | idx = int(key.lstrip("col")) 380 | if idx >= len(schema): 381 | continue 382 | 383 | if len(parts) == 2: 384 | key = parts[0] 385 | assert isinstance(values[key], int) 386 | values[key] = cast(int, values[key]) | (1 << int(parts[1])) 387 | else: 388 | values[key] = request.form[key] 389 | except ValueError: 390 | pass 391 | 392 | db.session.add(model(**values)) # type: ignore[arg-type] 393 | db.session.commit() 394 | 395 | if url := request.args.get("goto", None): 396 | return redirect(url) 397 | 398 | can_view_results: bool = ACF.HIDE_RESULTS not in ACF( 399 | form.access_control_flags 400 | ) or (g.user is not None and g.user.id == form.creator_id) 401 | results_url: str = url_for("forms.view_results", form_id=form_id) 402 | 403 | return render_template( 404 | "forms/submission_successful.html", 405 | can_view_results=can_view_results, 406 | results_url=results_url, 407 | ) 408 | 409 | schema = list(enumerate(schema)) 410 | for i, field in schema: 411 | if field["type"] == "choice": 412 | schema[i][1]["choices"] = list(enumerate(schema[i][1]["choices"])) 413 | 414 | return render_template("forms/form.html", schema=schema) 415 | 416 | 417 | @bp.route("//results") 418 | def view_results(form_id: int) -> ResponseReturnValue: 419 | form = Form.query.filter_by(id=form_id).first() 420 | if form is None: 421 | abort(404) 422 | 423 | if ACF.HIDE_RESULTS in ACF(form.access_control_flags) and ( 424 | g.user is None or g.user.id != form.creator_id 425 | ): 426 | abort(403) 427 | 428 | schema = json.loads(form.schema) 429 | fields = decode_fields(schema) 430 | model = create_model(str(form.id), fields) 431 | results = [] 432 | for res in model.query.all(): 433 | cols = [res.id] 434 | for i, field in enumerate(fields): 435 | if isinstance(field, InfoField): 436 | continue 437 | 438 | if not isinstance(field, ChoiceField): 439 | cols.append(getattr(res, f"col{i}")) 440 | else: 441 | if field.single: 442 | cols.append(field.choices[int(getattr(res, f"col{i}"))]) 443 | else: 444 | answer_flag: int = int(getattr(res, f"col{i}")) 445 | answer: list[str] = [] 446 | for choice_index, choice in enumerate(field.choices): 447 | if answer_flag & (1 << choice_index): 448 | answer.append(choice) 449 | cols.append("+".join(answer)) 450 | results.append(cols) 451 | 452 | if request.args.get("format", default=None, type=str) == "csv": 453 | buf = io.StringIO() 454 | csv.writer(buf).writerows(results) 455 | buf.seek(0) 456 | return cast(Union[Response, str], Response(buf.read(), mimetype="text/csv")) 457 | 458 | return render_template("forms/results.html", schema=schema, results=results) 459 | -------------------------------------------------------------------------------- /formie/models.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Any, TYPE_CHECKING 3 | 4 | from flask_sqlalchemy import SQLAlchemy 5 | 6 | db = SQLAlchemy() 7 | if TYPE_CHECKING: 8 | # Absolutely horrendous type checking hacks. Does not work anyways. 9 | # TODO: remove with SQLAlchemy. 10 | from dataclasses import dataclass as fake_dataclass 11 | 12 | class Query: 13 | filter_by: "Query" 14 | 15 | def __init__(self) -> None: 16 | ... 17 | 18 | def __call__(self, **kwargs: Any) -> "Query": 19 | ... 20 | 21 | def first(self) -> Any: 22 | ... 23 | 24 | def all(self) -> list[Any]: 25 | ... 26 | 27 | @fake_dataclass 28 | class _Model: 29 | query: Query = Query() 30 | __table__: Any = None 31 | 32 | Model = _Model 33 | else: 34 | Model = db.Model 35 | fake_dataclass = lambda x: x 36 | 37 | 38 | @fake_dataclass 39 | class User(Model): 40 | id: int = db.Column(db.Integer, primary_key=True) 41 | username: str = db.Column(db.Text, unique=True) 42 | password: str = db.Column(db.Text) # argon2 hash 43 | 44 | 45 | @fake_dataclass 46 | class Form(Model): 47 | id: int = db.Column(db.Integer, primary_key=True) 48 | schema: str = db.Column(db.Text) 49 | created_at: Any = db.Column(db.DateTime) 50 | creator_id: int = db.Column(db.Integer, db.ForeignKey(User.id)) 51 | access_control_flags: int = db.Column(db.Integer, nullable=False, default=0) 52 | 53 | creator: User = db.relationship("User", foreign_keys="Form.creator_id") 54 | 55 | 56 | @dataclass 57 | class Field: 58 | name: str # max 256 bytes 59 | 60 | 61 | @dataclass 62 | class InfoField: 63 | text: str # max 512 characters 64 | 65 | 66 | @dataclass 67 | class TextField(Field): 68 | default: str # max 1023 bytes 69 | multiline: bool 70 | 71 | 72 | @dataclass 73 | class ChoiceField(Field): 74 | single: bool 75 | default: int 76 | choices: list[str] # max 64 elements with 64 length 77 | 78 | 79 | @dataclass 80 | class RangeField(Field): 81 | default: int 82 | min: int 83 | max: int 84 | -------------------------------------------------------------------------------- /formie/static/new_form.js: -------------------------------------------------------------------------------- 1 | let fields_div = document.getElementById('fields'); 2 | 3 | let hide_results = document.getElementById('hide_results'); 4 | let disallow_anon_answer = document.getElementById('disallow_anon_answer'); 5 | 6 | var index = 0; 7 | 8 | function new_field() { 9 | fields_div.insertAdjacentHTML('beforeend', ` 10 |
11 | 12 | 18 |
19 | 20 |
`); 21 | change_field(fields_div.lastChild, "text"); 22 | index++; 23 | } 24 | 25 | function change_field(field, typ) { 26 | let extra = field.children[field.children.length - 2]; 27 | 28 | if (typ === "text") { 29 | extra.innerHTML = ''; 30 | } else if (typ === "single_choice") { 31 | extra.innerHTML = ''; 32 | } else if (typ === "multi_choice") { 33 | extra.innerHTML = ''; 34 | } else if (typ === "range") { 35 | extra.innerHTML = '' 36 | } 37 | } 38 | 39 | function new_info() { 40 | fields_div.insertAdjacentHTML('beforeend', ` 41 |
42 | 43 | 44 |
`); 45 | } 46 | 47 | function add_choice(element, is_radio) { 48 | var typ = 'checkbox'; 49 | if (is_radio) typ = 'radio'; 50 | element.insertAdjacentHTML('beforeend', ` 51 | 52 | `) 53 | } 54 | 55 | function make_schema() { 56 | let schema = []; 57 | for (field of fields_div.children) { 58 | let schema_field = {}; 59 | if (field.children[0].tagName === 'TEXTAREA') { 60 | // Information field 61 | schema_field.type = "info"; 62 | schema_field.text = field.children[0].value; 63 | } else { 64 | // Question field 65 | schema_field.name = field.children[0].value; 66 | 67 | if (field.children[1].selectedIndex === 3) { 68 | schema_field.type = "range"; 69 | schema_field.min = parseInt(field.children[2].children[1].value); 70 | schema_field.max = parseInt(field.children[2].children[3].value); 71 | schema_field.default = parseInt(field.children[2].children[5].value); 72 | } else if (field.children[1].selectedIndex === 0) { 73 | schema_field.type = "text"; 74 | schema_field.default = field.children[2].children[0].value; 75 | schema_field.multiline = field.children[2].children[1].checked; 76 | } else { 77 | schema_field.choices = []; 78 | schema_field.single = false; 79 | schema_field.type = "choice"; 80 | schema_field.default = 0; 81 | if (field.children[1].selectedIndex === 1) schema_field.single = true; 82 | for (choice of field.children[2].children) { 83 | if (choice.tagName == 'INPUT' && choice.type == 'text') schema_field.choices.push(choice.value); 84 | } 85 | } 86 | } 87 | schema.push(schema_field); 88 | } 89 | return schema; 90 | } 91 | 92 | function submit_form() { 93 | let req = new XMLHttpRequest(); 94 | const params = new URLSearchParams({"hide_results": hide_results.checked, "disallow_anon_answer": disallow_anon_answer.checked}); 95 | req.open('POST', document.location.href + `?${params}`, false); 96 | req.setRequestHeader('Content-Type', 'application/json'); 97 | req.send(JSON.stringify(make_schema())); 98 | if (req.status === 400) { 99 | alert(req.responseText); 100 | } else if (req.status === 200) { 101 | window.location.href = req.responseText; 102 | } else { 103 | document.open("text/html"); 104 | document.write(req.responseText); 105 | document.close(); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /formie/static/style.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | background-color: #EEEEEE; 3 | font-family: Tahoma, Verdana, Arial, sans-serif; 4 | margin: 0; 5 | padding: 0; 6 | height: 100%; 7 | display: flex; 8 | flex-direction: column; 9 | } 10 | 11 | nav { 12 | background-color: #111111; 13 | color: white; 14 | display: flex; 15 | width: calc(100% - 10px); 16 | padding: 5px; 17 | flex-grow: 0; 18 | flex-shrink: 0; 19 | } 20 | 21 | nav h1, footer li { 22 | margin-top: auto; 23 | margin-bottom: auto; 24 | margin-left: 10px; 25 | } 26 | 27 | nav ul, footer ul { 28 | list-style-type: none; 29 | margin-left: auto; 30 | } 31 | 32 | nav li, footer li { 33 | margin-right: 20px; 34 | float: right; 35 | } 36 | 37 | nav a, footer a { 38 | color: white; 39 | text-decoration: none; 40 | } 41 | 42 | footer { 43 | background-color: #111111; 44 | color: white; 45 | padding: 10px; 46 | display: flex; 47 | height: 10%; 48 | margin-top: 20px; 49 | max-height: 150px; 50 | flex-grow: 0; 51 | flex-shrink: 0; 52 | } 53 | 54 | .content { 55 | padding: 10px; 56 | padding-left: 20px; 57 | padding-right: 20px; 58 | margin-top: 20px; 59 | flex-grow: 1; 60 | } 61 | 62 | .content ul { 63 | padding: 0px; 64 | border: 1px solid #CCCCCC; 65 | } 66 | 67 | .content li { 68 | list-style-type: none; 69 | } 70 | 71 | .content li:nth-child(odd) { 72 | background-color: white; 73 | } 74 | 75 | .content li:nth-child(even) { 76 | background-color: #DDDDDD; 77 | } 78 | 79 | table { 80 | width: 100%; 81 | border: 1px solid #CCCCCC; 82 | border-collapse: collapse; 83 | margin-top: 10px; 84 | margin-bottom: 10px; 85 | } 86 | 87 | td, th { 88 | border: 1px solid #CCCCCC; 89 | padding: 5px; 90 | } 91 | 92 | tr:nth-child(odd) { 93 | background-color: white; 94 | } 95 | 96 | tr:nth-child(even) { 97 | background-color: #DDDDDD; 98 | } 99 | 100 | p { 101 | white-space: pre-wrap; 102 | } 103 | 104 | .user-form textarea { 105 | height: 10em; 106 | } 107 | 108 | @media screen and (max-width: 800px) { 109 | .user-form input[type="text"] { 110 | width: 95%; 111 | } 112 | 113 | .user-form input[type="number"] { 114 | width: 95%; 115 | } 116 | 117 | .user-form textarea { 118 | width: 95%; 119 | } 120 | 121 | .main-content { 122 | padding-left: 5%; 123 | padding-right: 5%; 124 | } 125 | } 126 | 127 | @media screen and (min-width: 800px) { 128 | .user-form input[type="text"] { 129 | width: 99%; 130 | } 131 | 132 | .user-form input[type="number"] { 133 | width: 99%; 134 | } 135 | 136 | .user-form textarea { 137 | width: 99%; 138 | } 139 | 140 | .main-content { 141 | padding-left: 20%; 142 | padding-right: 20%; 143 | } 144 | } 145 | 146 | /* --- LOGIN/REGISTER PAGE START ---- */ 147 | 148 | .auth-form { 149 | display: table; 150 | margin: 0 auto; 151 | } 152 | 153 | .auth-field { 154 | display: table-row; 155 | } 156 | 157 | .auth-field label { 158 | display: table-cell; 159 | padding-bottom: 7px; 160 | padding-right: 10px; 161 | } 162 | 163 | .auth-field input { 164 | display: table-cell; 165 | } 166 | 167 | /* ---- LOGIN/REGISTER PAGE END ---- */ 168 | -------------------------------------------------------------------------------- /formie/templates/auth/login.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block content %} 4 |
5 |
6 |

Log In

7 |
8 |
9 | 10 | 11 |
12 |
13 | 14 | 15 |
16 |
17 | 18 |
19 |
20 |
21 |
22 | {% endblock %} 23 | -------------------------------------------------------------------------------- /formie/templates/auth/register.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block content %} 4 |
5 |
6 |

Register

7 |
8 |
9 | 10 | 11 |
12 |
13 | 14 | 15 |
16 |
17 | 18 |
19 |
20 |
21 |
22 | {% endblock %} 23 | -------------------------------------------------------------------------------- /formie/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Formie 4 | 5 | 6 | 7 | 19 |
20 |
21 | {% block header %}{% endblock %} 22 |
23 | {% for message in get_flashed_messages() %} 24 |
{{ message }}
25 | {% endfor %} 26 | {% block content %}{% endblock %} 27 |
28 | 33 | -------------------------------------------------------------------------------- /formie/templates/forms/creation_successful.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | Form creation successful! 4 | -------------------------------------------------------------------------------- /formie/templates/forms/form.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block content %} 4 |
5 | {% for index, field in schema %} 6 |
7 |
8 | {% if 'name' in field %} 9 | {{ field['name'] }} 10 | {% endif %} 11 | 12 | {% if field['type'] == 'text' %} 13 | {% if field['multiline'] %} 14 | 15 | {% else %} 16 | 17 | {% endif %} 18 | {% elif field['type'] == 'choice' %} 19 | {% if field['single'] %} 20 | {% for choice_index, choice in field['choices'] %} 21 | 25 | {% endfor %} 26 | {% else %} 27 | {% for choice_index, choice in field['choices'] %} 28 | 32 | {% endfor %} 33 | {% endif %} 34 | {% elif field['type'] == 'range' %} 35 | 36 | {% elif field['type'] == 'info' %} 37 |

{{ field['text'] }}

38 | {% endif %} 39 |
40 | 41 |
42 | {% endfor %} 43 |
44 |
45 | 46 |
47 |
48 | 49 | {% endblock %} 50 | -------------------------------------------------------------------------------- /formie/templates/forms/forms.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block content %} 4 |
    5 | {% for form in forms %} 6 |
  • 7 | {{ form["id"] }} by {{ form["creator"] }} | Results 8 |
  • 9 | {% endfor %} 10 |
11 | New Form 12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /formie/templates/forms/new.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block header %} 4 | 5 | {% endblock %} 6 | 7 | {% block content %} 8 | 9 | 10 |
11 |
Make results private. 12 |
Block non-logged in users from answering. 13 |
14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /formie/templates/forms/results.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block content %} 4 | 5 | 6 | 7 | {% for question in schema %} 8 | {% if question["name"] %} 9 | 10 | {% endif %} 11 | {% endfor %} 12 | 13 | {% for result in results %} 14 | 15 | {% for field in result %} 16 | 17 | {% endfor %} 18 | 19 | {% endfor %} 20 |
ID{{ question["name"] }}
{{ field }}
21 | Export as CSV 22 | {% endblock %} 23 | -------------------------------------------------------------------------------- /formie/templates/forms/submission_successful.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block content %} 4 | Form submission successful! 5 |
6 |
7 | {% if can_view_results %} 8 | You can view the results by clicking here. 9 | {% endif %} 10 | {% endblock %} 11 | -------------------------------------------------------------------------------- /formie/templates/index.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hacettepeoyt/formie/128446a4ab664d84d20af24e3a22cfadbf5ad814/formie/templates/index.html -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==2.1.3 2 | Werkzeug>=2.2,<3.0 3 | Flask-SQLAlchemy==2.5.1 4 | SQLAlchemy==1.4.48 5 | argon2-cffi==21.3.0 6 | passlib==1.7.4 7 | -------------------------------------------------------------------------------- /setup-db.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | 5 | from formie import create_app, models 6 | 7 | 8 | def main() -> None: 9 | try: 10 | version: int = int(sys.argv[1]) 11 | except (IndexError, ValueError): 12 | print(f"USAGE: {sys.argv[0]} ") 13 | print() 14 | print("Setups or upgrades the database depending on the version argument.") 15 | print() 16 | print("0 - full setup") 17 | print("1 - form access control flags upgrade") 18 | sys.exit(1) 19 | 20 | if version == 0: 21 | with create_app().app_context(): 22 | models.db.create_all() 23 | elif version == 1: 24 | with create_app().app_context(): 25 | with models.db.engine.begin() as conn: 26 | conn.execute( 27 | "ALTER TABLE Form ADD COLUMN access_control_flags INT NOT NULL DEFAULT 0;" 28 | ) 29 | else: 30 | print("ERROR: invalid version", file=sys.stderr) 31 | sys.exit(1) 32 | 33 | 34 | if __name__ == "__main__": 35 | main() 36 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate rocket; 3 | 4 | use rocket::response::Redirect; 5 | use rocket_db_pools::{sqlx, Database}; 6 | 7 | mod proxy; 8 | 9 | #[derive(Database)] 10 | #[database("db")] 11 | struct DB(sqlx::SqlitePool); 12 | 13 | #[get("/")] 14 | fn index() -> Redirect { 15 | Redirect::to("/forms/") 16 | } 17 | 18 | #[launch] 19 | fn rocket() -> _ { 20 | let config = rocket::Config::figment().merge(( 21 | "databases.db.url", 22 | std::env::var("SQLALCHEMY_DATABASE_URI") 23 | .unwrap_or("sqlite:///formie.sqlite".to_string()) 24 | .strip_prefix("sqlite:///") 25 | .expect("Malformed SQLALCHEMY_DATABASE_URI"), 26 | )); 27 | 28 | rocket::custom(config) 29 | .attach(DB::init()) 30 | .mount("/", routes![index]) 31 | .mount("/", proxy::ProxyHandler) 32 | .manage(proxy::SecondaryServer::new()) 33 | } 34 | -------------------------------------------------------------------------------- /src/proxy.rs: -------------------------------------------------------------------------------- 1 | use rocket::data::ToByteUnit; 2 | use rocket::http::Method; 3 | use rocket::response::Responder; 4 | use rocket::route::Handler; 5 | use rocket::route::Outcome; 6 | use rocket::Data; 7 | use rocket::Request; 8 | use rocket::Route; 9 | 10 | pub struct SecondaryServer { 11 | process: std::process::Child, 12 | } 13 | 14 | impl SecondaryServer { 15 | pub fn new() -> SecondaryServer { 16 | #[cfg(debug_assertions)] 17 | SecondaryServer { 18 | process: std::process::Command::new("/usr/bin/env") 19 | .args(if cfg!(debug_assertions) { 20 | vec!["python", "-m", "flask", "run", "-p 5241"] 21 | } else { 22 | vec![ 23 | "python", 24 | "-m", 25 | "gunicorn", 26 | "--bind", 27 | "127.0.0.1:5241", 28 | "formie:create_app()", 29 | ] 30 | }) 31 | .spawn() 32 | .expect("Failed to start secondary server"), 33 | } 34 | } 35 | } 36 | 37 | impl Drop for SecondaryServer { 38 | fn drop(&mut self) { 39 | eprintln!("Cleaning up secondary server..."); 40 | 41 | match self.process.try_wait() { 42 | Ok(Some(_)) => (), 43 | _ => { 44 | eprintln!("Sending sigterm to secondary server."); 45 | unsafe { 46 | libc::kill(self.process.id() as i32, libc::SIGTERM); 47 | } 48 | } 49 | } 50 | 51 | let _ = self.process.wait(); 52 | } 53 | } 54 | 55 | fn transform_method(method: rocket::http::Method) -> reqwest::Method { 56 | match method { 57 | rocket::http::Method::Get => reqwest::Method::GET, 58 | rocket::http::Method::Put => reqwest::Method::PUT, 59 | rocket::http::Method::Post => reqwest::Method::POST, 60 | rocket::http::Method::Delete => reqwest::Method::DELETE, 61 | rocket::http::Method::Options => reqwest::Method::OPTIONS, 62 | rocket::http::Method::Head => reqwest::Method::HEAD, 63 | rocket::http::Method::Trace => reqwest::Method::TRACE, 64 | rocket::http::Method::Connect => reqwest::Method::CONNECT, 65 | rocket::http::Method::Patch => reqwest::Method::PATCH, 66 | } 67 | } 68 | 69 | pub async fn upstream_request( 70 | uri: &str, 71 | method: reqwest::Method, 72 | req_ctx: &Request<'_>, 73 | body: Option>, 74 | ) -> reqwest::Response { 75 | let client = reqwest::Client::builder() 76 | .redirect(reqwest::redirect::Policy::none()) 77 | .build() 78 | .unwrap(); 79 | 80 | let mut req_headers = reqwest::header::HeaderMap::new(); 81 | for h in req_ctx.headers().clone().iter() { 82 | req_headers.insert( 83 | reqwest::header::HeaderName::from_bytes(h.name.as_str().as_bytes()).unwrap(), 84 | h.value().parse().unwrap(), 85 | ); 86 | } 87 | 88 | client 89 | .request(method, format!("http://127.0.0.1:5241{}", uri)) 90 | .headers(req_headers) 91 | .body(if body.is_some() { 92 | body.unwrap() 93 | .open(8.mebibytes()) 94 | .into_bytes() 95 | .await 96 | .unwrap() 97 | .value 98 | } else { 99 | vec![] 100 | }) // TODO: stream this 101 | .send() 102 | .await 103 | .unwrap() 104 | } 105 | 106 | struct WrappedResponse<'r>(rocket::response::Result<'r>); 107 | 108 | impl WrappedResponse<'_> { 109 | async fn from<'r>(req: &'r Request<'_>, data: Data<'r>) -> WrappedResponse<'r> { 110 | let res = upstream_request( 111 | &format!("{}", req.uri()), 112 | transform_method(req.method()), 113 | req, 114 | Some(data), 115 | ) 116 | .await; 117 | let mut res2 = rocket::response::Response::build(); 118 | res2.status(rocket::http::Status { 119 | code: res.status().as_u16(), 120 | }); 121 | 122 | for (k, v) in res.headers().clone() { 123 | if let (Some(key), Ok(value)) = (k, v.to_str()) { 124 | res2.raw_header(key.as_str().to_owned(), value.to_owned()); 125 | } 126 | } 127 | 128 | // TODO: stream this 129 | let data = res.bytes().await.unwrap(); 130 | 131 | WrappedResponse(res2.sized_body(data.len(), std::io::Cursor::new(data)).ok()) 132 | } 133 | } 134 | 135 | #[rocket::async_trait] 136 | impl<'r> Responder<'r, 'r> for WrappedResponse<'r> { 137 | fn respond_to(self, _: &'r Request<'_>) -> rocket::response::Result<'r> { 138 | self.0 139 | } 140 | } 141 | 142 | #[derive(Clone)] 143 | pub struct ProxyHandler; 144 | 145 | #[rocket::async_trait] 146 | impl Handler for ProxyHandler { 147 | async fn handle<'r>(&self, req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r> { 148 | Outcome::from(req, WrappedResponse::from(req, data).await) 149 | } 150 | } 151 | 152 | #[allow(clippy::from_over_into)] 153 | impl Into> for ProxyHandler { 154 | fn into(self) -> Vec { 155 | vec![ 156 | Route::new(Method::Get, "/", self.clone()), 157 | Route::new(Method::Post, "/", self), 158 | ] 159 | } 160 | } 161 | --------------------------------------------------------------------------------