forked from Hay1tsme/artemis
Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
d400a0be4b | |||
31ca45fc68 | |||
ee667b9ea5 | |||
c12272feab | |||
2a8a4880c2 | |||
5c497032f1 | |||
06a7fdb1b1 | |||
68bbde209a | |||
02cee4198d | |||
b5715b8da6 | |||
2647baef1e | |||
ec7605eeb0 | |||
b5e7a59b5f | |||
d09f3e9907 | |||
add85aeab7 | |||
a497a9806d | |||
e88e1f82f8 | |||
1e84a50330 |
30
changelog.md
30
changelog.md
@ -1,6 +1,36 @@
|
||||
# Changelog
|
||||
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
|
||||
### DIVA
|
||||
+ Added configurable festa options'
|
||||
|
@ -2,5 +2,5 @@ from .base import ADBBaseRequest, ADBBaseResponse, ADBHeader, ADBHeaderException
|
||||
from .base import CompanyCodes, ReaderFwVer, CMD_CODE_GOODBYE, HEADER_SIZE
|
||||
from .lookup import ADBLookupRequest, ADBLookupResponse, ADBLookupExResponse
|
||||
from .campaign import ADBCampaignClearRequest, ADBCampaignClearResponse, ADBCampaignResponse, ADBOldCampaignRequest, ADBOldCampaignResponse
|
||||
from .felica import ADBFelicaLookupRequest, ADBFelicaLookupResponse, ADBFelicaLookup2Request, ADBFelicaLookup2Response
|
||||
from .felica import ADBFelicaLookupRequest, ADBFelicaLookupResponse, ADBFelicaLookupExRequest, ADBFelicaLookupExResponse
|
||||
from .log import ADBLogExRequest, ADBLogRequest, ADBStatusLogRequest, ADBLogExResponse
|
||||
|
@ -35,7 +35,7 @@ class ADBFelicaLookupResponse(ADBBaseResponse):
|
||||
|
||||
return self.head.make() + resp_struct
|
||||
|
||||
class ADBFelicaLookup2Request(ADBBaseRequest):
|
||||
class ADBFelicaLookupExRequest(ADBBaseRequest):
|
||||
def __init__(self, data: bytes) -> None:
|
||||
super().__init__(data)
|
||||
self.random = struct.unpack_from("<16s", data, 0x20)[0]
|
||||
@ -46,7 +46,7 @@ class ADBFelicaLookup2Request(ADBBaseRequest):
|
||||
self.company = CompanyCodes(int.from_bytes(company, 'little'))
|
||||
self.fw_ver = ReaderFwVer.from_byte(fw_ver)
|
||||
|
||||
class ADBFelicaLookup2Response(ADBBaseResponse):
|
||||
class ADBFelicaLookupExResponse(ADBBaseResponse):
|
||||
def __init__(self, user_id: Union[int, None] = None, access_code: Union[str, None] = None, game_id: str = "SXXX", store_id: int = 1, keychip_id: str = "A69E01A8888", code: int = 0x12, length: int = 0x130, status: int = 1) -> None:
|
||||
super().__init__(code, length, status, game_id, store_id, keychip_id)
|
||||
self.user_id = user_id if user_id is not None else -1
|
||||
@ -56,7 +56,7 @@ class ADBFelicaLookup2Response(ADBBaseResponse):
|
||||
self.auth_key = [0] * 256
|
||||
|
||||
@classmethod
|
||||
def from_req(cls, req: ADBHeader, user_id: Union[int, None] = None, access_code: Union[str, None] = None) -> "ADBFelicaLookup2Response":
|
||||
def from_req(cls, req: ADBHeader, user_id: Union[int, None] = None, access_code: Union[str, None] = None) -> "ADBFelicaLookupExResponse":
|
||||
c = cls(user_id, access_code, req.game_id, req.store_id, req.keychip_id)
|
||||
c.head.protocol_ver = req.protocol_ver
|
||||
return c
|
||||
|
@ -176,6 +176,12 @@ class AimedbServlette():
|
||||
|
||||
async def handle_lookup(self, data: bytes, resp_code: int) -> ADBBaseResponse:
|
||||
req = ADBLookupRequest(data)
|
||||
if req.access_code == "00000000000000000000":
|
||||
self.logger.warn(f"All-zero access code from {req.head.keychip_id}")
|
||||
ret = ADBLookupResponse.from_req(req.head, -1)
|
||||
ret.head.status = ADBStatus.BAN_SYS
|
||||
return ret
|
||||
|
||||
user_id = await self.data.card.get_user_id_from_card(req.access_code)
|
||||
is_banned = await self.data.card.get_card_banned(req.access_code)
|
||||
is_locked = await self.data.card.get_card_locked(req.access_code)
|
||||
@ -201,6 +207,12 @@ class AimedbServlette():
|
||||
|
||||
async def handle_lookup_ex(self, data: bytes, resp_code: int) -> ADBBaseResponse:
|
||||
req = ADBLookupRequest(data)
|
||||
if req.access_code == "00000000000000000000":
|
||||
self.logger.warn(f"All-zero access code from {req.head.keychip_id}")
|
||||
ret = ADBLookupExResponse.from_req(req.head, -1)
|
||||
ret.head.status = ADBStatus.BAN_SYS
|
||||
return ret
|
||||
|
||||
user_id = await self.data.card.get_user_id_from_card(req.access_code)
|
||||
|
||||
is_banned = await self.data.card.get_card_banned(req.access_code)
|
||||
@ -241,6 +253,12 @@ class AimedbServlette():
|
||||
"""
|
||||
req = ADBFelicaLookupRequest(data)
|
||||
idm = req.idm.zfill(16)
|
||||
if idm == "0000000000000000":
|
||||
self.logger.warn(f"All-zero IDm from {req.head.keychip_id}")
|
||||
ret = ADBFelicaLookupResponse.from_req(req.head, "00000000000000000000")
|
||||
ret.head.status = ADBStatus.BAN_SYS
|
||||
return ret
|
||||
|
||||
card = await self.data.card.get_card_by_idm(idm)
|
||||
if not card:
|
||||
ac = self.data.card.to_access_code(idm)
|
||||
@ -262,6 +280,14 @@ class AimedbServlette():
|
||||
because we don't implement felica_lookup properly.
|
||||
"""
|
||||
req = ADBFelicaLookupRequest(data)
|
||||
idm = req.idm.zfill(16)
|
||||
|
||||
if idm == "0000000000000000":
|
||||
self.logger.warn(f"All-zero IDm from {req.head.keychip_id}")
|
||||
ret = ADBFelicaLookupResponse.from_req(req.head, "00000000000000000000")
|
||||
ret.head.status = ADBStatus.BAN_SYS
|
||||
return ret
|
||||
|
||||
ac = self.data.card.to_access_code(req.idm)
|
||||
|
||||
if self.config.server.allow_user_registration:
|
||||
@ -292,9 +318,16 @@ class AimedbServlette():
|
||||
return ADBFelicaLookupResponse.from_req(req.head, ac)
|
||||
|
||||
async def handle_felica_lookup_ex(self, data: bytes, resp_code: int) -> bytes:
|
||||
req = ADBFelicaLookup2Request(data)
|
||||
req = ADBFelicaLookupExRequest(data)
|
||||
user_id = None
|
||||
idm = req.idm.zfill(16)
|
||||
|
||||
if idm == "0000000000000000":
|
||||
self.logger.warn(f"All-zero IDm from {req.head.keychip_id}")
|
||||
ret = ADBFelicaLookupExResponse.from_req(req.head, -1, "00000000000000000000")
|
||||
ret.head.status = ADBStatus.BAN_SYS
|
||||
return ret
|
||||
|
||||
card = await self.data.card.get_card_by_idm(idm)
|
||||
if not card:
|
||||
access_code = self.data.card.to_access_code(idm)
|
||||
@ -314,7 +347,7 @@ class AimedbServlette():
|
||||
f"idm {idm} ipm {req.pmm} -> access_code {access_code} user_id {user_id}"
|
||||
)
|
||||
|
||||
resp = ADBFelicaLookup2Response.from_req(req.head, user_id, access_code)
|
||||
resp = ADBFelicaLookupExResponse.from_req(req.head, user_id, access_code)
|
||||
|
||||
if user_id > 0:
|
||||
if card['is_banned'] and card['is_locked']:
|
||||
@ -347,6 +380,12 @@ class AimedbServlette():
|
||||
async def handle_register(self, data: bytes, resp_code: int) -> bytes:
|
||||
req = ADBLookupRequest(data)
|
||||
user_id = -1
|
||||
|
||||
if req.access_code == "00000000000000000000":
|
||||
self.logger.warn(f"All-zero access code from {req.head.keychip_id}")
|
||||
ret = ADBLookupResponse.from_req(req.head, -1)
|
||||
ret.head.status = ADBStatus.BAN_SYS
|
||||
return ret
|
||||
|
||||
if self.config.server.allow_user_registration:
|
||||
user_id = await self.data.user.create_user()
|
||||
|
@ -479,7 +479,8 @@ class FE_User(FE_Base):
|
||||
'chip_id': c['chip_id'],
|
||||
'idm': c['idm'],
|
||||
'type': c_type,
|
||||
"memo": c['memo']
|
||||
"memo": c['memo'],
|
||||
"id": c['id'],
|
||||
})
|
||||
|
||||
if "e" in request.query_params:
|
||||
@ -522,39 +523,100 @@ class FE_User(FE_Base):
|
||||
return RedirectResponse("/gate/", 303)
|
||||
|
||||
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:
|
||||
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:
|
||||
return RedirectResponse("/user/?e=2", 303)
|
||||
|
||||
if card['user'] != usr_sesh.user_id and not self.test_perm_minimum(usr_sesh.permissions, PermissionOffset.USERMOD):
|
||||
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")
|
||||
if len(memo) > 16 or len(memo) == 0:
|
||||
if len(memo) > 16:
|
||||
return RedirectResponse("/user/?e=4", 303)
|
||||
await self.data.card.set_memo_by_access_code(ac, memo)
|
||||
|
||||
if frm.get("add_felica_idm", None):
|
||||
idm = frm.get('add_felica_idm')
|
||||
if not all(c in string.hexdigits for c in idm):
|
||||
return RedirectResponse("/user/?e=4", 303)
|
||||
await self.data.card.set_idm_by_access_code(ac, idm)
|
||||
if False: # Saving this in case I want to allow editing idm/chip ID down the line
|
||||
if frm.get("add_felica_idm", None):
|
||||
idm = frm.get('add_felica_idm')
|
||||
if not all(c in string.hexdigits for c in 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):
|
||||
chip_id: str = frm.get('add_mifare_chip_id')
|
||||
if not all(c in string.hexdigits for c in idm):
|
||||
return RedirectResponse("/user/?e=4", 303)
|
||||
await self.data.card.set_chip_id_by_access_code(ac, int(chip_id, 16))
|
||||
if frm.get("add_mifare_chip_id", None):
|
||||
chip_id: str = frm.get('add_mifare_chip_id')
|
||||
if not all(c in string.hexdigits for c in idm):
|
||||
return RedirectResponse("/user/?e=4", 303)
|
||||
await self.data.card.set_chip_id_by_access_code(ac, int(chip_id, 16))
|
||||
|
||||
return RedirectResponse("/user/?s=4", 303)
|
||||
|
||||
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):
|
||||
frm = await request.form()
|
||||
|
@ -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");
|
||||
cid = document.getElementById("card_edit_frm_chip_id");
|
||||
fidm = document.getElementById("card_edit_frm_idm");
|
||||
memo = document.getElementById("card_edit_frm_memo");
|
||||
|
||||
|
||||
document.getElementById("card_edit_frm_card_id").value = card_id;
|
||||
|
||||
if (chip_id == "None" || chip_id == undefined) {
|
||||
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")) {
|
||||
cid.disabled = false;
|
||||
fidm.disabled = true;
|
||||
} else if (access_code.startsWith("5")) {
|
||||
} else if (access_code.startsWith("5") || access_code.startsWith("0008")) {
|
||||
cid.disabled = true;
|
||||
fidm.disabled = false;
|
||||
} else {
|
||||
@ -87,9 +103,23 @@ Card added successfully
|
||||
{% endif %}
|
||||
<div id="add_card_container" style="display: none; max-width: 33%;">
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
</form>
|
||||
<br>
|
||||
@ -101,7 +131,7 @@ Update successful
|
||||
{% endif %}
|
||||
<ul style="font-size: 20px;">
|
||||
{% for c in cards %}
|
||||
<li>{{ c.access_code }} ({{ c.type if c.memo is none or not c.memo else c.memo }}): {{ c.status }} <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> {% if c.status == 'Active'%}<button class="btn-warning btn">Lock</button>{% elif c.status == 'Locked' %}<button class="btn-warning btn">Unlock</button>{% endif %} <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 }} <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> {% if c.status == 'Active'%}<button class="btn-warning btn">Lock</button>{% elif c.status == 'Locked' %}<button class="btn-warning btn">Unlock</button>{% endif %} <button class="btn-danger btn" {{ "disabled" if cards|length == 1 else ""}}>Delete</button></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
@ -150,31 +180,31 @@ Update successful
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<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>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<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>
|
||||
<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>
|
||||
|
||||
<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>
|
||||
<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>
|
||||
|
||||
<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 class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary" form="frm_edit_card">Edit</button>
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<button type="submit" class="btn btn-primary">Update Memo</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -23,6 +23,10 @@ You must be logged in to preform this action
|
||||
Invalid serial number
|
||||
{% elif error == 11 %}
|
||||
Access Denied
|
||||
{% elif error == 12 %}
|
||||
Card already registered
|
||||
{% elif error == 13 %}
|
||||
AmusementIC Access Codes beginning with 5 must have IDm
|
||||
{% else %}
|
||||
An unknown error occoured
|
||||
{% endif %}
|
||||
|
@ -29,6 +29,7 @@ Games listed below have been tested and confirmed working. Only game versions ol
|
||||
+ NEW PLUS
|
||||
+ SUN
|
||||
+ SUN PLUS
|
||||
+ LUMINOUS
|
||||
|
||||
+ crossbeats REV.
|
||||
+ Crossbeats REV.
|
||||
|
@ -94,14 +94,19 @@ class ChuniServlet(BaseServlet):
|
||||
|
||||
known_iter_counts = {
|
||||
ChuniConstants.VER_CHUNITHM_CRYSTAL_PLUS: 67,
|
||||
f"{ChuniConstants.VER_CHUNITHM_CRYSTAL_PLUS}_int": 25, # SUPERSTAR
|
||||
ChuniConstants.VER_CHUNITHM_PARADISE: 44,
|
||||
f"{ChuniConstants.VER_CHUNITHM_PARADISE}_int": 25,
|
||||
f"{ChuniConstants.VER_CHUNITHM_PARADISE}_int": 51, # SUPERSTAR PLUS
|
||||
ChuniConstants.VER_CHUNITHM_NEW: 54,
|
||||
f"{ChuniConstants.VER_CHUNITHM_NEW}_int": 49,
|
||||
ChuniConstants.VER_CHUNITHM_NEW_PLUS: 25,
|
||||
f"{ChuniConstants.VER_CHUNITHM_NEW_PLUS}_int": 31,
|
||||
ChuniConstants.VER_CHUNITHM_SUN: 70,
|
||||
f"{ChuniConstants.VER_CHUNITHM_SUN}_int": 35,
|
||||
ChuniConstants.VER_CHUNITHM_SUN_PLUS: 36,
|
||||
f"{ChuniConstants.VER_CHUNITHM_SUN_PLUS}_int": 36,
|
||||
ChuniConstants.VER_CHUNITHM_LUMINOUS: 8,
|
||||
f"{ChuniConstants.VER_CHUNITHM_LUMINOUS}_int": 8,
|
||||
}
|
||||
|
||||
for version, keys in self.game_cfg.crypto.keys.items():
|
||||
@ -233,8 +238,10 @@ class ChuniServlet(BaseServlet):
|
||||
elif version >= 220: # LUMINOUS
|
||||
internal_ver = ChuniConstants.VER_CHUNITHM_LUMINOUS
|
||||
elif game_code == "SDGS": # Int
|
||||
if version < 110: # SUPERSTAR / SUPERSTAR PLUS
|
||||
internal_ver = ChuniConstants.VER_CHUNITHM_PARADISE # SUPERSTAR / SUPERSTAR PLUS worked fine with it
|
||||
if version < 105: # SUPERSTAR
|
||||
internal_ver = ChuniConstants.VER_CHUNITHM_CRYSTAL_PLUS
|
||||
elif version >= 105 and version < 110: # SUPERSTAR PLUS *Cursed but needed due to different encryption key
|
||||
internal_ver = ChuniConstants.VER_CHUNITHM_PARADISE
|
||||
elif version >= 110 and version < 115: # NEW
|
||||
internal_ver = ChuniConstants.VER_CHUNITHM_NEW
|
||||
elif version >= 115 and version < 120: # NEW PLUS!!
|
||||
@ -353,9 +360,9 @@ class ChuniServlet(BaseServlet):
|
||||
padded = pad(zipped, 16)
|
||||
|
||||
crypt = AES.new(
|
||||
bytes.fromhex(self.game_cfg.crypto.keys[internal_ver][0]),
|
||||
bytes.fromhex(self.game_cfg.crypto.keys[crypto_cfg_key][0]),
|
||||
AES.MODE_CBC,
|
||||
bytes.fromhex(self.game_cfg.crypto.keys[internal_ver][1]),
|
||||
bytes.fromhex(self.game_cfg.crypto.keys[crypto_cfg_key][1]),
|
||||
)
|
||||
|
||||
return Response(crypt.encrypt(padded))
|
||||
|
@ -16,4 +16,14 @@ class ChuniSun(ChuniNewPlus):
|
||||
|
||||
# hardcode lastDataVersion for CardMaker 1.35 A032
|
||||
user_data["lastDataVersion"] = "2.10.00"
|
||||
return user_data
|
||||
return user_data
|
||||
|
||||
#SDGS Exclusive
|
||||
async def handle_get_user_cto_c_play_api_request(self, data: Dict) -> Dict:
|
||||
return {
|
||||
"userId": data["userId"],
|
||||
"orderBy": "0",
|
||||
"count": "0",
|
||||
#game request c2c play history while login but seem unused(?)
|
||||
"userCtoCPlayList": [],
|
||||
}
|
@ -23,7 +23,7 @@ class DivaFrontend(FE_Base):
|
||||
self.game_cfg.update(
|
||||
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]:
|
||||
return [
|
||||
|
Loading…
Reference in New Issue
Block a user