Compare commits

..

224 Commits

Author SHA1 Message Date
Aravinth Manivannan
6f029d2945 fix: associate challenges with usernames 2023-06-17 16:13:48 +05:30
Aravinth Manivannan
e7b01a5b06 feat: impl auth challenges interfaces for pg 2023-06-13 19:26:21 +05:30
Aravinth Manivannan
0cfffed52e feat: impl auth challenges interfaces for mariadb 2023-06-13 19:24:03 +05:30
Aravinth Manivannan
c53fe2e3ff feat: define internfaces to create,fetch and rm auth challenges 2023-06-13 19:23:23 +05:30
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
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
229 changed files with 11247 additions and 3003 deletions

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"

View File

@@ -6,6 +6,7 @@ on:
push: push:
branches: branches:
- master - master
- db-abstract
jobs: jobs:
fmt: fmt:

View File

@@ -6,6 +6,7 @@ on:
push: push:
branches: branches:
- master - master
- db-abstract
jobs: jobs:
build_and_test: build_and_test:
@@ -33,11 +34,39 @@ jobs:
--health-retries 5 --health-retries 5
ports: ports:
- 5432:5432 - 5432:5432
mcaptcha-redis: mcaptcha-redis:
image: mcaptcha/cache image: mcaptcha/cache
ports: ports:
- 6379:6379 - 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
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: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: ⚡ Cache - name: ⚡ Cache
@@ -51,13 +80,18 @@ jobs:
target target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} 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 - uses: actions/setup-node@v2
with: with:
node-version: "16.x" node-version: "16.x"
- name: start smtp server
run: docker run -d -p 1080:1080 -p 10025:1025 maildev/maildev --incoming-user admin --incoming-pass password
- name: Install ${{ matrix.version }} - name: Install ${{ matrix.version }}
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
@@ -74,18 +108,21 @@ jobs:
- name: Run migrations - name: Run migrations
run: make migrate run: make migrate
env: 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 - name: build frontend
run: make frontend run: make frontend
- name: Generate coverage file - name: Generate coverage file
if: (github.ref == 'refs/heads/master' || github.event_name == 'pull_request') if: github.event_name == 'pull_request'
#if: (github.ref == 'refs/heads/master' || github.event_name == 'pull_request')
uses: actions-rs/tarpaulin@v0.1 uses: actions-rs/tarpaulin@v0.1
with: with:
args: "-t 1200" args: "-t 1200"
env: env:
DATABASE_URL: postgres://postgres:password@localhost:5432/postgres 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 # GIT_HASH is dummy value. I guess build.rs is skipped in tarpaulin
# execution so this value is required for preventing meta tests from # execution so this value is required for preventing meta tests from
# panicking # panicking
@@ -94,5 +131,5 @@ jobs:
COMPILED_DATE: "2021-07-21" COMPILED_DATE: "2021-07-21"
- name: Upload to Codecov - name: Upload to Codecov
if: (github.ref == 'refs/heads/master' || github.event_name == 'pull_request') if: github.event_name == 'pull_request'
uses: codecov/codecov-action@v2 uses: codecov/codecov-action@v2

View File

@@ -8,6 +8,8 @@ on:
push: push:
branches: branches:
- master - master
- "*"
- '!gh-pages'
jobs: jobs:
build_and_test: build_and_test:
@@ -36,10 +38,35 @@ jobs:
--health-retries 5 --health-retries 5
ports: ports:
- 5432:5432 - 5432:5432
mcaptcha-redis: mcaptcha-redis:
image: mcaptcha/cache image: mcaptcha/cache
ports: ports:
- 6379:6379 - 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
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: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@@ -54,12 +81,21 @@ jobs:
target target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- 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 - uses: actions/setup-node@v2
with: with:
node-version: '16.x' node-version: "16.x"
- name: start smtp server
run: docker run -d -p 1080:1080 -p 10025:1025 maildev/maildev --incoming-user admin --incoming-pass password
- name: Install ${{ matrix.version }} - name: Install ${{ matrix.version }}
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
@@ -68,15 +104,20 @@ jobs:
profile: minimal profile: minimal
override: true override: true
- name: install nightwatch dep
run: sudo apt-get install xvfb
- name: Run migrations - name: Run migrations
run: make migrate run: make migrate
env: 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 - name: build
run: make run: make
env: 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 # - name: build frontend
# run: make frontend # run: make frontend
@@ -87,13 +128,36 @@ jobs:
- name: run tests - name: run tests
run: make test run: make test
env: 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: Login to DockerHub
if: (github.ref == 'refs/heads/master' || github.event_name == 'push') && github.repository == 'mCaptcha/mCaptcha'
uses: docker/login-action@v1
with:
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:
DUMBSERVE_PASSWORD: ${{ secrets.DUMBSERVE_PASSWORD }}
GPG_PASSWORD: ${{ secrets.GPG_PASSWORD }}
- name: generate documentation - name: generate documentation
if: matrix.version == 'stable' && (github.repository == 'mCaptcha/mCaptcha') if: matrix.version == 'stable' && (github.repository == 'mCaptcha/mCaptcha')
run: make doc run: make doc
env: env:
DATABASE_URL: postgres://postgres:password@localhost:5432/postgres POSTGRES_DATABASE_URL: "${{ env.POSTGRES_DATABASE_URL }}"
MARIA_DATABASE_URL: "${{ env.MARIA_DATABASE_URL }}"
GIT_HASH: 8e77345f1597e40c2e266cb4e6dee74888918a61 # dummy value GIT_HASH: 8e77345f1597e40c2e266cb4e6dee74888918a61 # dummy value
COMPILED_DATE: "2021-07-21" COMPILED_DATE: "2021-07-21"

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 }}

View File

