mirror of
https://github.com/Expand-sys/CCash
synced 2025-12-17 00:22:14 +11:00
commit
da2f18e2ef
9 changed files with 496 additions and 244 deletions
31
README.md
31
README.md
|
|
@ -28,6 +28,7 @@ building the project
|
|||
|
||||
```
|
||||
git clone --recurse-submodule https://github.com/EntireTwix/CCash/
|
||||
cd CCash
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
|
|
@ -48,35 +49,8 @@ sudo ./bank <admin password> <saving frequency in minutes> <threads>
|
|||
|
||||
## Connected Services
|
||||
|
||||
Go to `{ip}/BankF/help` to see the bank's methods (also found in help.html). Using the Bank's API allows (you/others) to (make/use) connected services that utilize the bank, a couple ideas are
|
||||
|
||||
### Implemented:
|
||||
|
||||
- [Web Frontend](https://github.com/Expand-sys/ccashfrontend)
|
||||

|
||||
- [CC Frontend](https://github.com/Reactified/rpm/blob/main/packages/ccash-wallet)
|
||||
|
||||

|
||||
- [CC Shop](https://github.com/Reactified/rpm/tree/main/packages/ccash-shop)
|
||||

|
||||

|
||||
- [CC ATM](https://github.com/Reactified/misc/tree/main/lua/ccash-bank) an ATM for economies allowing for an initial exchange to start up
|
||||

|
||||
- [CC API](https://github.com/Reactified/rpm/blob/main/packages/ccash-api/api.lua)
|
||||
|
||||
### In-Dev:
|
||||
|
||||
- [a Market](https://github.com/STBoyden/market-api-2.0)
|
||||
- [Python API](https://github.com/fearlessdoggo21/ccashpythonclient)
|
||||
|
||||
### Ideas:
|
||||
|
||||
- Gambling
|
||||
- Shipping
|
||||
- High-level bank operations such as loans
|
||||
- Some trust based system for transactions similiar to Paypal
|
||||
|
||||
`**WARNING** : abruptly killing the program will result in data loss, use Close() method to close safely`
|
||||
Go to `{ip}/BankF/help` to see the bank's methods (also found in releases as help.html). Using the Bank's API allows (you/others) to (make/use) connected services that utilize the bank, a couple ideas can be found [here](services.md)
|
||||
|
||||
## FAQ
|
||||
**Q:** how is money initially injected into the economy
|
||||
|
|
@ -85,6 +59,7 @@ Go to `{ip}/BankF/help` to see the bank's methods (also found in help.html). Usi
|
|||
|
||||
## [Contributions](https://github.com/EntireTwix/CCash/graphs/contributors)
|
||||
Thank you to the contributors
|
||||
|
||||
| Name | Work |
|
||||
| :--- | --- |
|
||||
| [Expand](https://github.com/Expand-sys) | Frontend |
|
||||
|
|
|
|||
283
help.html
283
help.html
|
|
@ -1,85 +1,198 @@
|
|||
<body>
|
||||
<h1>ALL FUNCTIONS (that have args) ARE EXPECTING JSON AS DATA TYPE</h1>
|
||||
<h2>/BankF/<span style="color: #993300;">admin</span>/close (POST)</h2>
|
||||
<p><span style="background-color: #808080;"> attempt </span> - admin password</p>
|
||||
<blockquote>
|
||||
<p>Closes and Saves the server.</p>
|
||||
</blockquote>
|
||||
<h2>/BankF/user (POST)</h2>
|
||||
<p><span style="background-color: #808080;"> name </span> - name of the user being added (must be less then 50 characters)</p>
|
||||
<p><span style="background-color: #808080;"> init_pass </span> - initial password for the user being added</p>
|
||||
<blockquote>
|
||||
<p>Adds a user to the bank</p>
|
||||
</blockquote>
|
||||
<h2>/BankF/<span style="color: #993300;">admin</span>/user (POST)</h2>
|
||||
<p><span style="background-color: #808080;"> name </span> - name of the user being added</p>
|
||||
<p><span style="background-color: #808080;"> attempt </span> - admin password required to add user with balance</p>
|
||||
<p><span style="background-color: #808080;"> init_bal </span> - initial balance for user being added</p>
|
||||
<p><span style="background-color: #808080;"> init_pass </span> - initial password for user being added</p>
|
||||
<blockquote>
|
||||
<p>Adds a user with initial balance</p>
|
||||
</blockquote>
|
||||
<h2>/BankF/sendfunds (POST)</h2>
|
||||
<p><span style="background-color: #808080;"> a_name </span> - sender's name</p>
|
||||
<p><span style="background-color: #808080;"> b_name </span> - reciever's name</p>
|
||||
<p><span style="background-color: #808080;"> amount </span> - amount being sent</p>
|
||||
<p><span style="background-color: #808080;"> attempt </span> - password of sender</p>
|
||||
<blockquote>
|
||||
<p>Sends money from one user to another</p>
|
||||
</blockquote>
|
||||
<h2>/BankF/changepass (PATCH)</h2>
|
||||
<p><span style="background-color: #808080;"> name </span> - name of user's password being changes</p>
|
||||
<p><span style="background-color: #808080;"> attempt </span> - password of user being changed</p>
|
||||
<p><span style="background-color: #808080;"> new_pass </span> - new password to replace the current user's password</p>
|
||||
<blockquote>
|
||||
<p>Changes password of a user, returns -1 if user doesnt exist</p>
|
||||
</blockquote>
|
||||
<h2>/BankF/<span style="color: #993300;">admin</span>/{<span style="color: #339966;">name</span>}/bal (PATCH)</h2>
|
||||
<p><span style="background-color: #808080;"> name </span> - the name of the user being set</p>
|
||||
<p><span style="background-color: #808080;"> attempt </span> - the admin password required</p>
|
||||
<p><span style="background-color: #808080;"> amount </span> - the new balance of the user</p>
|
||||
<blockquote>
|
||||
<p>Sets the balance of a user</p>
|
||||
</blockquote>
|
||||
<h2>/BankF/help (GET)</h2>
|
||||
<blockquote>
|
||||
<p>the page you're looking at right now!</p>
|
||||
</blockquote>
|
||||
<h2>/BankF/vpass (POST)</h2>
|
||||
<p><span style="background-color: #808080;"> name </span> - name of user being verified</p>
|
||||
<p><span style="background-color: #808080;"> attempt </span> - password being verified</p>
|
||||
<blockquote>
|
||||
<p>returns 0 or 1 based on if [attempt] is equal to the password of the user [name], or -1 if user does not exist. The intended usage for this function is for connected services</p>
|
||||
</blockquote>
|
||||
<h2>/BankF/contains/{<span style="color: #339966;">name</span>} (GET)</h2>
|
||||
<blockquote>
|
||||
<p>returns a 0 or 1 based on if the bank contains the user</p>
|
||||
</blockquote>
|
||||
<h2>/BankF/{<span style="color: #339966;">name</span>}/bal (GET)</h2>
|
||||
<blockquote>
|
||||
<p>returns the balance of a given user's name, if -1 that means the user does not exist</p>
|
||||
</blockquote>
|
||||
<h2>/BankF/<span style="color: #993300;">admin</span>/vpass (POST)</h2>
|
||||
<p><span style="background-color: #808080;"> attempt </span> - admin password</p>
|
||||
<blockquote>
|
||||
<p>Verifies if password entered is admin password</p>
|
||||
</blockquote>
|
||||
<h2>/BankF/{<span style="color: #339966;">name</span>}/log (POST)</h2>
|
||||
<p><span style="background-color: #808080;"> attempt </span> - user password</p>
|
||||
<blockquote>
|
||||
<p>returns a list of last 100 transactions, -1 if user not found, 0 if invalid password</p>
|
||||
</blockquote>
|
||||
<h2>/BankF/user (DELETE)</h2>
|
||||
<p><span style="background-color: #808080;"> name </span> - name of user being deleted</p>
|
||||
<p><span style="background-color: #808080;"> attempt </span> - password of user being deleted</p>
|
||||
<blockquote>
|
||||
<p>Deletes a user with the password of the user as verification</p>
|
||||
</blockquote>
|
||||
<h2>/BankF/<span style="color: #993300;">admin</span>/user (DELETE)</h2>
|
||||
<p><span style="background-color: #808080;"> name </span> - name of user being deleted</p>
|
||||
<p><span style="background-color: #808080;"> attempt </span> - admin password</p>
|
||||
<blockquote>
|
||||
<p>Deletes a user with admin password as verification</p>
|
||||
</blockquote>
|
||||
</body>
|
||||
|
||||
<h1 class="code-line" data-line-start=0 data-line-end=1 ><a id="Error_Responses_0"></a>Error Responses</h1>
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>meaning</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>-1</td>
|
||||
<td>UserNotFound</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-2</td>
|
||||
<td>WrongPassword</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-3</td>
|
||||
<td>InvalidRequest</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-4</td>
|
||||
<td>WrongAdminPassword</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-5</td>
|
||||
<td>NameTooLong</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-6</td>
|
||||
<td>UserAlreadyExists</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-7</td>
|
||||
<td>InsufficientFunds</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h1 class="code-line" data-line-start=12 data-line-end=13 ><a id="Things_of_Note_12"></a>Things of Note</h1>
|
||||
<ul>
|
||||
<li class="has-line-data" data-line-start="13" data-line-end="14">all endpoints respond with <strong>JSON</strong> file type</li>
|
||||
<li class="has-line-data" data-line-start="14" data-line-end="16">"<strong>A</strong>" denotes requiring Authentication in the form of a header titled "<strong>Password</strong>"</li>
|
||||
</ul>
|
||||
<h1 class="code-line" data-line-start=16 data-line-end=17 ><a id="Usage_16"></a>Usage</h1>
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align:center">Name</th>
|
||||
<th style="text-align:left">Path</th>
|
||||
<th style="text-align:center">Method</th>
|
||||
<th style="text-align:center">A</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="text-align:center">GetBal</td>
|
||||
<td style="text-align:left">/{name}/bal</td>
|
||||
<td style="text-align:center">GET</td>
|
||||
<td style="text-align:center">true</td>
|
||||
<td>returns the balance of a given user <code>{name}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:center">GetLog</td>
|
||||
<td style="text-align:left">/{name}/log</td>
|
||||
<td style="text-align:center">GET</td>
|
||||
<td style="text-align:center">true</td>
|
||||
<td>returns a list of last <code>n</code> number of transactions (a configurable amount) of a given user <code>{name}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:center">SendFunds</td>
|
||||
<td style="text-align:left">/{name}/send/{to}/amount={amount}</td>
|
||||
<td style="text-align:center">POST</td>
|
||||
<td style="text-align:center">false</td>
|
||||
<td>sends <code>{amount}</code> from user <code>{name}</code> to user <code>{to}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:center">VerifyPassword</td>
|
||||
<td style="text-align:left">/{name}/pass/verify</td>
|
||||
<td style="text-align:center">GET</td>
|
||||
<td style="text-align:center">true</td>
|
||||
<td>returns <code>true</code> or <code>false</code> depending on if the supplied user <code>{name}</code>'s password matches the password supplied in the header</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h1 class="code-line" data-line-start=24 data-line-end=25 ><a id="Meta_Usage_24"></a>Meta Usage</h1>
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align:center">Name</th>
|
||||
<th style="text-align:left">Path</th>
|
||||
<th style="text-align:center">Method</th>
|
||||
<th style="text-align:center">A</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="text-align:center">ChangePassword</td>
|
||||
<td style="text-align:left">/{name}/pass/change</td>
|
||||
<td style="text-align:center">PATCH</td>
|
||||
<td style="text-align:center">true</td>
|
||||
<td>if the password supplied in the header matches the user <code>{name}</code>'s password, the user’s password is changed to the one given in the body</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:center">SetBal</td>
|
||||
<td style="text-align:left">/admin/{name}/bal/amount={amount}</td>
|
||||
<td style="text-align:center">PATCH</td>
|
||||
<td style="text-align:center">true</td>
|
||||
<td>sets the balance of a give user <code>{name}</code> if the supplied password matches the admin password</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h1 class="code-line" data-line-start=30 data-line-end=31 ><a id="System_Usage_30"></a>System Usage</h1>
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align:center">Name</th>
|
||||
<th style="text-align:left">Path</th>
|
||||
<th style="text-align:center">Method</th>
|
||||
<th style="text-align:center">A</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="text-align:center">Help</td>
|
||||
<td style="text-align:left">/help</td>
|
||||
<td style="text-align:center">GET</td>
|
||||
<td style="text-align:center">false</td>
|
||||
<td>the page you’re looking at right now!</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:center">Close</td>
|
||||
<td style="text-align:left">/admin/close</td>
|
||||
<td style="text-align:center">POST</td>
|
||||
<td style="text-align:center">true</td>
|
||||
<td>saves and then closes the program if the supplied password matches the admin password</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:center">Contains</td>
|
||||
<td style="text-align:left">/contains/{name}</td>
|
||||
<td style="text-align:center">GET</td>
|
||||
<td style="text-align:center">false</td>
|
||||
<td>returns <code>true</code> or <code>false</code> depending on if the supplied user <code>{name}</code> exists</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:center">AdminVerifyPass</td>
|
||||
<td style="text-align:left">/admin/verify</td>
|
||||
<td style="text-align:center">GET</td>
|
||||
<td style="text-align:center">true</td>
|
||||
<td>returns <code>true</code> or <code>false</code> depending on if the password supplied in the header matches the admin password</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h1 class="code-line" data-line-start=38 data-line-end=39 ><a id="User_Management_38"></a>User Management</h1>
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align:center">Name</th>
|
||||
<th style="text-align:left">Path</th>
|
||||
<th style="text-align:center">Method</th>
|
||||
<th style="text-align:center">A</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="text-align:center">AddUser</td>
|
||||
<td style="text-align:left">/user/{name}</td>
|
||||
<td style="text-align:center">POST</td>
|
||||
<td style="text-align:center">true</td>
|
||||
<td>registers a user with the name <code>{name}</code>, balance of 0 and a password of the password supplied in the header</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:center">AdminAddUser</td>
|
||||
<td style="text-align:left">/admin/user/{name}?init_bal={init_bal}</td>
|
||||
<td style="text-align:center">POST</td>
|
||||
<td style="text-align:center">true</td>
|
||||
<td>if the password supplied in the header matches the admin password, then it registers a user with the name <code>{name}</code>, balance of <code>init_bal</code> and a password supplied by the body of the request</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:center">DelUser</td>
|
||||
<td style="text-align:left">/user/{name}</td>
|
||||
<td style="text-align:center">DELETE</td>
|
||||
<td style="text-align:center">true</td>
|
||||
<td>if the password supplied in the header matches the user <code>{name}</code>'s password, then the user is deleted</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:center">AdminDelUser</td>
|
||||
<td style="text-align:left">/admin/user/{name}</td>
|
||||
<td style="text-align:center">DELETE</td>
|
||||
<td style="text-align:center">true</td>
|
||||
<td>if the password supplied in the header matches the admin password, then the user is deleted</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
45
help.md
Normal file
45
help.md
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
# Error Responses
|
||||
|
||||
| # | meaning |
|
||||
| --- | ------------------ |
|
||||
| -1 | UserNotFound |
|
||||
| -2 | WrongPassword |
|
||||
| -3 | InvalidRequest |
|
||||
| -4 | WrongAdminPassword |
|
||||
| -5 | NameTooLong |
|
||||
| -6 | UserAlreadyExists |
|
||||
| -7 | InsufficientFunds |
|
||||
|
||||
# Things of Note
|
||||
* all endpoints respond with **JSON** file type
|
||||
* "**A**" denotes requiring Authentication in the form of a header titled "**Password**"
|
||||
|
||||
# Usage
|
||||
| Name | Path | Method | A | Description |
|
||||
| :------------: | :-------------------------------- | :----: | :---: | --------------------------------------------------------------------------------------------------------------------------- |
|
||||
| GetBal | /{name}/bal | GET | true | returns the balance of a given user `{name}` |
|
||||
| GetLog | /{name}/log | GET | true | returns a list of last `n` number of transactions (a configurable amount) of a given user `{name}` |
|
||||
| SendFunds | /{name}/send/{to}/amount={amount} | POST | false | sends `{amount}` from user `{name}` to user `{to}` |
|
||||
| VerifyPassword | /{name}/pass/verify | GET | true | returns `true` or `false` depending on if the supplied user `{name}`'s password matches the password supplied in the header |
|
||||
|
||||
# Meta Usage
|
||||
| Name | Path | Method | A | Description |
|
||||
| :------------: | :-------------------------------- | :----: | :---: | ---------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| ChangePassword | /{name}/pass/change | PATCH | true | if the password supplied in the header matches the user `{name}`'s password, the user's password is changed to the one given in the body |
|
||||
| SetBal | /admin/{name}/bal/amount={amount} | PATCH | true | sets the balance of a give user `{name}` if the supplied password matches the admin password |
|
||||
|
||||
# System Usage
|
||||
| Name | Path | Method | A | Description |
|
||||
| :-------------: | :--------------- | :----: | :---: | -------------------------------------------------------------------------------------------------------- |
|
||||
| Help | /help | GET | false | the page you're looking at right now! |
|
||||
| Close | /admin/close | POST | true | saves and then closes the program if the supplied password matches the admin password |
|
||||
| Contains | /contains/{name} | GET | false | returns `true` or `false` depending on if the supplied user `{name}` exists |
|
||||
| AdminVerifyPass | /admin/verify | GET | true | returns `true` or `false` depending on if the password supplied in the header matches the admin password |
|
||||
|
||||
# User Management
|
||||
| Name | Path | Method | A | Description |
|
||||
| :----------: | :------------------------------------- | :----: | :---: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| AddUser | /user/{name} | POST | true | registers a user with the name `{name}`, balance of 0 and a password of the password supplied in the header |
|
||||
| AdminAddUser | /admin/user/{name}?init_bal={init_bal} | POST | true | if the password supplied in the header matches the admin password, then it registers a user with the name `{name}`, balance of `init_bal` and a password supplied by the body of the request |
|
||||
| DelUser | /user/{name} | DELETE | true | if the password supplied in the header matches the user `{name}`'s password, then the user is deleted |
|
||||
| AdminDelUser | /admin/user/{name} | DELETE | true | if the password supplied in the header matches the admin password, then the user is deleted |
|
||||
241
include/bank.hpp
241
include/bank.hpp
|
|
@ -2,6 +2,7 @@
|
|||
#include <fstream>
|
||||
#include <shared_mutex>
|
||||
#include "xxhash.h"
|
||||
#include "error_responses.hpp"
|
||||
#include "parallel-hashmap/parallel_hashmap/phmap.h"
|
||||
#include "user.hpp"
|
||||
|
||||
|
|
@ -32,125 +33,189 @@ private:
|
|||
public:
|
||||
std::string admin_pass;
|
||||
|
||||
bool AddUser(const std::string &name, std::string &&init_pass)
|
||||
int_fast8_t AddUser(const std::string &name, std::string &&init_pass)
|
||||
{
|
||||
if (name.size() > 50)
|
||||
if (name.size() > max_name_size)
|
||||
{
|
||||
return false;
|
||||
return ErrorResponse::NameTooLong;
|
||||
}
|
||||
std::shared_lock<std::shared_mutex> lock{size_l};
|
||||
return users.try_emplace_l(
|
||||
name, [](User &) {}, std::move(init_pass));
|
||||
}
|
||||
bool AdminAddUser(const std::string &attempt, std::string &&name, uint32_t init_bal, std::string &&init_pass)
|
||||
{
|
||||
if (name.size() > 50)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool state = (admin_pass == attempt);
|
||||
if (state)
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock{size_l};
|
||||
state = users.try_emplace_l(
|
||||
name, [](User &) {}, init_bal, std::move(init_pass));
|
||||
if (!users.try_emplace_l(
|
||||
name, [](User &) {}, std::move(init_pass)))
|
||||
{
|
||||
return ErrorResponse::UserAlreadyExists;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
int_fast8_t AdminAddUser(const std::string &attempt, std::string &&name, uint32_t init_bal, std::string &&init_pass)
|
||||
{
|
||||
if (name.size() > max_name_size)
|
||||
{
|
||||
return ErrorResponse::NameTooLong;
|
||||
}
|
||||
if (admin_pass != attempt)
|
||||
{
|
||||
return ErrorResponse::WrongAdminPassword;
|
||||
}
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock{size_l};
|
||||
if (!users.try_emplace_l(
|
||||
name, [](User &) {}, init_bal, std::move(init_pass)))
|
||||
{
|
||||
return ErrorResponse::UserAlreadyExists;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
bool DelUser(const std::string &name, const std::string &attempt)
|
||||
int_fast8_t DelUser(const std::string &name, const std::string &attempt)
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock{size_l};
|
||||
return users.erase_if(name, [&attempt](User &u) { return (XXH3_64bits(attempt.data(), attempt.size()) == u.password); });
|
||||
bool state = false;
|
||||
if (!users.erase_if(name, [&state, &attempt](User &u) { return state = (XXH3_64bits(attempt.data(), attempt.size()) == u.password); }))
|
||||
{
|
||||
return ErrorResponse::UserNotFound;
|
||||
}
|
||||
else
|
||||
{
|
||||
return state * ErrorResponse::WrongPassword;
|
||||
}
|
||||
}
|
||||
bool AdminDelUser(const std::string &name, const std::string &attempt)
|
||||
int_fast8_t AdminDelUser(const std::string &name, const std::string &attempt)
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock{size_l};
|
||||
return users.erase_if(name, [this, &attempt](const User &) { return (admin_pass == attempt); });
|
||||
bool state = false;
|
||||
if (!users.erase_if(name, [&state, this, &attempt](const User &) { return state = (admin_pass == attempt); }))
|
||||
{
|
||||
return ErrorResponse::UserNotFound;
|
||||
}
|
||||
else
|
||||
{
|
||||
return state * ErrorResponse::WrongAdminPassword;
|
||||
}
|
||||
}
|
||||
|
||||
bool SendFunds(const std::string &a_name, const std::string &b_name, uint32_t amount, const std::string &attempt)
|
||||
int_fast8_t SendFunds(const std::string &a_name, const std::string &b_name, uint32_t amount, const std::string &attempt)
|
||||
{
|
||||
//cant send money to self, from self or amount is 0
|
||||
if (a_name == b_name || !amount)
|
||||
{
|
||||
return false;
|
||||
return ErrorResponse::InvalidRequest;
|
||||
}
|
||||
|
||||
//if A exists, A can afford it, and A's password matches
|
||||
bool state = false;
|
||||
int_fast8_t state = false;
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock{send_funds_l}; //because SendFunds requires 3 locking operations
|
||||
users.modify_if(a_name, [&state, amount, &attempt](User &a) {
|
||||
if (state = (a.balance >= amount) && (a.password == XXH3_64bits(attempt.data(), attempt.size())))
|
||||
{
|
||||
a.balance -= amount;
|
||||
}
|
||||
});
|
||||
|
||||
if (state)
|
||||
if (users.modify_if(a_name, [&state, amount, &attempt](User &a) {
|
||||
//if A exists, A can afford it, and A's password matches
|
||||
if (a.balance < amount)
|
||||
{
|
||||
state = ErrorResponse::InsufficientFunds;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (a.password != XXH3_64bits(attempt.data(), attempt.size()))
|
||||
{
|
||||
state = ErrorResponse::WrongPassword;
|
||||
}
|
||||
else
|
||||
{
|
||||
a.balance -= amount;
|
||||
state = true;
|
||||
}
|
||||
}
|
||||
}))
|
||||
{
|
||||
//if B doesnt exist
|
||||
if (!users.modify_if(b_name, [amount](User &b) {
|
||||
b.balance += amount;
|
||||
}))
|
||||
return ErrorResponse::UserNotFound;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!state)
|
||||
{
|
||||
//attempt to refund if A exist
|
||||
users.modify_if(a_name, [amount](User &a) {
|
||||
a.balance += amount;
|
||||
});
|
||||
return false; //because had to refund transaction
|
||||
return state;
|
||||
}
|
||||
else
|
||||
{
|
||||
//if B doesnt exist
|
||||
if (!users.modify_if(b_name, [amount](User &b) {
|
||||
b.balance += amount;
|
||||
}))
|
||||
{
|
||||
//attempt to refund if A exist
|
||||
users.modify_if(a_name, [amount](User &a) {
|
||||
a.balance += amount;
|
||||
});
|
||||
return ErrorResponse::UserNotFound; //because had to refund transaction
|
||||
}
|
||||
else
|
||||
{
|
||||
if constexpr (max_log_size)
|
||||
{
|
||||
Transaction temp(a_name, b_name, amount);
|
||||
Transaction temp2 = temp;
|
||||
users.modify_if(a_name, [&temp](User &a) {
|
||||
a.log.AddTrans(std::move(temp));
|
||||
});
|
||||
users.modify_if(b_name, [&temp2](User &b) {
|
||||
b.log.AddTrans(std::move(temp2));
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if constexpr (max_log_size)
|
||||
{
|
||||
if (state)
|
||||
{
|
||||
Transaction temp(a_name, b_name, amount);
|
||||
Transaction temp2 = temp;
|
||||
users.modify_if(a_name, [&temp](User &a) {
|
||||
a.log.AddTrans(std::move(temp));
|
||||
});
|
||||
users.modify_if(b_name, [&temp2](User &b) {
|
||||
b.log.AddTrans(std::move(temp2));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
bool Contains(const std::string &name) const
|
||||
{
|
||||
return users.contains(name);
|
||||
}
|
||||
bool SetBal(const std::string &name, const std::string &attempt, uint32_t amount)
|
||||
{
|
||||
bool state = (admin_pass == attempt);
|
||||
if (state)
|
||||
{
|
||||
users.modify_if(name, [amount](User &u) {
|
||||
u.balance = amount;
|
||||
});
|
||||
}
|
||||
return state;
|
||||
}
|
||||
bool AdminVerifyPass(const std::string &attempt)
|
||||
{
|
||||
return admin_pass == attempt;
|
||||
return (admin_pass != attempt);
|
||||
}
|
||||
|
||||
int_fast8_t SetBal(const std::string &name, const std::string &attempt, uint32_t amount)
|
||||
{
|
||||
if (admin_pass != attempt)
|
||||
{
|
||||
return ErrorResponse::WrongAdminPassword;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!users.modify_if(name, [amount](User &u) {
|
||||
u.balance = amount;
|
||||
}))
|
||||
{
|
||||
return ErrorResponse::UserNotFound;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
int_fast64_t GetBal(const std::string &name) const
|
||||
{
|
||||
int_fast64_t res = -1;
|
||||
int_fast64_t res = ErrorResponse::UserNotFound;
|
||||
users.if_contains(name, [&res](const User &u) {
|
||||
res = u.balance;
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
int_fast8_t VerifyPassword(const std::string &name, const std::string &attempt) const
|
||||
{
|
||||
int_fast8_t res = -1;
|
||||
int_fast8_t res = ErrorResponse::UserNotFound;
|
||||
users.if_contains(name, [&res, &attempt](const User &u) {
|
||||
res = u.password == XXH3_64bits(attempt.data(), attempt.size());
|
||||
});
|
||||
|
|
@ -158,10 +223,13 @@ public:
|
|||
}
|
||||
int_fast8_t ChangePassword(const std::string &name, const std::string &attempt, std::string &&new_pass)
|
||||
{
|
||||
int_fast8_t res = -1;
|
||||
int_fast8_t res = ErrorResponse::UserNotFound;
|
||||
users.modify_if(name, [&res, &attempt, &new_pass](User &u) {
|
||||
res = (u.password == XXH3_64bits(attempt.data(), attempt.size()));
|
||||
if (res)
|
||||
if (u.password != XXH3_64bits(attempt.data(), attempt.size()))
|
||||
{
|
||||
res = ErrorResponse::WrongPassword;
|
||||
}
|
||||
else
|
||||
{
|
||||
u.password = XXH3_64bits(new_pass.data(), new_pass.size());
|
||||
}
|
||||
|
|
@ -175,7 +243,7 @@ public:
|
|||
if (!users.if_contains(name, [&res, &attempt](const User &u) {
|
||||
if (u.password != XXH3_64bits(attempt.data(), attempt.size()))
|
||||
{
|
||||
res = 0;
|
||||
res = ErrorResponse::WrongPassword;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -191,17 +259,13 @@ public:
|
|||
}
|
||||
}))
|
||||
{
|
||||
return -1;
|
||||
return ErrorResponse::UserNotFound;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void Save()
|
||||
{
|
||||
Json::StreamWriterBuilder builder;
|
||||
const std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());
|
||||
|
||||
std::ofstream user_save("../users.json");
|
||||
Json::Value temp;
|
||||
|
||||
//loading info into json temp
|
||||
|
|
@ -217,9 +281,16 @@ public:
|
|||
}
|
||||
if (!temp.isNull())
|
||||
{
|
||||
std::ofstream user_save("../users.json");
|
||||
Json::StreamWriterBuilder builder;
|
||||
const std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());
|
||||
writer->write(temp, &user_save);
|
||||
user_save.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::invalid_argument("Saving Failed\n");
|
||||
}
|
||||
user_save.close();
|
||||
}
|
||||
|
||||
//NOT THREAD SAFE, BY NO MEANS SHOULD THIS BE CALLED WHILE RECEIEVING REQUESTS
|
||||
|
|
@ -234,8 +305,8 @@ public:
|
|||
if (!parseFromStream(builder, user_save, &temp, &errs))
|
||||
{
|
||||
std::cerr << errs << '\n';
|
||||
throw std::invalid_argument("Parsing Failed\n");
|
||||
user_save.close();
|
||||
throw std::invalid_argument("Parsing Failed\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -254,3 +325,5 @@ public:
|
|||
}
|
||||
}
|
||||
} bank;
|
||||
|
||||
//TODO make branchless
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -3,3 +3,4 @@
|
|||
// Setting both values to 0 does not compile logging
|
||||
constexpr unsigned max_log_size = 100;
|
||||
constexpr unsigned pre_log_size = 10;
|
||||
constexpr unsigned max_name_size = 50;
|
||||
11
include/error_responses.hpp
Normal file
11
include/error_responses.hpp
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
enum ErrorResponse
|
||||
{
|
||||
UserNotFound = -1,
|
||||
WrongPassword = -2,
|
||||
InvalidRequest = -3,
|
||||
WrongAdminPassword = -4,
|
||||
NameTooLong = -5,
|
||||
UserAlreadyExists = -6,
|
||||
InsufficientFunds = -7,
|
||||
};
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include "log_consts.hpp"
|
||||
#include "consts.hpp"
|
||||
#include "transactions.hpp"
|
||||
|
||||
struct Log
|
||||
|
|
|
|||
27
services.md
Normal file
27
services.md
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# Connected Services
|
||||
|
||||
### Implemented:
|
||||
|
||||
- [Web Frontend](https://github.com/Expand-sys/ccashfrontend)
|
||||

|
||||
- [CC Frontend](https://github.com/Reactified/rpm/blob/main/packages/ccash-wallet)
|
||||
|
||||

|
||||
- [CC Shop](https://github.com/Reactified/rpm/tree/main/packages/ccash-shop)
|
||||

|
||||

|
||||
- [CC ATM](https://github.com/Reactified/misc/tree/main/lua/ccash-bank) an ATM for economies allowing for an initial exchange to start up
|
||||

|
||||
- [CC API](https://github.com/Reactified/rpm/blob/main/packages/ccash-api/api.lua)
|
||||
|
||||
### In-Dev:
|
||||
|
||||
- [a Market](https://github.com/STBoyden/market-api-2.0)
|
||||
- [Python API](https://github.com/fearlessdoggo21/ccashpythonclient)
|
||||
|
||||
### Ideas:
|
||||
|
||||
- Gambling
|
||||
- Shipping
|
||||
- High-level bank operations such as loans
|
||||
- Some trust based system for transactions similiar to Paypal
|
||||
Loading…
Reference in a new issue