Compare commits

...

12 Commits

6 changed files with 160 additions and 33 deletions

View File

@ -1,6 +1,36 @@
# Changelog # Changelog
Documenting updates to ARTEMiS, to be updated every time the master branch is pushed to. Documenting updates to ARTEMiS, to be updated every time the master branch is pushed to.
## 20240811
### System
+ Change backend from Twisted to Starlette
+ Implement async handlers
+ Reboot times for multiple games have been fixed (thanks zaphkito!)
### Frontend
+ Edit button changed to View on the user page, and is where you can edit the card memo
+ Add card now works as it should
+ Add event log viewer in the `sys` page for sysadmins
+ Add pages for Pokken, SAO, and maimai
### AimeDB
+ Now rejects all-zero access codes
+ Stores card IDm (for AmusementIC) and MiFare ID (for old aime/banapass)
+ ...unless that MiFare ID is 0x01020304 (the default for segatools)
### maimai
+ Add support for BUDDiES
+ Rivals and Favorite Music support
### Wacca
+ Add option to block unregistered serials from accessing the title server
### DIVA
+ Fix for reading modded content (Thanks ThatzOkay!)
### CHUNITHM
+ Save net battle info
## 20240630 ## 20240630
### DIVA ### DIVA
+ Added configurable festa options' + Added configurable festa options'

View File

@ -479,7 +479,8 @@ class FE_User(FE_Base):
'chip_id': c['chip_id'], 'chip_id': c['chip_id'],
'idm': c['idm'], 'idm': c['idm'],
'type': c_type, 'type': c_type,
"memo": c['memo'] "memo": c['memo'],
"id": c['id'],
}) })
if "e" in request.query_params: if "e" in request.query_params:
@ -522,39 +523,100 @@ class FE_User(FE_Base):
return RedirectResponse("/gate/", 303) return RedirectResponse("/gate/", 303)
frm = await request.form() frm = await request.form()
ac = frm.get("add_access_code", None) cid = frm.get("card_edit_frm_card_id", None)
if not cid:
return RedirectResponse("/user/?e=999", 303)
ac = frm.get("card_edit_frm_access_code", None)
if not ac: if not ac:
return RedirectResponse("/user/?e=999", 303) return RedirectResponse("/user/?e=999", 303)
card = await self.data.card.get_card_by_access_code(ac) card = await self.data.card.get_card_by_id(cid)
if not card: if not card:
return RedirectResponse("/user/?e=2", 303) return RedirectResponse("/user/?e=2", 303)
if card['user'] != usr_sesh.user_id and not self.test_perm_minimum(usr_sesh.permissions, PermissionOffset.USERMOD): if card['user'] != usr_sesh.user_id and not self.test_perm_minimum(usr_sesh.permissions, PermissionOffset.USERMOD):
return RedirectResponse("/user/?e=11", 303) return RedirectResponse("/user/?e=11", 303)
if frm.get("add_memo", None): if frm.get("add_memo", None) or frm.get("add_memo", None) == "":
memo = frm.get("add_memo") memo = frm.get("add_memo")
if len(memo) > 16 or len(memo) == 0: if len(memo) > 16:
return RedirectResponse("/user/?e=4", 303) return RedirectResponse("/user/?e=4", 303)
await self.data.card.set_memo_by_access_code(ac, memo) await self.data.card.set_memo_by_access_code(ac, memo)
if frm.get("add_felica_idm", None): if False: # Saving this in case I want to allow editing idm/chip ID down the line
idm = frm.get('add_felica_idm') if frm.get("add_felica_idm", None):
if not all(c in string.hexdigits for c in idm): idm = frm.get('add_felica_idm')
return RedirectResponse("/user/?e=4", 303) if not all(c in string.hexdigits for c in idm):
await self.data.card.set_idm_by_access_code(ac, idm) return RedirectResponse("/user/?e=4", 303)
await self.data.card.set_idm_by_access_code(ac, idm)
if frm.get("add_mifare_chip_id", None): if frm.get("add_mifare_chip_id", None):
chip_id: str = frm.get('add_mifare_chip_id') chip_id: str = frm.get('add_mifare_chip_id')
if not all(c in string.hexdigits for c in idm): if not all(c in string.hexdigits for c in idm):
return RedirectResponse("/user/?e=4", 303) return RedirectResponse("/user/?e=4", 303)
await self.data.card.set_chip_id_by_access_code(ac, int(chip_id, 16)) await self.data.card.set_chip_id_by_access_code(ac, int(chip_id, 16))
return RedirectResponse("/user/?s=4", 303) return RedirectResponse("/user/?s=4", 303)
async def add_card(self, request: Request) -> RedirectResponse: async def add_card(self, request: Request) -> RedirectResponse:
return RedirectResponse("/user/", 303) frm = await request.form()
card_type = frm.get("card_add_frm_type", None)
access_code = frm.get("add_access_code", None)
idm = frm.get("add_idm", None)
idm_caps = None
usr_sesh = self.validate_session(request)
if not usr_sesh or not self.test_perm(usr_sesh.permissions, PermissionOffset.USERMOD):
return RedirectResponse("/gate/", 303)
if not len(access_code) == 20 or (not access_code.startswith("5") and not access_code.startswith("3") \
and not access_code.startswith("010") and not access_code.startswith("0008")):
return RedirectResponse("/user/?e=4", 303)
if card_type == "0" and access_code.startswith("5") and len(idm) == 16:
idm_caps = idm.upper()
if not all([x in string.hexdigits for x in idm_caps]):
return RedirectResponse("/user/?e=4", 303)
if access_code.startswith("5") and not idm_caps:
return RedirectResponse("/user/?e=13", 303)
test = await self.data.card.get_card_by_access_code(access_code)
if test:
return RedirectResponse("/user/?e=12", 303)
if idm_caps:
test = await self.data.card.get_card_by_idm(idm_caps)
if test and test['user'] != usr_sesh.user_id:
return RedirectResponse("/user/?e=12", 303)
test = await self.data.card.get_card_by_access_code(self.data.card.to_access_code(idm_caps))
if test:
if test['user'] != usr_sesh.user_id:
return RedirectResponse("/user/?e=12", 303)
await self.data.card.set_access_code_by_access_code(test['access_code'], access_code)
self.logger.info(f"Update card {test['id']} from {test['access_code']} to {access_code} for user {usr_sesh.user_id}")
await self.data.card.set_idm_by_access_code(access_code, idm_caps)
self.logger.info(f"Set IDm for card {access_code} to {idm_caps}")
return RedirectResponse("/user/?s=1", 303)
if card_type == "0" and access_code.startswith("0008"):
test = await self.data.card.get_card_by_idm(self.data.card.to_idm(access_code))
if test:
return RedirectResponse("/user/?e=12", 303)
new_card = await self.data.card.create_card(usr_sesh.user_id, access_code)
self.logger.info(f"Created new card {new_card} with access code {access_code} for user {usr_sesh.user_id}")
if idm_caps:
await self.data.card.set_idm_by_access_code(access_code, idm_caps)
self.logger.info(f"Set IDm for card {access_code} to {idm_caps}")
return RedirectResponse("/user/?s=1", 303)
async def render_POST(self, request: Request): async def render_POST(self, request: Request):
frm = await request.form() frm = await request.form()

