This commit is contained in:
UnitedAirforce
2025-12-01 18:30:06 +08:00
parent 3dc00bab0d
commit cf409d78a1
8 changed files with 54 additions and 50 deletions

View File

@@ -323,7 +323,7 @@ async def ttag(request: Request):
bind_state = await get_bind(user_id)
if bind_state and bind_state['is_verified'] == 1:
bind_element = f'<p>Email verified: {bind_state["bind_acc"]}\nTo remove a bind, contact the administrator.</p>'
bind_element = f'<p>Email verified: {bind_state["bind_account"]}\nTo remove a bind, contact the administrator.</p>'
else:
bind_element = f"""
<form action="/send_email/?{original_field}" method="post">
@@ -348,9 +348,9 @@ async def ttag(request: Request):
elif AUTHORIZATION_MODE == 2:
bind_state = await get_bind(user_id)
bind_code = await generate_salt(username, user_id)
bind_code = await generate_salt(user_id)
if bind_state and bind_state['is_verified'] == 1:
bind_element = f'<p>Discord verified: {bind_state["bind_acc"]}<br>To remove a bind, contact the administrator.</p>'
bind_element = f'<p>Discord verified: {bind_state["bind_account"]}<br>To remove a bind, contact the administrator.</p>'
else:
bind_element = f"""
<p>To receive a verification code, please join our Discord server 'https://discord.gg/vugfJdc2rk' and use the !bind command with your account name and the following code. Do not leak this code to others.</p>

View File

