3
2
forked from Dniel97/artemis

Merge branch 'develop'

This commit is contained in:
Hay1tsme 2023-03-03 17:07:58 -05:00
commit a0e24c6742
9 changed files with 116 additions and 1646 deletions

View File

@ -14,6 +14,7 @@ from time import strptime
from core.config import CoreConfig from core.config import CoreConfig
from core.data import Data from core.data import Data
from core.utils import Utils from core.utils import Utils
from core.const import *
class AllnetServlet: class AllnetServlet:
def __init__(self, core_cfg: CoreConfig, cfg_folder: str): def __init__(self, core_cfg: CoreConfig, cfg_folder: str):
@ -115,6 +116,7 @@ class AllnetServlet:
else: else:
resp = AllnetPowerOnResponse2() resp = AllnetPowerOnResponse2()
self.logger.debug(f"Allnet request: {vars(req)}")
if req.game_id not in self.uri_registry: if req.game_id not in self.uri_registry:
msg = f"Unrecognised game {req.game_id} attempted allnet auth from {request_ip}." msg = f"Unrecognised game {req.game_id} attempted allnet auth from {request_ip}."
self.data.base.log_event("allnet", "ALLNET_AUTH_UNKNOWN_GAME", logging.WARN, msg) self.data.base.log_event("allnet", "ALLNET_AUTH_UNKNOWN_GAME", logging.WARN, msg)
@ -136,15 +138,19 @@ class AllnetServlet:
if machine is not None: if machine is not None:
arcade = self.data.arcade.get_arcade(machine["arcade"]) arcade = self.data.arcade.get_arcade(machine["arcade"])
resp.country = arcade["country"] if machine["country"] is None else machine["country"] country = arcade["country"] if machine["country"] is None else machine["country"]
if country is None:
country = AllnetCountryCode.JAPAN.value
resp.country = country
resp.place_id = arcade["id"] resp.place_id = arcade["id"]
resp.allnet_id = machine["id"] resp.allnet_id = machine["id"]
resp.name = arcade["name"] resp.name = arcade["name"] if arcade["name"] is not None else ""
resp.nickname = arcade["nickname"] resp.nickname = arcade["nickname"] if arcade["nickname"] is not None else ""
resp.region0 = arcade["region_id"] resp.region0 = arcade["region_id"] if arcade["region_id"] is not None else AllnetJapanRegionId.AICHI.value
resp.region_name0 = arcade["country"] resp.region_name0 = arcade["country"] if arcade["country"] is not None else AllnetCountryCode.JAPAN.value
resp.region_name1 = arcade["state"] resp.region_name1 = arcade["state"] if arcade["state"] is not None else AllnetJapanRegionId.AICHI.name
resp.region_name2 = arcade["city"] resp.region_name2 = arcade["city"] if arcade["city"] is not None else ""
resp.client_timezone = arcade["timezone"] if arcade["timezone"] is not None else "+0900" resp.client_timezone = arcade["timezone"] if arcade["timezone"] is not None else "+0900"
int_ver = req.ver.replace(".", "") int_ver = req.ver.replace(".", "")
@ -154,6 +160,7 @@ class AllnetServlet:
msg = f"{req.serial} authenticated from {request_ip}: {req.game_id} v{req.ver}" msg = f"{req.serial} authenticated from {request_ip}: {req.game_id} v{req.ver}"
self.data.base.log_event("allnet", "ALLNET_AUTH_SUCCESS", logging.INFO, msg) self.data.base.log_event("allnet", "ALLNET_AUTH_SUCCESS", logging.INFO, msg)
self.logger.info(msg) self.logger.info(msg)
self.logger.debug(f"Allnet response: {vars(resp)}")
return self.dict_to_http_form_string([vars(resp)]).encode("utf-8") return self.dict_to_http_form_string([vars(resp)]).encode("utf-8")

File diff suppressed because it is too large Load Diff

View File

