Merge branch 'EntireTwix:main' into main

This commit is contained in:
Expand-sys 2023-01-23 01:41:58 +11:00 committed by GitHub
commit 8f85e13f11
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 257 additions and 101 deletions

View file

@ -96,23 +96,10 @@ int main(int argc, char **argv)
#endif
Op(Bank::GetLogsV2("twix"), "get logs init (v2): ", 1);
Op(Bank::GetLogsV2("twix"), "get logs cached (v2): ", 1000000);
Op(Bank::GetLogsRange("twix", 0, 100), "get logs range: ", 1000000);
#endif
Op(Bank::PruneUsers(0, 0), "prune users: ", 1);
Op(Bank::Save(), "saving: ", 1);
//GetBal scalining test
//std::default_random_engine generator;
//std::uniform_real_distribution<double> distribution(0.0, 1.0);
// for (size_t i = 0; i < 10000000; ++i)
// {
// Bank::AddUser(std::to_string(i), 100000, "root");
// if (i % 10000 == 0)
// {
// auto u = std::to_string((int)(distribution(generator) * i));
// Op(Bank::GetBal(u), std::to_string(i) + ", ", 100000);
// }
// }
return 0;
}

View file

@ -4,7 +4,7 @@
You can with [build docs](https://github.com/EntireTwix/CCash/blob/main/docs/building.md) you can build from source or use the Docker package.
### Why is my username invalid
Usernames are restricted by minecraft's requirements
* lowercase letters
* letters
* numbers
* _
* length must be atleast 3 and at most 16 characters.
@ -16,7 +16,5 @@ Because this usecase requires none of the features a database would offer.
Consider disabling `ADD_USER_OPEN` in the [build proccess](https://github.com/EntireTwix/CCash/blob/main/docs/building.md).
### My instance is taking up too much storage or RAM
Reduce log size and/or use the prune users endpoint to remove dead accounts.
### How do I start an economy
I believe setting up a commodities exchange is the best way to get an economy going initially.
### Why not use an economy mod
Speed of operations, CCash being external to MC (and so compatible with any version/configuration), and the API are the main advantages to an economy mod.

View file

@ -6,21 +6,23 @@
| supported | :heavy_check_mark: |
| uses deprecated endpoints | ⚠ |
| uses defunt endpoints | :no_entry: |
| in development | :hammer: |
## General
| author | name | support | image |
| :-------------------------------------- | ----------------------------------------------------------- | :----------------: | :-------------------------------------------------------------------------------------------------------------: |
| [Expand](https://github.com/Expand-sys) | [Web Frontend](https://github.com/Expand-sys/ccashfrontend) | :heavy_check_mark: | ![image](https://user-images.githubusercontent.com/31377881/121337724-afe9fe80-c8d1-11eb-8851-23ec5e74cd26.png) |
| [Expand](https://github.com/Expand-sys) | [Discord Bot](https://github.com/Expand-sys/ccashbot) | :heavy_check_mark: | |
| [Expand](https://github.com/Expand-sys) | [Web Frontend](https://github.com/Expand-sys/ccashfrontend) | :heavy_check_mark: | ![image](https://user-images.githubusercontent.com/31377881/121337724-afe9fe80-c8d1-11eb-8851-23ec5e74cd26.png) | |
| [ArcNyxx](https://github.com/ArcNyxx) | [CCash CLI](https://github.com/ArcNyxx/ccash_cmd) | ⚠ | |
## Minecraft
| author | name | support | image |
| :------------------------------------------ | --------------------------------------------------------------------------- | :----------------: | :-------------------------------------------------------------------------------------------------------------: |
| [Reactified](https://github.com/Reactified) | [Shop](https://github.com/Reactified/rpm/tree/main/packages/ccash-shop) | :heavy_check_mark: | ![image](https://user-images.githubusercontent.com/31377881/120050327-de163700-bfd1-11eb-9d5a-f75c003e867c.png) |
| [Reactified](https://github.com/Reactified) | [Wallet](https://github.com/Reactified/rpm/tree/main/packages/ccash-wallet) | ⚠ | ![image](https://user-images.githubusercontent.com/31377881/121338034-fb041180-c8d1-11eb-8640-b18c141eb980.png) |
| [Reactified](https://github.com/Reactified) | [ATM](https://github.com/Reactified/rpm/tree/main/packages/ccash-bank) | :heavy_check_mark: | ![image](https://user-images.githubusercontent.com/31377881/121277361-4d6b1100-c885-11eb-87c8-cfebcf58da4f.png) |
| [STBoyden](https://github.com/STBoyden) | Commodities Exchange (in-development) | :heavy_check_mark: | |
| author | name | support | image |
| :------------------------------------------ | ---------------------------------------------------------------------------------------- | :----------------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| [Reactified](https://github.com/Reactified) | [Shop](https://github.com/Reactified/rpm/tree/main/packages/ccash-shop) | :heavy_check_mark: | ![image](https://user-images.githubusercontent.com/31377881/120050327-de163700-bfd1-11eb-9d5a-f75c003e867c.png) |
| [Reactified](https://github.com/Reactified) | [Wallet](https://github.com/Reactified/rpm/tree/main/packages/ccash-wallet) | ⚠ | ![image](https://user-images.githubusercontent.com/31377881/121338034-fb041180-c8d1-11eb-8640-b18c141eb980.png) |
| [Reactified](https://github.com/Reactified) | [ATM](https://github.com/Reactified/rpm/tree/main/packages/ccash-bank) | :heavy_check_mark: | ![image](https://user-images.githubusercontent.com/31377881/121277361-4d6b1100-c885-11eb-87c8-cfebcf58da4f.png) |
| [Reactified](https://github.com/Reactified) | [Chunk Loader Shop](https://github.com/Reactified/rpm/tree/main/packages/forceload-shop) | :heavy_check_mark: | ![image](https://user-images.githubusercontent.com/31377881/209894520-f7183f45-bbac-40f3-9f95-043bda3c0097.png) ![image](https://user-images.githubusercontent.com/31377881/209894553-16ef7e04-52e7-4198-8a39-9ad2ada6eaf7.png) |
| [STBoyden](https://github.com/STBoyden) | [Commodities Exchange](https://github.com/STBoyden/ccash-market) | :hammer: | |
## Desired
| idea | description |

View file

@ -17,73 +17,77 @@
## all error responses have JSON string along with them to describe
### Usage endpoints
| name | added on | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
| :------------- | :------: | ------------------------------------------------------------------------------ | -------------------------------- | ------------------------------- | :---------: | :------------: | :--------------: | :-----------------------------------------------------------: | :----------------: | :----------------: | :---: | :----------------: |
| GetBal | `v2.3.0` | retrieving the balance of a given user, `{name}` | `N/A` | api/v1/user/balance?name={name} | `GET` | 200 | uint32 | the user's balance | :heavy_check_mark: | :x: | :x: | :x: |
| GetLog | `v2.3.0` | retrieves the logs of a given user, length varies by server configuration | `N/A` | ⚠ api/v1/user/log | `GET` | 200 | array of objects | [{"to":string, "from":string, "amount":uint32, "time":int64}] | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
| GetLogV2 | `v2.5.1` | retrieves the logs of a given user, length varies by server configuration | `N/A` | api/v2/user/log | `GET` | 200 | array of objects | [{"counterparty":string, "amount":int64, "time":int64}] | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
| SendFunds | `v2.3.0` | sends funds from the authenticated user to the user `{name}` given in the json | {"name":string, "amount":uint32} | api/v1/user/transfer | `POST` | 200 | uint32 | the user's balance after the transaction | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: |
| VerifyPassword | `v2.3.0` | verifies the credentials, used for connected services for ease of use | `N/A` | api/v1/user/verify_password | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
| name | last change | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
| :------------- | :---------: | ------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | ------------------------------- | :---------: | :------------: | :--------------: | :-----------------------------------------------------------: | :----------------: | :----------------: | :---: | :----------------: |
| GetBal | `v2.3.0` | retrieving the balance of a given user, `{name}` | `N/A` | api/v1/user/balance?name={name} | `GET` | 200 | uint32 | the user's balance | :heavy_check_mark: | :x: | :x: | :x: |
| GetLogs | `v2.3.0` | retrieves the logs of a given user, length varies by server configuration (oldest to newest transactions) | `N/A` | ⚠ api/v1/user/log | `GET` | 200 | array of objects | [{"to":string, "from":string, "amount":uint32, "time":int64}] | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
| GetLogsV2 | `v2.6.1` | retrieves the logs of a given user, length varies by server configuration (newest to oldest transactions) | `N/A` | api/v2/user/log | `GET` | 200 | array of objects | [{"counterparty":string, "amount":int64, "time":int64}] | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
| GetLogsRange | `v2.6.1` | retrieves the logs of a given user, where `{start}` is the 0-indexed first log and `{length}` is the number of logs after that index. | `N/A` | api/v1/user/log_range | `GET` | 200 | array of objects | [{"counterparty":string, "amount":int64, "time":int64}] | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
| SendFunds | `v2.3.0` | sends funds from the authenticated user to the user `"name"` given in the json | {"name":string, "amount":uint32} | api/v1/user/transfer | `POST` | 200 | uint32 | the user's balance after the transaction | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: |
| ChangePassword | `v2.3.0` | changes the password of the Authenticated user | {"pass":string} | api/v1/user/change_password | `PATCH` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: |
| VerifyPassword | `v2.3.0` | verifies the credentials, used for connected services for ease of use | `N/A` | api/v1/user/verify_password | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
### Usage enpoint errors
| name | 400 | 401 | 404 | 406 |
| :------------- | :----------------: | :----------------: | :----------------: | :----------------: |
| GetBal | :x: | :x: | :heavy_check_mark: | :heavy_check_mark: |
| GetLog | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| GetLogV2 | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| GetLogs | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| GetLogsV2 | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| GetLogsRange | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| SendFunds | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| VerifyPassword | :x: | :heavy_check_mark: | :x: | :heavy_check_mark: |
| ChangePassword | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: |
### Meta Usage endpoints
| name | added on | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
| :------------------ | :------: | -------------------------------------------------------------------------------------------------- | ------------------------------- | --------------------------------- | :---------: | :------------: | :---------: | :----------------------------: | :----------------: | :----------------: | :----------------: | :----------------: |
| ChangePassword | `v2.3.0` | changes the password of the Authenticated user | {"pass":string} | api/v1/user/change_password | `PATCH` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: |
| AdminChangePassword | `v2.3.0` | changes the password of a given user `{name}` | {"name":string,"pass":string} | api/v1/admin/user/change_password | `PATCH` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
| SetBal | `v2.3.0` | sets the balance of a given user `{name}` | {"name":string,"amount":uint32} | api/v1/admin/set_balance | `PATCH` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
| ImpactBal | `v2.3.0` | modifies the user `{name}`'s balance by `{amount}` if positive itll add, if negative itll subtract | {"name":string,"amount":int64} | api/v1/admin/impact_balance | `POST` | 200 | uint32 | new balance after modification | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
| name | last change | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
| :------------------ | :---------: | -------------------------------------------------------------------------------------------------- | ------------------------------- | --------------------------------- | :---------: | :------------: | :--------------: | :-----------------------------------------------------: | :----------------: | :----------------: | :----------------: | :---: |
| AdminGetLogs | `v2.6.1` | retreives the logs of a given user `{name}`, length varies by server configuration | `N/A` | api/v1/admin/user/log?name={name} | `GET` | 200 | array of objects | [{"counterparty":string, "amount":int64, "time":int64}] | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: |
| AdminChangePassword | `v2.3.0` | changes the password of a given user `"name"` | {"name":string,"pass":string} | api/v1/admin/user/change_password | `PATCH` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
| AdminVerifyAccount | `v2.3.0` | checks wether a user is the admin | `N/A` | api/v1/admin/verify_account | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: |
| SetBal | `v2.3.0` | sets the balance of a given user `"name"` | {"name":string,"amount":uint32} | api/v1/admin/set_balance | `PATCH` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
| ImpactBal | `v2.3.0` | modifies the user `"name"`'s balance by `"amount"` if positive itll add, if negative itll subtract | {"name":string,"amount":int64} | api/v1/admin/impact_balance | `POST` | 200 | uint32 | new balance after modification | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
### Meta Usage endpoint errors
| name | 400 | 401 | 404 | 406 |
| :------------------ | :----------------: | :----------------: | :----------------: | :----------------: |
| ChangePassword | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: |
| AdminGetLogs | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| AdminChangePassword | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| AdminVerifyAccount | :x: | :heavy_check_mark: | :x: | :heavy_check_mark: |
| SetBal | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| ImpactBal | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
### Sytem Usage endpoints
| name | added on | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
| :----------------- | :------: | ------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | ------------------------------ | :---------: | :------------: | :---------: | :-----------------------------------------------------------------: | :----------------: | :----------------: | :----------------: | :---: |
| Help | `v2.3.0` | redirects to GitHub projects Docs | `N/A` | api/help | `GET` | 301 | `N/A` | `N/A` | :x: | :x: | :x: | :x: |
| Close | `v2.3.0` | saves & closes the CCash webserver | `N/A` | api/v1/admin/shutdown | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: |
| Contains | `v2.3.0` | checks wether a user exists | `N/A` | api/v1/user/exists?name={name} | `GET` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :x: | :x: |
| AdminVerifyAccount | `v2.3.0` | checks wether a user is the admin | `N/A` | api/v1/admin/verify_account | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: |
| PruneUsers | `v2.3.0` | deletes users with most recent transactions older then `{time}` (if logs are enabled) and have less money then `{amount}` | {"time":int64,"amount":uint32} or just {"amount":uint32} | api/v1/admin/prune_users | `POST` | 200 | uint64 | number of users deleted | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
| ApiProperties | `v2.5.1` | properties of the given instance | `N/A` | api/properties | `GET` | 200 | json object | {"max_log":uint64, "add_user_open":boolean, "return_on_del":string} | :heavy_check_mark: | :x: | :x: | :x: |
| name | last change | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
| :------------ | :---------: | ------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | ------------------------------ | :---------: | :------------: | :---------: | :-----------------------------------------------------------------: | :----------------: | :----------------: | :----------------: | :---: |
| Help | `v2.3.0` | redirects to GitHub projects Docs | `N/A` | api/help | `GET` | 301 | `N/A` | `N/A` | :x: | :x: | :x: | :x: |
| Close | `v2.3.0` | saves & closes the CCash webserver | `N/A` | api/v1/admin/shutdown | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: |
| Contains | `v2.3.0` | checks wether a given user `{name}` exists | `N/A` | api/v1/user/exists?name={name} | `GET` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :x: | :x: |
| PruneUsers | `v2.3.0` | deletes users with most recent transactions older then `"time"` (if logs are enabled) and have less money then `"amount"` | {"time":int64,"amount":uint32} or just {"amount":uint32} | api/v1/admin/prune_users | `POST` | 200 | uint64 | number of users deleted | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
| ApiProperties | `v2.5.1` | properties of the given instance | `N/A` | api/properties | `GET` | 200 | json object | {"max_log":uint64, "add_user_open":boolean, "return_on_del":string} | :heavy_check_mark: | :x: | :x: | :x: |
### System Usage endpoin errors
| name | 401 | 404 | 406 |
| :----------------- | :----------------: | :----------------: | :----------------: |
| Help | :x: | :x: | :x: |
| Close | :heavy_check_mark: | :x: | :heavy_check_mark: |
| Contains | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| AdminVerifyAccount | :heavy_check_mark: | :x: | :heavy_check_mark: |
| PruneUsers | :heavy_check_mark: | :x: | :heavy_check_mark: |
| ApiProperties | :x: | :x: | :x: |
| name | 401 | 404 | 406 |
| :------------ | :----------------: | :----------------: | :----------------: |
| Help | :x: | :x: | :x: |
| Close | :heavy_check_mark: | :x: | :heavy_check_mark: |
| Contains | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| PruneUsers | :heavy_check_mark: | :x: | :heavy_check_mark: |
| ApiProperties | :x: | :x: | :x: |
### Username Requirements
Valid
* lowercase letters
* letters
* numbers
* _
* Length must be atleast 3 and at most 16 characters.
### User Management endpoints
| name | added on | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
| :----------- | :------: | --------------------------------------- | --------------------------------------------- | -------------------------- | :---------: | :------------: | :---------: | :----------: | :----------------: | :----------------: | :----------------: | :----------------: |
| AddUser | `v2.3.0` | adding a user with a balance of 0 | {"name":string,"pass":string} | api/v1/user/register | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :x: | :x: |
| AdminAddUser | `v2.3.0` | adding a user with an arbitrary balance | {"name":string,"amount":uint32,"pass":string} | api/v1/admin/user/register | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
| DelSelf | `v2.3.0` | deletes a user | `N/A` | api/v1/user/delete | `DELETE` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
| AdminDelUser | `v2.3.0` | deletes a given user `{name}` | {"name":string} | api/v1/admin/user/delete | `DELETE` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
| name | last change | purpose | json input | path | HTTP Method | correct status | return type | return value | Jresp | Jreq | A | U |
| :----------- | :---------: | --------------------------------------- | --------------------------------------------- | -------------------------- | :---------: | :------------: | :---------: | :----------: | :----------------: | :----------------: | :----------------: | :----------------: |
| AddUser | `v2.3.0` | adding a user with a balance of 0 | {"name":string,"pass":string} | api/v1/user/register | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :x: | :x: |
| AdminAddUser | `v2.3.0` | adding a user with an arbitrary balance | {"name":string,"amount":uint32,"pass":string} | api/v1/admin/user/register | `POST` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
| DelSelf | `v2.3.0` | deletes a user | `N/A` | api/v1/user/delete | `DELETE` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: |
| AdminDelUser | `v2.3.0` | deletes a given user `"name"` | {"name":string} | api/v1/admin/user/delete | `DELETE` | 204 | `N/A` | `N/A` | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: |
### User Management endpoint errors
| name | 400 | 401 | 404 | 406 | 409 |

View file

@ -49,13 +49,13 @@ public:
static BankResponse GetLogs(const std::string &name) noexcept;
#endif
static BankResponse GetLogsV2(const std::string &name) noexcept;
static BankResponse GetLogsRange(const std::string &name, size_t n, size_t m) noexcept;
#endif
static BankResponse SendFunds(const std::string &a_name, const std::string &b_name, uint32_t amount) noexcept;
static bool VerifyPassword(const std::string &name, const std::string_view &attempt) noexcept;
static void ChangePassword(const std::string &name, const std::string &new_pass) noexcept;
static BankResponse SetBal(const std::string &name, uint32_t amount) noexcept;
static BankResponse SetBal(const std::string &name, int64_t amount) noexcept;
static BankResponse ImpactBal(const std::string &name, int64_t amount) noexcept;
static bool Contains(const std::string &name) noexcept;

View file

@ -16,18 +16,20 @@ public:
static void GetLogs(req_args);
#endif
static void GetLogsV2(req_args);
static void GetLogsRange(req_args, size_t start, size_t length);
static void SendFunds(req_args);
static void ChangePassword(req_args);
static void VerifyPassword(req_args);
static void ChangePassword(req_args);
static void AdminGetLogs(req_args, const std::string& name);
static void AdminChangePassword(req_args);
static void AdminVerifyAccount(req_args);
static void SetBal(req_args);
static void ImpactBal(req_args);
static void Help(req_args);
static void Close(req_args);
static void Contains(req_args, const std::string &name);
static void AdminVerifyAccount(req_args);
static void PruneUsers(req_args);
static void ApiProperties(req_args);
@ -38,39 +40,49 @@ public:
METHOD_LIST_BEGIN
METHOD_ADD(api::Help, "/help", Get, Options);
METHOD_ADD(api::ApiProperties, "/properties", Get, Options);
//Usage
METHOD_ADD(api::GetBal, "/v1/user/balance?name={name}", Get, Options, "JsonFilter<false>");
#if MAX_LOG_SIZE > 0
#if USE_DEPRECATED_ENDPOINTS
METHOD_ADD(api::GetLogs, "/v1/user/log", Get, Options, "JsonFilter<false>", "UserFilter<true, false>");
#endif
METHOD_ADD(api::GetLogsV2, "/v2/user/log", Get, Options, "JsonFilter<false>", "UserFilter<true, false>");
METHOD_ADD(api::GetLogsRange, "/v1/user/log_range?start={start}&length={length}", Get, Options, "JsonFilter<false>", "UserFilter<true, false>");
METHOD_ADD(api::AdminGetLogs, "/v1/admin/user/log?name={name}", Get, Options, "JsonFilter<false>", "UserFilter<false, true>");
#else
#if USE_DEPRECATED_ENDPOINTS
METHOD_ADD(api::GetLogs, "/v1/user/log", Get, Options, "JsonFilter<false>");
#endif
METHOD_ADD(api::GetLogsV2, "/v2/user/log", Get, Options, "JsonFilter<false>");
METHOD_ADD(api::GetLogsRange, "/v1/user/log_range?start={start}&length={length}", Get, Options, "JsonFilter<false>");
METHOD_ADD(api::AdminGetLogs, "/v1/admin/user/log?name={name}", Get, Options, "JsonFilter<false>");
#endif
METHOD_ADD(api::SendFunds, "/v1/user/transfer", Post, Options, "JsonFilter<true>", "UserFilter<true, false>"); //expects ["name"](string) and ["amount"](uint32)
METHOD_ADD(api::ChangePassword, "/v1/user/change_password", Patch, Options, "JsonFilter<true>", "UserFilter<true, false>"); //expects ["pass"](string)
METHOD_ADD(api::VerifyPassword, "/v1/user/verify_password", Post, Options, "UserFilter<false, false>", "JsonFilter<false>");
//Meta Usage
METHOD_ADD(api::ChangePassword, "/v1/user/change_password", Patch, Options, "JsonFilter<true>", "UserFilter<true, false>"); //expects ["pass"](string)
METHOD_ADD(api::AdminChangePassword, "/v1/admin/user/change_password", Patch, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string) and ["pass"](string)
METHOD_ADD(api::SetBal, "/v1/admin/set_balance", Patch, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string) and ["amount"](uint32)
METHOD_ADD(api::ImpactBal, "/v1/admin/impact_balance", Post, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string) and ["amount"](uint32)
METHOD_ADD(api::AdminVerifyAccount, "/v1/admin/verify_account", Post, Options, "UserFilter<false, true>", "JsonFilter<false>");
METHOD_ADD(api::SetBal, "/v1/admin/set_balance", Patch, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string) and ["amount"](uint32)
METHOD_ADD(api::ImpactBal, "/v1/admin/impact_balance", Post, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string) and ["amount"](uint32)
//System Usage
METHOD_ADD(api::Help, "/help", Get, Options);
METHOD_ADD(api::Close, "/v1/admin/shutdown", Post, Options, "UserFilter<false, true>", "JsonFilter<false>");
METHOD_ADD(api::Contains, "/v1/user/exists?name={name}", Get, Options, "JsonFilter<false>");
METHOD_ADD(api::AdminVerifyAccount, "/v1/admin/verify_account", Post, Options, "UserFilter<false, true>", "JsonFilter<false>");
METHOD_ADD(api::PruneUsers, "/v1/admin/prune_users", Post, "UserFilter<false, true>", "JsonFilter<true>"); //expects ["time"](int64) and ["amount"](uint32)
METHOD_ADD(api::ApiProperties, "/properties", Get, Options);
//User Managment
METHOD_ADD(api::AddUser, "/v1/user/register", Post, Options); //expects ["name"](string) ["pass"](string)
METHOD_ADD(api::AddUser, "/v1/user/register", Post, Options); //expects ["name"](string) ["pass"](string)
METHOD_ADD(api::AdminAddUser, "/v1/admin/user/register", Post, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string) ["amount"](uint32) ["pass"](string)
METHOD_ADD(api::DelSelf, "/v1/user/delete", Delete, Options, "UserFilter<true, false>", "JsonFilter<false>");
METHOD_ADD(api::AdminDelUser, "/v1/admin/user/delete", Delete, Options, "JsonFilter<true>", "UserFilter<false, true>"); //expects ["name"](string)

View file

@ -26,5 +26,6 @@ public:
std::string GetLogs(const std::string& name) noexcept;
#endif
std::string GetLogsV2() noexcept;
std::string GetLogsRange(size_t n, size_t m) noexcept;
void AddTrans(const std::string &counterparty_str, bool receiving, uint32_t amount, time_t time) noexcept;
};

View file

@ -34,28 +34,29 @@ int main(int argc, char **argv)
uint8_t temp[16]{16, 0, 0, 0, 4};
users_save.write((char *)temp, 16);
users_save.close();
std::cout << "User save file generated\nUsage: sudo ./bank <admin account name> <saving frequency in minutes> [daemon flag {default: false}]\n";
std::cout << "User save file generated\n" << "Usage: sudo ./bank <admin account> <saving frequency in minutes> [daemon flag {default: false}]\n";
return 0;
}
else
{
std::cerr << "File cannot be created (may already exist)\n";
return -1;
}
return 0;
}
if (argc < 3)
{
std::cerr << "Usage: sudo ./bank <admin account> <saving frequency in minutes> [daemon flag {default: false}]\n";
return 0;
return -1;
}
if (geteuid() != 0)
{
std::cerr << "ERROR: CCash MUST be ran as root\n";
return 0;
return -1;
}
const unsigned long saving_freq = std::stoul(std::string(argv[2]));
std::cout
<< "\nAPI : v2.5.1"
<< "\n\nAVX : " << (__builtin_cpu_supports("avx") ? "enabled" : "disabled")
<< "\nAPI : v2.6.1\n"
<< "\nAVX : " << (__builtin_cpu_supports("avx") ? "enabled" : "disabled")
<< "\nAVX 2 : " << (__builtin_cpu_supports("avx2") ? "enabled" : "disabled")
<< "\nSSE 2 : " << (__builtin_cpu_supports("sse2") ? "enabled" : "disabled")
<< "\nSSE 3 : " << (__builtin_cpu_supports("sse3") ? "enabled" : "disabled")
@ -92,18 +93,22 @@ int main(int argc, char **argv)
if (saving_freq) //if saving frequency is 0 then auto saving is turned off
{
std::thread([saving_freq]()
{
while (1)
{
std::this_thread::sleep_for(std::chrono::minutes(saving_freq));
std::cout << "Saving " << std::time(0) << "...\n"
<< Bank::Save();
}
})
.detach();
{
while (1)
{
std::this_thread::sleep_for(std::chrono::minutes(saving_freq));
std::cout << "Saving " << std::time(0) << "...\n" << Bank::Save();
}
})
.detach();
}
if (argc == 4 && !strcmp(argv[3], "true")) { app().enableRunAsDaemon(); }
else if (argc == 4 && strcmp(argv[3], "false"))
{
std::cerr << "daemon flag must be \"true\" or \"false\"\n";
return -1;
}
} //destroying setup variables
app()

View file

@ -36,7 +36,7 @@ inline bool ValidUsername(const std::string &name) noexcept
}
for (char c : name)
{
if (!((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_'))
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'))
{
return false;
}
@ -116,6 +116,28 @@ BankResponse Bank::GetLogsV2(const std::string &name) noexcept
}
}
BankResponse Bank::GetLogsRange(const std::string &name, size_t start, size_t length) noexcept
{
BankResponse res;
if (start >= MAX_LOG_SIZE)
{
return {k400BadRequest, "\"Invalid {start} index\""};
}
if (!length)
{
return {k400BadRequest, "\"Invalid {length}\""};
}
if (!Bank::users.modify_if(name, [&name, &res, start, length](User &u) { res = {k200OK, u.log.GetLogsRange(start, length)}; }))
{
return {k404NotFound, "\"User not found\""};
}
else
{
return res;
}
}
#endif
BankResponse Bank::SendFunds(const std::string &a_name, const std::string &b_name, uint32_t amount) noexcept
@ -179,15 +201,20 @@ bool Bank::VerifyPassword(const std::string &name, const std::string_view &attem
Bank::users.if_contains(name, [&res, &attempt](const User &u) { res = (u.password == xxHashStringGen{}(attempt)); });
return res;
}
void Bank::ChangePassword(const std::string &name, const std::string &new_pass) noexcept
{
SET_CHANGES_ON;
Bank::users.modify_if(name, [&new_pass](User &u) { u.password = xxHashStringGen{}(new_pass); });
}
BankResponse Bank::SetBal(const std::string &name, uint32_t amount) noexcept
BankResponse Bank::SetBal(const std::string &name, int64_t amount) noexcept
{
if (ValidUsername(name) && Bank::users.modify_if(name, [amount](User &u) { u.balance = amount; }))
if (ValidUsername(name) && Bank::users.modify_if(name, [&amount](User &u) {
amount -= u.balance;
u.balance += amount;
#if MAX_LOG_SIZE > 0
u.log.AddTrans("Ω", (amount > 0), std::abs(amount), time(NULL));
#endif
}))
{
SET_CHANGES_ON;
return {k204NoContent, std::nullopt}; //returns new balance
@ -204,7 +231,13 @@ BankResponse Bank::ImpactBal(const std::string &name, int64_t amount) noexcept
return {k400BadRequest, "\"Amount cannot be 0\""};
}
uint32_t bal;
if (ValidUsername(name) && Bank::users.modify_if(name, [&bal, amount](User &u) { bal = (u.balance < (amount * -1) ? u.balance = 0 : u.balance += amount); }))
if (ValidUsername(name) && Bank::users.modify_if(name, [&bal, &amount](User &u) {
if (u.balance < (amount * -1)) { amount = -int64_t(u.balance); };
bal = u.balance += amount;
#if MAX_LOG_SIZE > 0
u.log.AddTrans("Ω", (amount > 0), std::abs(amount), time(NULL));
#endif
}))
{
SET_CHANGES_ON;
return {k200OK, std::to_string(bal)}; //may return new balance

View file

@ -54,6 +54,30 @@ void api::GetLogsV2(req_args)
#endif
}
void api::GetLogsRange(req_args, size_t start, size_t length)
{
#if MAX_LOG_SIZE > 0
RESPONSE_PARSE(Bank::GetLogsRange(NAME_PARAM, start, length));
#else
auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k404NotFound, "\"Logs are Disabled\""});
CORS;
CACHE_FOREVER;
callback(resp);
#endif
}
void api::AdminGetLogs(req_args, const std::string& name)
{
#if MAX_LOG_SIZE > 0
RESPONSE_PARSE(Bank::GetLogsV2(name));
#else
auto resp = HttpResponse::newCustomHttpResponse(BankResponse{k404NotFound, "\"Logs are Disabled\""});
CORS;
CACHE_FOREVER;
callback(resp);
#endif
}
void api::SendFunds(req_args)
{
SIMD_JSON_GEN;

View file

@ -9,7 +9,7 @@ void Log::AddTrans(const std::string &counterparty_str, bool receiving, uint32_t
if (data.size() == MAX_LOG_SIZE)
{
data.pop_back();
data.pop_front();
}
data.emplace_back(counterparty_str, receiving, amount, time);
}
@ -17,7 +17,7 @@ void Log::AddTrans(const std::string &counterparty_str, bool receiving, uint32_t
#if USE_DEPRECATED_ENDPOINTS
std::string Log::GetLogs(const std::string& name) noexcept
{
if (log_flag.GetChangeState() && data.size()) //if there are changes
if (log_flag.GetChangeState() && data.size()) // if there are changes
{
log_snapshot.resize(0);
//re-generate snapshot
@ -49,7 +49,7 @@ std::string Log::GetLogs(const std::string& name) noexcept
std::string Log::GetLogsV2() noexcept
{
if (log_flag_v2.GetChangeState() && data.size()) //if there are changes
if (log_flag_v2.GetChangeState() && data.size()) // if there are changes
{
log_snapshot_v2.resize(0);
//re-generate snapshot
@ -59,11 +59,11 @@ std::string Log::GetLogsV2() noexcept
log_snapshot_v2.reserve(predicted_size);
}
log_snapshot_v2 = '['; //1
for (size_t i = 0; i < data.size(); ++i)
for (size_t i = data.size(); i --> 0;)
{
log_snapshot_v2 += "{\"counterparty\":\""; //17
log_snapshot_v2 += data[i].counterparty; //max_name_size?
log_snapshot_v2 += "\",\"amount\":"; //11
log_snapshot_v2 += "\",\"amount\":"; //11
if (!data[i].receiving) { log_snapshot_v2 += '-'; } //1
log_snapshot_v2 += std::to_string(data[i].amount); //10?
log_snapshot_v2 += ",\"time\":"; //8
@ -76,3 +76,93 @@ std::string Log::GetLogsV2() noexcept
return log_snapshot_v2;
}
std::string Log::GetLogsRange(size_t start, size_t length) noexcept
{
if (start >= data.size()) { return "[]"; }
if (start == 0 && length == MAX_LOG_SIZE) { return log_snapshot_v2; }
if (log_flag_v2.GetChangeState() && data.size()) { GetLogsV2(); }
size_t log_index_n, i;
if (start < (0.5 * MAX_LOG_SIZE))
{
// std::cout << "a\n";
i = 0;
log_index_n = 0;
while(i < log_snapshot_v2.size())
{
if (log_index_n == start)
{
log_index_n = i;
break;
}
i += (41 + min_name_size);
while (log_snapshot_v2[i] != ',') { ++i; }
++log_index_n;
}
}
else
{
// std::cout << "b\n";
i = log_snapshot_v2.size();
log_index_n = data.size();
while(i --> 0)
{
if (log_index_n == start)
{
log_index_n = i + 1;
break;
}
i -= (41 + min_name_size);
while (log_snapshot_v2[i] != ',') { --i; }
--log_index_n;
}
}
size_t log_index_m = std::string::npos;
if ((start + length) < data.size())
{
if (length < (0.5 * MAX_LOG_SIZE))
{
// std::cout << "c\n";
log_index_m = 0;
while(i < log_snapshot_v2.size())
{
if (log_index_m == length)
{
log_index_m = i + 1;
break;
}
i += (41 + min_name_size);
while (log_snapshot_v2[i] != ',') { ++i; }
++log_index_m;
}
}
else
{
// std::cout << "d\n";
i = log_snapshot_v2.size();
log_index_m = data.size();
while(i --> 0)
{
if (log_index_m == length)
{
log_index_m = i + 1;
break;
}
i -= (41 + min_name_size);
while (log_snapshot_v2[i] != ',') { --i; }
--log_index_m;
}
}
log_index_m -= log_index_n;
}
std::string res(log_snapshot_v2.substr(log_index_n, log_index_m));
res[0] = '[';
res[res.size() - 1] = ']';
// std::cout << res << '\n';
return res;
}

View file

@ -8,7 +8,7 @@ inline bool ValidUsername(const std::string &name) noexcept
}
for (char c : name)
{
if (!((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_'))
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'))
{
return false;
}