@@ -49,7 +49,7 @@ async def verify_user(request: Request):
if not decrypted_fields:
return inform_page("FAILED:<br>Invalid request data.", 0)
account_record, device_record = await decrypt_fields_to_user_info(decrypted_fields)
account_record, _ = await decrypt_fields_to_user_info(decrypted_fields)
if not account_record:
return inform_page("FAILED:<br>User does not exist.", 0)
@@ -85,7 +85,7 @@ async def discord_get_token(request: Request, form):
if bind_state and bind_state['is_verified'] < 0:
return JSONResponse({"state": 0, "message": "This account cannot be binded now. Please contact the administrator."}, status_code=400)
binded_search_query = binds.select().where(binds.c.bind_acc == discord_id).where(binds.c.is_verified == 1)
binded_search_query = binds.select().where(binds.c.bind_account == discord_id).where(binds.c.is_verified == 1)
binded_search_record = await player_database.fetch_one(binded_search_query)
if binded_search_record:
@@ -99,17 +99,17 @@ async def discord_get_token(request: Request, form):
if (datetime.utcnow() - bind_state['bind_date']).total_seconds() < 60:
return JSONResponse({"state": 0, "message": "Too many requests. Please wait a while before retrying."}, status_code=400)
verify_code, hash_code = generate_otp()
verify_code, _ = generate_otp()
if bind_state:
await player_database.execute(binds.update().where(binds.c.user_id == user_id).values(
bind_acc=discord_id,
bind_account=discord_id,
bind_code=verify_code,
bind_date=datetime.utcnow()
))
else:
query = binds.insert().values(
user_id=user_id,
bind_acc=discord_id,
bind_account=discord_id,
bind_code=verify_code,
is_verified=0,
bind_date=datetime.utcnow()
@@ -124,7 +124,7 @@ async def discord_get_token(request: Request, form):
async def discord_get_bind(request: Request, form):
discord_id = form.get("discord_id")
query = binds.select().where(binds.c.bind_acc == discord_id).where(binds.c.is_verified == 1)
query = binds.select().where(binds.c.bind_account == discord_id).where(binds.c.is_verified == 1)
bind_record = await player_database.fetch_one(query)
bind_record = dict(bind_record) if bind_record else None
if not bind_record:
@@ -145,7 +145,7 @@ async def discord_get_bind(request: Request, form):
async def discord_ban(request: Request, form):
discord_id = form.get("discord_id")
query = binds.select().where(binds.c.bind_acc == discord_id).where(binds.c.is_verified == 1)
query = binds.select().where(binds.c.bind_account == discord_id).where(binds.c.is_verified == 1)
bind_record = await player_database.fetch_one(query)
bind_record = dict(bind_record) if bind_record else None
@@ -166,7 +166,7 @@ async def discord_ban(request: Request, form):
async def discord_unban(request: Request, form):
discord_id = form.get("discord_id")
query = binds.select().where(binds.c.bind_acc == discord_id).where(binds.c.is_verified == -1)
query = binds.select().where(binds.c.bind_account == discord_id).where(binds.c.is_verified == -1)
bind_record = await player_database.fetch_one(query)
bind_record = dict(bind_record) if bind_record else None

View File

@@ -47,7 +47,7 @@ async def send_email_to_user(email, user_id):
if not email or not check_email(email):
return "Invalid Email."
verify = await player_database.fetch_one(binds.select().where(binds.c.bind_acc == email))
verify = await player_database.fetch_one(binds.select().where(binds.c.bind_account == email))
if verify:
if (datetime.utcnow() - verify['bind_date']).total_seconds() < 60:
return "Too many requests. Please try again later."
@@ -57,14 +57,14 @@ async def send_email_to_user(email, user_id):
await send_email(email, verify_code, "en")
if verify:
await player_database.execute(binds.update().where(binds.c.user_id == user_id).values(
bind_acc=email,
bind_account=email,
bind_code=verify_code,
bind_date=datetime.utcnow()
))
else:
query = binds.insert().values(
user_id=user_id,
bind_acc=email,
bind_account=email,
bind_code=verify_code,
is_verified=0,
bind_date=datetime.utcnow()

View File

@@ -253,6 +253,8 @@ async def should_serve(decrypted_fields):
if AUTHORIZATION_MODE and should_serve:
user_info, _ = await decrypt_fields_to_user_info(decrypted_fields)
if not user_info:
return False
bind_info = await get_bind(user_info["id"])
if not bind_info or bind_info['is_verified'] != 1:
should_serve = False

View File

@@ -12,11 +12,12 @@ from api.misc import get_model_pak, get_tune_pak, get_skin_pak, get_m4a_path, ge
from api.database import decrypt_fields_to_user_info, refresh_bind, get_user_entitlement_from_devices, set_device_data_using_decrypted_fields, create_device
from api.crypt import decrypt_fields
from api.template import START_AVATARS, START_STAGES, START_XML, SYNC_XML
from config import SIMULTANEOUS_LOGINS
async def info(request: Request):
try:
with open("web/history.html", "r", encoding="utf-8") as file:
html_content = file.read()
html_content = file.read().format(SIMULTANEOUS_LOGINS=SIMULTANEOUS_LOGINS)
except FileNotFoundError:
return inform_page("history.html not found", 1)
@@ -25,7 +26,7 @@ async def info(request: Request):
async def history(request: Request):
try:
with open("web/history.html", "r", encoding="utf-8") as file:
html_content = file.read()
html_content = file.read().format(SIMULTANEOUS_LOGINS=SIMULTANEOUS_LOGINS)
except FileNotFoundError:
return inform_page("history.html not found", 1)

View File

@@ -57,12 +57,12 @@ function loadUI() {
}
if (title === userObject['title']) {
titlesHtml += `
<img src="/files/image/title/${title}.png" alt="Title ${title}" class="title-image-selected">
<img src="/files/image/title/${title}.png" alt="Title ${title}" class="title-image-selected" loading="lazy">
`;
} else {
titlesHtml += `
<a onclick="setTitle(${title})" class="title-link">
<img src="/files/image/title/${title}.png" alt="Title ${title}" class="title-image">
<img src="/files/image/title/${title}.png" alt="Title ${title}" class="title-image" loading="lazy">
</a>
`;
}
@@ -162,6 +162,5 @@ function restoreBaseStructure() {
window.onload = function(){
restoreBaseStructure();
on_initialize();
};

View File

@@ -80,6 +80,7 @@
<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="bindTab">Bind</a></li>
<li class="nav-item"><a class="nav-link" href="#" id="websTab">Webs</a></li>
<li class="nav-item"><a class="nav-link" href="#" id="logsTab">Logs</a></li>
</ul>
<div class="d-flex ms-auto">
@@ -480,11 +481,12 @@ document.getElementById('whitelistTab').onclick = () => showTable("whitelist");
document.getElementById('blacklistTab').onclick = () => showTable("blacklist");
document.getElementById('batchTokensTab').onclick = () => showTable("batch_tokens");
document.getElementById('bindTab').onclick = () => showTable("binds");
document.getElementById('websTab').onclick = () => showTable("webs");
document.getElementById('logsTab').onclick = () => showTable("logs");
document.getElementById('logoutBtn').addEventListener('click', function() {
document.cookie = "token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
window.location.href = "/Login";
window.location.href = "/login";
});
document.getElementById('searchBtn').onclick = function() {
@@ -570,7 +572,7 @@ document.getElementById('insertRowForm').onsubmit = async function(e) {
}
};
const validTabs = ["accounts", "results", "devices", "whitelist", "blacklist", "batch_tokens", "binds", "logs"];
const validTabs = ["accounts", "results", "devices", "whitelist", "blacklist", "batch_tokens", "binds", "logs", "webs"];
const lastTab = getCookie("lastTab");
if (validTabs.includes(lastTab)) {
showTable(lastTab);

View File

@@ -13,21 +13,21 @@
<div id="wrapper">
<div class="wrapper_box">
<div class="a_left w100 d_ib mb10p">
<div class="f50 a_center pt50">This is a Private Server</div>
<div class="f90 a_center pt50">This is a Private Server</div>
<hr />
<div class="f30 plr25">Your text here</div>
<div class="f70 plr25">Your text here</div>
</div>
</div>
</div>
<div id="wrapper">
<div class="wrapper_box">
<div class="a_left w100 d_ib mb10p">
<div class="f50 a_center pt50">About Coins</div>
<div class="f90 a_center pt50">About Coins</div>
<hr />
<div class="f30 plr25">Coins are an in-game currency used within GROOVE COASTER ZERO.
<div class="f70 plr25">Coins are an in-game currency used within GROOVE COASTER ZERO.
They may be used to purchase special tracks, Avatars, and Items unavailable through regular game play.
Spent Coins will not be refunded under any circumstances.
Please note that Coin-related records are stored online, so a network connection is required for Coin use.
Please note that coin-related records are stored online, so a network connection is required for Coin use.
</div>
</div>
</div>
@@ -35,13 +35,13 @@
<div id="wrapper">
<div class="wrapper_box">
<div class="a_left w100 d_ib mb10p">
<div class="f50 a_center pt50">Regarding Data Backup</div>
<div class="f90 a_center pt50">Regarding Data Backup</div>
<hr />
<div class="f30 plr25">Please note that while the Backup/TAITO ID Registration option may be used to save play data.
<div class="f70 plr25">Please note that while the Backup/TAITO ID Registration option may be used to save play data.
Item stock information and replays are not saved.
Contrary to the official server, you can log out of the TAITO ID, change username, and password.
However, each account can only be linked to one device at a time.
When logging on to another device, the previous device will be automatically removed.
However, each account can only be linked to {SIMULTANEOUS_LOGINS} device(s) at a time.
When logging on to another device, the oldest device will be automatically removed.
Thus, please refrain from sharing credentials, and keep your password strong, as the username is on leaderboard display.
</div>
</div>
@@ -50,9 +50,9 @@
<div id="wrapper">
<div class="wrapper_box">
<div class="a_left w100 d_ib mb10p">
<div class="f50 a_center pt50">Regarding Online Use</div>
<div class="f90 a_center pt50">Regarding Online Use</div>
<hr />
<div class="f30 plr25">Once the application's tutorial is complete the game may be played offline (without a network connection).
<div class="f70 plr25">Once the application's tutorial is complete the game may be played offline (without a network connection).
However, please note that a network connection is required for certain operations, including track data downloads, SHOP use, save backup/restore, etc.
</div>
</div>
@@ -61,36 +61,36 @@
<div id="wrapper">
<div class="wrapper_box">
<div class="a_left w100 d_ib mb10p">
<div class="f4 0 a_center pt50 f60">About HELP and OPTIONS</div>
<div class="f90 a_center pt50">About HELP and OPTIONS</div>
<hr />
<div class="f30 plr25">Tapping on the question mark (?) in the top left of the screen will bring up the application's help and settings.</div>
<div class="f70 plr25">Tapping on the question mark (?) in the top left of the screen will bring up the application's help and settings.</div>
<br />
<div class="f30 plr25">There are many different settings under Options in the Help menu for you to customize to your liking.</div>
<div class="f70 plr25">There are many different settings under Options in the Help menu for you to customize to your liking.</div>
<br />
<div class="f30 plr25">- SCREEN SETTINGS</div>
<div class="f30 plr50">This menu is where you may adjust the visuals if you feel like the frame rate is unstable, or you want to disable AD-LIBS or Hit SFX when there's no TARGET to hit.</div>
<div class="f70 plr25">- SCREEN SETTINGS</div>
<div class="f60 plr50">This menu is where you may adjust the visuals if you feel like the frame rate is unstable, or you want to disable AD-LIBS or Hit SFX when there's no TARGET to hit.</div>
<br />
<div class="f30 plr25">- SOUND AND VISUAL TIMING ADJUSTMENT</div>
<div class="f30 plr50">Adjust the settings here when you feel like the visuals or audio is not in sync.</div>
<div class="f30 plr50">If you feel the visuals are ahead of the sound press the - button, if they're behind then use the + button. These buttons will adjust the visual display timing with the audio.</div>
<div class="f70 plr25">- SOUND AND VISUAL TIMING ADJUSTMENT</div>
<div class="f60 plr50">Adjust the settings here when you feel like the visuals or audio is not in sync.</div>
<div class="f60 plr50">If you feel the visuals are ahead of the sound press the - button, if they're behind then use the + button. These buttons will adjust the visual display timing with the audio.</div>
<br />
<div class="f30 plr25">- INPUT REGISTRY ADJUSTMENT</div>
<div class="f30 plr50">Adjust these settings if even though you feel like you're right in time with the beat, you still don't get a GREAT rating.</div>
<div class="f30 plr50">
<div class="f70 plr25">- INPUT REGISTRY ADJUSTMENT</div>
<div class="f60 plr50">Adjust these settings if even though you feel like you're right in time with the beat, you still don't get a GREAT rating.</div>
<div class="f60 plr50">
Press the - button if you feel like you have to press earlier than you should for a GREAT rating, or press the + button if you feel like you have to press later than you should for a GREAT rating.
</div>
<br />
<div class="f30 plr25">■MICROPHONE INPUT SENSITIVITY</div>
<div class="f30 plr50">This setting will help to make playing ORIGINAL STYLE more smooth.</div>
<div class="f70 plr25">■MICROPHONE INPUT SENSITIVITY</div>
<div class="f60 plr50">This setting will help to make playing ORIGINAL STYLE more smooth.</div>
</div>
</div>
</div>
<div id="wrapper">
<div class="wrapper_box">
<div class="a_left w100 d_ib mb10p">
<p class="a_center f60">About Arcade Mode</p>
<p class="a_center">About Arcade Mode</p>
<hr />
<p class="f30 plr50">
<p class="f60 plr50">
Now you can play Arcade Mode which lets you enjoy a the same experience you'd have on a Groove Coaster arcade machine!<br />
<br />
*Please be aware that you will not be able to play Arcade Mode, even if you own it, if you have not yet cleared the NORMAL difficulty on the specified track.
@@ -101,9 +101,9 @@
<div id="wrapper">
<div class="wrapper_box">
<div class="a_left w100 d_ib mb10p">
<p class="a_center f60">Play the game by making sounds!</p>
<p class="a_center">Play the game by making sounds!</p>
<hr />
<p class="f30 plr50">
<p class="f60 plr50">
★What's Original Style?<br />
<img src="./files/web/Info1.gif" class="w90 d_bl m_auto" /><br />
It gives you a brand new way to play the game by making sounds!<br />