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 from api.misc import crc32_decimal
TABLE_MAP = { TABLE_MAP = {
"accounts": (accounts, ["id", "username", "password_hash", "save_crc", "save_timestamp", "save_id", "coin_mp", "title", "avatar", "created_at", "updated_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", "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", "mobile_sum", "arcade_sum", "total_sum", "created_at", "updated_at", "last_login_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"]), "whitelist": (whitelists, ["id", "device_id"]),
"blacklist": (blacklists, ["id", "ban_terms", "reason"]), "blacklist": (blacklists, ["id", "ban_terms", "reason"]),
"batch_tokens": (batch_tokens, ["id", "batch_token", "expire_at", "uses_left", "auth_id", "created_at", "updated_at"]), "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"]), "webs": (webs, ["id", "user_id", "permission", "web_token", "last_save_export", "created_at", "updated_at"]),
"logs": (logs, ["id", "user_id", "filename", "filesize", "timestamp"]), "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()): if result['expire_at'] < int(time.time()):
return HTMLResponse(content="Token expired", status_code=400) return HTMLResponse(content="Token expired", status_code=400)
if result['uses_left'] <= 0: uses_left = result['uses_left']
return HTMLResponse(content="No uses left for this token", status_code=400) 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( 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() updated_at=datetime.utcnow()
) )
await player_database.execute(update_query) 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"): if not filename.endswith(".zip") and not filename.endswith(".pak"):
return Response("Unauthorized", status_code=403) 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) batch_result = await player_database.fetch_one(existing_batch_token)
if batch_result: if batch_result:
pass pass

View File

@@ -6,9 +6,8 @@ import secrets
import bcrypt import bcrypt
import hashlib import hashlib
import re import re
import aiofiles
import xml.etree.ElementTree as ET 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 from api.database import get_bind, check_whitelist, check_blacklist, decrypt_fields_to_user_info, user_id_to_user_info_simple
FMAX_VER = None FMAX_VER = None
@@ -66,7 +65,6 @@ def verify_password(password, hashed_password):
if type(hashed_password) == str: if type(hashed_password) == str:
hashed_password = hashed_password.encode('utf-8') hashed_password = hashed_password.encode('utf-8')
print("hashed_password:", hashed_password)
return bcrypt.checkpw(password.encode('utf-8'), hashed_password) return bcrypt.checkpw(password.encode('utf-8'), hashed_password)
def is_alphanumeric(username): def is_alphanumeric(username):
@@ -281,12 +279,11 @@ async def should_serve_web(user_id):
return should_serve return should_serve
async def generate_salt(user_id): async def generate_salt(user_id):
SALT = "jHENR3wq$zX9@LpO"
user_info = await user_id_to_user_info_simple(user_id) user_info = await user_id_to_user_info_simple(user_id)
user_pw_hash = user_info['password_hash'] user_pw_hash = user_info['password_hash']
username = user_info['username'] 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 crc32_hash = binascii.crc32(combined) & 0xFFFFFFFF
return str(crc32_hash) 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) return JSONResponse(payload)
async def user_ranking_total(request: Request): 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) await write_rank_cache(cache_key, records, expire_seconds=120)
total_count = len(records) total_count = len(records)
print("total_count fetched: " + str(total_count))
for index, record in enumerate(records): for index, record in enumerate(records):
if index >= page_number * page_count and index < (page_number + 1) * page_count: if index >= page_number * page_count and index < (page_number + 1) * page_count:
rank_user = await user_id_to_user_info_simple(record["id"]) 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) 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'): if 700 in my_stage and os.path.isfile('./files/4max_ver.txt'):
is_fmax_purchased = True 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) 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']: if price > device_info['coin']:
print("Insufficient coins for purchase.")
return JSONResponse({"state": 0, "message": "Insufficient coins."}, status_code=400) return JSONResponse({"state": 0, "message": "Insufficient coins."}, status_code=400)
new_coin_amount = device_info['coin'] - price 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) my_stage, my_avatar = await get_user_entitlement_from_devices(user_id)
coin = device_info['coin'] if device_info is not None else 0 coin = device_info['coin'] if device_info is not None else 0
print("user has entitlements:", my_stage, my_avatar)
elif device_info: elif device_info:
# This is a guest user with existing data # This is a guest user with existing data
my_avatar = set(device_info['my_avatar']) if device_info['my_avatar'] else START_AVATARS 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 # For auth mode 2
DISCORD_BOT_SECRET = "test" DISCORD_BOT_SECRET = "test"
DISCORD_BOT_API_KEY = "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) # Daily download limit per account in bytes (only activates for AUTHORIZATION_MODE 1 and 2)

View File

@@ -73,9 +73,9 @@
</button> </button>
<div class="collapse navbar-collapse" id="mainNavbar"> <div class="collapse navbar-collapse" id="mainNavbar">
<ul class="navbar-nav ms-4"> <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="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="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="blacklistTab">Blacklist</a></li>
<li class="nav-item"><a class="nav-link" href="#" id="batchTokensTab">BatchTokens</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", responsiveLayout: "collapse",
sortMode: "remote", sortMode: "remote",
autoColumnsDefinitions: function(definitions){ autoColumnsDefinitions: function(definitions){
if (tabName === "users") { if (tabName === "accounts") {
definitions.push({ definitions.push({
title: "data", title: "data",
field: "__data", field: "__data",
@@ -281,7 +281,7 @@ function showTable(tabName) {
} }
return value; 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){ col.editor = function(cell, onRendered, success, cancel){
const value = cell.getValue(); const value = cell.getValue();
let input; 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('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('whitelistTab').onclick = () => showTable("whitelist");
document.getElementById('blacklistTab').onclick = () => showTable("blacklist"); document.getElementById('blacklistTab').onclick = () => showTable("blacklist");
document.getElementById('batchTokensTab').onclick = () => showTable("batch_tokens"); 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('logsTab').onclick = () => showTable("logs");
document.getElementById('logoutBtn').addEventListener('click', function() { 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"); const lastTab = getCookie("lastTab");
if (validTabs.includes(lastTab)) { if (validTabs.includes(lastTab)) {
showTable(lastTab); showTable(lastTab);
} else { } else {
showTable("users"); showTable("accounts");
} }
function getCookie(name) { function getCookie(name) {

View File

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