This commit is contained in:
UnitedAirforce
2025-11-28 06:54:41 +08:00
parent 4d527a098a
commit fceb34944a
10 changed files with 25 additions and 31 deletions

View File

@@ -9,13 +9,13 @@ from api.database import player_database, accounts, results, devices, whitelists
from api.misc import crc32_decimal
TABLE_MAP = {
"accounts": (accounts, ["id", "username", "password_hash", "save_crc", "save_timestamp", "save_id", "coin_mp", "title", "avatar", "created_at", "updated_at"]),
"results": (results, ["id", "device_id", "stts", "song_id", "mode", "avatar", "score", "high_score", "play_rslt", "item", "os", "os_ver", "ver", "created_at", "updated_at"]),
"devices": (devices, ["device_id", "user_id", "my_stage", "my_avatar", "item", "daily_day", "coin", "lvl", "title", "avatar", "mobile_sum", "arcade_sum", "total_sum", "created_at", "updated_at", "last_login_at"]),
"accounts": (accounts, ["id", "username", "password_hash", "save_crc", "save_timestamp", "save_id", "coin_mp", "title", "avatar", "mobile_delta", "arcade_delta", "total_delta", "created_at", "updated_at"]),
"results": (results, ["id", "device_id", "stts", "song_id", "mode", "avatar", "score", "high_score", "play_rslt", "item", "os", "os_ver", "ver", "created_at"]),
"devices": (devices, ["device_id", "user_id", "my_stage", "my_avatar", "item", "daily_day", "coin", "lvl", "title", "avatar", "created_at", "updated_at", "last_login_at"]),
"whitelist": (whitelists, ["id", "device_id"]),
"blacklist": (blacklists, ["id", "ban_terms", "reason"]),
"batch_tokens": (batch_tokens, ["id", "batch_token", "expire_at", "uses_left", "auth_id", "created_at", "updated_at"]),
"binds": (binds, ["id", "user_id", "bind_account", "bind_code", "is_verified", "auth_token", "created_at", "updated_at"]),
"binds": (binds, ["id", "user_id", "bind_account", "bind_code", "is_verified", "auth_token", "bind_date"]),
"webs": (webs, ["id", "user_id", "permission", "web_token", "last_save_export", "created_at", "updated_at"]),
"logs": (logs, ["id", "user_id", "filename", "filesize", "timestamp"]),
}

View File

@@ -28,11 +28,16 @@ async def batch_handler(request: Request):
if result['expire_at'] < int(time.time()):
return HTMLResponse(content="Token expired", status_code=400)
if result['uses_left'] <= 0:
return HTMLResponse(content="No uses left for this token", status_code=400)
uses_left = result['uses_left']
if uses_left > 0:
uses_left -= 1
else:
uses_left = -1
return HTMLResponse(content="No uses left", status_code=400)
update_query = batch_tokens.update().where(batch_tokens.c.token == token).values(
uses_left=result['uses_left'] - 1,
uses_left=uses_left,
updated_at=datetime.utcnow()
)
await player_database.execute(update_query)

View File

@@ -20,7 +20,7 @@ async def serve_file(request: Request):
if not filename.endswith(".zip") and not filename.endswith(".pak"):
return Response("Unauthorized", status_code=403)
existing_batch_token = select(batch_tokens).where(batch_tokens.c.batch_token == auth_token)
existing_batch_token = select(batch_tokens).where((batch_tokens.c.batch_token == auth_token) & (batch_tokens.c.uses_left > -1))
batch_result = await player_database.fetch_one(existing_batch_token)
if batch_result:
pass

View File

@@ -6,9 +6,8 @@ import secrets
import bcrypt
import hashlib
import re
import aiofiles
import xml.etree.ElementTree as ET
from config import MODEL, TUNEFILE, SKIN, AUTHORIZATION_NEEDED, AUTHORIZATION_MODE, GRANDFATHERED_ACCOUNT_LIMIT
from config import MODEL, TUNEFILE, SKIN, AUTHORIZATION_NEEDED, AUTHORIZATION_MODE, GRANDFATHERED_ACCOUNT_LIMIT, BIND_SALT
from api.database import get_bind, check_whitelist, check_blacklist, decrypt_fields_to_user_info, user_id_to_user_info_simple
FMAX_VER = None
@@ -66,7 +65,6 @@ def verify_password(password, hashed_password):
if type(hashed_password) == str:
hashed_password = hashed_password.encode('utf-8')
print("hashed_password:", hashed_password)
return bcrypt.checkpw(password.encode('utf-8'), hashed_password)
def is_alphanumeric(username):
@@ -281,12 +279,11 @@ async def should_serve_web(user_id):
return should_serve
async def generate_salt(user_id):
SALT = "jHENR3wq$zX9@LpO"
user_info = await user_id_to_user_info_simple(user_id)
user_pw_hash = user_info['password_hash']
username = user_info['username']
combined = f"{username}{user_id}{user_pw_hash}{SALT}".encode('utf-8')
combined = f"{username}{user_id}{user_pw_hash}{BIND_SALT}".encode('utf-8')
crc32_hash = binascii.crc32(combined) & 0xFFFFFFFF
return str(crc32_hash)

View File

