cpp-login-menu
cpp-login-menu copied to clipboard
A simple and ready-to-use ImGui login menu with a fully functioning NodeJS Server for storing user info using SQLite.
cpp-login-menu
A simple and ready-to-use ImGui login menu with a fully functioning NodeJS Server for securely storing and accessing user info using SQLite.
SQLite Database Structure
Column | Type | Details |
---|---|---|
License | TEXT UNIQUE | For storing uuid4 serials. |
Username | TEXT UNIQUE | For storing users usernames. |
Password | TEXT | MD5 Password for hash authentication. |
HWID | TEXT | MD5 Hardware Identifier to lock a license to a single PC. |
LastLogin | TEXT | Time of last users login. |
LastIP | TEXT | Most recent IP the user logged in with. |
Expiry | TEXT | Expiry date of the license. |
UserVar | TEXT | User variable that can be set to anything. |
Rank | INTEGER | Rank of license. |
LastReset | TEXT | Stores the last HWID reset time for cooldown period. |
Database Commands
These are a list of functions that can be performed on the database to insert, modify, or delete table entries. You can test most of these functions in Server.js or also use a REST Client to test the HTTP Request (use /admin route to bypass encryption). I plan on adding some kind of Admin Panel built into the menu to have control of all these callbacks
Each command will take the form:
module.exports = {
name:"login", //the command name to be reference in the request ex. {"command": "login"}
adminOnly: false, //declare if the function can be only accessed with API Token
execute(db,body,out_obj,adminMode){//see below
db is the working sqlite database.
body is the incoming request body (JSON Object).
out_obj is the outgoing response JSON object (Use this to pass any data from the database to your client)
adminMode When true, certain commands will not have cooldown/argument restrictions (resethwid, resetpw)
ChangePassword.js
Name: resetpw
body: username, license, newPassword
Changes the password of the table entry where both username and license are found.
ChangeRank.js (Admin Only)
Name: rank
body: username,newRank
Changes the rank of the table entry where username is found.
CreateDB.js (Admin Only) **
Name: create
This function should only be called once if you want to create a new database.
ExtendLicense.js (Admin Only)
Name: extend
body: username, extendBy
Extends the expiry date of the table entry where username is found. extendBy takes days.
GenerateKey.js (Admin Only)
Name: generate
body: length, rank
Inserts a new license key into the table with length (in days) and rank.
Login.js
Name: login
body: username, password, HWID
Returns rank, user variable, expiry date, and login success if an entry is found in the table.
LookupUser.js (Admin Only)
Name: find
body: entry
Returns all key/value data of a user where either username or license are found in the table.
Redeem.js
Name: redeem
body: username, password, hwid, license
Populates an entry in the table where license is found.
ResetHWID.js (AdminOnly)
Name: resethwid
body: username, password (not required if calling from admin route)
Resets the HWID of an entry in the table where username is found. The HWID reset cooldown can be set in config.json.
ShowAllUsers.js (AdminOnly)
Name: show
body: n/a
Returns an array of objects of all entries in the table.
REST API Calls
To test any of the commands, simply provide the command name and the respective fields for each function (shown above). To test the calls w/o encryption, use the /admin endpoint instead of /post. Body of your request should be in JSON format.
Generating a key
POST http://localhost:80/admin
HTTP/1.1 content-type: application/json
Authorization: API_TOKEN
{
"command": "generate",
"length": "90",
"rank": "2",
"quantity": "1"
}
Changing users rank
POST http://localhost:80/admin
HTTP/1.1 content-type: application/json
Authorization: API_TOKEN
{
"command": "rank",
"username": "fsalinas26",
"newRank": "2"
}
Your API_TOKEN is declared in config.json and should be a random string of characters strictly for admin access.
HTTP Request C++
Each request to the server will look similar. The content-type is application/x-www-form-urlencoded.
Example of login request
request.add_field("command", c_crypto::encrypt("login", g_crypto.key, g_crypto.iv).c_str()); //command name to process
request.add_field("username", c_crypto::encrypt(username, g_crypto.key, g_crypto.iv).c_str());
request.add_field("password", c_crypto::encrypt(c_crypto::MD5_HASH(password), g_crypto.key, g_crypto.iv).c_str());
request.add_field("hwid", c_crypto::encrypt(c_crypto::MD5_HASH(HWID), g_crypto.key, g_crypto.iv).c_str());
request.add_field("token", c_crypto::encrypt(g_crypto.token, g_crypto.key, g_crypto.iv).c_str());
request.add_field("iv", (g_crypto.iv).c_str());
string tempRes;
vector<wstring> headers = { PUBLIC_TOKEN };
send.post(L"http://localhost/post", tempRes, request, headers);
Client Sends (encoded in x-www-form-urlencoded)...
command=09i_bfA6N4jXPIAw3BlROQ&username=GSAPIBQPtX41HpyrjS5QQg&password=AauvnS62Zak5hXh7dlTVzgg2RrNbj0qj7_btyVoVoILwi1iRTJHDPQLPLJ-CiDGg&hwid=VoQq3PCzdNpOiNxObbdaQhWriuiG0-X5zaUtb_UsJWBkAlZITieRPKamDvneEBbP&token=cc5peF3JrISAlIFRs5YzHLlnQWDIHeQ8L5zkKoc0mss&iv=uz3ubFnxgvXIStPXmnza0w
Server Receives...
{
command: 'Pwn--MvlX_K_Krm9z2mXjA',
username: 'hL6grsJbu9TGp0jWnmIhIw',
password: 'h8p97AgXxlk8Ioy4dVDF1wEVxQXQ7oYDsR-AFvKLZcK97wpAsPQywjnrF-tChQDj',
hwid: 'jYaktfdazKlC-RUVhkmG1X2aPyUFTGJDe5gO1OtIiR2zYj8gZxXH3m05BTMcdW5w',
token: 'm2BLP2fsWgthAmFdCyMb_VIQ7XK-2S2f1BNG2SsthJ8',
iv: 'u47uPTJ122TGXHL3PiQ_7w'
}
After Decryption...
{
command: 'login',
username: 'fsalinas12',
password: '052A1A3C0142AD636571F88EA2506EAC',
hwid: 'B689E0F6033D6369780DD6E649A0DA29',
token: 'G5uqEUETtZvyQkuLvNO84A',
iv: 'u47uPTJ122TGXHL3PiQ_7w'
}
Encryption
The body of each HTTP request and response is encrypted using AES-256-CBC with a randomly generated session IV that is initialized from the server. Both client and server will have a shared secret key. Each generated IV is stored in memory on the server and will become invalid after 30 seconds or destroyed after single use.
Each client request will include a randomly generated sequence of bytes encrypted using the session IV, which the server will decrypt for the client to compare.
I made this visual to show how the client communicates with the server.