@ -4,8 +4,10 @@ from sqlalchemy.sql.schema import ForeignKey, PrimaryKeyConstraint
from sqlalchemy.types import Integer, String, Boolean from sqlalchemy.types import Integer, String, Boolean
from sqlalchemy.sql import func, select from sqlalchemy.sql import func, select
from sqlalchemy.dialects.mysql import insert from sqlalchemy.dialects.mysql import insert
import re
from core.data.schema.base import BaseData, metadata from core.data.schema.base import BaseData, metadata
from core.const import *
arcade = Table( arcade = Table(
"arcade", "arcade",
@ -50,9 +52,20 @@ arcade_owner = Table(
class ArcadeData(BaseData): class ArcadeData(BaseData):
def get_machine(self, serial: str = None, id: int = None) -> Optional[Dict]: def get_machine(self, serial: str = None, id: int = None) -> Optional[Dict]:
if serial is not None: if serial is not None:
serial = serial.replace("-", "")
if len(serial) == 11:
sql = machine.select(machine.c.serial.like(f"{serial}%"))
elif len(serial) == 15:
sql = machine.select(machine.c.serial == serial) sql = machine.select(machine.c.serial == serial)
else:
self.logger.error(f"{__name__ }: Malformed serial {serial}")
return None
elif id is not None: elif id is not None:
sql = machine.select(machine.c.id == id) sql = machine.select(machine.c.id == id)
else: else:
self.logger.error(f"{__name__ }: Need either serial or ID to look up!") self.logger.error(f"{__name__ }: Need either serial or ID to look up!")
return None return None
@ -61,20 +74,28 @@ class ArcadeData(BaseData):
if result is None: return None if result is None: return None
return result.fetchone() return result.fetchone()
def put_machine(self, arcade_id: int, serial: str = None, board: str = None, game: str = None, is_cab: bool = False) -> Optional[int]: def put_machine(self, arcade_id: int, serial: str = "", board: str = None, game: str = None, is_cab: bool = False) -> Optional[int]:
if arcade_id: if arcade_id:
self.logger.error(f"{__name__ }: Need arcade id!") self.logger.error(f"{__name__ }: Need arcade id!")
return None return None
if serial is None:
pass
sql = machine.insert().values(arcade = arcade_id, keychip = serial, board = board, game = game, is_cab = is_cab) sql = machine.insert().values(arcade = arcade_id, keychip = serial, board = board, game = game, is_cab = is_cab)
result = self.execute(sql) result = self.execute(sql)
if result is None: return None if result is None: return None
return result.lastrowid return result.lastrowid
def set_machine_serial(self, machine_id: int, serial: str) -> None:
result = self.execute(machine.update(machine.c.id == machine_id).values(keychip = serial))
if result is None:
self.logger.error(f"Failed to update serial for machine {machine_id} -> {serial}")
return result.lastrowid
def set_machine_boardid(self, machine_id: int, boardid: str) -> None:
result = self.execute(machine.update(machine.c.id == machine_id).values(board = boardid))
if result is None:
self.logger.error(f"Failed to update board id for machine {machine_id} -> {boardid}")
def get_arcade(self, id: int) -> Optional[Dict]: def get_arcade(self, id: int) -> Optional[Dict]:
sql = arcade.select(arcade.c.id == id) sql = arcade.select(arcade.c.id == id)
result = self.execute(sql) result = self.execute(sql)
@ -109,5 +130,31 @@ class ArcadeData(BaseData):
if result is None: return None if result is None: return None
return result.lastrowid return result.lastrowid
def generate_keychip_serial(self, platform_id: int) -> str: def format_serial(self, platform_code: str, platform_rev: int, serial_num: int, append: int = 4152) -> str:
pass return f"{platform_code}{platform_rev:02d}A{serial_num:04d}{append:04d}" # 0x41 = A, 0x52 = R
def validate_keychip_format(self, serial: str) -> bool:
serial = serial.replace("-", "")
if len(serial) != 11 or len(serial) != 15:
self.logger.error(f"Serial validate failed: Incorrect length for {serial} (len {len(serial)})")
return False
platform_code = serial[:4]
platform_rev = serial[4:6]
const_a = serial[6]
num = serial[7:11]
append = serial[11:15]
if re.match("A[7|6]\d[E|X][0|1][0|1|2]A\d{4,8}", serial) is None:
self.logger.error(f"Serial validate failed: {serial} failed regex")
return False
if len(append) != 0 or len(append) != 4:
self.logger.error(f"Serial validate failed: {serial} had malformed append {append}")
return False
if len(num) != 4:
self.logger.error(f"Serial validate failed: {serial} had malformed number {num}")
return False
return True

View File

@ -33,15 +33,4 @@ if __name__=='__main__':
else: else:
data.migrate_database(args.game, int(args.version), args.action) data.migrate_database(args.game, int(args.version), args.action)
elif args.action == "migrate":
data.logger.info("Migrating from old schema to new schema")
data.restore_from_old_schema()
elif args.action == "dump":
data.logger.info("Dumping old schema to migrate to new schema")
data.dump_db()
elif args.action == "generate":
pass
data.logger.info("Done") data.logger.info("Done")

View File

@ -96,7 +96,7 @@ sudo ufw allow 8443
sudo ufw allow 22345 sudo ufw allow 22345
sudo ufw allow 8090 sudo ufw allow 8090
sudo ufw allow 8444 sudo ufw allow 8444
sudo ufw allow 9000 sudo ufw allow 8080
``` ```
## Running the ARTEMiS instance ## Running the ARTEMiS instance

View File

@ -57,7 +57,7 @@ title:
## Firewall Adjustements ## Firewall Adjustements
Make sure the following ports are open both on your router and local Windows firewall in case you want to use this for public use (NOT recommended): Make sure the following ports are open both on your router and local Windows firewall in case you want to use this for public use (NOT recommended):
> Port 80 (TCP), 443 (TCP), 8443 (TCP), 22345 (TCP), 8090 (TCP) **webui, 8444 (TCP) **mucha, 9000 (TCP) > Port 80 (TCP), 443 (TCP), 8443 (TCP), 22345 (TCP), 8080 (TCP), 8090 (TCP) **webui, 8444 (TCP) **mucha
## Running the ARTEMiS instance ## Running the ARTEMiS instance
> python index.py > python index.py

View File

@ -9,6 +9,7 @@ from titles.wacca.const import WaccaConstants
from titles.wacca.database import WaccaData from titles.wacca.database import WaccaData
from titles.wacca.handlers import * from titles.wacca.handlers import *
from core.const import AllnetCountryCode
class WaccaBase(): class WaccaBase():
def __init__(self, cfg: CoreConfig, game_cfg: WaccaConfig) -> None: def __init__(self, cfg: CoreConfig, game_cfg: WaccaConfig) -> None:
@ -74,6 +75,7 @@ class WaccaBase():
if prefecture_name not in [region.name for region in WaccaConstants.Region]: if prefecture_name not in [region.name for region in WaccaConstants.Region]:
self.logger.warning(f"Invalid prefecture name {game_cfg.server.prefecture_name} in config file") self.logger.warning(f"Invalid prefecture name {game_cfg.server.prefecture_name} in config file")
self.region_id = WaccaConstants.Region.HOKKAIDO self.region_id = WaccaConstants.Region.HOKKAIDO
else: else:
self.region_id = WaccaConstants.Region[prefecture_name] self.region_id = WaccaConstants.Region[prefecture_name]
@ -91,11 +93,29 @@ class WaccaBase():
def handle_housing_start_request(self, data: Dict) -> Dict: def handle_housing_start_request(self, data: Dict) -> Dict:
req = HousingStartRequestV1(data) req = HousingStartRequestV1(data)
if req.appVersion.country != "JPN" and req.appVersion.country in [region.name for region in WaccaConstants.Region]: machine = self.data.arcade.get_machine(req.chipId)
region_id = WaccaConstants.Region[req.appVersion.country] if machine is not None:
arcade = self.data.arcade.get_arcade(machine["arcade"])
allnet_region_id = arcade["region_id"]
if req.appVersion.country == AllnetCountryCode.JAPAN.value:
if allnet_region_id is not None:
region = WaccaConstants.allnet_region_id_to_wacca_region(allnet_region_id)
if region is None:
region_id = self.region_id
else:
region_id = region
else: else:
region_id = self.region_id region_id = self.region_id
elif req.appVersion.country in WaccaConstants.VALID_COUNTRIES:
region_id = WaccaConstants.Region[req.appVersion.country]
else:
region_id = WaccaConstants.Region.NONE
resp = HousingStartResponseV1(region_id) resp = HousingStartResponseV1(region_id)
return resp.make() return resp.make()

View File

@ -1,4 +1,7 @@
from enum import Enum from enum import Enum
from typing import Optional
from core.const import AllnetJapanRegionId
class WaccaConstants(): class WaccaConstants():
CONFIG_NAME = "wacca.yaml" CONFIG_NAME = "wacca.yaml"
@ -166,3 +169,21 @@ class WaccaConstants():
@classmethod @classmethod
def game_ver_to_string(cls, ver: int): def game_ver_to_string(cls, ver: int):
return cls.VERSION_NAMES[ver] return cls.VERSION_NAMES[ver]
@classmethod
def allnet_region_id_to_wacca_region(cls, region: int) -> Optional[Region]:
try:
return [
cls.Region.NONE, cls.Region.AICHI, cls.Region.AOMORI, cls.Region.AKITA, cls.Region.ISHIKAWA,
cls.Region.IBARAKI, cls.Region.IWATE, cls.Region.EHIME, cls.Region.OITA, cls.Region.OSAKA,
cls.Region.OKAYAMA, cls.Region.OKINAWA, cls.Region.KAGAWA, cls.Region.KAGOSHIMA, cls.Region.KANAGAWA,
cls.Region.GIFU, cls.Region.KYOTO, cls.Region.KUMAMOTO, cls.Region.GUNMA, cls.Region.KOCHI,
cls.Region.SAITAMA, cls.Region.SAGA, cls.Region.SHIGA, cls.Region.SHIZUOKA, cls.Region.SHIMANE,
cls.Region.CHIBA, cls.Region.TOKYO, cls.Region.TOKUSHIMA, cls.Region.TOCHIGI, cls.Region.TOTTORI,
cls.Region.TOYAMA, cls.Region.NAGASAKI, cls.Region.NAGANO, cls.Region.NARA, cls.Region.NIIGATA,
cls.Region.HYOGO, cls.Region.HIROSHIMA, cls.Region.FUKUI, cls.Region.FUKUOKA, cls.Region.FUKUSHIMA,
cls.Region.HOKKAIDO, cls.Region.MIE, cls.Region.MIYAGI, cls.Region.MIYAZAKI, cls.Region.YAMAGATA,
cls.Region.YAMAGUCHI, cls.Region.YAMANASHI, cls.Region.WAKAYAMA,
][region]
except: return None

View File

@ -78,9 +78,9 @@ class Version(ShortVersion):
super().__init__(version, major, minor, patch) super().__init__(version, major, minor, patch)
split = version.split(".") split = version.split(".")
if len(split) >= 6: if len(split) >= 6:
self.country = split[3] self.country: str = split[3]
self.build = int(split[4]) self.build = int(split[4])
self.role = split[5] self.role: str = split[5]
else: else:
self.country = country self.country = country