@@ -2,4 +2,18 @@
### Changed ### Changed
- Rename pow section in settings to captcha and add options to configure([`42544ec42`](https://github.com/mCaptcha/mCaptcha/commit/42544ec421e0c3ec4a8d132e6101ab4069bf0065)) - ([`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

862
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -13,14 +13,15 @@ build = "build.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # 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]] [[bin]]
name = "mcaptcha" name = "mcaptcha"
path = "./src/main.rs" path = "./src/main.rs"
[[bin]]
name = "tests-migrate"
path = "./src/tests-migrate.rs"
[dependencies] [dependencies]
actix-web = "4.0.1" actix-web = "4.0.1"
actix = "0.13" actix = "0.13"
@@ -29,7 +30,7 @@ actix-http = "3.0.4"
actix-rt = "2" actix-rt = "2"
actix-cors = "0.6.1" actix-cors = "0.6.1"
actix-service = "2.0.0" actix-service = "2.0.0"
#my-codegen = {version="0.5.0-beta.5", package = "actix-web-codegen", git ="https://github.com/realaravinth/actix-web"} async-trait = "0.1.51"
mime_guess = "2.0.3" mime_guess = "2.0.3"
rust-embed = "6.4.0" rust-embed = "6.4.0"
cache-buster = { git = "https://github.com/realaravinth/cache-buster" } cache-buster = { git = "https://github.com/realaravinth/cache-buster" }
@@ -37,7 +38,7 @@ cache-buster = { git = "https://github.com/realaravinth/cache-buster" }
futures = "0.3.15" futures = "0.3.15"
tokio = { version = "1.14", features = ["sync"]} tokio = { version = "1.14", features = ["sync"]}
sqlx = { version = "0.5.13", features = [ "runtime-actix-rustls", "postgres", "time", "offline" ] } 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 = { branch = "master", git = "https://github.com/realaravinth/argon2-creds"}
#argon2-creds = { version="*", path = "../../argon2-creds/" } #argon2-creds = { version="*", path = "../../argon2-creds/" }
config = "0.11" config = "0.11"
@@ -58,6 +59,7 @@ log = "0.4"
lazy_static = "1.4" lazy_static = "1.4"
#libmcaptcha = { version = "0.2.2", git = "https://github.com/mCaptcha/libmcaptcha", features = ["full"], tag ="0.2.2" }
libmcaptcha = { branch = "master", git = "https://github.com/mCaptcha/libmcaptcha", features = ["full"] } libmcaptcha = { branch = "master", git = "https://github.com/mCaptcha/libmcaptcha", features = ["full"] }
#libmcaptcha = { path = "../libmcaptcha", features = ["full"]} #libmcaptcha = { path = "../libmcaptcha", features = ["full"]}
@@ -67,6 +69,8 @@ sailfish = "0.4.0"
mime = "0.3.16" mime = "0.3.16"
num_cpus = "1.13.1"
lettre = { version = "0.10.0-rc.3", features = [ lettre = { version = "0.10.0-rc.3", features = [
"builder", "builder",
"tokio1", "tokio1",
@@ -74,7 +78,17 @@ lettre = { version = "0.10.0-rc.3", features = [
"smtp-transport" "smtp-transport"
]} ]}
openssl = { version = "0.10.29", features = ["vendored"] } openssl = { version = "0.10.48", features = ["vendored"] }
[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] [dependencies.my-codegen]
git = "https://github.com/realaravinth/actix-web" git = "https://github.com/realaravinth/actix-web"
@@ -87,12 +101,10 @@ features = ["actix_identity_backend"]
[build-dependencies] [build-dependencies]
serde_json = "1" serde_json = "1"
cache-buster = { version = "0.2.0", git = "https://github.com/realaravinth/cache-buster" } sqlx = { version = "0.5.13", features = [ "runtime-actix-rustls", "postgres", "time", "offline", "mysql" ] }
mime = "0.3.16"
sqlx = { version = "0.5.13", features = [ "runtime-actix-rustls", "postgres", "time", "offline" ] }
[dev-dependencies] [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" awc = "3.0.0"

View File

@@ -17,23 +17,33 @@ COPY Makefile /src/
COPY scripts /src/scripts COPY scripts /src/scripts
RUN make frontend 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 FROM rust:latest as rust
WORKDIR /src WORKDIR /src
RUN mkdir src && echo "fn main() {}" > src/main.rs COPY . .
COPY Cargo.toml . COPY --from=cacher /src/target target
RUN sed -i '/.*build.rs.*/d' Cargo.toml #COPY --from=cacher /src/db/db-core/target /src/db/db-core/target
COPY Cargo.lock . #COPY --from=cacher /src/db/db-sqlx-postgres/target /src/db/db-sqlx-postgres/target
COPY migrations /src/migrations #COPY --from=cacher /src/db/db-migrations/target /src/db/db-migrations/target
COPY sqlx-data.json /src/ #COPY --from=cacher /src/utils/cache-bust/target /src/utils/cache-bust/target
COPY src/tests-migrate.rs /src/src/tests-migrate.rs
COPY src/settings.rs /src/src/settings.rs
RUN cargo --version
RUN cargo build --release
COPY . /src
COPY --from=frontend /src/static/cache/bundle/ /src/static/cache/bundle/ COPY --from=frontend /src/static/cache/bundle/ /src/static/cache/bundle/
RUN cargo build --release 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 FROM debian:bullseye as mCaptcha
LABEL org.opencontainers.image.source https://github.com/mCaptcha/mCaptcha LABEL org.opencontainers.image.source https://github.com/mCaptcha/mCaptcha
RUN useradd -ms /bin/bash -u 1001 mcaptcha RUN useradd -ms /bin/bash -u 1001 mcaptcha
WORKDIR /home/mcaptcha WORKDIR /home/mcaptcha

View File

@@ -7,15 +7,36 @@ define frontend_env ## install frontend deps
cd docs/openapi && yarn install cd docs/openapi && yarn install
endef endef
define cache_bust ## run cache_busting program
cd utils/cache-bust && cargo run
endef
default: frontend ## Build app in debug mode default: frontend ## Build app in debug mode
$(call cache_bust)
cargo build cargo build
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
cache-bust: ## Run cache buster on static assets
$(call cache_bust)
clean: ## Delete build artifacts clean: ## Delete build artifacts
@cargo clean @cargo clean
@yarn cache clean @yarn cache clean
@-rm $(CLEAN_UP) @-rm $(CLEAN_UP)
coverage: migrate ## Generate code coverage report in HTML format coverage: migrate ## Generate code coverage report in HTML format
$(call cache_bust)
cargo tarpaulin -t 1200 --out Html cargo tarpaulin -t 1200 --out Html
doc: ## Generate documentation doc: ## Generate documentation
@@ -66,19 +87,47 @@ lint: ## Lint codebase
cd $(OPENAPI)&& yarn test cd $(OPENAPI)&& yarn test
migrate: ## Run database migrations migrate: ## Run database migrations
cargo run --bin tests-migrate cd db/db-migrations/ && cargo run
release: frontend ## Build app with release optimizations release: frontend ## Build app with release optimizations
$(call cache_bust)
cargo build --release cargo build --release
run: frontend ## Run app in debug mode run: frontend ## Run app in debug mode
$(call cache_bust)
cargo run cargo run
sqlx-offline-data: ## 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
# cd db/db-sqlx-sqlite/ \
# && DATABASE_URL=${SQLITE_DATABASE_URL} cargo sqlx prepare
test-db: ## run tests on database
cd db/db-sqlx-postgres &&\
DATABASE_URL=${POSTGRES_DATABASE_URL}\
cargo test --no-fail-fast
test: frontend-test frontend ## Run all available tests test: frontend-test frontend ## Run all available tests
./scripts/tests.sh $(call cache_bust)
# cargo test --all-features --no-fail-fast cd db/db-sqlx-postgres &&\
DATABASE_URL=${POSTGRES_DATABASE_URL}\
cargo test --no-fail-fast
cd db/db-sqlx-maria &&\
DATABASE_URL=${MARIA_DATABASE_URL}\
cargo test --no-fail-fast
cargo test --no-fail-fast
# ./scripts/tests.sh
test.integration: ## run integration tests with nightwatch.js
./scripts/integration.sh
xml-test-coverage: migrate ## Generate code coverage report in XML format xml-test-coverage: migrate ## Generate code coverage report in XML format
$(call cache_bust)
cargo tarpaulin -t 1200 --out Xml cargo tarpaulin -t 1200 --out Xml
help: ## Prints help for targets with comments help: ## Prints help for targets with comments

View File

@@ -32,18 +32,18 @@ yourself!](https://demo.mcaptcha.org/widget/?sitekey=pHy0AktWyOKuxZDzFfoaewncWec
## How does it work? ## How does it work?
mCaptcha uses SHA256 based proof-of-work(PoW) to rate limit users. mCaptcha uses SHA256 based proof-of-work (PoW) to rate limit users.
When a user wants to do something on an mCaptcha-protected website, When a user wants to do something on a mCaptcha-protected website,
1. they will have to generate proof-of-work(a bunch of math that will takes 1. they will have to generate proof-of-work (a bunch of math that will takes
time to compute) and submit it to mCaptcha. time to compute) and submit it to mCaptcha.
2. We'll validate the proof: 2. We'll validate the proof:
- **if validation is unsuccessful**, they will be prevented from - **if validation is unsuccessful**, they will be prevented from
accessing their target website accessing their target website
- **if validation is successful**, read on, - **if validation is successful**, read on,
3. They will be issued a token that they should submit along 3. They will be issued a token that they should submit along
with their request/form submission to the target website. with their request/form submission to the target website.
@@ -54,8 +54,8 @@ When a user wants to do something on an mCaptcha-protected website,
The whole process is automated from the user's POV. All they have to do The whole process is automated from the user's POV. All they have to do
is click on a button to initiate the process. is click on a button to initiate the process.
mCaptcha makes interacting with websites (computationally)expensive for mCaptcha makes interacting with websites (computationally) expensive for
the user. A well-behaving user will experience a slight delay(no delay 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 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 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 more work to send requests than your server will have to do to respond
@@ -63,14 +63,14 @@ to their request.
## Why use mCaptcha? ## Why use mCaptcha?
- [x] **Free software, privacy focused** - [x] **Free software, privacy focused**
- [x] **Seamless UX** - No more annoying CAPTCHAs! - [x] **Seamless UX** - No more annoying CAPTCHAs!
- [x] **No tracking:** Our CAPTCHA routes are cookie free! - [x] **No tracking:** Our CAPTCHA routes are cookie free!
- [x] **IP address independent:** your users are behind a NAT? We got you covered! - [x] **IP address independent:** your users are behind a NAT? We got you covered!
- [x] **Resistant to replay attacks:** proof-of-work configurations have - [x] **Resistant to replay attacks:** proof-of-work configurations have
short lifetimes(30s) and can be used only once. If a user submits a 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 PoW to an already used configuration or an expired one, their proof
will be rejected. will be rejected.
## Demo ## Demo
@@ -87,15 +87,15 @@ monitor console and network activity.
### Demo servers are available at: ### Demo servers are available at:
- https://demo.mcaptcha.org/ - https://demo.mcaptcha.org/
- https://demo2.mcaptcha.org/ (runs on a Raspberry Pi!) - https://demo2.mcaptcha.org/ (runs on a Raspberry Pi!)
> Core functionality is working but it's still very much > Core functionality is working but it's still very much
> work-in-progress. Since we don't have a stable release yet, hosted > 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 > demo servers might be a few versions behind `master`. Please check footer for
> build commit. > build commit.
Feel free to provide bogus information while signing up(project under Feel free to provide bogus information while signing up (project under
development, database frequently wiped). development, database frequently wiped).
### Self-hosted: ### Self-hosted:
@@ -103,12 +103,18 @@ development, database frequently wiped).
Clone the repo and run the following from the root of the repo: Clone the repo and run the following from the root of the repo:
```bash ```bash
$ docker-compose -d up git clone https://github.com/mCaptcha/mCaptcha.git
docker-compose up -d
``` ```
After the containers are up, visit [http://localhost:7000](http://localhost:7000) and login with the default credentials:
- username: aaronsw
- password: password
It takes a while to build the image so please be patient :) It takes a while to build the image so please be patient :)
See [DEPLOYMENT.md](./docs/DEPLOYMET.md) detailed alternate deployment See [DEPLOYMENT.md](./docs/DEPLOYMENT.md) detailed alternate deployment
methods. methods.
## Development: ## Development:
@@ -117,8 +123,26 @@ See [HACKING.md](./docs/HACKING.md)
## Deployment: ## Deployment:
See [DEPLOYMENT.md](./docs/DEPLOYMET.md) See [DEPLOYMENT.md](./docs/DEPLOYMENT.md)
## Configuration: ## Configuration:
See [CONFIGURATION.md](./docs/CONFIGURATION.md) See [CONFIGURATION.md](./docs/CONFIGURATION.md)
## Funding
### NLnet
<div align="center">
<img
height="150px"
alt="NLnet NGIZero logo"
src="./docs/third-party/NGIZero-green.hex.svg"
/>
</div>
<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

@@ -16,7 +16,6 @@
*/ */
use std::process::Command; use std::process::Command;
use cache_buster::{BusterBuilder, NoHashCategory};
use sqlx::types::time::OffsetDateTime; use sqlx::types::time::OffsetDateTime;
fn main() { fn main() {
@@ -30,32 +29,4 @@ fn main() {
let now = OffsetDateTime::now_utc().format("%y-%m-%d"); let now = OffsetDateTime::now_utc().format("%y-%m-%d");
println!("cargo:rustc-env=COMPILED_DATE={}", &now); println!("cargo:rustc-env=COMPILED_DATE={}", &now);
cache_bust();
}
fn cache_bust() {
// until APPLICATION_WASM gets added to mime crate
// PR: https://github.com/hyperium/mime/pull/138
// let types = vec![
// mime::IMAGE_PNG,
// mime::IMAGE_SVG,
// mime::IMAGE_JPEG,
// mime::IMAGE_GIF,
// mime::APPLICATION_JAVASCRIPT,
// mime::TEXT_CSS,
// ];
println!("cargo:rerun-if-changed=static/cache");
let no_hash = vec![NoHashCategory::FileExtentions(vec!["wasm"])];
let config = BusterBuilder::default()
.source("./static/cache/")
.result("./assets")
.no_hash(no_hash)
.follow_links(true)
.build()
.unwrap();
config.process().unwrap();
} }

View File

@@ -11,7 +11,7 @@ cookie_secret = "Zae0OOxf^bOJ#zN^&k7VozgW&QAx%n02TQFXpRMG4cCU0xMzgu3dna@tQ9dvc&T
# The port at which you want authentication to listen to # 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 # takes a number, choose from 1000-10000 if you dont know what you are doing
port = 7000 port = 7000
#IP address. Enter 0.0.0.0 to listen on all availale addresses #IP address. Enter 0.0.0.0 to listen on all available addresses
ip= "0.0.0.0" ip= "0.0.0.0"
# enter your hostname, eg: example.com # enter your hostname, eg: example.com
domain = "localhost" domain = "localhost"
@@ -28,6 +28,9 @@ salt = "asdl;kjfhjawehfpa;osdkjasdvjaksndfpoanjdfainsdfaijdsfajlkjdsaf;ajsdfwero
# garbage collection period to manage mCaptcha system # garbage collection period to manage mCaptcha system
# leave untouched if you don't know what you are doing # leave untouched if you don't know what you are doing
gc = 30 gc = 30
runners = 4
queue_length = 2000
enable_stats = true
[captcha.default_difficulty_strategy] [captcha.default_difficulty_strategy]
avg_traffic_difficulty = 50000 # almost instant solution avg_traffic_difficulty = 50000 # almost instant solution
@@ -49,6 +52,7 @@ username = "postgres"
password = "password" password = "password"
name = "postgres" name = "postgres"
pool = 4 pool = 4
database_type="postgres" # "postgres", "maria"
[redis] [redis]
# This section deals with the database location and how to access it # This section deals with the database location and how to access it

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

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

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

@@ -0,0 +1,25 @@
[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.2", git = "https://github.com/mCaptcha/libmcaptcha", features = ["minimal"], default-features = false, tag = "0.2.2"}
libmcaptcha = { branch = "master", git = "https://github.com/mCaptcha/libmcaptcha", features = ["full"] }
uuid = { version = "1.3.3", features = ["v4", "serde"] }
[features]
default = []
test = []
[dev-dependencies]
serde_json = "1"

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

@@ -0,0 +1,61 @@
/*
* Copyright (C) 2022 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/>.
*/
//! 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>;

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

@@ -0,0 +1,438 @@
/*
* Copyright (C) 2022 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/>.
*/
#![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 std::str::FromStr;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
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,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
/// Email challenge reason
pub enum ChallengeReason {
/// challenge created to verify a newly registered user
EmailVerification,
/// Challenge created to verify a password reset request
PasswordReset,
}
impl ChallengeReason {
pub fn to_str(&self) -> &'static str {
match self {
Self::EmailVerification => "email_verification",
Self::PasswordReset => "password_resset",
}
}
}
impl ToString for ChallengeReason {
fn to_string(&self) -> String {
self.to_str().into()
}
}
impl FromStr for ChallengeReason {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
for reason in [Self::PasswordReset, Self::EmailVerification].iter() {
if s == reason.to_str() {
return Ok(reason.clone());
}
}
Err(())
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
/// Minimal user representation for use in challenge verification
pub struct ChallengeUser {
/// username of the user
pub username: String,
/// email ID of the user
pub email: String,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
/// Email challenge
pub struct Challenge {
/// challenge unique identifier
pub challenge: Uuid,
/// reason why the challenge was create
pub reason: ChallengeReason,
}
impl Challenge {
/// create new Challenge instance for a given reason. Challenge text is auto-generated
pub fn new(reason: ChallengeReason) -> Self {
let challenge = Uuid::new_v4();
Self { challenge, reason }
}
/// Generate new ID (useful when ID clashes)
pub fn new_id(&mut self) {
self.challenge = Uuid::new_v4();
}
}
#[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 challenge in database
async fn new_challenge(&self, user: &str, challenge: &mut Challenge)
-> DBResult<()>;
/// Record challenge in database
async fn fetch_challenge_user(
&self,
challenge: &Challenge,
) -> DBResult<ChallengeUser>;
/// Delete a challenge from database
async fn delete_challenge(&self, challenge: &Challenge) -> DBResult<()>;
}
#[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()
}
}

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

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2022 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/>.
*/
//! 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<()>;
}

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

@@ -0,0 +1,307 @@
/*
* Copyright (C) 2022 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/>.
*/
//! 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();
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());
let mut challenge = Challenge::new(ChallengeReason::PasswordReset);
db.new_challenge(p.username, &mut challenge).await.unwrap();
db.new_challenge(p.username, &mut challenge).await.unwrap();
let c = db.fetch_challenge_user(&challenge).await.unwrap();
assert_eq!(c.username, p.username);
assert_eq!(&c.email, p.email.as_ref().unwrap());
db.delete_challenge(&challenge).await.unwrap();
assert!(db.fetch_challenge_user(&challenge).await.is_err())
}

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,56 @@
/*
* Copyright (C) 2022 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/>.
*/
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,21 @@
[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" ] }
[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,9 @@
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,16 @@
-- 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,12 @@
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,10 @@
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,9 @@
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,10 @@
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,19 @@
-- 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,13 @@
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,3 @@
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,2 @@
-- Add migration script here
ALTER TABLE mcaptcha_notifications MODIFY heading varchar(100) NOT NULL;

View File

@@ -0,0 +1,27 @@
CREATE TABLE IF NOT EXISTS mcaptcha_challenge_reason (
id INT auto_increment,
PRIMARY KEY(id),
name VARCHAR(40) NOT NULL UNIQUE
);
CREATE TABLE IF NOT EXISTS mcaptcha_challenge (
id INT auto_increment,
PRIMARY KEY(id),
reason INT NOT NULL,
challenge_id varchar(40) NOT NULL UNIQUE,
received timestamp NOT NULL DEFAULT now(),
user_id INT NOT NULL,
CONSTRAINT `fk_mcaptcha_challenge_user`
FOREIGN KEY (user_id)
REFERENCES mcaptcha_users (ID)
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT `fk_mcaptcha_mcaptcha_challenge_reason`
FOREIGN KEY (reason)
REFERENCES mcaptcha_challenge_reason (id)
ON DELETE CASCADE
ON UPDATE CASCADE
);

View File

@@ -0,0 +1,954 @@
{
"db": "MySQL",
"04e79a67bc8c1b18eca95fc4d2602ed5dd41b6d864796f034540efec3da05fa8": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 1
}
},
"query": "INSERT IGNORE INTO\n mcaptcha_challenge_reason (name)\n VALUES (?)"
},
"12a7d765fb683c8134d032563f2d101e2fd70c261e71696e7a90387507e0ef43": {
"describe": {
"columns": [
{
"name": "name",
"ordinal": 0,
"type_info": {
"char_set": 224,
"flags": {
"bits": 4101
},
"max_size": 400,
"type": "VarString"
}
},
{
"name": "email",
"ordinal": 1,
"type_info": {
"char_set": 224,
"flags": {
"bits": 4
},
"max_size": 400,
"type": "VarString"
}
}
],
"nullable": [
false,
true
],
"parameters": {
"Right": 2
}
},
"query": "SELECT name, email\n FROM mcaptcha_users\n WHERE ID = (SELECT user_id \n FROM mcaptcha_challenge\n WHERE\n challenge_id = ?\n AND reason = (\n SELECT id FROM mcaptcha_challenge_reason WHERE name = ?\n )\n );"
},
"1367dceb151a766a901b5dd771d0b75d0bc61d2fef17a94a90c8ffa0065e2c44": {
"describe": {
"columns": [
{
"name": "time",
"ordinal": 0,
"type_info": {
"char_set": 63,
"flags": {
"bits": 1185
},
"max_size": 19,
"type": "Timestamp"
}
}
],
"nullable": [
false
],
"parameters": {
"Right": 2
}
},
"query": "SELECT time FROM mcaptcha_pow_confirmed_stats \n WHERE \n config_id = (\n SELECT 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"
},
"22e697114c3ed5b0156cdceab11a398f1ef3a804f482e1cd948bc615ef95fc92": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 5
}
},
"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 ), ?, ?, ?)"
},
"34b29417f9ff3f4d5987df0ce81023b1985eb84e560602b36182f55de6cd9d83": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 2
}
},
"query": "INSERT INTO mcaptcha_pow_confirmed_stats \n (config_id, time) VALUES ((SELECT config_id FROM mcaptcha_config where captcha_key= ?), ?)"
},
"3812693a9ae4402d900bcbf680981e6194073bd1937af11a77daa3776fb4c873": {
"describe": {
"columns": [
{
"name": "captcha_key",
"ordinal": 0,
"type_info": {
"char_set": 224,
"flags": {
"bits": 4101
},
"max_size": 400,
"type": "VarString"
}
},
{
"name": "name",
"ordinal": 1,
"type_info": {
"char_set": 224,
"flags": {
"bits": 4097
},
"max_size": 400,
"type": "VarString"
}
},
{
"name": "config_id",
"ordinal": 2,
"type_info": {
"char_set": 63,
"flags": {
"bits": 515
},
"max_size": 11,
"type": "Long"
}
},
{
"name": "duration",
"ordinal": 3,
"type_info": {
"char_set": 63,
"flags": {
"bits": 1
},
"max_size": 11,
"type": "Long"
}
}
],
"nullable": [
false,
false,
false,
false
],
"parameters": {
"Right": 1
}
},
"query": "SELECT captcha_key, name, config_id, duration FROM mcaptcha_config WHERE\n user_id = (SELECT ID FROM mcaptcha_users WHERE name = ?) "
},
"3a8381eb0f0542a492d9dd51368e769e2b313e0576a1873e5c7630011e463daf": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 4
}
},
"query": "UPDATE mcaptcha_config SET name = ?, duration = ?\n WHERE user_id = (SELECT ID FROM mcaptcha_users WHERE name = ?)\n AND captcha_key = ?"
},
"413ea53cea8b8f114fc009bad527b054a68a94477dfcc50d860d45bbd864d4f1": {
"describe": {
"columns": [
{
"name": "email",
"ordinal": 0,
"type_info": {
"char_set": 224,
"flags": {
"bits": 4
},
"max_size": 400,
"type": "VarString"
}
}
],
"nullable": [
true
],
"parameters": {
"Right": 1
}
},
"query": "SELECT email FROM mcaptcha_users WHERE name = ?"
},
"598a8202942771eff460faa6f09bd3fb1fc910d5fab7edb07c49dadbbaeb1cb8": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 2
}
},
"query": "INSERT INTO mcaptcha_pow_fetched_stats \n (config_id, time) VALUES ((SELECT config_id FROM mcaptcha_config where captcha_key= ?), ?)"
},
"5d5a106981345e9f62bc2239c00cdc683d3aaaa820d63da300dc51e3f6f363d3": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 3
}
},
"query": "INSERT INTO mcaptcha_users \n (name , password, secret) VALUES (?, ?, ?)"
},
"66ec7df10484f8e0206f3c97afc9136021589556c38dbbed341d6574487f79f2": {
"describe": {
"columns": [
{
"name": "config_id",
"ordinal": 0,
"type_info": {
"char_set": 63,
"flags": {
"bits": 515
},
"max_size": 11,
"type": "Long"
}
}
],
"nullable": [
false
],
"parameters": {
"Right": 2
}
},
"query": "SELECT config_id FROM mcaptcha_config\n WHERE\n captcha_key = ? \n AND user_id = (SELECT ID FROM mcaptcha_users WHERE name = ?)"
},
"676a9f1761c3b63cf16d7d4dd6261507cc7707feb32d458f4b946ed9caa53721": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 2
}
},
"query": "UPDATE mcaptcha_users set name = ?\n WHERE name = ?"
},
"6d1b6e5e58ca2ba285cab7b050bbdc43de1f3e46cf7d420bc95c124a1c7c9d1f": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 1
}
},
"query": "DELETE FROM mcaptcha_users WHERE name = (?)"
},
"6d43e6ceb54a0ff8a803bd96dd9134b15da01d48776ac0cf3d66a2997dadce5e": {
"describe": {
"columns": [
{
"name": "difficulty_factor",
"ordinal": 0,
"type_info": {
"char_set": 63,
"flags": {
"bits": 4097
},
"max_size": 11,
"type": "Long"
}
},
{
"name": "visitor_threshold",
"ordinal": 1,
"type_info": {
"char_set": 63,
"flags": {
"bits": 4097
},
"max_size": 11,
"type": "Long"
}
}
],
"nullable": [
false,
false
],
"parameters": {
"Right": 1
}
},
"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;"
},
"740ed2dab8c07c718c1b0e8e4262251bbf2501cdebfc4872fb903f70ec3d0dc8": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 4
}
},
"query": "INSERT INTO mcaptcha_challenge (challenge_id, received, reason, user_id)\n VALUES (?, ?,\n (SELECT id FROM mcaptcha_challenge_reason WHERE name = ?),\n (SELECT id FROM mcaptcha_users WHERE name = ?)\n );\n "
},
"74d68a86f852d3d85957e94ed04e8acd8e6144744f7b13e383ebcb2bcf3360ae": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 4
}
},
"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 )));"
},
"7838ade4a48068e25c6f117ee8e38f088b867b1ab08a7dd0269b76891266ace6": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 2
}
},
"query": "UPDATE mcaptcha_users set secret = ?\n WHERE name = ?"
},
"7894dda54cd65559fe3b81bab7df8cc848e21ed5c7f5e88951bf1c98c78ed820": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 2
}
},
"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 )"
},
"89386c46668a2653a54687e65958af5cf7a8da268339a1f5a379ede47b3c6d2a": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 5
}
},
"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 );"
},
"8acbf84d4801e86221d8f6324ae50488a0986182d66b20ad414bce4e2ac18eca": {
"describe": {
"columns": [
{
"name": "duration",
"ordinal": 0,
"type_info": {
"char_set": 63,
"flags": {
"bits": 1
},
"max_size": 11,
"type": "Long"
}
}
],
"nullable": [
false
],
"parameters": {
"Right": 1
}
},
"query": "SELECT duration FROM mcaptcha_config \n where captcha_key= ?"
},
"8e6026abf7c0e8ab90ee8eb7ada9f66962ab6999d3127944b058d6f96346e72f": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 3
}
},
"query": "UPDATE mcaptcha_config SET captcha_key = ? \n WHERE captcha_key = ? AND user_id = (SELECT ID FROM mcaptcha_users WHERE name = ?)"
},
"8ec8bbde0c02a99f74d12e6778f123a973283e6d56b6861b30f559768617848a": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 4
}
},
"query": "insert into mcaptcha_users \n (name , password, email, secret) values (?, ?, ?, ?)"
},
"9c435148ed5655e79dd1e73e3566ce23b7c6d38edcedbb988c95813c5da893ed": {
"describe": {
"columns": [
{
"name": "config_id",
"ordinal": 0,
"type_info": {
"char_set": 63,
"flags": {
"bits": 515
},
"max_size": 11,
"type": "Long"
}
},
{
"name": "duration",
"ordinal": 1,
"type_info": {
"char_set": 63,
"flags": {
"bits": 1
},
"max_size": 11,
"type": "Long"
}
},
{
"name": "name",
"ordinal": 2,
"type_info": {
"char_set": 224,
"flags": {
"bits": 4097
},
"max_size": 400,
"type": "VarString"
}
},
{
"name": "captcha_key",
"ordinal": 3,
"type_info": {
"char_set": 224,
"flags": {
"bits": 4101
},
"max_size": 400,
"type": "VarString"
}
}
],
"nullable": [
false,
false,
false,
false
],
"parameters": {
"Right": 2
}
},
"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 = ?) "
},
"9cb416de904872d66af90baa0024f382ce6f8344464c607fe6e6c2572816dfc2": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 2
}
},
"query": "UPDATE mcaptcha_users set email = ?\n WHERE name = ?"
},
"a89c066db044cddfdebee6a0fd0d80a5a26dcb7ecc00a9899f5634b72ea0a952": {
"describe": {
"columns": [
{
"name": "config_id",
"ordinal": 0,
"type_info": {
"char_set": 63,
"flags": {
"bits": 515
},
"max_size": 11,
"type": "Long"
}
}
],
"nullable": [
false
],
"parameters": {
"Right": 1
}
},
"query": "SELECT config_id from mcaptcha_config WHERE captcha_key = ?"
},
"b9258c2494d95701d19703cf5cd05a222057a0ccad943192138b1a4a94bf823b": {
"describe": {
"columns": [
{
"name": "secret",
"ordinal": 0,
"type_info": {
"char_set": 224,
"flags": {
"bits": 4101
},
"max_size": 200,
"type": "VarString"
}
}
],
"nullable": [
false
],
"parameters": {
"Right": 1
}
},
"query": "SELECT secret FROM mcaptcha_users WHERE ID = (\n SELECT user_id FROM mcaptcha_config WHERE captcha_key = ?\n )"
},
"b95e5a60a202cb646d5e76df8c7395e4bf881a6dd14e28e6f2e8b93e0536b331": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 2
}
},
"query": "DELETE FROM mcaptcha_config where captcha_key= (?)\n AND\n user_id = (SELECT ID FROM mcaptcha_users WHERE name = ?)"
},
"b9b0c63380bc0dfdea8aae092dcefceb316fe94667d74f53d53063810cdd2ba8": {
"describe": {
"columns": [
{
"name": "id",
"ordinal": 0,
"type_info": {
"char_set": 63,
"flags": {
"bits": 515
},
"max_size": 11,
"type": "Long"
}
},
{
"name": "heading",
"ordinal": 1,
"type_info": {
"char_set": 224,
"flags": {
"bits": 4097
},
"max_size": 400,
"type": "VarString"
}
},
{
"name": "message",
"ordinal": 2,
"type_info": {
"char_set": 224,
"flags": {
"bits": 4097
},
"max_size": 1000,
"type": "VarString"
}
},
{
"name": "received",
"ordinal": 3,
"type_info": {
"char_set": 63,
"flags": {
"bits": 1185
},
"max_size": 19,
"type": "Timestamp"
}
},
{
"name": "name",
"ordinal": 4,
"type_info": {
"char_set": 224,
"flags": {
"bits": 4101
},
"max_size": 400,
"type": "VarString"
}
}
],
"nullable": [
false,
false,
false,
false,
false
],
"parameters": {
"Right": 1
}
},
"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"
},
"caa1638ee510ef62b86817e5d2baeaca8dfa432c23d7630c0e70737211a4680b": {
"describe": {
"columns": [
{
"name": "name",
"ordinal": 0,
"type_info": {
"char_set": 224,
"flags": {
"bits": 4101
},
"max_size": 400,
"type": "VarString"
}
}
],
"nullable": [
false
],
"parameters": {
"Right": 1
}
},
"query": "SELECT name from mcaptcha_users WHERE email = ?"
},
"cad5b403470f26c565e74a1dca19b7dee066141dec0f708070067e34d5bf72cc": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 2
}
},
"query": "UPDATE mcaptcha_users set password = ?\n WHERE name = ?"
},
"cf333541509213f11a9bf7119dcb3289bb77abf1482fc1d47e7f5bb27bdc8d97": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 2
}
},
"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"
},
"d05b84966f4e70c53789221f961bf3637f404f3ba45e880115e97ed1ba5a2809": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 4
}
},
"query": "INSERT INTO mcaptcha_config\n (`captcha_key`, `user_id`, `duration`, `name`)\n VALUES (?, (SELECT ID FROM mcaptcha_users WHERE name = ?), ?, ?)"
},
"d4b92e8099cd29cfdb99aadeeada739bb6858667fc65f528ec484e98a9da21bc": {
"describe": {
"columns": [
{
"name": "time",
"ordinal": 0,
"type_info": {
"char_set": 63,
"flags": {
"bits": 1185
},
"max_size": 19,
"type": "Timestamp"
}
}
],
"nullable": [
false
],
"parameters": {
"Right": 2
}
},
"query": "SELECT time FROM mcaptcha_pow_solved_stats \n WHERE config_id = (\n SELECT 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"
},
"daac5e937aeac2f106eb89154b431fa8bd1bd7baa95e51704fdcdf50bd970a1d": {
"describe": {
"columns": [
{
"name": "time",
"ordinal": 0,
"type_info": {
"char_set": 63,
"flags": {
"bits": 1185
},
"max_size": 19,
"type": "Timestamp"
}
}
],
"nullable": [
false
],
"parameters": {
"Right": 2
}
},
"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"
},
"dd5ff10b88fa6f374e105b6bed9e34e0870ac8dd7ce36dfb09d13a1b7005b2eb": {
"describe": {
"columns": [
{
"name": "name",
"ordinal": 0,
"type_info": {
"char_set": 224,
"flags": {
"bits": 4101
},
"max_size": 400,
"type": "VarString"
}
},
{
"name": "password",
"ordinal": 1,
"type_info": {
"char_set": 224,
"flags": {
"bits": 4113
},
"max_size": 262140,
"type": "Blob"
}
}
],
"nullable": [
false,
false
],
"parameters": {
"Right": 1
}
},
"query": "SELECT name, password FROM mcaptcha_users WHERE name = ?"
},
"dd9b4dec39405ff19af21faabb6a7c3bb3207e7e785fe15357146b88c6c27f01": {
"describe": {
"columns": [
{
"name": "secret",
"ordinal": 0,
"type_info": {
"char_set": 224,
"flags": {
"bits": 4101
},
"max_size": 200,
"type": "VarString"
}
}
],
"nullable": [
false
],
"parameters": {
"Right": 1
}
},
"query": "SELECT secret FROM mcaptcha_users WHERE name = ?"
},
"df6de3b96afcfb7f364f98954995e506b19e80e7f88204405d970c360ad5e1a0": {
"describe": {
"columns": [
{
"name": "difficulty_factor",
"ordinal": 0,
"type_info": {
"char_set": 63,
"flags": {
"bits": 4097
},
"max_size": 11,
"type": "Long"
}
},
{
"name": "visitor_threshold",
"ordinal": 1,
"type_info": {
"char_set": 63,
"flags": {
"bits": 4097
},
"max_size": 11,
"type": "Long"
}
}
],
"nullable": [
false,
false
],
"parameters": {
"Right": 2
}
},
"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;"
},
"e2b0b85f2afac1cbca43ce684641bf75ef070e44ce3d00404fc6151d2f4d7bcf": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 2
}
},
"query": "INSERT INTO mcaptcha_pow_solved_stats \n (config_id, time) VALUES ((SELECT config_id FROM mcaptcha_config where captcha_key= ?), ?)"
},
"e6569a6064d0e07abea4c0bd4686cdfdaac64f0109ac40efaed06a744a2eaf5e": {
"describe": {
"columns": [
{
"name": "name",
"ordinal": 0,
"type_info": {
"char_set": 224,
"flags": {
"bits": 4101
},
"max_size": 400,
"type": "VarString"
}
}
],
"nullable": [
false
],
"parameters": {
"Right": 1
}
},
"query": "SELECT name from mcaptcha_users WHERE name = ?"
},
"e91116ebce127833488130cf1060e0817e5677f39588632452b8d621688c405a": {
"describe": {
"columns": [
{
"name": "avg_traffic",
"ordinal": 0,
"type_info": {
"char_set": 63,
"flags": {
"bits": 4097
},
"max_size": 11,
"type": "Long"
}
},
{
"name": "peak_sustainable_traffic",
"ordinal": 1,
"type_info": {
"char_set": 63,
"flags": {
"bits": 4097
},
"max_size": 11,
"type": "Long"
}
},
{
"name": "broke_my_site_traffic",
"ordinal": 2,
"type_info": {
"char_set": 63,
"flags": {
"bits": 0
},
"max_size": 11,
"type": "Long"
}
}
],
"nullable": [
false,
false,
true
],
"parameters": {
"Right": 2
}
},
"query": "SELECT \n avg_traffic, \n peak_sustainable_traffic, \n broke_my_site_traffic \n FROM \n mcaptcha_sitekey_user_provided_avg_traffic \n WHERE \n config_id = (\n SELECT \n config_id \n FROM \n mcaptcha_config \n WHERE \n captcha_key = ? \n AND user_id = (\n SELECT \n id \n FROM \n mcaptcha_users \n WHERE \n NAME = ?\n )\n )\n "
},
"ed943cbf7e16536d81010255ce2f5beb207b2b9d44cb859fa9f2233405b80ae0": {
"describe": {
"columns": [
{
"name": "name",
"ordinal": 0,
"type_info": {
"char_set": 224,
"flags": {
"bits": 4101
},
"max_size": 400,
"type": "VarString"
}
},
{
"name": "password",
"ordinal": 1,
"type_info": {
"char_set": 224,
"flags": {
"bits": 4113
},
"max_size": 262140,
"type": "Blob"
}
}
],
"nullable": [
false,
false
],
"parameters": {
"Right": 1
}
},
"query": "SELECT name, password FROM mcaptcha_users WHERE email = ?"
},
"f47c05c0a7da41a2176f08a44c6c945dabb84558a4d09369b6108bfce8b9d2bf": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 2
}
},
"query": "DELETE\n FROM mcaptcha_challenge\n WHERE\n challenge_id = ?\n AND reason = (SELECT id FROM mcaptcha_challenge_reason WHERE name = ?);"
},
"fc717ff0827ccfaa1cc61a71cc7f71c348ebb03d35895c54b011c03121ad2385": {
"describe": {
"columns": [],
"nullable": [],
"parameters": {
"Right": 2
}
},
"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 );"
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) 2022 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/>.
*/
//! 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,24 @@
-- 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;

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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,14 @@
-- 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,92 @@
/*
* Copyright (C) 2022 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/>.
*/
#![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"
}

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,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": "INSERT INTO mcaptcha_users \n (name , password, secret) VALUES (?, ?, ?)",
"describe": {
"columns": [],
"parameters": {
"Right": 3
},
"nullable": []
},
"hash": "5d5a106981345e9f62bc2239c00cdc683d3aaaa820d63da300dc51e3f6f363d3"
}

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,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,26 @@
{
"query": "SELECT time FROM mcaptcha_pow_confirmed_stats \n WHERE \n config_id = (\n SELECT 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": "1367dceb151a766a901b5dd771d0b75d0bc61d2fef17a94a90c8ffa0065e2c44"
}

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,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 name from mcaptcha_users WHERE name = ?",
"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": "e6569a6064d0e07abea4c0bd4686cdfdaac64f0109ac40efaed06a744a2eaf5e"
}

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,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,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,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"
}

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