@@ -259,8 +259,6 @@ async def user_ranking_individual(request: Request):
}
}
print("toital_count: " + str(total_count))
return JSONResponse(payload)
async def user_ranking_total(request: Request):
@@ -316,7 +314,6 @@ async def user_ranking_total(request: Request):
await write_rank_cache(cache_key, records, expire_seconds=120)
total_count = len(records)
print("total_count fetched: " + str(total_count))
for index, record in enumerate(records):
if index >= page_number * page_count and index < (page_number + 1) * page_count:
rank_user = await user_id_to_user_info_simple(record["id"])

View File

@@ -81,7 +81,6 @@ async def api_shop_player_data(request: Request):
item_id for item_id in range(item_low_end, item_high_end)
]
print(my_stage)
if 700 in my_stage and os.path.isfile('./files/4max_ver.txt'):
is_fmax_purchased = True
@@ -263,7 +262,6 @@ async def api_shop_purchase_item(request: Request):
return JSONResponse({"state": 0, "message": "EXTRA already owned. Exit the shop and it will be added to the game."}, status_code=400)
if price > device_info['coin']:
print("Insufficient coins for purchase.")
return JSONResponse({"state": 0, "message": "Insufficient coins."}, status_code=400)
new_coin_amount = device_info['coin'] - price

View File

@@ -113,8 +113,6 @@ async def start(request: Request):
my_stage, my_avatar = await get_user_entitlement_from_devices(user_id)
coin = device_info['coin'] if device_info is not None else 0
print("user has entitlements:", my_stage, my_avatar)
elif device_info:
# This is a guest user with existing data
my_avatar = set(device_info['my_avatar']) if device_info['my_avatar'] else START_AVATARS

View File

@@ -67,6 +67,7 @@ SMTP_PASSWORD = "test"
# For auth mode 2
DISCORD_BOT_SECRET = "test"
DISCORD_BOT_API_KEY = "test"
BIND_SALT = "SET YOUR SALT HERE"
# Daily download limit per account in bytes (only activates for AUTHORIZATION_MODE 1 and 2)

View File

@@ -73,9 +73,9 @@
</button>
<div class="collapse navbar-collapse" id="mainNavbar">
<ul class="navbar-nav ms-4">
<li class="nav-item"><a class="nav-link" href="#" id="usersTab">Users</a></li>
<li class="nav-item"><a class="nav-link" href="#" id="accountsTab">Accounts</a></li>
<li class="nav-item"><a class="nav-link" href="#" id="resultsTab">Results</a></li>
<li class="nav-item"><a class="nav-link" href="#" id="dailyRewardsTab">DailyRewards</a></li>
<li class="nav-item"><a class="nav-link" href="#" id="devicesTab">Devices</a></li>
<li class="nav-item"><a class="nav-link" href="#" id="whitelistTab">Whitelist</a></li>
<li class="nav-item"><a class="nav-link" href="#" id="blacklistTab">Blacklist</a></li>
<li class="nav-item"><a class="nav-link" href="#" id="batchTokensTab">BatchTokens</a></li>
@@ -196,7 +196,7 @@ function showTable(tabName) {
responsiveLayout: "collapse",
sortMode: "remote",
autoColumnsDefinitions: function(definitions){
if (tabName === "users") {
if (tabName === "accounts") {
definitions.push({
title: "data",
field: "__data",
@@ -281,7 +281,7 @@ function showTable(tabName) {
}
return value;
};
if (col.field !== "id" && col.field !== "objectId" && col.field !== "__delete" && col.field !== "__data") {
if (col.field !== "id" && col.field !== "__delete" && col.field !== "__data") {
col.editor = function(cell, onRendered, success, cancel){
const value = cell.getValue();
let input;
@@ -473,13 +473,13 @@ document.getElementById('dataModalSaveBtn').onclick = async function() {
}
};
document.getElementById('usersTab').onclick = () => showTable("users");
document.getElementById('accountsTab').onclick = () => showTable("accounts");
document.getElementById('resultsTab').onclick = () => showTable("results");
document.getElementById('dailyRewardsTab').onclick = () => showTable("daily_rewards");
document.getElementById('devicesTab').onclick = () => showTable("devices");
document.getElementById('whitelistTab').onclick = () => showTable("whitelist");
document.getElementById('blacklistTab').onclick = () => showTable("blacklist");
document.getElementById('batchTokensTab').onclick = () => showTable("batch_tokens");
document.getElementById('bindTab').onclick = () => showTable("bind");
document.getElementById('bindTab').onclick = () => showTable("binds");
document.getElementById('logsTab').onclick = () => showTable("logs");
document.getElementById('logoutBtn').addEventListener('click', function() {
@@ -570,12 +570,12 @@ document.getElementById('insertRowForm').onsubmit = async function(e) {
}
};
const validTabs = ["users", "results", "daily_rewards", "whitelist", "blacklist", "batch_tokens", "bind", "logs"];
const validTabs = ["accounts", "results", "devices", "whitelist", "blacklist", "batch_tokens", "binds", "logs"];
const lastTab = getCookie("lastTab");
if (validTabs.includes(lastTab)) {
showTable(lastTab);
} else {
showTable("users");
showTable("accounts");
}
function getCookie(name) {

View File

@@ -161,8 +161,6 @@
}
}
document.addEventListener("DOMContentLoaded", fetchUserData);
</script>
</body>