View File

@ -28,12 +28,28 @@ function toggle_add_card_form() {
} }
} }
function prep_edit_form(access_code, chip_id, idm, card_type, u_memo) { function toggle_idm_disabled(is_disabled) {
document.getElementById("btn_add_card");
let dv = document.getElementById("add_card_container")
if (dv.style['display'] != "") {
btn.innerText = "Cancel";
dv.style['display'] = "";
} else {
btn.innerText = "Add";
dv.style['display'] = "none";
}
}
function prep_edit_form(access_code, chip_id, idm, card_type, u_memo, card_id) {
ac = document.getElementById("card_edit_frm_access_code"); ac = document.getElementById("card_edit_frm_access_code");
cid = document.getElementById("card_edit_frm_chip_id"); cid = document.getElementById("card_edit_frm_chip_id");
fidm = document.getElementById("card_edit_frm_idm"); fidm = document.getElementById("card_edit_frm_idm");
memo = document.getElementById("card_edit_frm_memo"); memo = document.getElementById("card_edit_frm_memo");
document.getElementById("card_edit_frm_card_id").value = card_id;
if (chip_id == "None" || chip_id == undefined) { if (chip_id == "None" || chip_id == undefined) {
chip_id = "" chip_id = ""
} }
@ -52,7 +68,7 @@ function prep_edit_form(access_code, chip_id, idm, card_type, u_memo) {
if (access_code.startsWith("3") || access_code.startsWith("010")) { if (access_code.startsWith("3") || access_code.startsWith("010")) {
cid.disabled = false; cid.disabled = false;
fidm.disabled = true; fidm.disabled = true;
} else if (access_code.startsWith("5")) { } else if (access_code.startsWith("5") || access_code.startsWith("0008")) {
cid.disabled = true; cid.disabled = true;
fidm.disabled = false; fidm.disabled = false;
} else { } else {
@ -87,9 +103,23 @@ Card added successfully
{% endif %} {% endif %}
<div id="add_card_container" style="display: none; max-width: 33%;"> <div id="add_card_container" style="display: none; max-width: 33%;">
<form action="/user/add.card" method="post", id="frm_add_card"> <form action="/user/add.card" method="post", id="frm_add_card">
<div class="form-check">
<input type="radio" id="card_add_frm_type_aicc" value="0" name="card_add_frm_type" aria-describedby="aicc_help" onclick="document.getElementById('card_add_frm_idm').disabled = false;">
<label class="form-label" for="card_add_frm_type_aicc">AmusementIC</label>
<div id="aicc_help" class="form-text">Starts with 5. If you don't have the IDm, use the 0008 access code shown in-game</div>
<br>
<input type="radio" id="card_add_frm_type_old" value="1" name="card_add_frm_type" aria-describedby="old_help" onclick="document.getElementById('card_add_frm_idm').disabled = true;">
<label class="form-label" for="card_add_frm_type_old">Old Aime/Banapass</label>
<div id="old_help" class="form-text">Starts with 010 (aime) or 3 (banapass)</div>
</div>
<label class="form-label" for="card_add_frm_access_code">Access Code:</label> <label class="form-label" for="card_add_frm_access_code">Access Code:</label>
<input class="form-control" name="add_access_code" id="card_add_frm_access_code" maxlength="20" type="text" required aria-describedby="ac_help"> <input class="form-control" name="add_access_code" id="card_add_frm_access_code" maxlength="20" type="text" required aria-describedby="ac_help">
<div id="ac_help" class="form-text">20 digit code on the back of the card.</div> <div id="ac_help" class="form-text">20 digit code on the back of the card.</div>
<label class="form-label" for="card_add_frm_access_code">IDm:</label>
<input class="form-control" name="add_idm" id="card_add_frm_idm" maxlength="16" type="text" aria-describedby="idm_help">
<div id="idm_help" class="form-text">AmusementIC cards only! 16 hexidecimal digits, sometimes called the serial number, gotten by scanning the card with a reader.</div>
<br>
<button type="submit" class="btn btn-primary">Add</button> <button type="submit" class="btn btn-primary">Add</button>
</form> </form>
<br> <br>
@ -101,7 +131,7 @@ Update successful
{% endif %} {% endif %}
<ul style="font-size: 20px;"> <ul style="font-size: 20px;">
{% for c in cards %} {% for c in cards %}
<li>{{ c.access_code }} ({{ c.type if c.memo is none or not c.memo else c.memo }}): {{ c.status }}&nbsp;<button onclick="prep_edit_form('{{ c.access_code }}', '{{ c.chip_id}}', '{{ c.idm }}', '{{ c.type }}', '{{ c.memo }}')" data-bs-toggle="modal" data-bs-target="#card_edit" class="btn btn-secondary" id="btn_edit_card_{{ c.access_code }}">Edit</button>&nbsp;{% if c.status == 'Active'%}<button class="btn-warning btn">Lock</button>{% elif c.status == 'Locked' %}<button class="btn-warning btn">Unlock</button>{% endif %}&nbsp;<button class="btn-danger btn" {{ "disabled" if cards|length == 1 else ""}}>Delete</button></li> <li>{{ c.access_code }} ({{ c.type if c.memo is none or not c.memo else c.memo }}): {{ c.status }}&nbsp;<button onclick="prep_edit_form('{{ c.access_code }}', '{{ c.chip_id}}', '{{ c.idm }}', '{{ c.type }}', '{{ c.memo }}', '{{ c.id }}')" data-bs-toggle="modal" data-bs-target="#card_edit" class="btn btn-secondary" id="btn_edit_card_{{ c.access_code }}">View</button>&nbsp;{% if c.status == 'Active'%}<button class="btn-warning btn">Lock</button>{% elif c.status == 'Locked' %}<button class="btn-warning btn">Unlock</button>{% endif %}&nbsp;<button class="btn-danger btn" {{ "disabled" if cards|length == 1 else ""}}>Delete</button></li>
{% endfor %} {% endfor %}
</ul> </ul>
@ -150,31 +180,31 @@ Update successful
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h1 class="modal-title fs-5" id="card_edit_label">Edit Card</h1> <h1 class="modal-title fs-5" id="card_edit_label">Card Information</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form action="/user/edit.card" method="post" id="frm_edit_card"> <form action="/user/edit.card" method="post" id="frm_edit_card">
<input type="hidden" readonly name="card_edit_frm_card_id" id="card_edit_frm_card_id">
<label class="form-label" for="card_edit_frm_access_code">Access Code:</label> <label class="form-label" for="card_edit_frm_access_code">Access Code:</label>
<input class="form-control" readonly name="add_access_code" id="card_edit_frm_access_code" maxlength="20" type="text" required aria-describedby="ac_help"> <input class="form-control-plaintext" readonly name="card_edit_frm_access_code" id="card_edit_frm_access_code" maxlength="20" type="text" required aria-describedby="ac_help">
<div id="ac_help" class="form-text">20 digit code on the back of the card. If this is incorrect, contact a sysadmin.</div> <div id="ac_help" class="form-text">20 digit code on the back of the card. If this is incorrect, contact a sysadmin.</div>
<label class="form-label" for="card_edit_frm_idm" id="card_edit_frm_idm_lbl">FeliCa IDm:</label>
<input class="form-control-plaintext" aria-describedby="idm_help" name="add_felica_idm" id="card_edit_frm_idm" maxlength="16" type="text" readonly>
<div id="idm_help" class="form-text">8 bytes that uniquly idenfites a FeliCa card. Obtained by reading the card with an NFC reader.</div>
<label class="form-label" for="card_edit_frm_chip_id" id="card_edit_frm_chip_id_lbl">Mifare UID:</label>
<input class="form-control-plaintext" aria-describedby="chip_id_help" name="add_mifare_chip_id" id="card_edit_frm_chip_id" maxlength="8" type="text" readonly>
<div id="chip_id_help" class="form-text">4 byte integer that uniquly identifies a Mifare card. Obtained by reading the card with an NFC reader.</div>
<label class="form-label" for="card_edit_frm_memo" id="card_edit_frm_memo_lbl">Memo:</label> <label class="form-label" for="card_edit_frm_memo" id="card_edit_frm_memo_lbl">Memo:</label>
<input class="form-control" aria-describedby="memo_help" name="add_memo" id="card_edit_frm_memo" maxlength="16" type="text"> <input class="form-control" aria-describedby="memo_help" name="add_memo" id="card_edit_frm_memo" maxlength="16" type="text">
<div id="memo_help" class="form-text">Must be 16 characters or less.</div> <div id="memo_help" class="form-text">Must be 16 characters or less.</div>
<label class="form-label" for="card_edit_frm_idm" id="card_edit_frm_idm_lbl">FeliCa IDm:</label>
<input class="form-control" aria-describedby="idm_help" name="add_felica_idm" id="card_edit_frm_idm" maxlength="16" type="text">
<div id="idm_help" class="form-text">8 bytes that uniquly idenfites a FeliCa card. Obtained by reading the card with an NFC reader.</div>
<label class="form-label" for="card_edit_frm_chip_id" id="card_edit_frm_chip_id_lbl">Mifare UID:</label>
<input class="form-control" aria-describedby="chip_id_help" name="add_mifare_chip_id" id="card_edit_frm_chip_id" maxlength="8" type="text">
<div id="chip_id_help" class="form-text">4 byte integer that uniquly identifies a Mifare card. Obtained by reading the card with an NFC reader.</div>
</form>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="submit" class="btn btn-primary" form="frm_edit_card">Edit</button> <button type="submit" class="btn btn-primary">Update Memo</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> </form>
</div> </div>
</div> </div>
</div> </div>

View File

@ -23,6 +23,10 @@ You must be logged in to preform this action
Invalid serial number Invalid serial number
{% elif error == 11 %} {% elif error == 11 %}
Access Denied Access Denied
{% elif error == 12 %}
Card already registered
{% elif error == 13 %}
AmusementIC Access Codes beginning with 5 must have IDm
{% else %} {% else %}
An unknown error occoured An unknown error occoured
{% endif %} {% endif %}

View File

@ -29,6 +29,7 @@ Games listed below have been tested and confirmed working. Only game versions ol
+ NEW PLUS + NEW PLUS
+ SUN + SUN
+ SUN PLUS + SUN PLUS
+ LUMINOUS
+ crossbeats REV. + crossbeats REV.
+ Crossbeats REV. + Crossbeats REV.

View File

@ -23,7 +23,7 @@ class DivaFrontend(FE_Base):
self.game_cfg.update( self.game_cfg.update(
yaml.safe_load(open(f"{cfg_dir}/{DivaConstants.CONFIG_NAME}")) yaml.safe_load(open(f"{cfg_dir}/{DivaConstants.CONFIG_NAME}"))
) )
self.nav_name = "diva" self.nav_name = "Project Diva"
def get_routes(self) -> List[Route]: def get_routes(self) -> List[Route]:
return [ return [