2023-08-14 05:32:03 +02:00
|
|
|
from construct import Struct, Int32sl, Padding, Int8ub, Int16sl
|
|
|
|
from typing import Union
|
|
|
|
from .base import *
|
|
|
|
|
|
|
|
class ADBFelicaLookupRequest(ADBBaseRequest):
|
|
|
|
def __init__(self, data: bytes) -> None:
|
|
|
|
super().__init__(data)
|
|
|
|
idm, pmm = struct.unpack_from(">QQ", data, 0x20)
|
|
|
|
self.idm = hex(idm)[2:].upper()
|
|
|
|
self.pmm = hex(pmm)[2:].upper()
|
|
|
|
|
|
|
|
class ADBFelicaLookupResponse(ADBBaseResponse):
|
|
|
|
def __init__(self, access_code: str = None, game_id: str = "SXXX", store_id: int = 1, keychip_id: str = "A69E01A8888", code: int = 0x03, length: int = 0x30, status: int = 1) -> None:
|
|
|
|
super().__init__(code, length, status, game_id, store_id, keychip_id)
|
|
|
|
self.access_code = access_code if access_code is not None else "00000000000000000000"
|
2023-08-19 07:35:37 +02:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def from_req(cls, req: ADBHeader, access_code: str = None) -> "ADBFelicaLookupResponse":
|
|
|
|
c = cls(access_code, req.game_id, req.store_id, req.keychip_id)
|
|
|
|
c.head.protocol_ver = req.protocol_ver
|
|
|
|
return c
|
|
|
|
|
2023-08-14 05:32:03 +02:00
|
|
|
def make(self) -> bytes:
|
|
|
|
resp_struct = Struct(
|
|
|
|
"felica_idx" / Int32ul,
|
|
|
|
"access_code" / Int8ub[10],
|
|
|
|
Padding(2)
|
|
|
|
).build(dict(
|
|
|
|
felica_idx = 0,
|
|
|
|
access_code = bytes.fromhex(self.access_code)
|
|
|
|
))
|
|
|
|
|
|
|
|
self.head.length = HEADER_SIZE + len(resp_struct)
|
|
|
|
|
|
|
|
return self.head.make() + resp_struct
|
|
|
|
|
|
|
|
class ADBFelicaLookup2Request(ADBBaseRequest):
|
|
|
|
def __init__(self, data: bytes) -> None:
|
|
|
|
super().__init__(data)
|
|
|
|
self.random = struct.unpack_from("<16s", data, 0x20)[0]
|
|
|
|
idm, pmm = struct.unpack_from(">QQ", data, 0x30)
|
|
|
|
self.card_key_ver, self.write_ct, self.maca, company, fw_ver, self.dfc = struct.unpack_from("<16s16sQccH", data, 0x40)
|
|
|
|
self.idm = hex(idm)[2:].upper()
|
|
|
|
self.pmm = hex(pmm)[2:].upper()
|
2023-08-15 16:43:49 +02:00
|
|
|
self.company = CompanyCodes(int.from_bytes(company, 'little'))
|
2023-08-14 05:32:03 +02:00
|
|
|
self.fw_ver = ReaderFwVer.from_byte(fw_ver)
|
|
|
|
|
|
|
|
class ADBFelicaLookup2Response(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
|
|
|
|
self.access_code = access_code if access_code is not None else "00000000000000000000"
|
|
|
|
self.company = CompanyCodes.SEGA
|
|
|
|
self.portal_status = PortalRegStatus.NO_REG
|
|
|
|
|
2023-08-19 07:35:37 +02:00
|
|
|
@classmethod
|
|
|
|
def from_req(cls, req: ADBHeader, user_id: Union[int, None] = None, access_code: Union[str, None] = None) -> "ADBFelicaLookup2Response":
|
|
|
|
c = cls(user_id, access_code, req.game_id, req.store_id, req.keychip_id)
|
|
|
|
c.head.protocol_ver = req.protocol_ver
|
|
|
|
return c
|
|
|
|
|
2023-08-14 05:32:03 +02:00
|
|
|
def make(self) -> bytes:
|
|
|
|
resp_struct = Struct(
|
|
|
|
"user_id" / Int32sl,
|
2023-08-15 16:43:49 +02:00
|
|
|
"relation1" / Int32sl,
|
|
|
|
"relation2" / Int32sl,
|
2023-08-14 05:32:03 +02:00
|
|
|
"access_code" / Int8ub[10],
|
|
|
|
"portal_status" / Int8ub,
|
|
|
|
"company_code" / Int8ub,
|
|
|
|
Padding(8),
|
|
|
|
"auth_key" / Int8ub[256],
|
|
|
|
).build(dict(
|
|
|
|
user_id = self.user_id,
|
|
|
|
relation1 = -1, # Unsupported
|
|
|
|
relation2 = -1, # Unsupported
|
|
|
|
access_code = bytes.fromhex(self.access_code),
|
|
|
|
portal_status = self.portal_status.value,
|
|
|
|
company_code = self.company.value,
|
|
|
|
auth_key = [0] * 256 # Unsupported
|
|
|
|
))
|
|
|
|
|
|
|
|
self.head.length = HEADER_SIZE + len(resp_struct)
|
|
|
|
|
|
|
|
return self.head.make() + resp_struct
|