Compare commits

..

526 Commits

Author SHA1 Message Date
dependabot[bot]
77b0ede555 chore(deps): bump aes-gcm from 0.10.2 to 0.10.3
Bumps [aes-gcm](https://github.com/RustCrypto/AEADs) from 0.10.2 to 0.10.3.
- [Commits](https://github.com/RustCrypto/AEADs/compare/aes-gcm-v0.10.2...aes-gcm-v0.10.3)

---
updated-dependencies:
- dependency-name: aes-gcm
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-22 16:13:33 +00:00
Aravinth Manivannan
f337ee0643 Merge pull request #90 from mCaptcha/wip-reuse
feat: init reuse tool
2023-07-04 16:03:55 +05:30
Aravinth Manivannan
19d07489f0 fix: run make sqlx to update offline data with license header modification 2023-07-04 15:37:52 +05:30
Aravinth Manivannan
78d85ab9a9 feat: annotate license headers using reuse on text source files 2023-07-03 23:19:51 +05:30
Aravinth Manivannan
d707a2265c feat: init reuse tool 2023-07-03 23:19:38 +05:30
Aravinth Manivannan
376a9348cb Merge pull request #96 from mCaptcha/update-deps
chore: update swagger ui
2023-07-03 20:12:48 +05:30
Aravinth Manivannan
6b94708935 chore: temporarily disable OPENAPI testing
TODO: fix tests
2023-07-03 19:30:55 +05:30
Aravinth Manivannan
0094bac559 feat: use redocly instead of the possibly deprecated swagger-cli 2023-07-03 19:30:36 +05:30
Aravinth Manivannan
04cb724df1 Merge pull request #95 from mCaptcha/fix-integration
debug: first run firefox tests
2023-07-03 19:09:27 +05:30
Aravinth Manivannan
461020d413 chore: update swagger ui 2023-07-03 19:09:03 +05:30
Aravinth Manivannan
c8e6b81d6e debug: first run firefox tests 2023-07-03 17:56:30 +05:30
Aravinth Manivannan
71ef95e4c4 Merge pull request #94 from mCaptcha/update-deps
Update deps
2023-07-03 00:08:53 +05:30
Aravinth Manivannan
b2f373dffd Merge pull request #93 from mCaptcha/pow-live-stats
Pow live stats
2023-07-02 23:22:05 +05:30
Aravinth Manivannan
c3ab7f8b0e chore: use node v18.0.0 2023-07-02 22:05:23 +05:30
Aravinth Manivannan
c4a286454b chore: update rust and js deps 2023-07-02 22:05:23 +05:30
Aravinth Manivannan
4a25f7f3a6 fix: truncate pow compute time before submitting 2023-07-02 22:05:23 +05:30
Aravinth Manivannan
32762cf6b5 fix: linting 2023-07-02 22:04:42 +05:30
Aravinth Manivannan
43024f1940 fix: CI: update make command 2023-07-02 21:54:42 +05:30
Aravinth Manivannan
1e0aedad61 chore: linting 2023-07-02 21:51:24 +05:30
Aravinth Manivannan
1b05cdc391 fix: truncate pow compute time before submitting 2023-07-02 20:27:03 +05:30
Aravinth Manivannan
3e5936cb83 fix: CI: pin mariadb to version 10 2023-07-02 18:37:38 +05:30
Aravinth Manivannan
2ca49cffe4 feat: see publication status in sitekey view page 2023-06-30 16:50:04 +05:30
Aravinth Manivannan
468752f691 feat: advance siteey create now allows setting publication status 2023-06-30 16:49:35 +05:30
Aravinth Manivannan
22edb04ce2 feat: advance sitekey edit now allows modifying publication status 2023-06-30 16:48:53 +05:30
Aravinth Manivannan
6834e555d8 chore: use db util method to check publication status 2023-06-30 16:33:20 +05:30
Aravinth Manivannan
3c6b13f947 feat: utility method to check if captcha is published 2023-06-30 16:15:44 +05:30
Aravinth Manivannan
99db889867 chore: refactor test (coverage and frontend) subroutines in Makefile 2023-06-30 07:55:53 +05:30
Aravinth Manivannan
56dba7b77f feat: option to publish pow performance numbers. Can un/publish from edit page too. 2023-06-30 07:55:12 +05:30
Aravinth Manivannan
1c4ee5b622 feat: upload pow performance benchmarks 2023-06-30 07:54:54 +05:30
Aravinth Manivannan
d8a145cf87 chore: refactor test workflows in Makefile 2023-06-30 07:28:13 +05:30
Aravinth Manivannan
8ca48d85ff fix: worker_type should not be unique 2023-06-30 07:18:34 +05:30
Aravinth Manivannan
2b82af9a0c feat: update novice captcha creation form to include publish_benchmarks
preference
2023-06-30 03:20:57 +05:30
Aravinth Manivannan
2cf5e48d8e feat: log pow performance stats while pow verification 2023-06-30 03:19:38 +05:30
Aravinth Manivannan
679a35216c feat: delete analytics when webmaster updates publishing status 2023-06-30 03:16:43 +05:30
Aravinth Manivannan
68b59ade8c feat: add psuedo ID support to publish campaign IDs 2023-06-30 01:48:24 +05:30
Aravinth Manivannan
8af09939ff feat: pagination on performance logs fetches 2023-06-28 22:54:18 +05:30
Aravinth Manivannan
dc380adfcf chore: bump libmcaptcha 2023-06-28 22:49:08 +05:30
Aravinth Manivannan
f8e3b720de fix: ignore failures when creating dependency containers.
Failures happen when containers already exist, so ignoring is alright
2023-06-28 11:59:26 +05:30
Aravinth Manivannan
5ae3b1f26e feat: store pow performance statistics against statistics 2023-06-27 19:47:04 +05:30
Aravinth Manivannan
2a1bda653d feat: run migrations using sqlx also 2023-06-27 19:46:54 +05:30
Aravinth Manivannan
b0db04f26a feat: make: deploy dependencies 2023-06-27 15:14:08 +05:30
Aravinth Manivannan
746748f98c Merge pull request #84 from Timwi/patch-1
Typo in README.md
2023-06-07 10:12:23 +05:30
Timwi
003ed983cb Typo in README.md 2023-05-30 12:47:41 +02:00
Aravinth Manivannan
78de0b266f Merge pull request #77 from mCaptcha/nighwatch
Integration testing using Nighwatch (firefox + chromium)
2023-05-25 21:23:37 +05:30
Aravinth Manivannan
6ede578ad5 Merge pull request #83 from Benjamin-Loison/master
Correct a typo and add necessary spaces in `README.md`
2023-05-25 21:08:10 +05:30
Aravinth Manivannan
efed5f5f93 Merge pull request #82 from Supernova3339/patch-1
🐛 Typo fix in Documentation
2023-05-25 21:05:08 +05:30
Benjamin Loison
4a6850631a Correct a typo and add necessary spaces in README.md 2023-05-23 15:08:55 +02:00
SuperDev
0adbb0aa2f Update CONFIGURATION.md
FIx typo in documentation
2023-05-18 12:44:39 -05:00
Aravinth Manivannan
8f3faaa279 Merge pull request #75 from WizardTales/licensefix
fix(license): accidential AGPL in MIT licensed files
2023-05-01 16:02:58 +05:30
Aravinth Manivannan
5324969bd2 feat: install selenium drivers 2023-04-30 23:46:58 +05:30
Aravinth Manivannan
43dab030df feat: run nightwatch integration tests on CI 2023-04-30 20:18:47 +05:30
Aravinth Manivannan
9cc667851c feat: run integration tests using nightwatch js 2023-04-30 20:17:51 +05:30
Tobias Gurtzick
9fc7c31083 fix(license): accidential AGPL in MIT licensed files
fixes #69

Signed-off-by: Tobias Gurtzick <magic@wizardtales.com>
2023-04-18 11:20:12 +02:00
Aravinth Manivannan
90e60b0486 Merge pull request #70 from mCaptcha/fix-53
fix: update libmcaptcha to use connection manager
2023-03-31 17:29:58 +05:30
Aravinth Manivannan
58f93cb602 fix: update libmcaptcha to use connection manager
closes: https://github.com/mCaptcha/mCaptcha/issues/53
2023-03-31 16:20:13 +05:30
Aravinth Manivannan
fae50b19f8 Merge pull request #67 from mCaptcha/dependabot/cargo/openssl-0.10.48
chore(deps): bump openssl from 0.10.41 to 0.10.48
2023-03-25 11:43:57 +05:30
dependabot[bot]
e890ba0f57 chore(deps): bump openssl from 0.10.41 to 0.10.48
Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.41 to 0.10.48.
- [Release notes](https://github.com/sfackler/rust-openssl/releases)
- [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.41...openssl-v0.10.48)

---
updated-dependencies:
- dependency-name: openssl
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-25 05:03:34 +00:00
Aravinth Manivannan
744d94cf8d Merge pull request #66 from mCaptcha/dependabot/npm_and_yarn/docs/openapi/minimist-1.2.8
chore(deps): bump minimist from 1.2.5 to 1.2.8 in /docs/openapi
2023-03-25 10:33:03 +05:30
Aravinth Manivannan
31d12206aa feat: add NLnet funding details 2023-03-08 17:08:39 +05:30
dependabot[bot]
7764eda05d chore(deps): bump minimist from 1.2.5 to 1.2.8 in /docs/openapi
Bumps [minimist](https://github.com/minimistjs/minimist) from 1.2.5 to 1.2.8.
- [Release notes](https://github.com/minimistjs/minimist/releases)
- [Changelog](https://github.com/minimistjs/minimist/blob/main/CHANGELOG.md)
- [Commits](https://github.com/minimistjs/minimist/compare/v1.2.5...v1.2.8)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-06 12:38:56 +00:00
Aravinth Manivannan
f78669955c Merge pull request #60 from mCaptcha/fix-59
fix: copy OpenAPI build from build container to final container
2023-01-17 04:26:20 +05:30
Aravinth Manivannan
cadc15a7a1 fix: copy OpenAPI build from build container to final container
fixes: https://github.com/mCaptcha/mCaptcha/issues/59
2023-01-17 03:54:54 +05:30
Aravinth Manivannan
c1f6ce3ae2 Merge pull request #52 from Gusted/close-register-page
Hide register page when registrations are closed
2022-11-07 13:39:34 +05:30
Gusted
864549cb4c Fix copyright 2022-11-06 19:42:22 +01:00
Gusted
5713d4b1ae Hide register page when registrations are closed
- Improve UX for "private" instances.
2022-10-24 22:47:07 +02:00
Aravinth Manivannan
ac502b7c08 Merge pull request #51 from Gusted/fix-compiling
Fix compiling
2022-10-24 21:22:34 +05:30
Gusted
8dc690ca01 Remove redunant format 2022-10-24 16:22:10 +02:00
Gusted
a4f9c92b32 Update cargo 2022-10-22 21:53:18 +02:00
Gusted
8826f6df8f Fix compiling
- I made some mistakes while checking my two previous PRs(Seems like I
don't understand Rust that great after all).
- Do the url encoding only on the password part, not only the whole URL.
- Fix `temporary value dropped while borrowed` compile error.
2022-10-22 21:28:58 +02:00
Aravinth Manivannan
af35fdb48e Merge pull request #46 from Gusted/relax-port-env
Allow `PORT` environment to be not set
2022-10-18 15:51:22 +05:30
Gusted
9fd8ffd666 Add more logging for configuration/env 2022-10-17 19:49:42 +02:00
Aravinth Manivannan
521abd82d6 Merge pull request #47 from Gusted/encode-url-postgres
Encode connection URL to database
2022-10-17 15:42:02 +05:30
Gusted
021f2fe5b4 Encode connection URL to database
- If you have a database password that contains characters like `#` or `*`, sqlx
will error about a InvalidPort, this is due to not encoding the url.
[See issue on sqlx](https://github.com/launchbadge/sqlx/issues/1624).
- Removed useless statements.
2022-10-16 23:37:24 +02:00
Gusted
b3e0ff6769 Allow PORT environment to be not set
- It's quite weird to require the `PORT` environment to be set, when it
already can be set via the config file.
2022-10-16 23:07:10 +02:00
Aravinth Manivannan
97abca2520 Merge pull request #45 from DarianAnjuhal/master
feat: open mail link with target=_blank
2022-10-12 15:28:13 +05:30
Daniel Antlinger
96a6c98c10 feat: open mail link with target=_blank 2022-10-12 11:50:55 +02:00
realaravinth
9d285573d7 fix: typo in widget 2022-09-26 16:40:40 +05:30
Aravinth Manivannan
d506d291c3 Merge pull request #43 from DarianAnjuhal/master
feat: open links from widget in new pages target=_blank
2022-09-07 23:31:56 +05:30
Daniel Antlinger
223e8fb8c2 feat: open links from widget in new pages target=_blank 2022-09-07 14:05:25 +02:00
realaravinth
2abf57d16b fix: set correct upload dir 2022-08-15 18:01:41 +05:30
realaravinth
b3ee57d042 fix: configure gpg key 2022-08-15 17:37:48 +05:30
realaravinth
8c65edd257 fix: upload path 2022-08-15 17:25:22 +05:30
realaravinth
9f521fe199 feat: publish mcaptcha bin to dl.mcaptcha.org 2022-08-15 17:03:46 +05:30
realaravinth
8ac1e2b81e feat: package and sign dist assets 2022-08-15 17:03:46 +05:30
Aravinth Manivannan
5db58d477b Merge pull request #24 from mCaptcha/dependabot/npm_and_yarn/nanoid-3.3.4
Bump nanoid from 3.1.29 to 3.3.4
2022-08-14 01:32:55 +05:30
Aravinth Manivannan
db03cd3b1f Merge pull request #34 from mCaptcha/dependabot/npm_and_yarn/terser-5.14.2
chore(deps): bump terser from 5.9.0 to 5.14.2
2022-08-14 01:32:25 +05:30
realaravinth
e5e89bd8a0 chore: bump libmcaptcha, switch to master 2022-08-13 01:58:40 +05:30
Aravinth Manivannan
2dd6f063c5 Merge pull request #40 from Gusted/automate-releases
Automate releases via Github Actions
2022-08-12 18:39:48 +05:30
Gusted
bb81e7fb9b Automate releases via Github Actions
- Use Github Actions to compile static linked binaries for the three
major OS and upload them to Github Releases.
2022-08-12 14:55:57 +02:00
realaravinth
b3d00c89a6 feat: increase demo test waint time 2022-08-09 17:08:26 +05:30
realaravinth
8c9587ad65 feat: set custom runers and queue length 2022-08-09 16:30:04 +05:30
realaravinth
21825582e5 feat: fallabck to localhost when running tests 2022-08-09 16:29:24 +05:30
realaravinth
f8e6bdf229 feat: bump libmcaptcha 2022-08-09 16:29:05 +05:30
realaravinth
8c576d2b07 feat: queue length and IP runner config 2022-08-09 16:28:30 +05:30
realaravinth
c377cf431e feat & fix: ip queues 2022-08-09 02:52:17 +05:30
realaravinth
ce1b3b0856 feat: bump libmcaptcha and pow_sha256 2022-08-09 02:51:40 +05:30
Aravinth Manivannan
cd6cecfe4a Merge pull request #39 from evilsocket/master
fix: fixes broken docker-compose.yml (#38)
2022-08-05 17:40:05 +05:30
Simone Margaritelli
a66d75c3c3 fix: fixes broken docker-compose.yml (#38) 2022-08-05 14:00:40 +02:00
Aravinth Manivannan
3d9056e968 Merge pull request #36 from kianmeng/fix-typos
Fix typos
2022-08-05 14:26:11 +05:30
Kian-Meng Ang
bb42841a66 Fix typos 2022-08-04 23:06:54 +08:00
Aravinth Manivannan
961bb6c5f4 Merge pull request #35 from Gusted/use-full-screen
Let widget use full-screen
2022-07-27 21:35:52 +05:30
Gusted
f56bc6d9e4 Let widget use full-screen
- Instead of using static values for dimensions. Use responsive CSS and
take up the whole screen. Let the user deal with setting the correct
dimensions accordingly.
2022-07-26 22:58:17 +02:00
realaravinth
a040b39558 fix: set db type when overriding with DATABASE_URL 2022-07-23 16:46:49 +05:30
realaravinth
80214b776c feat: add database_type attr and make db connection parameter descriptions generic 2022-07-23 16:22:51 +05:30
realaravinth
6de9129cd0 feat: add instructions to setup mariadb 2022-07-23 16:17:59 +05:30
realaravinth
1fded38ee8 fix: gh-pages branch CI trigger exclusion 2022-07-23 15:57:24 +05:30
realaravinth
96119fdc71 feat: adapt migrate and sqlx-offline-data to include mariadb support 2022-07-23 15:50:47 +05:30
realaravinth
337a378b08 feat: add checks to verify the DB error situations 2022-07-23 15:50:25 +05:30
realaravinth
d5b17ac00e fix: mariadb error to lib error conversion 2022-07-23 15:50:01 +05:30
realaravinth
a50763f520 feat: implement get_secret_from_captcha for db-sqlx-mariadb 2022-07-23 15:49:41 +05:30
realaravinth
6f5c09185f feat: add MARIA_DATABASE_URL to .env_sample and load maria config in CI 2022-07-23 12:04:17 +05:30
realaravinth
249b6461ee chore: migrate tests to also run with mariadb 2022-07-23 11:59:42 +05:30
realaravinth
912b342e0e feat: conditionally init postgres/mariadb connection 2022-07-23 11:59:42 +05:30
realaravinth
f9efb062e0 feat: accept alt DB configuration 2022-07-23 11:59:42 +05:30
realaravinth
b8d3b1449a feat: adapt db/db-migrations to run mariadb migrations 2022-07-23 11:59:42 +05:30
realaravinth
9b5b34a1f8 feat: impl MCDatabase for mariadb 2022-07-23 11:59:42 +05:30
realaravinth
0b2af2f900 feat: setup CI for mariadb support 2022-07-23 11:59:41 +05:30
realaravinth
9371416398 fix: normalize username during login process too
credits: @gusted
2022-07-23 02:24:30 +05:30
realaravinth
9a687f99ee feat: mv maildev to services 2022-07-23 02:13:12 +05:30
realaravinth
b6afe79a81 fix: initialize DOM elements only when executing methods/in pages that
contain those elements

SUMMARY
    Trying to grab elements globally in a script results in it trying to
    initialize in all pages. When the element is absent, the script
    fails and JavaScript crashes.
2022-07-23 00:48:51 +05:30
realaravinth
b12c30e956 feat: cache-bust when make run is called 2022-07-23 00:48:05 +05:30
realaravinth
c5dc72a83c fix: don't escape license prefixes and script content 2022-07-23 00:47:44 +05:30
realaravinth
3c3982bad5 feat: CI: publish docker img 2022-07-22 23:42:25 +05:30
realaravinth
c92a35a01f fix: add sqlx offline compilation data 2022-07-22 20:04:41 +05:30
realaravinth
5410a4657b feat: add changelog entry to doc change in access token verification
payload
2022-07-22 19:49:07 +05:30
realaravinth
7d0e4c6be4 fix: prevent sitekey abuse with account secret authentication for access token validation
SUMMARY
    At present, sitekey can be abused by installing it on a third-party
    site as verifying the access token returned from CAPTCHA validation
    doesn't require any authentication.

    This fix uses account secret authentication to verify access tokens

credits: by @gusted
2022-07-22 19:44:35 +05:30
realaravinth
85f91cb79b feat: update libmcaptcha 2022-07-21 18:29:16 +05:30
realaravinth
31978a83f2 fix: docker-compose -d up -> docker-compose up -d 2022-07-20 14:45:25 +05:30
realaravinth
22b312b8c5 fix: services.mcaptcha.depends_on must be a list 2022-07-20 14:44:46 +05:30
dependabot[bot]
8a667ad71f chore(deps): bump terser from 5.9.0 to 5.14.2
Bumps [terser](https://github.com/terser/terser) from 5.9.0 to 5.14.2.
- [Release notes](https://github.com/terser/terser/releases)
- [Changelog](https://github.com/terser/terser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/terser/terser/commits)

---
updated-dependencies:
- dependency-name: terser
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-20 06:01:46 +00:00
PierreC
2dce6eb2e8 Fixing some docs issues and adding some lines in docker-compose.yml (#33)
* Update README.md

* Update README.md

* Update DEPLOYMENT.md

* Update docker-compose.yml
2022-07-19 15:54:42 +05:30
realaravinth
c7d1bc3191 fix: rename postgres in docker-compose to avoid namespace collision
fixes: https://github.com/mCaptcha/mCaptcha/issues/31
2022-07-18 22:58:02 +05:30
Aravinth Manivannan
37004c7b4f Merge pull request #30 from felixonmars/patch-1
Correct typos in HACKING.md
2022-07-17 14:37:53 +05:30
Felix Yan
fa9a1a2f4c Correct typos in HACKING.md 2022-07-17 13:29:21 +08:00
realaravinth
5daeffd6fb chore: tests to verify mCaptcha counter 2022-05-31 12:46:09 +05:30
realaravinth
be9c6b757e fix: invert debug flag to set DB logging flag 2022-05-30 16:56:55 +05:30
realaravinth
b30bc67bd4 feat: conditional SQL statements logging for db-sqlx-postgres 2022-05-30 15:48:54 +05:30
realaravinth
a9f8cc24a6 feat: docker build caching with cargo-chef 2022-05-28 16:22:34 +05:30
realaravinth
3710c8f653 feat: fix sqlx offline compilation 2022-05-27 19:06:07 +05:30
realaravinth
629c841e2d chore: cleanup and addressing clippy lints 2022-05-27 18:37:59 +05:30
realaravinth
d7fd23f565 chore: get rid of direct DB init and use db_* 2022-05-27 18:25:27 +05:30
realaravinth
cd72ae6ffe feat: migrate fetch captcha config to use db_* 2022-05-27 18:16:47 +05:30
realaravinth
3a535c04a6 feat: impl traits to fetch captcha config sqlx postgres 2022-05-27 18:16:27 +05:30
realaravinth
2212b3b974 feat: def traits to get captcha config 2022-05-27 18:14:51 +05:30
realaravinth
a15d963c3e feat: migrate get_levels to use db_* 2022-05-27 17:24:40 +05:30
realaravinth
098d0cfc24 feat: migrate fetching stats to use db_* 2022-05-27 17:11:15 +05:30
realaravinth
bc90a51d30 feat: impl fetch captcha stats sqlx postgres 2022-05-27 17:08:55 +05:30
realaravinth
cf66e7efc6 feat: def traits to fetch captcha stats 2022-05-27 17:07:10 +05:30
realaravinth
21dcc2144b feat: add cmd to run db tests only 2022-05-27 17:07:05 +05:30
realaravinth
bbc8873762 feat: migrate record_stats to use db_* 2022-05-27 16:23:33 +05:30
realaravinth
d28d752a78 feat: impl record stats traits for sqlx postgres 2022-05-27 16:22:45 +05:30
realaravinth
0d395ea67e feat: def traits to record captcha fetch stats 2022-05-27 16:21:47 +05:30
realaravinth
851874f8cf feat: load config to make captcha stats optional 2022-05-27 15:25:33 +05:30
realaravinth
4cd4605266 chore: use local app ctx 2022-05-27 15:25:10 +05:30
realaravinth
12edac7915 feat: migrate get_email to use db_* 2022-05-27 03:08:37 +05:30
realaravinth
38d518d843 feat: impl def_email for sqlx postgres 2022-05-26 20:35:38 +05:30
realaravinth
6e45c643b1 feat: def get_email trait 2022-05-26 20:35:25 +05:30
realaravinth
aad49dbb94 feat: migrate notifications add, mark_read and get to use db_* traits 2022-05-26 20:03:05 +05:30
realaravinth
44740535c2 feat: impl traits to add, get and mark read notifications for sqlx
postgres
2022-05-26 19:32:16 +05:30
realaravinth
e9921db55b feat: def traits for adding, getting notifications and marking them read 2022-05-26 19:31:36 +05:30
realaravinth
e4cf625d48 feat: migrate del traffic pattern to use db_* interface 2022-05-14 18:57:58 +05:30
realaravinth
84a92468a1 feat: impl sqlx postgress interface to del traffic pattern 2022-05-14 18:57:21 +05:30
realaravinth
5270ced600 feat: def interface to del traffic pattern 2022-05-14 18:56:41 +05:30
realaravinth
2dd18897b0 feat: migrate getting traffic pattern to use db_* interface 2022-05-14 18:45:59 +05:30
realaravinth
b983f08884 feat: impl sqlx postgress interface to get traffic pattern 2022-05-14 18:45:42 +05:30
realaravinth
212c03a0e2 feat: def interface to get traffic pattern 2022-05-14 18:45:25 +05:30
realaravinth
a6920f5f36 feat: migrate add user's traffic pattern sqlx postgres to use db_* 2022-05-14 18:22:50 +05:30
realaravinth
dacdd2cb8e feat: implement interface to add user's traffic pattern sqlx postgres 2022-05-14 18:22:36 +05:30
realaravinth
2132ab5791 feat: define interface to add user's traffic pattern 2022-05-14 18:22:21 +05:30
realaravinth
04b0073d7c feat: migrate DB migrations to use db_* 2022-05-14 16:44:42 +05:30
realaravinth
d061824660 feat: migrate get captcha cooldown period to use db_* 2022-05-14 16:27:44 +05:30
realaravinth
7daffe767c feat: implement get captcha cooldown period interface for sqlx postgres 2022-05-14 16:27:28 +05:30
realaravinth
09a8591cb4 feat: define get captcha cooldown period interface 2022-05-14 16:27:15 +05:30
realaravinth
9d7bb3c0be feat: use cache busting bin and load assets generated by it 2022-05-14 16:00:22 +05:30
realaravinth
0593e254bb feat: run cache busting via a separate bin 2022-05-14 15:59:40 +05:30
realaravinth
a971d4209d fix and chore: refactor tests to minimize initializing DB connections
SUMMARY
    The test suite was spinning up way too many database connections that what's
    strictly needed and so the test suite was failing with[0]:
	code: "53300", message: "sorry, too many clients already"

EXPERIMENTS
    Tried sharing database connection pool across all tests with
    async_once[0] but faced:
	- IO errors
	    The connections were probably getting dropped in between tests
	- actix Actor errors
	    The actor was probably not getting initialized before a
	    a reference to the async_once initialized app
	    context(crate::data::Data) is retrieved and used

FIX
    crate::tests was spinning up an App context
    instance(crate::data::Data) for most utility functions, which was
    unnecessarily excessive.

    Each test now creates an instance of the application context at the
    beginning and shared a reference with all test utility functions. So
    number of database connections/app context instance = number of unit
    tests.

[0]: permanently fixes #22
[1]: https://docs.rs/async_once/latest/async_once/
2022-05-14 12:55:56 +05:30
realaravinth
176df3c7a7 feat: migrate get captcha levels to use db_* 2022-05-13 19:09:29 +05:30
realaravinth
ddb6d336f7 feat: implement accountnotfound and captcha notfound err vals for sqlx postgres 2022-05-13 19:09:00 +05:30
realaravinth
3edb2252af feat: define accountnotfound and captcha notfound err vals 2022-05-13 19:08:14 +05:30
realaravinth
a7590ea14e feat: implement getting captcha levels for sqlx postgres 2022-05-13 19:07:50 +05:30
realaravinth
04a9bc5cc7 feat: define interface for getting captcha levels 2022-05-13 19:07:27 +05:30
realaravinth
2dff139ae2 feat: migrate update_key to use db_* 2022-05-12 20:22:43 +05:30
realaravinth
b2d32c6113 feat: implement update_captcha_key for sqlx postgres 2022-05-12 20:19:08 +05:30
realaravinth
e2ebae6e2e feat: define interface for update_captcha_key 2022-05-12 20:18:53 +05:30
realaravinth
aa5bdcf1dc fix: upload coverage on all branches that run the coverage CI run 2022-05-12 20:18:28 +05:30
realaravinth
add7271531 feat: migrate updating captcha metadata to use db_* 2022-05-12 20:09:56 +05:30
realaravinth
6b10ed6982 feat: implement updating captcha metadata for sqlx postgres 2022-05-12 20:09:40 +05:30
realaravinth
1e6a259d57 feat: define interface for updating captcha metadata 2022-05-12 20:09:18 +05:30
realaravinth
c458e4a233 fix: inject postgres URL while running migrations 2022-05-12 19:57:06 +05:30
realaravinth
b6445000fe feat: migrate delete captcha to use db_* interface 2022-05-12 19:56:23 +05:30
realaravinth
15c352f6b5 feat: implement delete_captcha_levels and delete_captcha for sqlx postgres 2022-05-12 19:55:51 +05:30
realaravinth
af46a3c54d feat: define interfaces for delete_captcha_levels and delete_captcha 2022-05-12 19:55:03 +05:30
realaravinth
0c1a82b4c5 feat: migrate tests utils to use db_* interface 2022-05-12 19:33:26 +05:30
realaravinth
81ad030338 feat: migrate captcha exists to use db_* interface 2022-05-12 19:32:08 +05:30
realaravinth
0bb975a230 feat: implement captcha exists interface for sqlx postgres 2022-05-12 19:31:50 +05:30
realaravinth
55518ef650 feat: define captcha_exists interface 2022-05-12 19:31:26 +05:30
realaravinth
2f924607ab fix: harden failure modes on hotfix test fix 2022-05-12 19:30:13 +05:30
realaravinth
28e9d67fce fix: load correct env file 2022-05-12 19:29:48 +05:30
realaravinth
bd75fc625c feat: migrate adding captcha to use db_* interface 2022-05-12 19:10:04 +05:30
realaravinth
79ff7b9917 feat: implement adding captcha for sqlx postgres 2022-05-12 19:09:44 +05:30
realaravinth
277d2bb9e5 feat: define interface for adding captcha 2022-05-12 19:09:25 +05:30
realaravinth
0d3d552ae0 feat: migrate create captcha to use db_* 2022-05-12 18:59:44 +05:30
realaravinth
d64b05c84f feat: implement create captcha for sqlx postgres 2022-05-12 11:52:53 +05:30
realaravinth
00dca4a069 feat: define interface for creating captcha 2022-05-12 11:50:24 +05:30
realaravinth
049f2b6eea feat: migrate update secret to use db_* interface 2022-05-12 10:42:55 +05:30
realaravinth
ec6b49c2e1 feat: implement update secret interface for sqlx postgres 2022-05-12 10:21:13 +05:30
realaravinth
d4a080b5fc feat: define interface for updating user secret 2022-05-12 10:20:41 +05:30
realaravinth
25b3d316db feat: migrate get password and get secret to use db_* interface 2022-05-11 20:21:55 +05:30
realaravinth
8813cf80ce feat: implement get secret interface for sqlx postgres 2022-05-11 20:21:33 +05:30
realaravinth
28ddadc5fe feat: define interface for getting user secret 2022-05-11 20:21:06 +05:30
realaravinth
f165581e17 chore: lints 2022-05-11 20:11:11 +05:30
realaravinth
96995bc068 feat: migrate get password to use db_* interface 2022-05-11 20:11:02 +05:30
realaravinth
39ee2ad221 feat: migrate update username to use db_* interface 2022-05-11 20:02:03 +05:30
realaravinth
f79d159468 feat: implement update username for sqlx postgres 2022-05-11 20:01:48 +05:30
realaravinth
83f6456a59 feat: define interface for updating username 2022-05-11 20:01:32 +05:30
realaravinth
748f48e0d2 feat: migrate update password to use db_* interface 2022-05-11 19:52:20 +05:30
realaravinth
374bbb2403 feat: implement change password for sqlx postgres 2022-05-11 19:51:39 +05:30
realaravinth
f55a383eb5 feat: define interface to change password 2022-05-11 19:51:06 +05:30
realaravinth
f398c4b61c feat: migrate get password to use db_* interface 2022-05-11 18:54:36 +05:30
realaravinth
5bcf7beddc fix: return username to store in sessions when getting password 2022-05-11 18:54:17 +05:30
realaravinth
d9b36179d1 feat: implement fetching password with either username or email 2022-05-11 18:30:01 +05:30
realaravinth
7e2be86c12 feat: get password using either username or email 2022-05-11 18:26:35 +05:30
realaravinth
fdf4f0bef9 feat: implement password fetching for sqlx postgres 2022-05-11 15:43:25 +05:30
realaravinth
6377d07dce feat: define interface for fetching user password 2022-05-11 15:43:03 +05:30
realaravinth
78eac8b6b7 feat: migrate email update to use db_* interface 2022-05-11 15:26:00 +05:30
realaravinth
66226f893a feat: implement email updates for sqlx postgres 2022-05-11 15:25:43 +05:30
realaravinth
58216f0f63 feat: define interface for updating email of a user 2022-05-11 15:25:25 +05:30
realaravinth
8861201727 feat: run linting and coverage CI runs on db-abstract branch 2022-05-11 13:34:11 +05:30
realaravinth
621e400ea8 feat: migrate email exists to use db_* interface 2022-05-11 13:33:30 +05:30
realaravinth
84671c4a11 feat: implement email exists for sqlx postgres 2022-05-11 13:33:30 +05:30
realaravinth
9595ea232b feat: define interface for checking if user email exists 2022-05-11 13:33:30 +05:30
realaravinth
136439c97a feat: add sqlx offline data generation 2022-05-11 13:33:30 +05:30
realaravinth
6ab6df02ed fix: use db/db-migrations for DB migrations 2022-05-11 13:33:29 +05:30
realaravinth
af36961299 feat: implement postgres migrations 2022-05-11 13:33:29 +05:30
realaravinth
95e7a74559 feat: setup CI to use .env_sample and postgres URI 2022-05-11 13:33:29 +05:30
realaravinth
1cd4ce7318 feat: migrate username exists to use db_* interface 2022-05-11 13:33:29 +05:30
realaravinth
3a80281e86 feat: setup and run tests for sqlx postgres 2022-05-11 13:33:29 +05:30
realaravinth
79cc28bfd8 feat: implement username exists for postgres via sqlx 2022-05-11 13:33:29 +05:30
realaravinth
e244713ad7 feat: implement basic tests 2022-05-11 13:33:29 +05:30
realaravinth
454075a3d9 feat: define username exists endpoint 2022-05-11 13:33:29 +05:30
realaravinth
9e5b54a23d feat: setup tests on db_* workspaces 2022-05-11 13:33:29 +05:30
realaravinth
5359795ddc feat: enable CI for db-abstract 2022-05-11 13:33:29 +05:30
realaravinth
9f91854c4d feat: migrate account deletion to use db_* interface 2022-05-11 13:33:29 +05:30
realaravinth
5dc818a1c1 feat: implemente delete account for postgres via sqlx 2022-05-11 13:33:29 +05:30
realaravinth
4bdbb52d8f feat: define delete account db interface 2022-05-11 13:33:29 +05:30
realaravinth
4248959b13 feat: migrate user regisration to use db_* 2022-05-11 13:33:29 +05:30
realaravinth
26a0935e5f feat: implement user registration for postgres via sqlx 2022-05-11 13:33:29 +05:30
realaravinth
8dde022851 feat: define interface for username registration" 2022-05-11 13:33:29 +05:30
realaravinth
43aac949e3 feat: convert db errors to service errors 2022-05-11 13:33:29 +05:30
realaravinth
f337721b25 feat: move health endpoint to use ping from db_* 2022-05-11 13:33:29 +05:30
realaravinth
79506a93b9 feat: load db_* db connection 2022-05-11 13:33:29 +05:30
realaravinth
1d8554cb36 chore: rust fmpt 2022-05-11 13:33:29 +05:30
realaravinth
b7a8716a82 feat: define checking routine 2022-05-11 13:33:29 +05:30
realaravinth
dba1f662a7 feat: init postgres implementation via sqlx 2022-05-11 13:33:29 +05:30
realaravinth
02abffd63a feat: init and define database ops as interfaces to support multiple DBs 2022-05-11 13:33:29 +05:30
realaravinth
246dcfddb7 feat: mv db migrations to workspace 2022-05-11 13:33:29 +05:30
realaravinth
56225ae2e4 chore: actix-web updates: replace deprecated methods 2022-05-11 13:33:28 +05:30
realaravinth
6550266aef feat: don't run cache busting routines during debug build 2022-05-11 13:33:28 +05:30
realaravinth
100fb4d5ab feat: document .env 2022-05-11 13:33:28 +05:30
Aravinth Manivannan
8b7164635d Merge pull request #26 from ChocoMilkWithoutSugar/master
Update README.md
2022-05-11 12:00:14 +05:30
Aravinth Manivannan
76230eed9e Update README.md
Formatting default credentials
2022-05-11 06:28:06 +00:00
Luca
e2d126da30 Update README.md
add default credentials
2022-05-10 20:35:09 -03:00
realaravinth
2592b7a113 fix: use pre-built images in docker-compose 2022-05-10 22:33:26 +05:30
realaravinth
a00823544e hotfix: run tests one at a time
SUMMARY
    The test suite messy and inefficient in every imaginable way. It
    creates a DB connection pool for every unit test and Postgres failed
    with the following error:

    code: "53300", message: "sorry, too many clients already

    This hotfix runs tests via scripts/tests.sh, which executes one test
    at a time.

    Ideally, the connection pool must be shared across the whole test
    suite but this requires a major refactor of the test suite and even
    the app code. A refactor towards this is in progress in the
    `db-abstract` branch, which I hope to complete within this week.

fixes #22
2022-05-09 11:33:28 +05:30
realaravinth
5160e210f3 chore: upgrade sailfish 2022-05-08 17:57:29 +05:30
realaravinth
87f09b6bfb chore: migrate dart-sass to sass 2022-05-08 17:36:49 +05:30
dependabot[bot]
72cff2a470 Bump nanoid from 3.1.29 to 3.3.4
Bumps [nanoid](https://github.com/ai/nanoid) from 3.1.29 to 3.3.4.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/3.1.29...3.3.4)

---
updated-dependencies:
- dependency-name: nanoid
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-07 10:54:21 +00:00
realaravinth
91c6f77cab chore: update actix-* deps 2022-05-07 16:10:14 +05:30
realaravinth
6d6b494c6f feat: rm middleware mod and migrate codebase to use actix_auth_middleware 2022-05-07 12:30:00 +05:30
realaravinth
a668fafa62 feat: migrate v1 api mod to use actix_auth_middleware 2022-05-07 12:29:37 +05:30
realaravinth
b057e48d72 feat: migrate pages mod to use actix_auth_middleware 2022-05-07 12:29:02 +05:30
realaravinth
abe494b6e5 feat: upadte cache-busted 2022-05-07 12:28:37 +05:30
realaravinth
fdf94f1f06 feat: CI: run build every day at 0900 2022-05-06 17:14:09 +05:30
realaravinth
fc8a1670d2 update copyright notice 2022-01-08 22:16:05 +05:30
realaravinth
53e966958b update sqlx offline compilation schema data 2021-12-18 21:04:35 +05:30
realaravinth
c46b3f4f4c Implement easy edit view
When user tries to visit this view without an easy configuration
available, i.e, user had created the CAPTCHA using advance view and no
TrafficPattern is available in database, the user will be automatically
redirected to the advance edit page.

But the default edit link everywhere is to the easy edit view.
2021-12-18 21:01:19 +05:30
realaravinth
ebde9775fc use easy edit option by default in list view 2021-12-18 20:55:01 +05:30
realaravinth
56b05ec901 include link to easy edit option 2021-12-18 20:53:47 +05:30
realaravinth
7b0fe7c4b2 break view form into multiple parts 2021-12-18 20:53:10 +05:30
realaravinth
708a157ee1 rm comments 2021-12-18 19:39:59 +05:30
realaravinth
7a76214701 mark avg_traffic and peak_sustainable_traffic in
mcaptcha_sitekey_user_provided_avg_traffic as non-nullable
2021-12-18 19:09:59 +05:30
realaravinth
784aa26dbb mv edit sitekey into advance edit sitekey 2021-12-18 18:19:23 +05:30
realaravinth
ff3f5504dd update sqlx offline compilation schema data 2021-12-18 17:44:07 +05:30
realaravinth
a73542cf18 implement easy sitekey addition 2021-12-18 16:42:27 +05:30
realaravinth
081cdcc803 use crates::PAGES.panel.sitekey.get_edit_easy to get edit route 2021-12-18 16:41:30 +05:30
realaravinth
fa9762200e mv sitekey edit to easy edit 2021-12-18 16:41:00 +05:30
realaravinth
e874d1477d link easy variant from advance sitekey add form 2021-12-18 16:40:25 +05:30
realaravinth
fc40593c5d split sitekey add and edit routes into easy and advance variants 2021-12-18 16:39:20 +05:30
realaravinth
5a49940b89 Get sitekey routes using methods on pages::panel::sitekey::routes::Sitekey
for consistency purposes
2021-12-18 16:00:09 +05:30
realaravinth
f15df541c1 rm url field from DatabaseBuilder 2021-12-18 15:33:17 +05:30
realaravinth
fe1fc3fb20 address clippy lints 2021-12-18 14:10:05 +05:30
realaravinth
e3ff7278a9 update coverage workflow's rust version and tarpaulin version 2021-12-18 14:03:18 +05:30
realaravinth
855dbc60ef Fixes #8
```
$ cargo test
<--- snip --->
 thread panicked while panicking. aborting.
     Running unittests (target/debug/deps/tests_migrate-7d90f83f506b1b25)
 ```

gdb revealed that demo::demo_account_works receives a SIGKILL due to a
failed test. No idea why it didn't fail the usual way. The part where
the test fails hits an endpoint with the wrong datatype payload, it
should have failed with a 404 when the status was asserted but it
didn't. Fixing that fixed #8.

Additionally, all demo user functionality was restructured to include an
abort functionality, which can be used to kill the loop that deletes and
creates demo user throughout the runtime of the app.
2021-12-18 13:53:05 +05:30
realaravinth
9999bd887a migrate mcaptcha-glue to @mcaptcha/vanilla-glue 2021-12-16 20:57:39 +05:30
realaravinth
73ce2d1cb1 refactor captcha.rs and levels.rs and rm duration routes 2021-12-16 20:46:50 +05:30
realaravinth
cf4a0f9b73 Update CAPTCHA configuration by updating user provided traffic pattern 2021-12-16 18:15:15 +05:30
realaravinth
05f7e81c21 rename from_user_provided_traffic_pattern to create_easy
isolate non-async test in separate module
2021-12-16 17:47:30 +05:30
realaravinth
5ac0b36255 update dockerfile to make config 2021-12-16 15:55:46 +05:30
realaravinth
b2297eab6d mv add form into advance 2021-12-10 06:16:38 +05:30
realaravinth
5afa531bb8 build sass using dart-sass, bypassing css extractor 2021-12-10 06:16:03 +05:30
realaravinth
e399f82ac4 Load pow-sha256 polyfill to support browsers that aren't capable of
executing WASM
2021-12-08 14:52:06 +05:30
realaravinth
a075607bae Document pow section being renamed to captcha 2021-12-03 14:50:55 +05:30
realaravinth
54b14291ec Implement CAPTCHA configuration estimation from avg, peak and
broke_my_site_traffic

The above metrics are sourced from the user and are stored in the
database to reuse at a later point in time when the mCaptcha instance's
admin changes suggested configuration.

I'm not sure if I want to recompute configuration every time the admin
updates suggested configurations or give the user an option to recompute
based on latest trends. If we recompute on every update, then should the
admin choose very high difficulty_factors then it would hold back the
user's visitors, which is not nice. But there should also be an option
to rerun estimates when older configuration no longer works properly.
2021-12-03 14:26:23 +05:30
realaravinth
42544ec421 rename pow section in settings to captcha and add options to configure
suggested difficulty factors for use in CAPTCHA configurations
estimates

The current CAPTCHA configuration panel requires the user to provide
difficulty factor <--> visitor threshold mapping, which can be tedious
if the user isn't familiar with those parameters. Also, it could lead to
ineffective limiting from mCaptcha's side, should it be configured
improperly.

So an estimate computed from well known statistics like peak, avg and
broke-my-site traffic could go a long way.
2021-12-03 14:21:18 +05:30
realaravinth
032f6040b8 fix clippy lints 2021-12-03 13:41:24 +05:30
realaravinth
2b10aa5d40 run cachebuster in docker build 2021-12-02 20:28:17 +05:30
realaravinth
410232041b setup librejs license and cachebust service worker file 2021-12-02 14:25:50 +05:30
realaravinth
0126dc0e3a call proof generator from within a web worker 2021-12-02 14:24:53 +05:30
realaravinth
ab77eed91c move pow wasm lib out to a separate repo 2021-12-01 21:18:30 +05:30
realaravinth
41b99c1019 LibreJS processing:
Apply X11 and Apache-2.0 to widget JavaScript code to permit
proprietary integration.
2021-12-01 18:12:53 +05:30
realaravinth
7154a309be mv widget js from out of subdir 2021-12-01 17:43:44 +05:30
realaravinth
481246ffd5 update demo widget link in readme 2021-11-30 21:29:59 +05:30
realaravinth
1883ef1c1c Docker: update image and optimize for layer caching 2021-11-30 20:57:32 +05:30
realaravinth
eedec7da34 implement librejs compliance 2021-11-30 18:45:02 +05:30
realaravinth
b5af9ee259 it appears actix-web's scope behaviour has changed in the latest beta
release:

Routes 404'd when scope contained trailing slash like so:
let scope = "/api/v1/pow/";
web::scope(scope)//

So had to rm trailing slash in scope
2021-11-29 17:33:08 +05:30
realaravinth
f2f8632679 udpate deps and test openapi spec 2021-11-29 17:32:33 +05:30
realaravinth
6eb75d7a66 upgrade dev dependencies 2021-10-13 10:37:51 +05:30
realaravinth
e78e18a411 fix CI error and cache clippy and fmt jobs 2021-10-08 18:58:20 +05:30
realaravinth
46e7656967 make: clean up help and add documentaiton 2021-10-08 16:02:35 +05:30
realaravinth
975b6ca57a make: add openapi deps installtion 2021-10-08 15:57:27 +05:30
realaravinth
428d60ebb0 setup openapi spec build chain 2021-10-08 15:55:53 +05:30
realaravinth
9afb63c738 use yaml directly for displaying open api spec 2021-10-08 15:36:42 +05:30
realaravinth
53720ff740 frontend linting 2021-10-08 15:24:29 +05:30
realaravinth
f7afc72d81 update levels in cache when db is updated 2021-08-31 13:54:05 +05:30
realaravinth
b1fd56e9b6 navbar animation 2021-08-23 18:55:57 +05:30
realaravinth
a8c3eaa617 clean up systemgroup interface 2021-08-20 19:17:40 +05:30
realaravinth
068c49080e handle libmcaptcha actor errors 2021-08-20 18:15:55 +05:30
realaravinth
6ef941f73d update username 2021-08-13 18:58:04 +05:30
realaravinth
595e79a014 update sqlx data, delete user in username_change test 2021-08-12 17:22:41 +05:30
realaravinth
a65b1c219c username update 2021-08-12 17:13:17 +05:30
realaravinth
751a1046fb add sitekey helper in list sitekey page 2021-08-12 08:38:09 +05:30
realaravinth
78ebc46c64 register demo user only when it's absent 2021-08-12 08:26:49 +05:30
realaravinth
9269539a8a fix broken sitekey delete link 2021-08-09 18:59:35 +05:30
realaravinth
00acf0c193 fix show password button in sudo pages 2021-08-09 13:02:54 +05:30
realaravinth
02b62fb1d0 demo user banner 2021-08-09 12:23:06 +05:30
realaravinth
147f563ec8 demo user task 2021-08-09 11:56:25 +05:30
realaravinth
3c72d27b36 demo user 2021-08-09 10:37:19 +05:30
realaravinth
a5558e4b6f clippy fixes and env docs update 2021-08-08 18:29:17 +05:30
realaravinth
65ffc37549 strict transport policy heaer 2021-08-05 21:05:27 +05:30
realaravinth
6763867cbe make billing section optional 2021-08-04 19:24:35 +05:30
realaravinth
1d759fcb25 captcha stats 2021-07-27 15:28:21 +05:30
realaravinth
9bc11f3518 lazy init edit submit btn and update demo link 2021-07-26 11:49:07 +05:30
realaravinth
8830961e04 stats endpoint 2021-07-25 21:15:59 +05:30
realaravinth
0a8d36dc9f sitemap generates URL 2021-07-25 20:15:44 +05:30
realaravinth
189510c008 lazy init asset paths, store asset alt and prep svg for embedding 2021-07-22 12:35:25 +05:30
realaravinth
746e4a2d1a use buttons in login, reigster and sudo forms 2021-07-22 09:19:27 +05:30
realaravinth
e9e6aac770 sitemap 2021-07-21 22:15:52 +05:30
realaravinth
257b3a2b88 widget uses LazyElemnt 2021-07-21 21:02:03 +05:30
realaravinth
5044d78378 update tests to use lazyelement 2021-07-21 20:48:31 +05:30
realaravinth
861998af75 lazy element, settings: account delete and secret update 2021-07-21 20:44:22 +05:30
realaravinth
2c2f79e1cd settings page styling 2021-07-21 14:46:31 +05:30
realaravinth
b603208d48 add-data rendering & clipboard takes element 2021-07-21 10:42:25 +05:30
realaravinth
4b18992f6a settings page, clipboard component 2021-07-20 18:14:23 +05:30
realaravinth
db941d51b7 delete captcha option and sudo page 2021-07-20 15:22:15 +05:30
realaravinth
00768cce34 delete captcha 2021-07-20 13:02:53 +05:30
realaravinth
f7c9217667 update and rename captcha plumbing 2021-07-19 17:12:56 +05:30
realaravinth
1b0a95e768 tests: get status code from err 2021-07-17 18:57:33 +05:30
realaravinth
c3e43ff584 update password 2021-07-17 18:51:20 +05:30
realaravinth
dda936d207 "duplicate email check" 2021-07-17 18:14:03 +05:30
realaravinth
8f87efeeb3 error correction, tests for err branches, rm get_token, get_token,
delete captcha
2021-07-17 17:43:53 +05:30
realaravinth
6f690734c5 notification mark read 2021-07-16 21:16:49 +05:30
realaravinth
102ef5b4a1 edit sitekey button in sitekey list table 2021-07-16 17:50:38 +05:30
realaravinth
ea8264054a edit sitekey, router pattern matching, sitekey update optimization, rm level delete and level err handling 2021-07-16 17:40:52 +05:30
realaravinth
863d22f62c list sitekey: copy sitekey 2021-07-15 18:07:12 +05:30
realaravinth
97db774e70 docker: wasm build step 2021-07-15 15:27:01 +05:30
realaravinth
883aa122b2 notification date formatting 2021-07-14 21:38:03 +05:30
realaravinth
69de0aaeef notifications styling 2021-07-14 20:09:00 +05:30
realaravinth
558dbef712 dupe email check and notifications table 2021-07-13 21:23:08 +05:30
realaravinth
47cca5c9a7 notifications view 2021-07-12 21:22:26 +05:30
realaravinth
b7ec1bca22 duplicate email check and address clippy warnings 2021-07-11 21:46:50 +05:30
realaravinth
1d1b9e650f force run build.rs 2021-07-11 21:00:51 +05:30
realaravinth
704f8bf2b4 add mcaptcha-browser as dep 2021-07-09 13:57:55 +05:30
realaravinth
5daa46e76e CI: list assets when running test 2021-07-09 13:16:54 +05:30
realaravinth
0880dd27ce configuration docs, make test 2021-07-09 12:04:48 +05:30
realaravinth
67a35a6e43 clear cookie after account deletion and CI: skip build 2021-07-09 11:49:01 +05:30
realaravinth
4c293bdb5a correct errors in readme 2021-07-07 21:32:20 +05:30
realaravinth
2e50c263a8 makeifle: clean and test workflows 2021-07-07 21:10:15 +05:30
realaravinth
eb5c0164dc makeifle: make migrate 2021-07-07 18:20:06 +05:30
realaravinth
5fa668ad97 updated cache buster 2021-07-07 18:10:01 +05:30
realaravinth
40801575b2 update wasm binary loading 2021-07-07 00:48:04 +05:30
realaravinth
bfebca6e0e widget static resources are now built locally 2021-07-07 00:28:32 +05:30
realaravinth
5d55971f19 docker makefile rules and updated widget res 2021-07-05 02:22:02 +05:30
realaravinth
e1e1040ca9 clickable logo 2021-07-03 22:32:40 +05:30
realaravinth
791935f245 mobile layout: fix logo highlight 2021-07-03 22:17:45 +05:30
realaravinth
43d970980f responsive navbar 2021-07-01 22:36:22 +05:30
realaravinth
362e2aeae0 email verification test 2021-07-01 15:48:59 +05:30
realaravinth
8d32ebcf95 sqlx update and verification button styling 2021-06-30 23:08:53 +05:30
realaravinth
b22ea88d7e coverage workflow to run on 1.51.0 2021-06-30 22:54:06 +05:30
realaravinth
46098ec85b CI: smtp server now started as a command 2021-06-30 22:44:06 +05:30
realaravinth
8f0c4c093b udpate rust version 2021-06-30 22:29:20 +05:30
realaravinth
ac46f1da6a udpate rust version 2021-06-30 22:20:08 +05:30
realaravinth
024321a2f6 CI: smtp service container fix 2021-06-30 21:07:17 +05:30
realaravinth
574efc2252 email verification 2021-06-30 20:57:26 +05:30
realaravinth
c05888d648 cargo fmt 2021-06-30 20:14:15 +05:30
realaravinth
9f940c317a upgrading to actix-v4-beta 2021-06-30 20:13:12 +05:30
realaravinth
9ed458ebfa create email client 2021-06-30 14:16:48 +05:30
Aravinth Manivannan
8118e73df6 added donation links 2021-06-30 13:03:47 +05:30
realaravinth
96fafb339c error handling levels 2021-06-29 23:20:54 +05:30
realaravinth
f10741d09f moved sass improt to index to fix CI failure 2021-06-29 21:48:52 +05:30
realaravinth
e6bcd5f940 error styling 2021-06-29 21:41:24 +05:30
realaravinth
804c81da38 read SMTP configuration 2021-06-29 21:08:40 +05:30
realaravinth
481cb95cd2 addressing clippy lints 2021-06-29 20:12:51 +05:30
realaravinth
1065fa3864 sqlx data for login with email 2021-06-29 19:59:27 +05:30
realaravinth
11cba8f32e UX: log in with email 2021-06-29 19:52:22 +05:30
realaravinth
d5aceb60b4 sign in with email 2021-06-29 19:42:07 +05:30
realaravinth
c581d8d0a3 error handling in auth 2021-06-28 23:03:15 +05:30
realaravinth
d298ef4719 ts: error component 2021-06-28 20:50:13 +05:30
realaravinth
6cd477e227 multipart form was a bad idea 2021-06-28 19:58:01 +05:30
realaravinth
cc17f2048f errorable and seperated runner methods for auth 2021-06-28 19:16:59 +05:30
realaravinth
2162d32455 block floc fmt 2021-06-16 19:42:04 +05:30
realaravinth
6a56ff8ea9 block floc 2021-06-15 20:23:39 +05:30
realaravinth
5e6e04514e preload creds manager 2021-06-13 13:35:09 +05:30
realaravinth
1ddbf196ff docs: deployment and configuration for redis 2021-06-13 13:01:23 +05:30
realaravinth
9636180673 redis health check: return err when unable to connect 2021-06-13 12:53:58 +05:30
realaravinth
3132a48087 add redis to health check 2021-06-12 13:44:18 +05:30
realaravinth
055ce540c6 docker-compose: added redis 2021-06-12 12:24:05 +05:30
realaravinth
dcfba60c86 addressing clippy lints 2021-06-11 23:39:38 +05:30
realaravinth
ffdd1865bb run redis as service 2021-06-11 20:02:08 +05:30
realaravinth
dc53cd76d4 CI: launch redis early 2021-06-11 19:47:49 +05:30
realaravinth
086dd85a83 coverage workflow: launch redis 2021-06-11 19:32:36 +05:30
realaravinth
f5624947b9 redis storage for captcha mech 2021-06-11 19:31:03 +05:30
realaravinth
17ae532162 rename guard -> mcaptcha in docker files 2021-06-02 18:17:25 +05:30
realaravinth
2925f82aa5 enforcing username profanity and blacklist policy 2021-06-01 17:35:48 +05:30
realaravinth
9e70f8f756 rename guard -> mcaptcha 2021-06-01 17:33:47 +05:30
realaravinth
ba39483635 widget locking mech bug fix 2021-05-30 21:34:12 +05:30
realaravinth
abe6fd403f readme 2021-05-30 20:52:54 +05:30
realaravinth
dea99209a0 link to demo vid and widget 2021-05-30 20:43:23 +05:30
realaravinth
3b72c6e441 widget demo video 2021-05-30 20:26:29 +05:30
realaravinth
8486f3be04 configuration instructions 2021-05-30 20:06:13 +05:30
realaravinth
f4deb20fbc deployment instructions 2021-05-30 19:53:53 +05:30
realaravinth
5ade3af325 widget: err handling 2021-05-30 18:54:19 +05:30
realaravinth
2ea818591e cache control 2021-05-30 17:55:11 +05:30
realaravinth
1aaf362b0c widget: msg DOM manipulations 2021-05-30 13:16:54 +05:30
realaravinth
2c5dbc7c5f fixed rm lvl's update legend bug 2021-05-30 12:18:27 +05:30
realaravinth
f448f28d01 rm static from dockerignore 2021-05-30 00:19:22 +05:30
realaravinth
98cf4a476d widget: verification works 2021-05-29 21:19:45 +05:30
realaravinth
d9cb38ac13 widget: messages for various stages 2021-05-29 19:45:56 +05:30
realaravinth
fd32f5be32 csp headers and img compression 2021-05-29 17:31:11 +05:30
realaravinth
fd67a9fa42 widget noscript and styling 2021-05-29 13:40:11 +05:30
realaravinth
fc34353e67 test util: update cahce processor & update readme badge 2021-05-29 13:01:15 +05:30
realaravinth
c873d152c3 rearranged static files 2021-05-29 12:22:31 +05:30
realaravinth
417e008c27 favicons 2021-05-29 00:04:11 +05:30
realaravinth
2c209bf8d5 widget template 2021-05-28 21:26:36 +05:30
realaravinth
282b285afa fixed view urls 2021-05-28 20:54:46 +05:30
realaravinth
50234435ec footer: link to src of build version 2021-05-28 13:07:58 +05:30
realaravinth
5963df19f2 abount, security and donation links 2021-05-27 19:58:25 +05:30
realaravinth
fcdbe66b26 captcha stats 2021-05-27 14:47:29 +05:30
realaravinth
df89938f2a added demo servers 2021-05-26 14:47:56 +05:30
realaravinth
f560e3f9db sqlx offline queries 2021-05-26 13:04:41 +05:30
realaravinth
bfc6bca73c view sitekey route and redirection 2021-05-26 12:51:23 +05:30
realaravinth
3d8cd9daed sitekey form mobile styling 2021-05-26 12:36:47 +05:30
realaravinth
32e46586e4 seperate css file for mobile layout 2021-05-25 21:18:59 +05:30
realaravinth
80352fb390 mobile css setup 2021-05-25 20:40:57 +05:30
realaravinth
90fa5ebd19 mark notifications read 2021-05-25 17:22:49 +05:30
realaravinth
72667bd2e1 using custom version of actix-codegen and cors for pow routes 2021-05-25 14:34:24 +05:30
realaravinth
0421cb681c show password compoenent 2021-05-15 21:36:52 +05:30
realaravinth
6b740a980b show password component 2021-05-14 16:33:18 +05:30
realaravinth
bb6cc840ea configuration env seperator 2021-05-12 21:27:07 +05:30
realaravinth
bf9f2a6cbc docker compose 2021-05-12 19:13:09 +05:30
realaravinth
d0c5ffb486 Docker build 2021-05-12 18:23:25 +05:30
realaravinth
4df220edad read configuration from multiple locations 2021-05-12 18:02:16 +05:30
realaravinth
a4b409e914 sqlx offline compilation 2021-05-12 17:37:11 +05:30
realaravinth
d151793648 readme: added basic info on the project 2021-05-10 16:39:48 +05:30
realaravinth
91ca00ea79 get notifications 2021-05-10 15:38:09 +05:30
realaravinth
aa0c30f1bd send notifications 2021-05-10 00:55:47 +05:30
realaravinth
bd20b4238b sitekey view 2021-05-09 19:54:10 +05:30
realaravinth
95bc1feef7 panel: overview 2021-05-09 19:45:25 +05:30
realaravinth
527724ecda pow stats for solution and verification 2021-05-09 19:33:28 +05:30
realaravinth
7792d5ccc7 footer 2021-05-09 18:59:23 +05:30
realaravinth
686774a182 dom manipulations uses elements 2021-05-09 16:39:52 +05:30
realaravinth
cd729effb9 updated docs route 2021-05-08 15:12:25 +05:30
realaravinth
9809cb7bea CI: coverage build step 2021-05-08 13:59:13 +05:30
realaravinth
5466d1f136 CI: coverage seperated 2021-05-08 13:05:45 +05:30
realaravinth
1a381f8efa details 2021-05-08 00:29:19 +05:30
realaravinth
7e0670d1d8 removelevelbutton tests 2021-05-07 21:14:15 +05:30
realaravinth
d42a9c6bb8 view sitekey 2021-05-07 19:44:44 +05:30
realaravinth
d4cf24493a removelevelbutton tests 2021-05-07 18:37:44 +05:30
realaravinth
5b5a995f57 removelevelbutton tests 2021-05-07 17:55:42 +05:30
realaravinth
7b3f910da7 addlevelbutton test 2021-05-07 15:21:27 +05:30
realaravinth
d2e4cf5187 auth forms styling updated 2021-05-06 20:32:44 +05:30
realaravinth
ab3147e11d add site form validation tests 2021-05-06 18:16:13 +05:30
realaravinth
20ee5c35c6 levels tests 2021-05-06 17:22:25 +05:30
realaravinth
6069509504 addlevel and getlevel tests 2021-05-06 14:38:42 +05:30
realaravinth
30f457ca43 deprecated mcaptcha add route 2021-05-06 13:57:14 +05:30
realaravinth
b5a9c0d772 registration tests 2021-05-06 13:48:28 +05:30
realaravinth
14859ab594 utils tests 2021-05-06 12:56:53 +05:30
realaravinth
c8d2ddbaf3 javascript test coverage 2021-05-06 12:11:06 +05:30
realaravinth
f0e3940868 javascript test coverage 2021-05-06 11:02:29 +05:30
realaravinth
9ee4cb13f6 router.ts tests 2021-05-06 10:53:05 +05:30
realaravinth
dc982c31c6 tsconfig 2021-05-06 09:28:44 +05:30
realaravinth
6184fe7efe build tools: webpack with typescript and scss compilation 2021-05-05 23:21:59 +05:30
realaravinth
6069962d3e refactored sitekey routes 2021-05-05 12:57:05 +05:30
realaravinth
f0254b3b77 static assets caching 2021-05-04 23:27:58 +05:30
realaravinth
98719670df sitekey list 2021-05-04 18:34:36 +05:30
realaravinth
3ac95e1005 error pages 2021-05-04 17:04:03 +05:30
realaravinth
266b8dea88 error page 2021-05-04 16:19:24 +05:30
realaravinth
fe02c43c2c static pages are rendered and cached 2021-05-04 15:45:53 +05:30
realaravinth
f817f49182 doc handler uses const and js, I give upT-T 2021-05-04 15:18:07 +05:30
realaravinth
1e1ec187dc add new site accepts duration 2021-05-04 11:07:18 +05:30
realaravinth
e83a362e75 added duration field to add_level 2021-05-04 10:49:44 +05:30
realaravinth
e9c84b4ed4 Dockerfile init 2021-05-04 10:30:22 +05:30
realaravinth
6964faf8f4 logger 2021-05-03 23:16:00 +05:30
realaravinth
729a90cea1 updated styling for existing-level compoenent 2021-05-03 20:27:11 +05:30
realaravinth
812b0ff2c9 add site key form 2021-05-03 20:24:03 +05:30
realaravinth
0531a26274 docs use const routes 2021-05-02 18:36:39 +05:30
realaravinth
4b6e3496cd added code_of_conduct.md 2021-05-02 18:13:13 +05:30
realaravinth
9d6b27a95b pages use const routes 2021-05-02 18:11:56 +05:30
realaravinth
0829ee1c74 pow uses const routes 2021-05-02 17:13:04 +05:30
realaravinth
ef778687e0 cleanup 2021-05-02 16:44:54 +05:30
realaravinth
5361e9b43a mcaptcah uses const routes 2021-05-02 16:35:15 +05:30
realaravinth
76ae2b03e9 migrated auth, account and meta to use const routes 2021-05-02 16:11:01 +05:30
realaravinth
4f27e1ab8d using constants for routes 2021-05-02 12:39:37 +05:30
realaravinth
c7bac9e623 server-side password validation 2021-05-02 10:32:22 +05:30
realaravinth
a82d61ed27 api endpoints migrated to use auth middleware 2021-05-01 23:39:52 +05:30
realaravinth
191e9658ec frontend: level validation 2021-05-01 21:27:02 +05:30
realaravinth
bc749c387b yarn workflow updated 2021-05-01 19:28:58 +05:30
realaravinth
9c6398a7c5 typescript migration 2021-05-01 19:22:44 +05:30
realaravinth
90424219f5 site-key form made resulable 2021-05-01 14:41:22 +05:30
realaravinth
7058af84d6 static dir renamed and cookie auth middleware 2021-05-01 11:28:39 +05:30
realaravinth
c96f890236 cache_bustere upgrade and static assets tests 2021-04-30 21:34:44 +05:30
realaravinth
343c37ae1c changed login route 2021-04-30 18:06:28 +05:30
realaravinth
6e63771868 frontend: logout and add sitekey 2021-04-30 17:30:40 +05:30
realaravinth
a5cfa3b305 pow stats 2021-04-30 11:14:29 +05:30
realaravinth
a3ba746b6a color scheme 2021-04-16 23:57:36 +05:30
realaravinth
f6663acbc7 panel css buldled and form redirects 2021-04-15 10:25:23 +05:30
realaravinth
06815469b7 set email 2021-04-14 09:45:59 +05:30
621 changed files with 59808 additions and 10892 deletions

14
.dockerignore Normal file
View File

@@ -0,0 +1,14 @@
/target
tarpaulin-report.html
.env
cobertura.xml
prod/
node_modules/
/static-assets/bundle
./templates/**/*.js
/static/cache/bundle/*
src/cache_buster_data.json
browser/target
browser/cobertura.xml
browser/docs

2
.env_sample Normal file
View File

@@ -0,0 +1,2 @@
export POSTGRES_DATABASE_URL="postgres://postgres:password@localhost:5432/postgres"
export MARIA_DATABASE_URL="mysql://maria:password@localhost:3306/maria"

21
.eslintrc.js Normal file
View File

@@ -0,0 +1,21 @@
module.exports = {
env: {
browser: true,
es2021: true,
},
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: 12,
sourceType: "module",
},
plugins: ["@typescript-eslint"],
rules: {
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/ban-types": "off",
indent: ["error", 2],
"linebreak-style": ["error", "unix"],
quotes: ["error", "double"],
semi: ["error", "always"],
},
};

12
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
# These are supported funding model platforms
# github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
# patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
# ko_fi: # Replace with a single Ko-fi username
# tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
# community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: mcaptcha
issuehunt: # Replace with a single IssueHunt username
# otechie: # Replace with a single Otechie username
custom: ['https://mcaptcha.org/donate']

75
.github/workflows/clippy-fmt.yml vendored Normal file
View File

@@ -0,0 +1,75 @@
name: Lint
on:
pull_request:
types: [opened, synchronize, reopened]
push:
branches:
- master
- db-abstract
jobs:
fmt:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: ⚡ Cache
uses: actions/cache@v2
with:
path: |
~/.cargo/registry
~/.cargo/git
node_modules
./docs/openapi/node_modules
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- uses: actions/checkout@v2
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
components: rustfmt
- name: Check with rustfmt
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
clippy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: ⚡ Cache
uses: actions/cache@v2
with:
path: |
~/.cargo/registry
~/.cargo/git
node_modules
./docs/openapi/node_modules
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- uses: actions/checkout@v2
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
components: clippy
override: true
- uses: actions/setup-node@v2
with:
node-version: "18.0.0"
- name: Build frontend
run: make frontend
- name: Check with Clippy
uses: actions-rs/clippy-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --workspace --tests --all-features

135
.github/workflows/coverage.yml vendored Normal file
View File

@@ -0,0 +1,135 @@
name: Coverage
on:
pull_request:
types: [opened, synchronize, reopened]
push:
branches:
- master
- db-abstract
jobs:
build_and_test:
strategy:
fail-fast: false
matrix:
version:
- stable
#- 1.51.0
name: ${{ matrix.version }} - x86_64-unknown-linux-gnu
runs-on: ubuntu-latest
services:
postgres:
image: postgres
env:
POSTGRES_PASSWORD: password
POSTGRES_USER: postgres
POSTGRES_DB: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
mcaptcha-redis:
image: mcaptcha/cache
ports:
- 6379:6379
mcaptcha-smtp:
image: maildev/maildev
env:
MAILDEV_WEB_PORT: "1080"
MAILDEV_INCOMING_USER: "admin"
MAILDEV_INCOMING_PASS: "password"
ports:
- 1080:1080
- 10025:1025
maria:
image: mariadb:10
env:
MARIADB_USER: "maria"
MARIADB_PASSWORD: "password"
MARIADB_ROOT_PASSWORD: "password"
MARIADB_DATABASE: "maria"
options: >-
--health-cmd="mysqladmin ping"
--health-interval=10s
--health-timeout=5s
--health-retries=10
ports:
- 3306:3306
steps:
- uses: actions/checkout@v2
- name: ⚡ Cache
uses: actions/cache@v2
with:
path: |
~/.cargo/registry
~/.cargo/git
node_modules
./docs/openapi/node_modules
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: load env
run: |
source .env_sample \
&& echo "POSTGRES_DATABASE_URL=$POSTGRES_DATABASE_URL" >> $GITHUB_ENV \
&& echo "MARIA_DATABASE_URL=$MARIA_DATABASE_URL" >> $GITHUB_ENV
- uses: actions/setup-node@v2
with:
node-version: "18.0.0"
- name: Install ${{ matrix.version }}
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.version }}-x86_64-unknown-linux-gnu
profile: minimal
override: true
- name: Build frontend
run: make frontend
- name: Run the frontend tests
run: make test.frontend
- name: Run migrations
run: make migrate
env:
POSTGRES_DATABASE_URL: "${{ env.POSTGRES_DATABASE_URL }}"
MARIA_DATABASE_URL: "${{ env.MARIA_DATABASE_URL }}"
- name: build frontend
run: make frontend
- name: Generate coverage file
if: github.event_name == 'pull_request'
#if: (github.ref == 'refs/heads/master' || github.event_name == 'pull_request')
uses: actions-rs/tarpaulin@v0.1
with:
args: "-t 1200"
env:
POSTGRES_DATABASE_URL: "${{ env.POSTGRES_DATABASE_URL }}"
MARIA_DATABASE_URL: "${{ env.MARIA_DATABASE_URL }}"
# GIT_HASH is dummy value. I guess build.rs is skipped in tarpaulin
# execution so this value is required for preventing meta tests from
# panicking
GIT_HASH: 8e77345f1597e40c2e266cb4e6dee74888918a61
CACHE_BUSTER_FILE_MAP: '{"map":{"./static/bundle/main.js":"./prod/bundle/main.1417115E59909BE0A01040A45A398ADB09D928DF89CCF038FA44B14850442096.js"},"base_dir":"./prod"}'
COMPILED_DATE: "2021-07-21"
- name: Upload to Codecov
if: github.event_name == 'pull_request'
uses: codecov/codecov-action@v2

View File

@@ -1,12 +1,15 @@
name: CI (Linux)
name: Build
on:
schedule:
- cron: "0 9 * * *"
pull_request:
types: [opened, synchronize, reopened]
push:
branches:
- master
- "*"
- '!gh-pages'
jobs:
build_and_test:
@@ -14,14 +17,14 @@ jobs:
fail-fast: false
matrix:
version:
#- 1.51.0
- stable
- nightly
# - nightly
name: ${{ matrix.version }} - x86_64-unknown-linux-gnu
runs-on: ubuntu-latest
services:
postgres:
image: postgres
env:
@@ -36,6 +39,35 @@ jobs:
ports:
- 5432:5432
mcaptcha-redis:
image: mcaptcha/cache
ports:
- 6379:6379
mcaptcha-smtp:
image: maildev/maildev
env:
MAILDEV_WEB_PORT: "1080"
MAILDEV_INCOMING_USER: "admin"
MAILDEV_INCOMING_PASS: "password"
ports:
- 1080:1080
- 10025:1025
maria:
image: mariadb:10
env:
MARIADB_USER: "maria"
MARIADB_PASSWORD: "password"
MARIADB_ROOT_PASSWORD: "password"
MARIADB_DATABASE: "maria"
options: >-
--health-cmd="mysqladmin ping"
--health-interval=10s
--health-timeout=5s
--health-retries=10
ports:
- 3306:3306
steps:
- uses: actions/checkout@v2
- name: ⚡ Cache
@@ -44,15 +76,26 @@ jobs:
path: |
~/.cargo/registry
~/.cargo/git
node_modules
./docs/openapi/node_modules
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- uses: borales/actions-yarn@v2.0.0
- name: configure GPG key
if: (github.ref == 'refs/heads/master' || github.event_name == 'push') && github.repository == 'mCaptcha/mCaptcha'
run: echo -n "$RELEASE_BOT_GPG_SIGNING_KEY" | gpg --batch --import --pinentry-mode loopback
env:
RELEASE_BOT_GPG_SIGNING_KEY: ${{ secrets.RELEASE_BOT_GPG_SIGNING_KEY }}
- name: load env
run: |
source .env_sample \
&& echo "POSTGRES_DATABASE_URL=$POSTGRES_DATABASE_URL" >> $GITHUB_ENV \
&& echo "MARIA_DATABASE_URL=$MARIA_DATABASE_URL" >> $GITHUB_ENV
- uses: actions/setup-node@v2
with:
cmd: install # will run `yarn install` command
- uses: borales/actions-yarn@v2.0.0
with:
cmd: build # will run `yarn build` command
node-version: "18.0.0"
- name: Install ${{ matrix.version }}
uses: actions-rs/toolchain@v1
@@ -61,67 +104,65 @@ jobs:
profile: minimal
override: true
- name: install nightwatch dep
run: sudo apt-get install xvfb
- name: Run migrations
uses: actions-rs/cargo@v1
with:
command: run
args: --bin tests-migrate
run: make migrate
env:
DATABASE_URL: postgres://postgres:password@localhost:5432/postgres
POSTGRES_DATABASE_URL: "${{ env.POSTGRES_DATABASE_URL }}"
MARIA_DATABASE_URL: "${{ env.MARIA_DATABASE_URL }}"
- name: check build
uses: actions-rs/cargo@v1
with:
command: check
args: --all --bins --examples --tests
- name: build
run: make
env:
DATABASE_URL: postgres://postgres:password@localhost:5432/postgres
POSTGRES_DATABASE_URL: "${{ env.POSTGRES_DATABASE_URL }}"
MARIA_DATABASE_URL: "${{ env.MARIA_DATABASE_URL }}"
# - name: build frontend
# run: make frontend
#
- name: lint frontend
run: yarn lint
- name: tests
uses: actions-rs/cargo@v1
timeout-minutes: 40
with:
command: test
args: --all --all-features --no-fail-fast
- name: run tests
run: make test
env:
DATABASE_URL: postgres://postgres:password@localhost:5432/postgres
POSTGRES_DATABASE_URL: "${{ env.POSTGRES_DATABASE_URL }}"
MARIA_DATABASE_URL: "${{ env.MARIA_DATABASE_URL }}"
- name: run integration tests
run: make test.integration
- name: Generate coverage file
if: matrix.version == 'stable' && (github.ref == 'refs/heads/master' || github.event_name == 'pull_request')
uses: actions-rs/tarpaulin@v0.1
- name: Login to DockerHub
if: (github.ref == 'refs/heads/master' || github.event_name == 'push') && github.repository == 'mCaptcha/mCaptcha'
uses: docker/login-action@v1
with:
version: '0.15.0'
args: '-t 1200'
username: mcaptcha
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: publish docker images
if: (github.ref == 'refs/heads/master' || github.event_name == 'push') && github.repository == 'mCaptcha/mCaptcha'
run: make docker-publish
- name: publish bins
if: (github.ref == 'refs/heads/master' || github.event_name == 'push') && github.repository == 'mCaptcha/mCaptcha'
run: ./scripts/publish.sh publish master latest $DUMBSERVE_PASSWORD
env:
DATABASE_URL: postgres://postgres:password@localhost:5432/postgres
# GIT_HASH is dummy value. I guess build.rs is skipped in tarpaulin
# execution so this value is required for preventing meta tests from
# panicking
GIT_HASH: 8e77345f1597e40c2e266cb4e6dee74888918a61
OPEN_API_DOCS: 8e77345f1597e40c2e266cb4e6dee74888918a61
CACHE_BUSTER_FILE_MAP: '{"map":{"./static/bundle/main.js":"./prod/bundle/main.1417115E59909BE0A01040A45A398ADB09D928DF89CCF038FA44B14850442096.js"},"base_dir":"./prod"}'
- name: Upload to Codecov
if: matrix.version == 'stable' && (github.ref == 'refs/heads/master' || github.event_name == 'pull_request')
uses: codecov/codecov-action@v1
with:
file: cobertura.xml
DUMBSERVE_PASSWORD: ${{ secrets.DUMBSERVE_PASSWORD }}
GPG_PASSWORD: ${{ secrets.GPG_PASSWORD }}
- name: generate documentation
if: matrix.version == 'stable' && (github.repository == 'mCaptcha/guard')
uses: actions-rs/cargo@v1
with:
command: doc
args: --no-deps --workspace --all-features
if: matrix.version == 'stable' && (github.repository == 'mCaptcha/mCaptcha')
run: make doc
env:
DATABASE_URL: postgres://postgres:password@localhost:5432/postgres
GIT_HASH: 8e77345f1597e40c2e266cb4e6dee74888918a61 # dummy value
OPEN_API_DOCS: 8e77345f1597e40c2e266cb4e6dee74888918a61
POSTGRES_DATABASE_URL: "${{ env.POSTGRES_DATABASE_URL }}"
MARIA_DATABASE_URL: "${{ env.MARIA_DATABASE_URL }}"
GIT_HASH: 8e77345f1597e40c2e266cb4e6dee74888918a61 # dummy value
COMPILED_DATE: "2021-07-21"
- name: Deploy to GitHub Pages
if: matrix.version == 'stable' && (github.repository == 'mCaptcha/guard')
if: matrix.version == 'stable' && (github.repository == 'mCaptcha/mCaptcha')
uses: JamesIves/github-pages-deploy-action@3.7.1
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

32
.github/workflows/tagged-release.yml vendored Normal file
View File

@@ -0,0 +1,32 @@
name: Create binary for release
# Only on tags that start with a "v"
on:
push:
tags:
- "v*"
jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-pc-windows-gnu
archive: zip
- target: x86_64-unknown-linux-musl
archive: tar.gz tar.xz
- target: x86_64-apple-darwin
archive: zip
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Compile and release
uses: rust-build/rust-build.action@v1.3.2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
RUSTTARGET: ${{ matrix.target }}
ARCHIVE_TYPES: ${{ matrix.archive }}

11
.gitignore vendored
View File

@@ -5,3 +5,14 @@ tarpaulin-report.html
cobertura.xml
prod/
node_modules/
/static-assets/bundle
static/cache/bundle
./templates/**/*.js
/static-assets/bundle/*
src/cache_buster_data.json
coverage
dist
assets
yarn-error.log
src/cache_buster_data.json.license
**/**/target

10
.reuse/dep5 Normal file
View File

@@ -0,0 +1,10 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: mCaptcha
Upstream-Contact: Aravinth Manivannan <realaravinth@batsense.net>
Source: https://mcaptcha.org
# Sample paragraph, commented out:
#
# Files: src/*
# Copyright: $YEAR $NAME <$CONTACT>
# License: ...

19
CHANGELOG.md Normal file
View File

@@ -0,0 +1,19 @@
## 0.1.0(unreleased)
### Changed
- ([`7d0e4c6`](https://github.com/mCaptcha/mCaptcha/commit/7d0e4c6be4b0769921cda7681858ebe16ec9a07b)) Add `secret` parameter to token verification request payload(`/api/v1/pow/siteverify`) to mitigate a security issue that @gusted found:
> ...A malicious user could grab the sitekey
> and use that sitekey with mcaptcha to use it for their own server.
> While they can now go abuse it for illegal stuff or other stuff.
> You might decide, oh I don't want this! and terminate a legitimate
> siteKey.
> New request payload:
```json
{
"secret": "<your-users-secret>", // found in /settings in the dashbaord
"token": "<token-presented-by-the-user>",
"key": "<your-sitekey>"
}
```
- ([`42544ec42`](https://github.com/mCaptcha/mCaptcha/commit/42544ec421e0c3ec4a8d132e6101ab4069bf0065)) Rename pow section in settings to captcha and add options to configure

3307
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,57 +1,57 @@
[package]
name = "guard"
name = "mcaptcha"
version = "0.1.0"
description = "mCaptcha - a PoW-based CAPTCHA system"
homepage = "https://mcaptcha.org"
repository = "https://github.com/mCaptcha/guard"
repository = "https://github.com/mCaptcha/mCaptcha"
documentation = "https://mcaptcha.org/docs/"
lisense = "AGPLv3 or later version"
license = "AGPLv3 or later version"
authors = ["realaravinth <realaravinth@batsense.net>"]
edition = "2018"
default-run = "guard"
edition = "2021"
default-run = "mcaptcha"
build = "build.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[workspace]
exclude = ["db/db-migrations", "utils/cache-bust"]
memebers = [".", "db/db-core", "db/db-sqlx-postgres", "db/db-sqlx-maria"]
[[bin]]
name = "guard"
name = "mcaptcha"
path = "./src/main.rs"
[[bin]]
name = "tests-migrate"
path = "./src/tests-migrate.rs"
[dependencies]
actix-web = "3.3.2"
actix = "0.10"
actix-identity = "0.3"
actix-http = "2.2"
actix-rt = "1"
actix-cors = "0.5.4"
actix-service = "1.0.6"
csrf = "0.4.0"
actix-web = "4.0.1"
actix = "0.13"
actix-identity = "0.4.0"
actix-http = "3.0.4"
actix-rt = "2"
actix-cors = "0.6.1"
actix-service = "2.0.0"
async-trait = "0.1.51"
mime_guess = "2.0.3"
rust-embed = "5.9.0"
cache-buster = { version = "0.1.0", git = "https://github.com/realaravinth/cache-buster" }
rust-embed = "6.4.0"
cache-buster = { git = "https://github.com/realaravinth/cache-buster" }
futures = "0.3.14"
sqlx = { version = "0.4.0", features = [ "runtime-actix-rustls", "postgres" ] }
argon2-creds = { version = "0.2", git = "https://github.com/realaravinth/argon2-creds", commit = "61f2d1d" }
futures = "0.3.15"
tokio = { version = "1.14", features = ["sync"]}
sqlx = { version = "0.5.13", features = [ "runtime-actix-rustls", "postgres", "time", "offline", "mysql"] }
argon2-creds = { branch = "master", git = "https://github.com/realaravinth/argon2-creds"}
#argon2-creds = { version="*", path = "../../argon2-creds/" }
config = "0.11"
validator = { version = "0.13", features = ["derive"]}
validator = { version = "0.15", features = ["derive"]}
derive_builder = "0.10"
derive_builder = "0.11"
derive_more = "0.99"
serde = "1"
serde_json = "1"
serde_yaml = "0.8.17"
url = "2.2"
urlencoding = "2.1.0"
pretty_env_logger = "0.4"
log = "0.4"
@@ -59,23 +59,55 @@ log = "0.4"
lazy_static = "1.4"
# m_captcha = { version = "0.1.2", git = "https://github.com/mCaptcha/mCaptcha" }
m_captcha = { branch = "master", git = "https://github.com/mCaptcha/mCaptcha" }
libmcaptcha = { version = "0.2.3", git = "https://github.com/mCaptcha/libmcaptcha", features = ["full"], tag ="0.2.3" }
#libmcaptcha = { branch = "master", git = "https://github.com/mCaptcha/libmcaptcha", features = ["full"] }
#libmcaptcha = { path = "../libmcaptcha", features = ["full"]}
rand = "0.8"
sailfish = "0.3.2"
sailfish = "0.4.0"
mime = "0.3.16"
num_cpus = "1.13.1"
lettre = { version = "0.10.0-rc.3", features = [
"builder",
"tokio1",
"tokio1-native-tls",
"smtp-transport"
]}
openssl = { version = "0.10.48", features = ["vendored"] }
uuid = { version = "1.4.0", features = ["v4", "serde"] }
[dependencies.db-core]
path = "./db/db-core"
[dependencies.db-sqlx-postgres]
path = "./db/db-sqlx-postgres"
[dependencies.db-sqlx-maria]
path = "./db/db-sqlx-maria"
[dependencies.my-codegen]
git = "https://github.com/realaravinth/actix-web"
package = "actix-web-codegen"
[dependencies.actix-auth-middleware]
version = "0.2.0"
git = "https://github.com/realaravinth/actix-auth-middleware"
features = ["actix_identity_backend"]
[build-dependencies]
serde_yaml = "0.8.17"
serde = "1"
serde_json = "1"
yaml-rust = "0.4.5"
cache-buster = { version = "0.1.0", git = "https://github.com/realaravinth/cache-buster" }
mime = "0.3.16"
log = "0.4"
config = "0.11"
url = "2.2"
sqlx = { version = "0.5.13", features = [ "runtime-actix-rustls", "postgres", "time", "offline", "mysql" ] }
[dev-dependencies]
pow_sha256 = { version = "0.2.1", git = "https://github.com/mcaptcha/pow_sha256" }
pow_sha256 = { version = "0.3.1", git = "https://github.com/mcaptcha/pow_sha256", tag="0.3.1" }
awc = "3.0.0"
[target.x86_64-unknown-linux-musl]
linker = "x86_64"

5
Cross.toml Normal file
View File

@@ -0,0 +1,5 @@
[build.env]
passthrough = [
"RUST_BACKTRACE",
"RUST_LOG",
]

View File

@@ -1,108 +0,0 @@
# Development Setup
## Setting up development environment
### Toolchain
You'll have to install before you can start writing code.
1. Install Rust:
Install Cargo(Rust toolchain) using [rustup](https://rustup.rs/) with:
```
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```
2. Install Node:
Please refer to [official instructions](https://nodejs.org/en/download/)
3. Install yarn:
`npm install -g yarn`
For more details, refer to [official
instructions](https://yarnpkg.com/getting-started/install)
4. GNU Make:
If you are on Linux, it's probably already installed on your machine.
You can check it's existence by running:
```bash
$ make --version
```
If it's not available, you download it with your package manager or
refer to [official instructions](https://www.gnu.org/software/make/)
### External Dependencies:
### Postgres databse:
The backend requires a Postgres database. We have
compiletime SQL checks so without a database available, you won't be
able to build the project.
I use Postgres in Docker.
1. To install Docker, please refer to [official
instructions](https://docs.docker.com/engine/install/].
2. Create create database user:
```bash
$ docker create --name mcaptcha-postgres \
-e POSTGRES_PASSWORD=password \
-p 5432:5432 postgres
```
3. Start database container:
```bash
$ docker start mcaptcha-postgres
```
4. Set configurations:
```bash
$ cd guard # your copy of https://github.com/mCaptcha/guard
$ echo 'export DATABASE_URL="postgres://postgres:password@localhost:5432/postgres"' > .env
```
**NOTE: Don't use this database for other projects**
5. Run migrations:
This step is only required when migrations are updated. The server
binary has inbuilt migrations manager but that can only be used after
the server is compiled. Since we are trying to compile the server here,
we can't use that.
However, this project ships with a utility to run migrations!
```bash
$ cd guard # your copy of https://github.com/mCaptcha/guard
$ cargo run --bin tests-migrate
```
That's it, you are all set!
## Build commands:
### Compile:
```bash
$ cd guard # your copy of https://github.com/mCaptcha/guard
$ make
```
### Additional commands:
```bash
➜ guard git:(master) ✗ make help
docs - build documentation
run - run developer instance
test - run unit and integration tests
migrate - run database migrations
dev-env - download dependencies
clean - drop builds and environments
coverage - build test coverage in HTML format
xml-coverage - build test coverage in XML for upload to codecov
```

57
Dockerfile Normal file
View File

@@ -0,0 +1,57 @@
# SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
#
# SPDX-License-Identifier: AGPL-3.0-or-later
FROM node:18.0.0 as frontend
RUN set -ex; \
apt-get update; \
DEBIAN_FRONTEND=noninteractive \
apt-get install -y --no-install-recommends make
RUN mkdir -p /src/docs/openapi/
COPY package.json yarn.lock /src/
COPY docs/openapi/package.json docs/openapi/yarn.lock /src/docs/openapi/
WORKDIR /src
RUN yarn install && cd docs/openapi && yarn install
WORKDIR /src
RUN mkdir -p /src/static/cache/bundle
COPY tsconfig.json webpack.config.js jest.config.ts /src/
COPY templates /src/templates/
COPY docs/openapi /src/docs/openapi/
COPY Makefile /src/
COPY scripts /src/scripts
RUN make frontend
FROM rust:latest as planner
RUN cargo install cargo-chef
WORKDIR /src
COPY . /src/
RUN cargo chef prepare --recipe-path recipe.json
FROM rust:latest as cacher
WORKDIR /src/
RUN cargo install cargo-chef
COPY --from=planner /src/recipe.json recipe.json
RUN cargo chef cook --release --recipe-path recipe.json
FROM rust:latest as rust
WORKDIR /src
COPY . .
COPY --from=cacher /src/target target
#COPY --from=cacher /src/db/db-core/target /src/db/db-core/target
#COPY --from=cacher /src/db/db-sqlx-postgres/target /src/db/db-sqlx-postgres/target
#COPY --from=cacher /src/db/db-migrations/target /src/db/db-migrations/target
#COPY --from=cacher /src/utils/cache-bust/target /src/utils/cache-bust/target
COPY --from=frontend /src/static/cache/bundle/ /src/static/cache/bundle/
COPY --from=frontend /src/docs/openapi/dist/ /src/docs/openapi/dist/
RUN cargo --version
RUN make cache-bust
RUN cargo build --release
FROM debian:bullseye as mCaptcha
LABEL org.opencontainers.image.source https://github.com/mCaptcha/mCaptcha
RUN useradd -ms /bin/bash -u 1001 mcaptcha
WORKDIR /home/mcaptcha
COPY --from=rust /src/target/release/mcaptcha /usr/local/bin/
COPY --from=rust /src/config/default.toml /etc/mcaptcha/config.toml
USER mcaptcha
CMD [ "/usr/local/bin/mcaptcha" ]

View File

@@ -0,0 +1,235 @@
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users.
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software.
A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public.
The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version.
An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license.
The precise terms and conditions for copying, distribution and modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based on the Program.
To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work.
A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.
The Corresponding Source for a work in source code form is that same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.
When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified it, and giving a relevant date.
b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices".
c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.
A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:
a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.
d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.
A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.
"Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.
If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).
The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or authors of the material; or
e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.
All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).
However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.
If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.
A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph.
Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation.
If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.
Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements.
You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see <http://www.gnu.org/licenses/>.

73
LICENSES/Apache-2.0.txt Normal file
View File

@@ -0,0 +1,73 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
(a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

9
LICENSES/MIT.txt Normal file
View File

@@ -0,0 +1,9 @@
MIT License
Copyright (c) <year> <copyright holders>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

13
LICENSES/X11.txt Normal file
View File

@@ -0,0 +1,13 @@
X11 License
Copyright (C) 1996 X Consortium
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium.
X Window System is a trademark of X Consortium, Inc.

232
Makefile
View File

@@ -1,49 +1,215 @@
# WIP
default: build-frontend
# SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
#
# SPDX-License-Identifier: AGPL-3.0-or-later
BUNDLE = static/cache/bundle
OPENAPI = docs/openapi
CLEAN_UP = $(BUNDLE) src/cache_buster_data.json assets
define deploy_dependencies ## deploy dependencies
@-docker create --name ${db} \
-e POSTGRES_PASSWORD=password \
-p 5432:5432 \
postgres
@-docker create \
-p 3306:3306 \
--name ${mdb} \
--env MARIADB_USER=maria \
--env MARIADB_PASSWORD=password \
--env MARIADB_ROOT_PASSWORD=password \
--env MARIADB_DATABASE=maria \
mariadb:latest
@-docker create \
-p 6379:6379 \
--name mcaptcha-cache \
mcaptcha/cache:latest
docker start ${db}
docker start ${mdb}
docker start mcaptcha-cache
endef
define run_migrations ## run database migrations
cd db/db-migrations/ && cargo run
endef
define run_dev_migrations ## run database migrations
cd db/db-sqlx-maria/ && \
DATABASE_URL=${MARIA_DATABASE_URL} sqlx migrate run
cd db/db-sqlx-postgres/ && \
DATABASE_URL=${POSTGRES_DATABASE_URL} sqlx migrate run
endef
define frontend_env ## install frontend deps
yarn install
cd docs/openapi && yarn install
endef
define cache_bust ## run cache_busting program
cd utils/cache-bust && cargo run
endef
define test_frontend ## run frontend tests
yarn test
# cd $(OPENAPI)&& yarn test
endef
define test_db_sqlx_postgres
cd db/db-sqlx-postgres &&\
DATABASE_URL=${POSTGRES_DATABASE_URL}\
cargo test --no-fail-fast
endef
define test_db_sqlx_maria
cd db/db-sqlx-maria &&\
DATABASE_URL=${MARIA_DATABASE_URL}\
cargo test --no-fail-fast
endef
define test_core
cargo test --no-fail-fast
endef
default: frontend ## Build app in debug mode
$(call cache_bust)
cargo build
run: build-frontend-dev
cargo run
check: ## Check for syntax errors on all workspaces
cargo check --workspace --tests --all-features
cd utils/cache-bust && cargo check --tests --all-features
cd db/db-migrations && cargo check --tests --all-features
cd db/db-sqlx-postgres &&\
DATABASE_URL=${POSTGRES_DATABASE_URL}\
cargo check
cd db/db-sqlx-maria &&\
DATABASE_URL=${MARIA_DATABASE_URL}\
cargo check
cd db/db-core/ && cargo check
dev-env:
cargo fetch
yarn install
cache-bust: ## Run cache buster on static assets
$(call cache_bust)
docs:
clean: ## Delete build artifacts
@cargo clean
@yarn cache clean
@-rm $(CLEAN_UP)
doc: ## Generate documentation
#yarn doc
cargo doc --no-deps --workspace --all-features
build-frontend-dev:
yarn start
docker: ## Build Docker image
docker build -t mcaptcha/mcaptcha:master -t mcaptcha/mcaptcha:latest .
build-frontend:
docker-publish: docker ## Build and publish Docker image
docker push mcaptcha/mcaptcha:master
docker push mcaptcha/mcaptcha:latest
env: ## Setup development environtment
cargo fetch
$(call frontend_env)
env.db: ## Deploy dependencies
$(call deploy_dependencies)
sleep 5
$(call run_migrations)
env.db.recreate: ## Deploy dependencies from scratch
@-docker rm -f ${db}
@-docker rm -f ${mdb}
@-docker rm -f mcaptcha-cache
$(call deploy_dependencies)
sleep 5
$(call run_migrations)
frontend-env: ## Install frontend deps
$(call frontend_env)
frontend: ## Build frontend
$(call frontend_env)
cd $(OPENAPI) && yarn build
yarn install
@-rm -rf $(BUNDLE)
@-mkdir $(BUNDLE)
yarn build
@yarn run sass -s \
compressed templates/main.scss \
./static/cache/bundle/css/main.css
@yarn run sass -s \
compressed templates/mobile.scss \
./static/cache/bundle/css/mobile.css
@yarn run sass -s \
compressed templates/widget/main.scss \
./static/cache/bundle/css/widget.css
@./scripts/librejs.sh
@./scripts/cachebust.sh
test: migrate
cargo test
lint: ## Lint codebase
cargo fmt -v --all -- --emit files
cargo clippy --workspace --tests --all-features
yarn lint
#cd $(OPENAPI)&& yarn test
xml-test-coverage: migrate
cargo tarpaulin -t 1200 --out Xml
migrate: ## Run database migrations
$(call run_migrations)
coverage: migrate
cargo tarpaulin -t 1200 --out Html
migrate.dev: ## Run database migrations during development
$(call run_dev_migrations)
release: build-frontend
release: frontend ## Build app with release optimizations
$(call cache_bust)
cargo build --release
clean:
cargo clean
yarn clean
run: frontend ## Run app in debug mode
$(call cache_bust)
cargo run
migrate:
cargo run --bin tests-migrate
help:
@echo ' docs - build documentation'
@echo ' run - run developer instance'
@echo ' test - run unit and integration tests'
@echo ' migrate - run database migrations'
@echo ' dev-env - download dependencies'
@echo ' clean - drop builds and environments'
@echo ' coverage - build test coverage in HTML format'
@echo ' xml-coverage - build test coverage in XML for upload to codecov'
@echo ''
db.sqlx.offline: ## prepare sqlx offline data
cd db/db-sqlx-postgres && cargo sqlx prepare \
--database-url=${POSTGRES_DATABASE_URL} -- \
--all-features
cd db/db-sqlx-maria && cargo sqlx prepare \
--database-url=${MARIA_DATABASE_URL} -- \
--all-features
test: frontend ## Run all available tests
$(call test_frontend)
$(call cache_bust)
$(call test_db_sqlx_postgres)
$(call test_db_sqlx_maria)
$(call test_core)
# ./scripts/tests.sh
test.cov.html: migrate ## Generate code coverage report in HTML format
$(call cache_bust)
cargo tarpaulin -t 1200 --out Html
test.cov.xml: migrate ## Generate code coverage report in XML format
$(call cache_bust)
cargo tarpaulin -t 1200 --out Xml
test.core: ## Run all core tests
$(call test_core)
test.db: ## Run all database driver tests
$(call test_db_sqlx_postgres)
$(call test_db_sqlx_maria)
test.db.pg: ## Run Postgres database driver tests
$(call test_db_sqlx_postgres)
test.db.maria: ## Run Maria database driver tests
$(call test_db_sqlx_maria)
test.frontend: ## Run frontend tests
$(call test_frontend)
test.integration: ## run integration tests with nightwatch.js
./scripts/integration.sh
help: ## Prints help for targets with comments
@cat $(MAKEFILE_LIST) | grep -E '^[a-zA-Z_-].+:.*?## .*$$' | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

166
README.md
View File

@@ -1,80 +1,148 @@
<div align="center">
<h1>mCaptcha Guard</h1>
<img width="100px" alt="mcaptcha logo" src="./docs/res/icon-trans.png" />
<h1>mCaptcha</h1>
<p>
<strong>Back-end component of mCaptcha</strong>
<strong>
Proof of work based, privacy respecting CAPTCHA system with a kickass UX.
</strong>
</p>
[![Documentation](https://img.shields.io/badge/docs-master-blue)](https://mcaptcha.github.io/guard/guard/)
![CI (Linux)](<https://github.com/mCaptcha/guard/workflows/CI%20(Linux)/badge.svg>)
[![dependency status](https://deps.rs/repo/github/mCaptcha/guard/status.svg)](https://deps.rs/repo/github/mCaptcha/guard)
[![codecov](https://codecov.io/gh/mCaptcha/guard/branch/master/graph/badge.svg)](https://codecov.io/gh/mCaptcha/guard)
[![Documentation](https://img.shields.io/badge/docs-master-blue?style=flat-square)](https://mcaptcha.github.io/mCaptcha/mCaptcha/)
[![Build](https://github.com/mCaptcha/mCaptcha/actions/workflows/linux.yml/badge.svg)](https://github.com/mCaptcha/mCaptcha/actions/workflows/linux.yml)
[![Docker](https://img.shields.io/docker/pulls/mcaptcha/mcaptcha)](https://hub.docker.com/r/mcaptcha/mcaptcha)
[![dependency status](https://deps.rs/repo/github/mCaptcha/mCaptcha/status.svg?style=flat-square)](https://deps.rs/repo/github/mCaptcha/mCaptcha)
[![codecov](https://codecov.io/gh/mCaptcha/mCaptcha/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/mCaptcha/mCaptcha)
<br />
[![AGPL License](https://img.shields.io/badge/license-AGPL-blue.svg)](http://www.gnu.org/licenses/agpl-3.0)
[![AGPL License](https://img.shields.io/badge/license-AGPL-blue.svg?style=flat-square)](http://www.gnu.org/licenses/agpl-3.0)
[![Chat](https://img.shields.io/badge/matrix-+mcaptcha:matrix.batsense.net-purple?style=flat-square)](https://matrix.to/#/+mcaptcha:matrix.batsense.net)
**STATUS: ACTIVE DEVELOPMENT**
</div>
</div>
Guard is the back-end component of [mCaptcha](https://mcaptcha.org)
system.
**Skip to [demo](#demo)**
**STATUS: UNUSABLE BUT ACTIVE DEVELOPMENT**
[mCaptcha](https://mcaptcha.org) is a privacy respecting, _free_ CAPTCHA
system with a kickass UX. Your users no longer have to interact with
ridiculous image-based CAPTCHA system, wasting precious mental
bandwidth. Instead, your computer will do the work for you, [see for
yourself!](https://demo.mcaptcha.org/widget/?sitekey=pHy0AktWyOKuxZDzFfoaewncWecCHo23)
### Development:
## How does it work?
See [DEVELOPMENT.md](./DEVELOPMENT.md)
mCaptcha uses SHA256 based proof-of-work (PoW) to rate limit users.
### How to build
When a user wants to do something on a mCaptcha-protected website,
- Install Cargo using [rustup](https://rustup.rs/) with:
1. they will have to generate proof-of-work (a bunch of math that will takes
time to compute) and submit it to mCaptcha.
```
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
2. We'll validate the proof:
- **if validation is unsuccessful**, they will be prevented from
accessing their target website
- **if validation is successful**, read on,
3. They will be issued a token that they should submit along
with their request/form submission to the target website.
4. The target website should validate the user-submitted token with mCaptcha
before processing the user's request.
The whole process is automated from the user's POV. All they have to do
is click on a button to initiate the process.
mCaptcha makes interacting with websites (computationally) expensive for
the user. A well-behaving user will experience a slight delay (no delay
when under moderate load to 2s when under attack; PoW difficulty is
variable) but if someone wants to hammer your site, they will have to do
more work to send requests than your server will have to do to respond
to their request.
## Why use mCaptcha?
- [x] **Free software, privacy focused**
- [x] **Seamless UX** - No more annoying CAPTCHAs!
- [x] **No tracking:** Our CAPTCHA routes are cookie free!
- [x] **IP address independent:** your users are behind a NAT? We got you covered!
- [x] **Resistant to replay attacks:** proof-of-work configurations have
short lifetimes (30s) and can be used only once. If a user submits a
PoW to an already used configuration or an expired one, their proof
will be rejected.
## Demo
## Client-side widget:
mCaptcha's UX is super silent, solving CAPTCHAs have never been more
easier. One click and you are on your way.
To observe mCaptcha in action, open dev tools and
monitor console and network activity.
1. [Link to widget](https://demo.mcaptcha.org/widget/?sitekey=pHy0AktWyOKuxZDzFfoaewncWecCHo23)
2. [Video](https://github.com/mCaptcha/mCaptcha/blob/master/docs/res/widget-in-action.mp4?raw=true):
### Demo servers are available at:
- https://demo.mcaptcha.org/
- https://demo2.mcaptcha.org/ (runs on a Raspberry Pi!)
> Core functionality is working but it's still very much
> work-in-progress. Since we don't have a stable release yet, hosted
> demo servers might be a few versions behind `master`. Please check footer for
> build commit.
Feel free to provide bogus information while signing up (project under
development, database frequently wiped).
### Self-hosted:
Clone the repo and run the following from the root of the repo:
```bash
git clone https://github.com/mCaptcha/mCaptcha.git
docker-compose up -d
```
- Clone the repository with:
After the containers are up, visit [http://localhost:7000](http://localhost:7000) and login with the default credentials:
```
$ git clone https://github.com/mCaptcha/guard
```
- username: aaronsw
- password: password
- Build with Cargo:
It takes a while to build the image so please be patient :)
```
$ cd guard && cargo build
```
See [DEPLOYMENT.md](./docs/DEPLOYMENT.md) for detailed alternate deployment
methods.
### Configuration:
## Development:
Guard is highly configurable.
Configuration is applied/merged in the following order:
See [HACKING.md](./docs/HACKING.md)
1. `config/default.toml`
2. environment variables.
## Deployment:
#### Setup
See [DEPLOYMENT.md](./docs/DEPLOYMENT.md)
##### Environment variables:
## Configuration:
Setting environment variables are optional. The configuration files have
all the necessary parameters listed. By setting environment variables,
you will be overriding the values set in the configuration files.
See [CONFIGURATION.md](./docs/CONFIGURATION.md)
###### Database:
## Funding
| Name | Value |
| ------------------------- | -------------------------------------- |
| `GUARD_DATEBASE_PASSWORD` | Postgres password |
| `GUARD_DATEBASE_NAME` | Postgres database name |
| `GUARD_DATEBASE_PORT` | Postgres port |
| `GUARD_DATEBASE_HOSTNAME` | Postgres hostmane |
| `GUARD_DATEBASE_USERNAME` | Postgres username |
| `GUARD_DATEBASE_POOL` | Postgres database connection pool size |
### NLnet
###### Server:
<div align="center">
<img
height="150px"
alt="NLnet NGIZero logo"
src="./docs/third-party/NGIZero-green.hex.svg"
/>
</div>
| Name | Value |
| ----------------------------------- | --------------------------------------------------- |
| `GUARD_SERVER_PORT` (or) `PORT`\*\* | The port on which you want wagon to listen to |
| `GUARD_SERVER_IP` | The IP address on which you want wagon to listen to |
| `GUARD_SERVER_STATIC_FILES_DIR` | Path to directory containing static files |
<br />
2023 development is funded through the [NGI0 Entrust
Fund](https://nlnet.nl/entrust), via [NLnet](https://nlnet.nl/). Please
see [here](https://nlnet.nl/project/mCaptcha/) for more details.

View File

@@ -1,65 +1,21 @@
/*
* Copyright (C) 2021 Aravinth Manivannan <realaravinth@batsense.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// Copyright (C) 2021 Aravinth Manivannan <realaravinth@batsense.net>
// SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::process::Command;
use cache_buster::BusterBuilder;
#[path = "./src/settings.rs"]
mod settings;
use sqlx::types::time::OffsetDateTime;
fn main() {
// note: add error checking yourself.
let output = Command::new("git")
.args(&["rev-parse", "HEAD"])
.args(["rev-parse", "HEAD"])
.output()
.unwrap();
let git_hash = String::from_utf8(output.stdout).unwrap();
println!("cargo:rustc-env=GIT_HASH={}", git_hash);
let yml = include_str!("./openapi.yaml");
let api_json: serde_json::Value = serde_yaml::from_str(yml).unwrap();
println!(
"cargo:rustc-env=OPEN_API_DOCS={}",
serde_json::to_string(&api_json).unwrap()
);
cache_bust();
}
fn cache_bust() {
let settings = settings::Settings::new().unwrap();
let types = vec![
mime::IMAGE_PNG,
mime::IMAGE_SVG,
mime::IMAGE_JPEG,
mime::IMAGE_GIF,
mime::APPLICATION_JAVASCRIPT,
mime::TEXT_CSS,
];
let config = BusterBuilder::default()
.source("./static")
.result("./prod")
.prefix(settings.server.url_prefix)
.mime_types(types)
.copy(true)
.follow_links(true)
.build()
.unwrap();
config.process().unwrap();
let now = OffsetDateTime::now_utc().format("%y-%m-%d");
println!("cargo:rustc-env=COMPILED_DATE={}", &now);
}

132
code_of_conduct.md Normal file
View File

@@ -0,0 +1,132 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
- Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
- The use of sexualized language or imagery, and sexual attention or
advances of any kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email
address, without their explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
[INSERT CONTACT METHOD].
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][mozilla coc].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][faq]. Translations are available
at [https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html
[mozilla coc]: https://github.com/mozilla/diversity
[faq]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

View File

@@ -1,4 +1,42 @@
debug = true
source_code = "https://github.com/mCaptcha/mCaptcha"
commercial = false
allow_demo = true
allow_registration = true
[server]
# Please set a unique value, your mCaptcha instance's security depends on this being
# unique
cookie_secret = "Zae0OOxf^bOJ#zN^&k7VozgW&QAx%n02TQFXpRMG4cCU0xMzgu3dna@tQ9dvc&TlE6p*n#kXUdLZJCQsuODIV%r$@o4%770ePQB7m#dpV!optk01NpY0@615w5e2Br4d"
# The port at which you want authentication to listen to
# takes a number, choose from 1000-10000 if you dont know what you are doing
port = 7000
#IP address. Enter 0.0.0.0 to listen on all available addresses
ip= "0.0.0.0"
# enter your hostname, eg: example.com
domain = "localhost"
# Set true if you have setup TLS with a reverse proxy like Nginx.
# Does HTTPS redirect and sends additional headers that can only be used if
# HTTPS available to improve security
proxy_has_tls = false
#url_prefix = ""
[captcha]
# Please set a unique value, your mCaptcha instance's security depends on this being
# unique
salt = "asdl;kjfhjawehfpa;osdkjasdvjaksndfpoanjdfainsdfaijdsfajlkjdsaf;ajsdfweroire"
# garbage collection period to manage mCaptcha system
# leave untouched if you don't know what you are doing
gc = 30
runners = 4
queue_length = 2000
enable_stats = true
[captcha.default_difficulty_strategy]
avg_traffic_difficulty = 50000 # almost instant solution
peak_sustainable_traffic_difficulty = 3000000 # roughly 1.5s
broke_my_site_traffic_difficulty = 5000000 # greater than 3.5s
duration = 30 # cooldown period in seconds
[database]
# This section deals with the database location and how to access it
@@ -14,26 +52,23 @@ username = "postgres"
password = "password"
name = "postgres"
pool = 4
database_type="postgres" # "postgres", "maria"
# This section deals with the configuration of the actual server
[server]
# Please set a unique value, your mCaptcha instance's security depends on this being
# unique
cookie_secret = "Zae0OOxf^bOJ#zN^&k7VozgW&QAx%n02TQFXpRMG4cCU0xMzgu3dna@tQ9dvc&TlE6p*n#kXUdLZJCQsuODIV%r$@o4%770ePQB7m#dpV!optk01NpY0@615w5e2Br4d"
# The port at which you want authentication to listen to
# takes a number, choose from 1000-10000 if you dont know what you are doing
port = 7000
#IP address. Enter 0.0.0.0 to listen on all availale addresses
ip= "0.0.0.0"
# enter your hostname, eg: example.com
domain = "localhost"
allow_registration = true
url_prefix = "/test"
[redis]
# This section deals with the database location and how to access it
# Please note that at the moment, we have support for only postgresqa.
# Example, if you are Batman, your config would be:
# hostname = "batcave.org"
# port = "5432"
# username = "batman"
# password = "somereallycomplicatedBatmanpassword"
url = "redis://127.0.0.1"
pool = 4
[pow]
# Please set a unique value, your mCaptcha instance's security depends on this being
# unique
salt = "asdl;kjfhjawehfpa;osdkjasdvjaksndfpoanjdfainsdfaijdsfajlkjdsaf;ajsdfweroire"
# garbage collection period to manage mCaptcha system
# leave untouched if you don't know what you are doing
gc = 30
[smtp]
from = "admin@localhost"
reply = "admin@localhost"
url = "127.0.0.1"
port = 10025
username = "admin"
password = "password"

2
db/db-core/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/target
/Cargo.lock

24
db/db-core/Cargo.toml Normal file
View File

@@ -0,0 +1,24 @@
[package]
name = "db-core"
version = "0.1.0"
edition = "2021"
homepage = "https://mcaptcha.org"
repository = "https://github.com/mCaptcha/mCaptcha"
documentation = "https://mcaptcha.org/docs/"
license = "AGPLv3 or later version"
authors = ["realaravinth <realaravinth@batsense.net>"]
[dependencies]
async-trait = "0.1.51"
thiserror = "1.0.30"
serde = { version = "1", features = ["derive"]}
url = { version = "2.2.2", features = ["serde"] }
libmcaptcha = { version = "0.2.3", git = "https://github.com/mCaptcha/libmcaptcha", features = ["minimal"], default-features = false, tag = "0.2.3"}
#libmcaptcha = { branch = "master", git = "https://github.com/mCaptcha/libmcaptcha", features = ["full"] }
[features]
default = []
test = []
[dev-dependencies]
serde_json = "1"

50
db/db-core/src/errors.rs Normal file
View File

@@ -0,0 +1,50 @@
// Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
// SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
//! represents all the ways a trait can fail using this crate
use std::error::Error as StdError;
//use derive_more::{error, Error as DeriveError};
use thiserror::Error;
/// Error data structure grouping various error subtypes
#[derive(Debug, Error)]
pub enum DBError {
/// errors that are specific to a database implementation
#[error("{0}")]
DBError(#[source] BoxDynError),
/// Username is taken
#[error("Username is taken")]
UsernameTaken,
/// Email is taken
#[error("Email is taken")]
EmailTaken,
/// Secret is taken
#[error("Secret is taken")]
SecretTaken,
/// Captcha key is taken
#[error("Captcha key is taken")]
CaptchaKeyTaken,
/// Account not found
#[error("Account not found")]
AccountNotFound,
/// Captcha not found
#[error("Captcha not found")]
CaptchaNotFound,
/// Traffic pattern not found
#[error("Traffic pattern not found")]
TrafficPatternNotFound,
/// Notification not found
#[error("Notification not found")]
NotificationNotFound,
}
/// Convenience type alias for grouping driver-specific errors
pub type BoxDynError = Box<dyn StdError + 'static + Send + Sync>;
/// Generic result data structure
pub type DBResult<V> = std::result::Result<V, DBError>;

417
db/db-core/src/lib.rs Normal file
View File

@@ -0,0 +1,417 @@
// Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
// SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
#![warn(missing_docs)]
//! # `mCaptcha` database operations
//!
//! Traits and datastructures used in mCaptcha to interact with database.
//!
//! To use an unsupported database with mCaptcha, traits present within this crate should be
//! implemented.
//!
//!
//! ## Organisation
//!
//! Database functionality is divided across various modules:
//!
//! - [errors](crate::auth): error data structures used in this crate
//! - [ops](crate::ops): meta operations like connection pool creation, migrations and getting
//! connection from pool
use serde::{Deserialize, Serialize};
pub use libmcaptcha::defense::Level;
pub mod errors;
pub mod ops;
#[cfg(feature = "test")]
pub mod tests;
use dev::*;
pub use ops::GetConnection;
pub mod prelude {
//! useful imports for users working with a supported database
pub use super::errors::*;
pub use super::ops::*;
pub use super::*;
}
pub mod dev {
//! useful imports for supporting a new database
pub use super::prelude::*;
pub use async_trait::async_trait;
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
/// Data required to register a new user
pub struct Register<'a> {
/// username of new user
pub username: &'a str,
/// secret of new user
pub secret: &'a str,
/// hashed password of new use
pub hash: &'a str,
/// Optionally, email of new use
pub email: Option<&'a str>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
/// data required to update them email of a user
pub struct UpdateEmail<'a> {
/// username of the user
pub username: &'a str,
/// new email address of the user
pub new_email: &'a str,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
/// types of credentials used as identifiers during login
pub enum Login<'a> {
/// username as login
Username(&'a str),
/// email as login
Email(&'a str),
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
/// type encapsulating username and hashed password of a user
pub struct NameHash {
/// username
pub username: String,
/// hashed password
pub hash: String,
}
#[async_trait]
/// mCaptcha's database requirements. To implement support for $Database, kindly implement this
/// trait.
pub trait MCDatabase: std::marker::Send + std::marker::Sync + CloneSPDatabase {
/// ping DB
async fn ping(&self) -> bool;
/// register a new user
async fn register(&self, p: &Register) -> DBResult<()>;
/// delete a user
async fn delete_user(&self, username: &str) -> DBResult<()>;
/// check if username exists
async fn username_exists(&self, username: &str) -> DBResult<bool>;
/// get user email
async fn get_email(&self, username: &str) -> DBResult<Option<String>>;
/// check if email exists
async fn email_exists(&self, email: &str) -> DBResult<bool>;
/// update a user's email
async fn update_email(&self, p: &UpdateEmail) -> DBResult<()>;
/// get a user's password
async fn get_password(&self, l: &Login) -> DBResult<NameHash>;
/// update user's password
async fn update_password(&self, p: &NameHash) -> DBResult<()>;
/// update username
async fn update_username(&self, current: &str, new: &str) -> DBResult<()>;
/// get a user's secret
async fn get_secret(&self, username: &str) -> DBResult<Secret>;
/// get a user's secret from a captcha key
async fn get_secret_from_captcha(&self, key: &str) -> DBResult<Secret>;
/// update a user's secret
async fn update_secret(&self, username: &str, secret: &str) -> DBResult<()>;
/// create new captcha
async fn create_captcha(&self, username: &str, p: &CreateCaptcha) -> DBResult<()>;
/// Get captcha config
async fn get_captcha_config(&self, username: &str, key: &str) -> DBResult<Captcha>;
/// Get all captchas belonging to user
async fn get_all_user_captchas(&self, username: &str) -> DBResult<Vec<Captcha>>;
/// update captcha metadata; doesn't change captcha key
async fn update_captcha_metadata(
&self,
username: &str,
p: &CreateCaptcha,
) -> DBResult<()>;
/// update captcha key; doesn't change metadata
async fn update_captcha_key(
&self,
username: &str,
old_key: &str,
new_key: &str,
) -> DBResult<()>;
/// Add levels to captcha
async fn add_captcha_levels(
&self,
username: &str,
captcha_key: &str,
levels: &[Level],
) -> DBResult<()>;
/// check if captcha exists
async fn captcha_exists(
&self,
username: Option<&str>,
captcha_key: &str,
) -> DBResult<bool>;
/// Delete all levels of a captcha
async fn delete_captcha_levels(
&self,
username: &str,
captcha_key: &str,
) -> DBResult<()>;
/// Delete captcha
async fn delete_captcha(&self, username: &str, captcha_key: &str) -> DBResult<()>;
/// Get captcha levels
async fn get_captcha_levels(
&self,
username: Option<&str>,
captcha_key: &str,
) -> DBResult<Vec<Level>>;
/// Get captcha's cooldown period
async fn get_captcha_cooldown(&self, captcha_key: &str) -> DBResult<i32>;
/// Add traffic configuration
async fn add_traffic_pattern(
&self,
username: &str,
captcha_key: &str,
pattern: &TrafficPattern,
) -> DBResult<()>;
/// Get traffic configuration
async fn get_traffic_pattern(
&self,
username: &str,
captcha_key: &str,
) -> DBResult<TrafficPattern>;
/// Delete traffic configuration
async fn delete_traffic_pattern(
&self,
username: &str,
captcha_key: &str,
) -> DBResult<()>;
/// create new notification
async fn create_notification(&self, p: &AddNotification) -> DBResult<()>;
/// get all unread notifications
async fn get_all_unread_notifications(
&self,
username: &str,
) -> DBResult<Vec<Notification>>;
/// mark a notification read
async fn mark_notification_read(&self, username: &str, id: i32) -> DBResult<()>;
/// record PoWConfig fetches
async fn record_fetch(&self, key: &str) -> DBResult<()>;
/// record PoWConfig solves
async fn record_solve(&self, key: &str) -> DBResult<()>;
/// record PoWConfig confirms
async fn record_confirm(&self, key: &str) -> DBResult<()>;
/// fetch PoWConfig fetches
async fn fetch_config_fetched(&self, user: &str, key: &str) -> DBResult<Vec<i64>>;
/// fetch PoWConfig solves
async fn fetch_solve(&self, user: &str, key: &str) -> DBResult<Vec<i64>>;
/// fetch PoWConfig confirms
async fn fetch_confirm(&self, user: &str, key: &str) -> DBResult<Vec<i64>>;
/// record PoW timing
async fn analysis_save(
&self,
captcha_id: &str,
d: &CreatePerformanceAnalytics,
) -> DBResult<()>;
/// fetch PoW analytics
async fn analytics_fetch(
&self,
captcha_id: &str,
limit: usize,
offset: usize,
) -> DBResult<Vec<PerformanceAnalytics>>;
/// Create psuedo ID against campaign ID to publish analytics
async fn analytics_create_psuedo_id_if_not_exists(
&self,
captcha_id: &str,
) -> DBResult<()>;
/// Get psuedo ID from campaign ID
async fn analytics_get_psuedo_id_from_capmaign_id(
&self,
captcha_id: &str,
) -> DBResult<String>;
/// Get campaign ID from psuedo ID
async fn analytics_get_capmaign_id_from_psuedo_id(
&self,
psuedo_id: &str,
) -> DBResult<String>;
/// Delete all records for campaign
async fn analytics_delete_all_records_for_campaign(
&self,
campaign_id: &str,
) -> DBResult<()>;
/// Get publishing status of pow analytics for captcha ID/ campaign ID
async fn analytics_captcha_is_published(&self, campaign_id: &str) -> DBResult<bool> {
match self
.analytics_get_psuedo_id_from_capmaign_id(campaign_id)
.await
{
Ok(_) => Ok(true),
Err(errors::DBError::CaptchaNotFound) => Ok(false),
Err(e) => Err(e),
}
}
}
#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq)]
/// Log Proof-of-Work CAPTCHA performance analytics
pub struct CreatePerformanceAnalytics {
/// time taken to generate proof
pub time: u32,
/// difficulty factor for which the proof was generated
pub difficulty_factor: u32,
/// worker/client type: wasm, javascript, python, etc.
pub worker_type: String,
}
#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq)]
/// Proof-of-Work CAPTCHA performance analytics
pub struct PerformanceAnalytics {
/// log ID
pub id: usize,
/// time taken to generate proof
pub time: u32,
/// difficulty factor for which the proof was generated
pub difficulty_factor: u32,
/// worker/client type: wasm, javascript, python, etc.
pub worker_type: String,
}
#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq)]
/// Captcha statistics with time recorded in UNIX epoch formats
pub struct StatsUnixTimestamp {
/// times at which the configuration were fetched
pub config_fetches: Vec<i64>,
/// times at which the PoW was solved
pub solves: Vec<i64>,
/// times at which the PoW token was verified
pub confirms: Vec<i64>,
}
#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq)]
/// Represents notification
pub struct Notification {
/// receiver name of the notification
pub name: Option<String>,
/// heading of the notification
pub heading: Option<String>,
/// message of the notification
pub message: Option<String>,
/// when notification was received
pub received: Option<i64>,
/// db assigned ID of the notification
pub id: Option<i32>,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
/// Data required to add notification
pub struct AddNotification<'a> {
/// who is the notification addressed to?
pub to: &'a str,
/// notification sender
pub from: &'a str,
/// heading of the notification
pub heading: &'a str,
/// message of the notification
pub message: &'a str,
}
#[derive(Default, PartialEq, Serialize, Deserialize, Clone, Debug)]
/// User's traffic pattern; used in generating a captcha configuration
pub struct TrafficPattern {
/// average traffic of user's website
pub avg_traffic: u32,
/// the peak traffic that the user's website can handle
pub peak_sustainable_traffic: u32,
/// traffic that bought the user's website down; optional
pub broke_my_site_traffic: Option<u32>,
}
#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)]
/// data required to create new captcha
pub struct CreateCaptcha<'a> {
/// cool down duration
pub duration: i32,
/// description of the captcha
pub description: &'a str,
/// secret key of the captcha
pub key: &'a str,
}
#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)]
/// Data representing a captcha
pub struct Captcha {
/// Database assigned ID
pub config_id: i32,
/// cool down duration
pub duration: i32,
/// description of the captcha
pub description: String,
/// secret key of the captcha
pub key: String,
}
#[derive(Clone, Debug, Deserialize, PartialEq, Default, Serialize)]
/// datastructure representing a user's secret
pub struct Secret {
/// user's secret
pub secret: String,
}
/// Trait to clone MCDatabase
pub trait CloneSPDatabase {
/// clone DB
fn clone_db(&self) -> Box<dyn MCDatabase>;
}
impl<T> CloneSPDatabase for T
where
T: MCDatabase + Clone + 'static,
{
fn clone_db(&self) -> Box<dyn MCDatabase> {
Box::new(self.clone())
}
}
impl Clone for Box<dyn MCDatabase> {
fn clone(&self) -> Self {
(**self).clone_db()
}
}

38
db/db-core/src/ops.rs Normal file
View File

@@ -0,0 +1,38 @@
// Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
// SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
//! meta operations like migration and connecting to a database
use crate::dev::*;
/// Database operations trait(migrations, pool creation and fetching connection from pool)
pub trait DBOps: GetConnection + Migrate {}
/// Get database connection
#[async_trait]
pub trait GetConnection {
/// database connection type
type Conn;
/// database specific error-type
/// get connection from connection pool
async fn get_conn(&self) -> DBResult<Self::Conn>;
}
/// Create database connection
#[async_trait]
pub trait Connect {
/// database specific pool-type
type Pool: MCDatabase;
/// database specific error-type
/// create connection pool
async fn connect(self) -> DBResult<Self::Pool>;
}
/// database migrations
#[async_trait]
pub trait Migrate: MCDatabase {
/// database specific error-type
/// run migrations
async fn migrate(&self) -> DBResult<()>;
}

341
db/db-core/src/tests.rs Normal file
View File

@@ -0,0 +1,341 @@
// Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
// SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
//! Test utilities
use crate::errors::*;
use crate::prelude::*;
/// test all database functions
pub async fn database_works<'a, T: MCDatabase>(
db: &T,
p: &Register<'a>,
c: &CreateCaptcha<'a>,
l: &[Level],
tp: &TrafficPattern,
an: &AddNotification<'a>,
) {
assert!(db.ping().await, "ping test");
if db.username_exists(p.username).await.unwrap() {
db.delete_user(p.username).await.unwrap();
assert!(
!db.username_exists(p.username).await.unwrap(),
"user is deleted so username shouldn't exist"
);
}
assert!(matches!(
db.get_secret(&p.username).await,
Err(DBError::AccountNotFound)
));
db.register(p).await.unwrap();
assert!(matches!(db.register(&p).await, Err(DBError::UsernameTaken)));
// testing get secret
let secret = db.get_secret(p.username).await.unwrap();
assert_eq!(secret.secret, p.secret, "user secret matches");
// testing update secret: setting secret = username
db.update_secret(p.username, p.username).await.unwrap();
let secret = db.get_secret(p.username).await.unwrap();
assert_eq!(
secret.secret, p.username,
"user secret matches username; as set by previous step"
);
// testing get_password
// with username
let name_hash = db.get_password(&Login::Username(p.username)).await.unwrap();
assert_eq!(name_hash.hash, p.hash, "user password matches");
assert_eq!(name_hash.username, p.username, "username matches");
// with email
let mut name_hash = db
.get_password(&Login::Email(p.email.as_ref().unwrap()))
.await
.unwrap();
assert_eq!(name_hash.hash, p.hash, "user password matches");
assert_eq!(name_hash.username, p.username, "username matches");
// testing get_email
assert_eq!(
db.get_email(p.username)
.await
.unwrap()
.as_ref()
.unwrap()
.as_str(),
p.email.unwrap()
);
// testing email exists
assert!(
db.email_exists(p.email.as_ref().unwrap()).await.unwrap(),
"user is registered so email should exist"
);
assert!(
db.username_exists(p.username).await.unwrap(),
"user is registered so username should exist"
);
// update password test. setting password = username
name_hash.hash = name_hash.username.clone();
db.update_password(&name_hash).await.unwrap();
let name_hash = db.get_password(&Login::Username(p.username)).await.unwrap();
assert_eq!(
name_hash.hash, p.username,
"user password matches with changed value"
);
assert_eq!(name_hash.username, p.username, "username matches");
// update username to p.email
assert!(
!db.username_exists(p.email.as_ref().unwrap()).await.unwrap(),
"user with p.email doesn't exist. pre-check to update username to p.email"
);
db.update_username(p.username, p.email.as_ref().unwrap())
.await
.unwrap();
assert!(
db.username_exists(p.email.as_ref().unwrap()).await.unwrap(),
"user with p.email exist post-update"
);
// deleting user for re-registration with email = None
db.delete_user(p.email.as_ref().unwrap()).await.unwrap();
assert!(
!db.username_exists(p.email.as_ref().unwrap()).await.unwrap(),
"user is deleted so username shouldn't exist"
);
// register with email = None
let mut p2 = p.clone();
p2.email = None;
db.register(&p2).await.unwrap();
assert!(
db.username_exists(p2.username).await.unwrap(),
"user is registered so username should exist"
);
assert!(
!db.email_exists(p.email.as_ref().unwrap()).await.unwrap(),
"user registration with email is deleted; so email shouldn't exist"
);
// testing get_email = None
assert_eq!(db.get_email(p.username).await.unwrap(), None);
// testing update email
let update_email = UpdateEmail {
username: p.username,
new_email: p.email.as_ref().unwrap(),
};
db.update_email(&update_email).await.unwrap();
println!(
"null user email: {}",
db.email_exists(p.email.as_ref().unwrap()).await.unwrap()
);
assert!(
db.email_exists(p.email.as_ref().unwrap()).await.unwrap(),
"user was with empty email but email is set; so email should exist"
);
/*
* test notification workflows
* 1. Add notifications: a minimum of two, to mark as read and test if it has affected it
* 2. Get unread notifications
* 3. Mark a notification read, check if it has affected Step #2
*/
// 1. add notification
db.create_notification(an).await.unwrap();
db.create_notification(an).await.unwrap();
// 2. Get notifications
let notifications = db.get_all_unread_notifications(an.to).await.unwrap();
assert_eq!(notifications.len(), 2);
assert_eq!(notifications[0].heading.as_ref().unwrap(), an.heading);
// 3. mark a notification read
db.mark_notification_read(an.to, notifications[0].id.unwrap())
.await
.unwrap();
let new_notifications = db.get_all_unread_notifications(an.to).await.unwrap();
assert_eq!(new_notifications.len(), 1);
// create captcha
db.create_captcha(p.username, c).await.unwrap();
assert!(db.captcha_exists(None, c.key).await.unwrap());
assert!(db.captcha_exists(Some(p.username), c.key).await.unwrap());
// get secret from captcha key
let secret_from_captcha = db.get_secret_from_captcha(&c.key).await.unwrap();
assert_eq!(secret_from_captcha.secret, p.secret, "user secret matches");
// get captcha configuration
let captcha = db.get_captcha_config(p.username, c.key).await.unwrap();
assert_eq!(captcha.key, c.key);
assert_eq!(captcha.duration, c.duration);
assert_eq!(captcha.description, c.description);
// get all captchas that belong to user
let all_user_captchas = db.get_all_user_captchas(p.username).await.unwrap();
assert_eq!(all_user_captchas.len(), 1);
assert_eq!(all_user_captchas[0], captcha);
// get captcha cooldown duration
assert_eq!(db.get_captcha_cooldown(c.key).await.unwrap(), c.duration);
// add traffic pattern
db.add_traffic_pattern(p.username, c.key, tp).await.unwrap();
assert_eq!(
&db.get_traffic_pattern(p.username, c.key).await.unwrap(),
tp
);
// delete traffic pattern
db.delete_traffic_pattern(p.username, c.key).await.unwrap();
assert!(
matches!(
db.get_traffic_pattern(p.username, c.key).await,
Err(DBError::TrafficPatternNotFound)
),
"deletion successful; traffic pattern no longer exists"
);
// add captcha levels
db.add_captcha_levels(p.username, c.key, l).await.unwrap();
// get captcha levels with username
let levels = db
.get_captcha_levels(Some(p.username), c.key)
.await
.unwrap();
assert_eq!(levels, l);
// get captcha levels without username
let levels = db.get_captcha_levels(None, c.key).await.unwrap();
assert_eq!(levels, l);
/*
* Test stats
* 1. record fetch config
* 2. record solve
* 3. record token verify
* 4. fetch config fetches
* 5. fetch solves
* 6. fetch token verify
*/
assert!(db
.fetch_config_fetched(p.username, c.key)
.await
.unwrap()
.is_empty());
assert!(db.fetch_solve(p.username, c.key).await.unwrap().is_empty());
assert!(db
.fetch_confirm(p.username, c.key)
.await
.unwrap()
.is_empty());
db.record_fetch(c.key).await.unwrap();
db.record_solve(c.key).await.unwrap();
db.record_confirm(c.key).await.unwrap();
// analytics start
db.analytics_create_psuedo_id_if_not_exists(c.key)
.await
.unwrap();
let psuedo_id = db
.analytics_get_psuedo_id_from_capmaign_id(c.key)
.await
.unwrap();
db.analytics_create_psuedo_id_if_not_exists(c.key)
.await
.unwrap();
assert_eq!(
psuedo_id,
db.analytics_get_psuedo_id_from_capmaign_id(c.key)
.await
.unwrap()
);
assert_eq!(
c.key,
db.analytics_get_capmaign_id_from_psuedo_id(&psuedo_id)
.await
.unwrap()
);
let analytics = CreatePerformanceAnalytics {
time: 0,
difficulty_factor: 0,
worker_type: "wasm".into(),
};
db.analysis_save(c.key, &analytics).await.unwrap();
let limit = 50;
let mut offset = 0;
let a = db.analytics_fetch(c.key, limit, offset).await.unwrap();
assert_eq!(a[0].time, analytics.time);
assert_eq!(a[0].difficulty_factor, analytics.difficulty_factor);
assert_eq!(a[0].worker_type, analytics.worker_type);
offset += 1;
assert!(db
.analytics_fetch(c.key, limit, offset)
.await
.unwrap()
.is_empty());
db.analytics_delete_all_records_for_campaign(c.key)
.await
.unwrap();
assert_eq!(db.analytics_fetch(c.key, 1000, 0).await.unwrap().len(), 0);
assert!(!db.analytics_captcha_is_published(c.key).await.unwrap());
db.analytics_delete_all_records_for_campaign(c.key)
.await
.unwrap();
// analytics end
assert_eq!(db.fetch_solve(p.username, c.key).await.unwrap().len(), 1);
assert_eq!(
db.fetch_config_fetched(p.username, c.key)
.await
.unwrap()
.len(),
1
);
assert_eq!(db.fetch_solve(p.username, c.key).await.unwrap().len(), 1);
assert_eq!(db.fetch_confirm(p.username, c.key).await.unwrap().len(), 1);
// update captcha key; set key = username;
db.update_captcha_key(p.username, c.key, p.username)
.await
.unwrap();
// checking for captcha with old key; shouldn't exist
assert!(!db.captcha_exists(Some(p.username), c.key).await.unwrap());
// checking for captcha with new key; shouldn exist
assert!(db
.captcha_exists(Some(p.username), p.username)
.await
.unwrap());
// delete captcha levels
db.delete_captcha_levels(p.username, c.key).await.unwrap();
// update captcha; set description = username and duration *= duration;
let mut c2 = c.clone();
c2.duration *= c2.duration;
c2.description = p.username;
db.update_captcha_metadata(p.username, &c2).await.unwrap();
// delete captcha; updated key = p.username so invoke delete with it
db.delete_captcha(p.username, p.username).await.unwrap();
assert!(!db.captcha_exists(Some(p.username), c.key).await.unwrap());
}

2
db/db-migrations/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/target
/Cargo.lock

View File

@@ -0,0 +1,13 @@
[package]
name = "db-migrations"
version = "0.1.0"
edition = "2021"
homepage = "https://mcaptcha.org"
repository = "https://github.com/mCaptcha/mCaptcha"
documentation = "https://mcaptcha.org/docs/"
license = "AGPLv3 or later version"
authors = ["realaravinth <realaravinth@batsense.net>"]
[dependencies]
actix-rt = "2"
sqlx = { version = "0.5.13", features = [ "runtime-actix-rustls", "postgres", "time", "offline", "mysql" ] }

View File

@@ -0,0 +1,3 @@
{
"db": "PostgreSQL"
}

View File

@@ -0,0 +1,45 @@
// Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
// SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
use std::env;
use sqlx::postgres::PgPoolOptions;
use sqlx::mysql::MySqlPoolOptions;
#[cfg(not(tarpaulin_include))]
#[actix_rt::main]
async fn main() {
//TODO featuregate sqlite and postgres
postgres_migrate().await;
maria_migrate().await;
}
async fn postgres_migrate() {
let db_url = env::var("POSTGRES_DATABASE_URL").expect("set POSTGRES_DATABASE_URL env var");
let db = PgPoolOptions::new()
.max_connections(2)
.connect(&db_url)
.await
.expect("Unable to form database pool");
sqlx::migrate!("../db-sqlx-postgres/migrations/")
.run(&db)
.await
.unwrap();
}
async fn maria_migrate() {
let db_url = env::var("MARIA_DATABASE_URL").expect("set POSTGRES_DATABASE_URL env var");
let db = MySqlPoolOptions::new()
.max_connections(2)
.connect(&db_url)
.await
.expect("Unable to form database pool");
sqlx::migrate!("../db-sqlx-maria/migrations/")
.run(&db)
.await
.unwrap();
}

16
db/db-sqlx-maria/.gitignore vendored Normal file
View File

@@ -0,0 +1,16 @@
/target
tarpaulin-report.html
.env
.env
cobertura.xml
prod/
node_modules/
/static-assets/bundle
static/cache/bundle
./templates/**/*.js
/static-assets/bundle/*
src/cache_buster_data.json
coverage
dist
assets
yarn-error.log

View File

@@ -0,0 +1,22 @@
[package]
name = "db-sqlx-maria"
version = "0.1.0"
edition = "2021"
homepage = "https://mcaptcha.org"
repository = "https://github.com/mCaptcha/mCaptcha"
documentation = "https://mcaptcha.org/docs/"
license = "AGPLv3 or later version"
authors = ["realaravinth <realaravinth@batsense.net>"]
[dependencies]
async-trait = "0.1.51"
db-core = {path = "../db-core"}
futures = "0.3.15"
sqlx = { version = "0.5.13", features = [ "runtime-actix-rustls", "mysql", "time", "offline" ] }
uuid = { version = "1.4.0", features = ["v4", "serde"] }
[dev-dependencies]
actix-rt = "2"
sqlx = { version = "0.5.13", features = [ "runtime-actix-rustls", "mysql", "time", "offline" ] }
db-core = {path = "../db-core", features = ["test"]}
url = { version = "2.2.2", features = ["serde"] }

View File

@@ -0,0 +1,13 @@
-- SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
--
-- SPDX-License-Identifier: AGPL-3.0-or-later
CREATE TABLE IF NOT EXISTS mcaptcha_users (
name VARCHAR(100) NOT NULL UNIQUE,
email VARCHAR(100) UNIQUE DEFAULT NULL,
email_verified BOOLEAN DEFAULT NULL,
secret varchar(50) NOT NULL UNIQUE,
password TEXT NOT NULL,
ID INT auto_increment,
PRIMARY KEY(ID)
);

View File

@@ -0,0 +1,20 @@
-- SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
--
-- SPDX-License-Identifier: AGPL-3.0-or-later
-- TODO: changed key -> captcha_key
CREATE TABLE IF NOT EXISTS mcaptcha_config (
config_id INT auto_increment,
PRIMARY KEY(config_id),
user_id INT NOT NULL,
captcha_key varchar(100) NOT NULL UNIQUE,
name varchar(100) NOT NULL,
duration integer NOT NULL DEFAULT 30,
CONSTRAINT `fk_mcaptcha_user`
FOREIGN KEY (user_id)
REFERENCES mcaptcha_users (ID)
ON DELETE CASCADE
ON UPDATE CASCADE
);

View File

@@ -0,0 +1,16 @@
-- SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
--
-- SPDX-License-Identifier: AGPL-3.0-or-later
CREATE TABLE IF NOT EXISTS mcaptcha_levels (
config_id INTEGER NOT NULL,
difficulty_factor INTEGER NOT NULL,
visitor_threshold INTEGER NOT NULL,
level_id INT auto_increment,
PRIMARY KEY(level_id),
CONSTRAINT `fk_mcaptcha_config_id`
FOREIGN KEY (config_id)
REFERENCES mcaptcha_config (config_id)
ON DELETE CASCADE
ON UPDATE CASCADE
);

View File

@@ -0,0 +1,14 @@
-- SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
--
-- SPDX-License-Identifier: AGPL-3.0-or-later
CREATE TABLE IF NOT EXISTS mcaptcha_pow_fetched_stats (
config_id INTEGER NOT NULL,
time timestamp NOT NULL DEFAULT now(),
CONSTRAINT `fk_mcaptcha_config_id_pow_fetched_stats`
FOREIGN KEY (config_id)
REFERENCES mcaptcha_config (config_id)
ON DELETE CASCADE
ON UPDATE CASCADE
);

View File

@@ -0,0 +1,13 @@
-- SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
--
-- SPDX-License-Identifier: AGPL-3.0-or-later
CREATE TABLE IF NOT EXISTS mcaptcha_pow_solved_stats (
config_id INTEGER NOT NULL,
time timestamp NOT NULL DEFAULT now(),
CONSTRAINT `fk_mcaptcha_config_id_pow_solved_stats`
FOREIGN KEY (config_id)
REFERENCES mcaptcha_config (config_id)
ON DELETE CASCADE
ON UPDATE CASCADE
);

View File

@@ -0,0 +1,14 @@
-- SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
--
-- SPDX-License-Identifier: AGPL-3.0-or-later
CREATE TABLE IF NOT EXISTS mcaptcha_pow_confirmed_stats (
config_id INTEGER NOT NULL,
time timestamp NOT NULL DEFAULT now(),
CONSTRAINT `fk_mcaptcha_config_id_pow_confirmed_stats`
FOREIGN KEY (config_id)
REFERENCES mcaptcha_config (config_id)
ON DELETE CASCADE
ON UPDATE CASCADE
);

View File

@@ -0,0 +1,23 @@
-- SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
--
-- SPDX-License-Identifier: AGPL-3.0-or-later
-- Add migration script here
CREATE TABLE IF NOT EXISTS mcaptcha_notifications (
id INT auto_increment,
PRIMARY KEY(id),
tx INT NOT NULL,
rx INT NOT NULL,
heading varchar(30) NOT NULL,
message varchar(250) NOT NULL,
-- todo: mv read -> read_notification
read_notification BOOLEAN DEFAULT null,
received timestamp NOT NULL DEFAULT now(),
CONSTRAINT `fk_mcaptcha_mcaptcha_user_notifications_tx`
FOREIGN KEY (tx)
REFERENCES mcaptcha_users (ID)
ON DELETE CASCADE
ON UPDATE CASCADE
);

View File

@@ -0,0 +1,17 @@
-- SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
--
-- SPDX-License-Identifier: AGPL-3.0-or-later
CREATE TABLE IF NOT EXISTS mcaptcha_sitekey_user_provided_avg_traffic (
config_id INT NOT NULL,
PRIMARY KEY(config_id),
avg_traffic INTEGER DEFAULT NULL,
peak_sustainable_traffic INTEGER DEFAULT NULL,
broke_my_site_traffic INT DEFAULT NULL,
CONSTRAINT `fk_mcaptcha_sitekey_user_provided_avg_trafic_config_id`
FOREIGN KEY (config_id)
REFERENCES mcaptcha_config (config_id)
ON DELETE CASCADE
ON UPDATE CASCADE
);

View File

@@ -0,0 +1,7 @@
-- SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
--
-- SPDX-License-Identifier: AGPL-3.0-or-later
ALTER TABLE mcaptcha_sitekey_user_provided_avg_traffic
MODIFY avg_traffic INTEGER NOT NULL,
MODIFY peak_sustainable_traffic INTEGER NOT NULL;

View File

@@ -0,0 +1,6 @@
-- SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
--
-- SPDX-License-Identifier: AGPL-3.0-or-later
-- Add migration script here
ALTER TABLE mcaptcha_notifications MODIFY heading varchar(100) NOT NULL;

View File

@@ -0,0 +1,13 @@
CREATE TABLE IF NOT EXISTS mcaptcha_pow_analytics (
ID INT auto_increment,
PRIMARY KEY(ID),
config_id INTEGER NOT NULL,
time INTEGER NOT NULL,
difficulty_factor INTEGER NOT NULL,
worker_type VARCHAR(100) NOT NULL,
CONSTRAINT `fk_mcaptcha_config_id_pow_analytics`
FOREIGN KEY (config_id)
REFERENCES mcaptcha_config (config_id)
ON DELETE CASCADE
ON UPDATE CASCADE
);

View File

@@ -0,0 +1,13 @@
CREATE TABLE IF NOT EXISTS mcaptcha_psuedo_campaign_id (
ID INT auto_increment,
PRIMARY KEY(ID),
psuedo_id varchar(100) NOT NULL UNIQUE,
config_id INT NOT NULL,
CONSTRAINT `fk_mcaptcha_psuedo_campaign_id_config_id`
FOREIGN KEY (config_id)
REFERENCES mcaptcha_config (config_id)
ON DELETE CASCADE
ON UPDATE CASCADE
);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,43 @@
// Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
// SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
//! Error-handling utilities
use std::borrow::Cow;
use db_core::dev::*;
use sqlx::Error;
/// map custom row not found error to DB error
pub fn map_row_not_found_err(e: Error, row_not_found: DBError) -> DBError {
if let Error::RowNotFound = e {
row_not_found
} else {
map_register_err(e)
}
}
/// map postgres errors to [DBError](DBError) types
pub fn map_register_err(e: Error) -> DBError {
if let Error::Database(err) = e {
if err.code() == Some(Cow::from("23000")) {
let msg = err.message();
if msg.contains("for key 'name'") {
DBError::UsernameTaken
} else if msg.contains("for key 'email'") {
DBError::EmailTaken
} else if msg.contains("for key 'secret'") {
DBError::SecretTaken
} else if msg.contains("for key 'captcha_key'") {
DBError::CaptchaKeyTaken
} else {
DBError::DBError(Box::new(Error::Database(err)))
}
} else {
DBError::DBError(Box::new(Error::Database(err)))
}
} else {
DBError::DBError(Box::new(e))
}
}

View File

@@ -0,0 +1,28 @@
-- SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
--
-- SPDX-License-Identifier: AGPL-3.0-or-later
-- gets all unread notifications a user has
SELECT
mcaptcha_notifications.id,
mcaptcha_notifications.heading,
mcaptcha_notifications.message,
mcaptcha_notifications.received,
mcaptcha_users.name
FROM
mcaptcha_notifications
INNER JOIN
mcaptcha_users
ON
mcaptcha_notifications.tx = mcaptcha_users.id
WHERE
mcaptcha_notifications.rx = (
SELECT
id
FROM
mcaptcha_users
WHERE
name = ?
)
AND
mcaptcha_notifications.read_notification IS NULL;

1137
db/db-sqlx-maria/src/lib.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,18 @@
-- SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
--
-- SPDX-License-Identifier: AGPL-3.0-or-later
-- mark a notification as read
UPDATE mcaptcha_notifications
SET read_notification = TRUE
WHERE
mcaptcha_notifications.id = ?
AND
mcaptcha_notifications.rx = (
SELECT
id
FROM
mcaptcha_users
WHERE
name = ?
);

View File

@@ -0,0 +1,81 @@
// Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
// SPDX-FileCopyrightText: 2023 Aravinth Manivannan <realaravinth@batsense.net>
//
// SPDX-License-Identifier: AGPL-3.0-or-later
#![cfg(test)]
use sqlx::mysql::MySqlPoolOptions;
use std::env;
use crate::*;
use db_core::tests::*;
#[actix_rt::test]
async fn everyting_works() {
const EMAIL: &str = "mariadbuser@foo.com";
const NAME: &str = "mariadbuser";
const PASSWORD: &str = "pasdfasdfasdfadf";
const SECRET1: &str = "mariadbsecret1";
// captcha config
const CAPTCHA_SECRET: &str = "mariadbcaptchasecret";
const CAPTCHA_DESCRIPTION: &str = "mariadbcaptchadescription";
const CAPTCHA_DURATION: i32 = 30;
// notification config
const HEADING: &str = "testing notifications get db mariadb";
const MESSAGE: &str = "testing notifications get message db mariadb";
// easy traffic pattern
const TRAFFIC_PATTERN: TrafficPattern = TrafficPattern {
avg_traffic: 500,
peak_sustainable_traffic: 5_000,
broke_my_site_traffic: Some(10_000),
};
const LEVELS: [Level; 3] = [
Level {
difficulty_factor: 1,
visitor_threshold: 1,
},
Level {
difficulty_factor: 2,
visitor_threshold: 2,
},
Level {
difficulty_factor: 3,
visitor_threshold: 3,
},
];
const ADD_NOTIFICATION: AddNotification = AddNotification {
from: NAME,
to: NAME,
message: MESSAGE,
heading: HEADING,
};
let url = env::var("MARIA_DATABASE_URL").unwrap();
let pool_options = MySqlPoolOptions::new().max_connections(2);
let connection_options = ConnectionOptions::Fresh(Fresh {
pool_options,
url,
disable_logging: false,
});
let db = connection_options.connect().await.unwrap();
db.migrate().await.unwrap();
let p = Register {
username: NAME,
email: Some(EMAIL),
hash: PASSWORD,
secret: SECRET1,
};
let c = CreateCaptcha {
duration: CAPTCHA_DURATION,
key: CAPTCHA_SECRET,
description: CAPTCHA_DESCRIPTION,
};
database_works(&db, &p, &c, &LEVELS, &TRAFFIC_PATTERN, &ADD_NOTIFICATION).await;
}

View File

@@ -0,0 +1,39 @@
{
"query": "SELECT name, password FROM mcaptcha_users WHERE email = ?",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "name",
"type_info": {
"type": "VarString",
"flags": {
"bits": 4101
},
"char_set": 224,
"max_size": 400
}
},
{
"ordinal": 1,
"name": "password",
"type_info": {
"type": "Blob",
"flags": {
"bits": 4113
},
"char_set": 224,
"max_size": 262140
}
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false
]
},
"hash": "ed943cbf7e16536d81010255ce2f5beb207b2b9d44cb859fa9f2233405b80ae0"
}

View File

@@ -0,0 +1,11 @@
{
"query": "INSERT INTO mcaptcha_users \n (name , password, secret) VALUES (?, ?, ?)",
"describe": {
"columns": [],
"parameters": {
"Right": 3
},
"nullable": []
},
"hash": "5d5a106981345e9f62bc2239c00cdc683d3aaaa820d63da300dc51e3f6f363d3"
}

View File

@@ -0,0 +1,11 @@
{
"query": "INSERT INTO mcaptcha_notifications (\n heading, message, tx, rx, received)\n VALUES (\n ?, ?,\n (SELECT ID FROM mcaptcha_users WHERE name = ?),\n (SELECT ID FROM mcaptcha_users WHERE name = ?),\n ?\n );",
"describe": {
"columns": [],
"parameters": {
"Right": 5
},
"nullable": []
},
"hash": "89386c46668a2653a54687e65958af5cf7a8da268339a1f5a379ede47b3c6d2a"
}

View File

@@ -0,0 +1,39 @@
{
"query": "SELECT name, password FROM mcaptcha_users WHERE name = ?",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "name",
"type_info": {
"type": "VarString",
"flags": {
"bits": 4101
},
"char_set": 224,
"max_size": 400
}
},
{
"ordinal": 1,
"name": "password",
"type_info": {
"type": "Blob",
"flags": {
"bits": 4113
},
"char_set": 224,
"max_size": 262140
}
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false
]
},
"hash": "dd5ff10b88fa6f374e105b6bed9e34e0870ac8dd7ce36dfb09d13a1b7005b2eb"
}

View File

@@ -0,0 +1,11 @@
{
"query": "UPDATE mcaptcha_config SET captcha_key = ? \n WHERE captcha_key = ? AND user_id = (SELECT ID FROM mcaptcha_users WHERE name = ?)",
"describe": {
"columns": [],
"parameters": {
"Right": 3
},
"nullable": []
},
"hash": "8e6026abf7c0e8ab90ee8eb7ada9f66962ab6999d3127944b058d6f96346e72f"
}

View File

@@ -0,0 +1,65 @@
{
"query": "SELECT captcha_key, name, config_id, duration FROM mcaptcha_config WHERE\n user_id = (SELECT ID FROM mcaptcha_users WHERE name = ?) ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "captcha_key",
"type_info": {
"type": "VarString",
"flags": {
"bits": 4101
},
"char_set": 224,
"max_size": 400
}
},
{
"ordinal": 1,
"name": "name",
"type_info": {
"type": "VarString",
"flags": {
"bits": 4097
},
"char_set": 224,
"max_size": 400
}
},
{
"ordinal": 2,
"name": "config_id",
"type_info": {
"type": "Long",
"flags": {
"bits": 515
},
"char_set": 63,
"max_size": 11
}
},
{
"ordinal": 3,
"name": "duration",
"type_info": {
"type": "Long",
"flags": {
"bits": 1
},
"char_set": 63,
"max_size": 11
}
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false,
false,
false
]
},
"hash": "3812693a9ae4402d900bcbf680981e6194073bd1937af11a77daa3776fb4c873"
}

View File

@@ -0,0 +1,11 @@
{
"query": "UPDATE mcaptcha_users set email = ?\n WHERE name = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "9cb416de904872d66af90baa0024f382ce6f8344464c607fe6e6c2572816dfc2"
}

View File

@@ -0,0 +1,11 @@
{
"query": "UPDATE mcaptcha_config SET captcha_key = ? \n WHERE captcha_key = ? AND user_id = (SELECT ID FROM mcaptcha_users WHERE name = ?)",
"describe": {
"columns": [],
"parameters": {
"Right": 3
},
"nullable": []
},
"hash": "8e6026abf7c0e8ab90ee8eb7ada9f66962ab6999d3127944b058d6f96346e72f"
}

View File

@@ -0,0 +1,11 @@
{
"query": "DELETE FROM mcaptcha_sitekey_user_provided_avg_traffic\n WHERE config_id = (\n SELECT config_id \n FROM \n mcaptcha_config \n WHERE\n captcha_key = ?\n AND \n user_id = (SELECT ID FROM mcaptcha_users WHERE name = ?)\n );",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "fc717ff0827ccfaa1cc61a71cc7f71c348ebb03d35895c54b011c03121ad2385"
}

View File

@@ -0,0 +1,11 @@
{
"query": "UPDATE mcaptcha_users set password = ?\n WHERE name = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "cad5b403470f26c565e74a1dca19b7dee066141dec0f708070067e34d5bf72cc"
}

View File

@@ -0,0 +1,26 @@
{
"query": "SELECT config_id FROM mcaptcha_config\n WHERE\n captcha_key = ? \n AND user_id = (SELECT ID FROM mcaptcha_users WHERE name = ?)",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "config_id",
"type_info": {
"type": "Long",
"flags": {
"bits": 515
},
"char_set": 63,
"max_size": 11
}
}
],
"parameters": {
"Right": 2
},
"nullable": [
false
]
},
"hash": "66ec7df10484f8e0206f3c97afc9136021589556c38dbbed341d6574487f79f2"
}

View File

@@ -0,0 +1,11 @@
{
"query": "DELETE FROM mcaptcha_levels \n WHERE config_id = (\n SELECT config_id FROM mcaptcha_config where captcha_key= (?) \n AND user_id = (\n SELECT ID from mcaptcha_users WHERE name = ?\n )\n )",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "7894dda54cd65559fe3b81bab7df8cc848e21ed5c7f5e88951bf1c98c78ed820"
}

View File

@@ -0,0 +1,26 @@
{
"query": "SELECT duration FROM mcaptcha_config \n where captcha_key= ?",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "duration",
"type_info": {
"type": "Long",
"flags": {
"bits": 1
},
"char_set": 63,
"max_size": 11
}
}
],
"parameters": {
"Right": 1
},
"nullable": [
false
]
},
"hash": "8acbf84d4801e86221d8f6324ae50488a0986182d66b20ad414bce4e2ac18eca"
}

View File

@@ -0,0 +1,11 @@
{
"query": "UPDATE mcaptcha_users set name = ?\n WHERE name = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "676a9f1761c3b63cf16d7d4dd6261507cc7707feb32d458f4b946ed9caa53721"
}

View File

@@ -0,0 +1,65 @@
{
"query": "SELECT `config_id`, `duration`, `name`, `captcha_key` from mcaptcha_config WHERE\n `captcha_key` = ? AND\n user_id = (SELECT ID FROM mcaptcha_users WHERE name = ?) ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "config_id",
"type_info": {
"type": "Long",
"flags": {
"bits": 515
},
"char_set": 63,
"max_size": 11
}
},
{
"ordinal": 1,
"name": "duration",
"type_info": {
"type": "Long",
"flags": {
"bits": 1
},
"char_set": 63,
"max_size": 11
}
},
{
"ordinal": 2,
"name": "name",
"type_info": {
"type": "VarString",
"flags": {
"bits": 4097
},
"char_set": 224,
"max_size": 400
}
},
{
"ordinal": 3,
"name": "captcha_key",
"type_info": {
"type": "VarString",
"flags": {
"bits": 4101
},
"char_set": 224,
"max_size": 400
}
}
],
"parameters": {
"Right": 2
},
"nullable": [
false,
false,
false,
false
]
},
"hash": "9c435148ed5655e79dd1e73e3566ce23b7c6d38edcedbb988c95813c5da893ed"
}

View File

@@ -0,0 +1,11 @@
{
"query": "DELETE FROM mcaptcha_config where captcha_key= (?)\n AND\n user_id = (SELECT ID FROM mcaptcha_users WHERE name = ?)",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "b95e5a60a202cb646d5e76df8c7395e4bf881a6dd14e28e6f2e8b93e0536b331"
}

View File

@@ -0,0 +1,39 @@
{
"query": "SELECT difficulty_factor, visitor_threshold FROM mcaptcha_levels WHERE\n config_id = (\n SELECT config_id FROM mcaptcha_config where captcha_key= (?)\n AND user_id = (SELECT ID from mcaptcha_users WHERE name = ?)\n )\n ORDER BY difficulty_factor ASC;",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "difficulty_factor",
"type_info": {
"type": "Long",
"flags": {
"bits": 4097
},
"char_set": 63,
"max_size": 11
}
},
{
"ordinal": 1,
"name": "visitor_threshold",
"type_info": {
"type": "Long",
"flags": {
"bits": 4097
},
"char_set": 63,
"max_size": 11
}
}
],
"parameters": {
"Right": 2
},
"nullable": [
false,
false
]
},
"hash": "df6de3b96afcfb7f364f98954995e506b19e80e7f88204405d970c360ad5e1a0"
}

View File

@@ -0,0 +1,11 @@
{
"query": "INSERT INTO mcaptcha_config\n (`captcha_key`, `user_id`, `duration`, `name`)\n VALUES (?, (SELECT ID FROM mcaptcha_users WHERE name = ?), ?, ?)",
"describe": {
"columns": [],
"parameters": {
"Right": 4
},
"nullable": []
},
"hash": "d05b84966f4e70c53789221f961bf3637f404f3ba45e880115e97ed1ba5a2809"
}

View File

@@ -0,0 +1,11 @@
{
"query": "INSERT INTO mcaptcha_levels (\n difficulty_factor, \n visitor_threshold,\n config_id) VALUES (\n ?, ?, (\n SELECT config_id FROM mcaptcha_config WHERE\n captcha_key = (?) AND user_id = (\n SELECT ID FROM mcaptcha_users WHERE name = ?\n )));",
"describe": {
"columns": [],
"parameters": {
"Right": 4
},
"nullable": []
},
"hash": "74d68a86f852d3d85957e94ed04e8acd8e6144744f7b13e383ebcb2bcf3360ae"
}

View File

@@ -0,0 +1,11 @@
{
"query": "UPDATE mcaptcha_config SET name = ?, duration = ?\n WHERE user_id = (SELECT ID FROM mcaptcha_users WHERE name = ?)\n AND captcha_key = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 4
},
"nullable": []
},
"hash": "3a8381eb0f0542a492d9dd51368e769e2b313e0576a1873e5c7630011e463daf"
}

View File

@@ -0,0 +1,26 @@
{
"query": "SELECT email FROM mcaptcha_users WHERE name = ?",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "email",
"type_info": {
"type": "VarString",
"flags": {
"bits": 4
},
"char_set": 224,
"max_size": 400
}
}
],
"parameters": {
"Right": 1
},
"nullable": [
true
]
},
"hash": "413ea53cea8b8f114fc009bad527b054a68a94477dfcc50d860d45bbd864d4f1"
}

View File

@@ -0,0 +1,11 @@
{
"query": "UPDATE mcaptcha_users set secret = ?\n WHERE name = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "7838ade4a48068e25c6f117ee8e38f088b867b1ab08a7dd0269b76891266ace6"
}

View File

@@ -0,0 +1,26 @@
{
"query": "SELECT name from mcaptcha_users WHERE email = ?",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "name",
"type_info": {
"type": "VarString",
"flags": {
"bits": 4101
},
"char_set": 224,
"max_size": 400
}
}
],
"parameters": {
"Right": 1
},
"nullable": [
false
]
},
"hash": "caa1638ee510ef62b86817e5d2baeaca8dfa432c23d7630c0e70737211a4680b"
}

View File

@@ -0,0 +1,11 @@
{
"query": "UPDATE mcaptcha_users set email = ?\n WHERE name = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "9cb416de904872d66af90baa0024f382ce6f8344464c607fe6e6c2572816dfc2"
}

View File

@@ -0,0 +1,39 @@
{
"query": "SELECT difficulty_factor, visitor_threshold FROM mcaptcha_levels WHERE\n config_id = (\n SELECT config_id FROM mcaptcha_config where captcha_key= (?)\n ) ORDER BY difficulty_factor ASC;",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "difficulty_factor",
"type_info": {
"type": "Long",
"flags": {
"bits": 4097
},
"char_set": 63,
"max_size": 11
}
},
{
"ordinal": 1,
"name": "visitor_threshold",
"type_info": {
"type": "Long",
"flags": {
"bits": 4097
},
"char_set": 63,
"max_size": 11
}
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false
]
},
"hash": "6d43e6ceb54a0ff8a803bd96dd9134b15da01d48776ac0cf3d66a2997dadce5e"
}

View File

@@ -0,0 +1,78 @@
{
"query": "-- gets all unread notifications a user has\nSELECT \n mcaptcha_notifications.id,\n mcaptcha_notifications.heading,\n mcaptcha_notifications.message,\n mcaptcha_notifications.received,\n mcaptcha_users.name\nFROM\n mcaptcha_notifications \nINNER JOIN \n mcaptcha_users \nON \n mcaptcha_notifications.tx = mcaptcha_users.id\nWHERE \n mcaptcha_notifications.rx = (\n SELECT \n id \n FROM \n mcaptcha_users\n WHERE\n name = ?\n )\nAND \n mcaptcha_notifications.read_notification IS NULL;\n",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": {
"type": "Long",
"flags": {
"bits": 515
},
"char_set": 63,
"max_size": 11
}
},
{
"ordinal": 1,
"name": "heading",
"type_info": {
"type": "VarString",
"flags": {
"bits": 4097
},
"char_set": 224,
"max_size": 400
}
},
{
"ordinal": 2,
"name": "message",
"type_info": {
"type": "VarString",
"flags": {
"bits": 4097
},
"char_set": 224,
"max_size": 1000
}
},
{
"ordinal": 3,
"name": "received",
"type_info": {
"type": "Timestamp",
"flags": {
"bits": 1185
},
"char_set": 63,
"max_size": 19
}
},
{
"ordinal": 4,
"name": "name",
"type_info": {
"type": "VarString",
"flags": {
"bits": 4101
},
"char_set": 224,
"max_size": 400
}
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false,
false,
false,
false
]
},
"hash": "b9b0c63380bc0dfdea8aae092dcefceb316fe94667d74f53d53063810cdd2ba8"
}

View File

@@ -0,0 +1,11 @@
{
"query": "INSERT INTO mcaptcha_notifications (\n heading, message, tx, rx, received)\n VALUES (\n ?, ?,\n (SELECT ID FROM mcaptcha_users WHERE name = ?),\n (SELECT ID FROM mcaptcha_users WHERE name = ?),\n ?\n );",
"describe": {
"columns": [],
"parameters": {
"Right": 5
},
"nullable": []
},
"hash": "89386c46668a2653a54687e65958af5cf7a8da268339a1f5a379ede47b3c6d2a"
}

View File

@@ -0,0 +1,11 @@
{
"query": "DELETE FROM mcaptcha_users WHERE name = (?)",
"describe": {
"columns": [],
"parameters": {
"Right": 1
},
"nullable": []
},
"hash": "6d1b6e5e58ca2ba285cab7b050bbdc43de1f3e46cf7d420bc95c124a1c7c9d1f"
}

View File

@@ -0,0 +1,11 @@
{
"query": "INSERT INTO mcaptcha_pow_confirmed_stats \n (config_id, time) VALUES ((SELECT config_id FROM mcaptcha_config where captcha_key= ?), ?)",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "34b29417f9ff3f4d5987df0ce81023b1985eb84e560602b36182f55de6cd9d83"
}

View File

@@ -0,0 +1,11 @@
{
"query": "INSERT INTO mcaptcha_pow_solved_stats \n (config_id, time) VALUES ((SELECT config_id FROM mcaptcha_config where captcha_key= ?), ?)",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "e2b0b85f2afac1cbca43ce684641bf75ef070e44ce3d00404fc6151d2f4d7bcf"
}

View File

@@ -0,0 +1,11 @@
{
"query": "-- mark a notification as read\nUPDATE mcaptcha_notifications\n SET read_notification = TRUE\nWHERE \n mcaptcha_notifications.id = ?\nAND\n mcaptcha_notifications.rx = (\n SELECT\n id\n FROM\n mcaptcha_users\n WHERE\n name = ?\n );\n",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "cf333541509213f11a9bf7119dcb3289bb77abf1482fc1d47e7f5bb27bdc8d97"
}

View File

@@ -0,0 +1,11 @@
{
"query": "INSERT INTO mcaptcha_pow_fetched_stats \n (config_id, time) VALUES ((SELECT config_id FROM mcaptcha_config where captcha_key= ?), ?)",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "598a8202942771eff460faa6f09bd3fb1fc910d5fab7edb07c49dadbbaeb1cb8"
}

View File

@@ -0,0 +1,11 @@
{
"query": "INSERT INTO mcaptcha_sitekey_user_provided_avg_traffic (\n config_id,\n avg_traffic,\n peak_sustainable_traffic,\n broke_my_site_traffic\n ) VALUES ( \n (SELECT config_id FROM mcaptcha_config where captcha_key= (?)\n AND user_id = (SELECT ID FROM mcaptcha_users WHERE name = ?)\n ), ?, ?, ?)",
"describe": {
"columns": [],
"parameters": {
"Right": 5
},
"nullable": []
},
"hash": "22e697114c3ed5b0156cdceab11a398f1ef3a804f482e1cd948bc615ef95fc92"
}

View File

@@ -0,0 +1,26 @@
{
"query": "SELECT email FROM mcaptcha_users WHERE name = ?",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "email",
"type_info": {
"type": "VarString",
"flags": {
"bits": 4
},
"char_set": 224,
"max_size": 400
}
}
],
"parameters": {
"Right": 1
},
"nullable": [
true
]
},
"hash": "413ea53cea8b8f114fc009bad527b054a68a94477dfcc50d860d45bbd864d4f1"
}

View File

@@ -0,0 +1,26 @@
{
"query": "SELECT duration FROM mcaptcha_config \n where captcha_key= ?",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "duration",
"type_info": {
"type": "Long",
"flags": {
"bits": 1
},
"char_set": 63,
"max_size": 11
}
}
],
"parameters": {
"Right": 1
},
"nullable": [
false
]
},
"hash": "8acbf84d4801e86221d8f6324ae50488a0986182d66b20ad414bce4e2ac18eca"
}

View File

@@ -0,0 +1,26 @@
{
"query": "SELECT time FROM mcaptcha_pow_fetched_stats\n WHERE \n config_id = (\n SELECT \n config_id FROM mcaptcha_config \n WHERE \n captcha_key = ?\n AND\n user_id = (\n SELECT \n ID FROM mcaptcha_users WHERE name = ?))\n ORDER BY time DESC",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "time",
"type_info": {
"type": "Timestamp",
"flags": {
"bits": 1185
},
"char_set": 63,
"max_size": 19
}
}
],
"parameters": {
"Right": 2
},
"nullable": [
false
]
},
"hash": "daac5e937aeac2f106eb89154b431fa8bd1bd7baa95e51704fdcdf50bd970a1d"
}

View File

@@ -0,0 +1,26 @@
{
"query": "SELECT secret FROM mcaptcha_users WHERE name = ?",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "secret",
"type_info": {
"type": "VarString",
"flags": {
"bits": 4101
},
"char_set": 224,
"max_size": 200
}
}
],
"parameters": {
"Right": 1
},
"nullable": [
false
]
},
"hash": "dd9b4dec39405ff19af21faabb6a7c3bb3207e7e785fe15357146b88c6c27f01"
}

View File

@@ -0,0 +1,11 @@
{
"query": "insert into mcaptcha_users \n (name , password, email, secret) values (?, ?, ?, ?)",
"describe": {
"columns": [],
"parameters": {
"Right": 4
},
"nullable": []
},
"hash": "8ec8bbde0c02a99f74d12e6778f123a973283e6d56b6861b30f559768617848a"
}

View File

@@ -0,0 +1,11 @@
{
"query": "INSERT INTO mcaptcha_pow_fetched_stats \n (config_id, time) VALUES ((SELECT config_id FROM mcaptcha_config where captcha_key= ?), ?)",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "598a8202942771eff460faa6f09bd3fb1fc910d5fab7edb07c49dadbbaeb1cb8"
}

View File

@@ -0,0 +1,11 @@
{
"query": "DELETE FROM mcaptcha_levels \n WHERE config_id = (\n SELECT config_id FROM mcaptcha_config where captcha_key= (?) \n AND user_id = (\n SELECT ID from mcaptcha_users WHERE name = ?\n )\n )",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "7894dda54cd65559fe3b81bab7df8cc848e21ed5c7f5e88951bf1c98c78ed820"
}

View File

@@ -0,0 +1,11 @@
{
"query": "UPDATE mcaptcha_users set password = ?\n WHERE name = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "cad5b403470f26c565e74a1dca19b7dee066141dec0f708070067e34d5bf72cc"
}

View File

@@ -0,0 +1,39 @@
{
"query": "SELECT difficulty_factor, visitor_threshold FROM mcaptcha_levels WHERE\n config_id = (\n SELECT config_id FROM mcaptcha_config where captcha_key= (?)\n AND user_id = (SELECT ID from mcaptcha_users WHERE name = ?)\n )\n ORDER BY difficulty_factor ASC;",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "difficulty_factor",
"type_info": {
"type": "Long",
"flags": {
"bits": 4097
},
"char_set": 63,
"max_size": 11
}
},
{
"ordinal": 1,
"name": "visitor_threshold",
"type_info": {
"type": "Long",
"flags": {
"bits": 4097
},
"char_set": 63,
"max_size": 11
}
}
],
"parameters": {
"Right": 2
},
"nullable": [
false,
false
]
},
"hash": "df6de3b96afcfb7f364f98954995e506b19e80e7f88204405d970c360ad5e1a0"
}

View File

@@ -0,0 +1,11 @@
{
"query": "UPDATE mcaptcha_users set secret = ?\n WHERE name = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
},
"hash": "7838ade4a48068e25c6f117ee8e38f088b867b1ab08a7dd0269b76891266ace6"
}

View File

@@ -0,0 +1,26 @@
{
"query": "SELECT config_id from mcaptcha_config WHERE captcha_key = ?",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "config_id",
"type_info": {
"type": "Long",
"flags": {
"bits": 515
},
"char_set": 63,
"max_size": 11
}
}
],
"parameters": {
"Right": 1
},
"nullable": [
false
]
},
"hash": "a89c066db044cddfdebee6a0fd0d80a5a26dcb7ecc00a9899f5634b72ea0a952"
}

View File

@@ -0,0 +1,26 @@
{
"query": "SELECT config_id FROM mcaptcha_config\n WHERE\n captcha_key = ? \n AND user_id = (SELECT ID FROM mcaptcha_users WHERE name = ?)",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "config_id",
"type_info": {
"type": "Long",
"flags": {
"bits": 515
},
"char_set": 63,
"max_size": 11
}
}
],
"parameters": {
"Right": 2
},
"nullable": [
false
]
},
"hash": "66ec7df10484f8e0206f3c97afc9136021589556c38dbbed341d6574487f79f2"
}

Some files were not shown because too many files have changed in this diff Show More