Merge branch 'develop' into diva_handler_classes

This commit is contained in:
Hay1tsme 2023-03-13 02:27:12 -04:00
commit 3076bdf575
22 changed files with 221 additions and 202 deletions

View File

@ -12,8 +12,8 @@ from Crypto.Signature import PKCS1_v1_5
from time import strptime
from core.config import CoreConfig
from core.data import Data
from core.utils import Utils
from core.data import Data
from core.const import *
@ -65,11 +65,11 @@ class AllnetServlet:
self.uri_registry[code] = (uri, host)
self.logger.info(
f"Allnet serving {len(self.uri_registry)} games on port {core_cfg.allnet.port}"
f"Serving {len(self.uri_registry)} game codes port {core_cfg.allnet.port}"
)
def handle_poweron(self, request: Request, _: Dict):
request_ip = request.getClientAddress().host
request_ip = Utils.get_ip_addr(request)
try:
req_dict = self.allnet_req_to_dict(request.content.getvalue())
if req_dict is None:
@ -78,13 +78,7 @@ class AllnetServlet:
req = AllnetPowerOnRequest(req_dict[0])
# Validate the request. Currently we only validate the fields we plan on using
if (
not req.game_id
or not req.ver
or not req.token
or not req.serial
or not req.ip
):
if not req.game_id or not req.ver or not req.serial or not req.ip:
raise AllnetRequestException(
f"Bad auth request params from {request_ip} - {vars(req)}"
)
@ -94,7 +88,7 @@ class AllnetServlet:
self.logger.error(e)
return b""
if req.format_ver == 3:
if req.format_ver == "3":
resp = AllnetPowerOnResponse3(req.token)
else:
resp = AllnetPowerOnResponse2()
@ -168,7 +162,7 @@ class AllnetServlet:
return self.dict_to_http_form_string([vars(resp)]).encode("utf-8")
def handle_dlorder(self, request: Request, _: Dict):
request_ip = request.getClientAddress().host
request_ip = Utils.get_ip_addr(request)
try:
req_dict = self.allnet_req_to_dict(request.content.getvalue())
if req_dict is None:
@ -261,7 +255,7 @@ class AllnetServlet:
return resp_str.encode("utf-8")
def handle_naomitest(self, request: Request, _: Dict) -> bytes:
self.logger.info(f"Ping from {request.getClientAddress().host}")
self.logger.info(f"Ping from {Utils.get_ip_addr(request)}")
return b"naomi ok"
def kvp_to_dict(self, kvp: List[str]) -> List[Dict[str, Any]]:
@ -346,20 +340,16 @@ class AllnetPowerOnRequest:
def __init__(self, req: Dict) -> None:
if req is None:
raise AllnetRequestException("Request processing failed")
self.game_id: str = req["game_id"] if "game_id" in req else ""
self.ver: str = req["ver"] if "ver" in req else ""
self.serial: str = req["serial"] if "serial" in req else ""
self.ip: str = req["ip"] if "ip" in req else ""
self.firm_ver: str = req["firm_ver"] if "firm_ver" in req else ""
self.boot_ver: str = req["boot_ver"] if "boot_ver" in req else ""
self.encode: str = req["encode"] if "encode" in req else ""
try:
self.hops = int(req["hops"]) if "hops" in req else 0
self.format_ver = int(req["format_ver"]) if "format_ver" in req else 2
self.token = int(req["token"]) if "token" in req else 0
except ValueError as e:
raise AllnetRequestException(f"Failed to parse int: {e}")
self.game_id: str = req.get("game_id", "")
self.ver: str = req.get("ver", "")
self.serial: str = req.get("serial", "")
self.ip: str = req.get("ip", "")
self.firm_ver: str = req.get("firm_ver", "")
self.boot_ver: str = req.get("boot_ver", "")
self.encode: str = req.get("encode", "")
self.hops = int(req.get("hops", "0"))
self.format_ver = req.get("format_ver", "2")
self.token = int(req.get("token", "0"))
class AllnetPowerOnResponse3:
@ -413,10 +403,10 @@ class AllnetPowerOnResponse2:
class AllnetDownloadOrderRequest:
def __init__(self, req: Dict) -> None:
self.game_id = req["game_id"] if "game_id" in req else ""
self.ver = req["ver"] if "ver" in req else ""
self.serial = req["serial"] if "serial" in req else ""
self.encode = req["encode"] if "encode" in req else ""
self.game_id = req.get("game_id", "")
self.ver = req.get("ver", "")
self.serial = req.get("serial", "")
self.encode = req.get("encode", "")
class AllnetDownloadOrderResponse:

View File

@ -267,24 +267,6 @@ class MuchaConfig:
self.__config, "core", "mucha", "hostname", default="localhost"
)
@property
def port(self) -> int:
return CoreConfig.get_config_field(
self.__config, "core", "mucha", "port", default=8444
)
@property
def ssl_cert(self) -> str:
return CoreConfig.get_config_field(
self.__config, "core", "mucha", "ssl_cert", default="cert/server.pem"
)
@property
def signing_key(self) -> str:
return CoreConfig.get_config_field(
self.__config, "core", "mucha", "signing_key", default="cert/billing.key"
)
class CoreConfig(dict):
def __init__(self) -> None:

View File

@ -71,7 +71,8 @@ class Data:
games = Utils.get_all_titles()
for game_dir, game_mod in games.items():
try:
title_db = game_mod.database(self.config)
if hasattr(game_mod, "database") and hasattr(game_mod, "current_schema_version"):
game_mod.database(self.config)
metadata.create_all(self.__engine.connect())
self.base.set_schema_ver(
@ -109,7 +110,8 @@ class Data:
mod = importlib.import_module(f"titles.{dir}")
try:
title_db = mod.database(self.config)
if hasattr(mod, "database"):
mod.database(self.config)
metadata.drop_all(self.__engine.connect())
except Exception as e:

View File

@ -10,9 +10,8 @@ from twisted.python.components import registerAdapter
import jinja2
import bcrypt
from core.config import CoreConfig
from core import CoreConfig, Utils
from core.data import Data
from core.utils import Utils
class IUserSession(Interface):
@ -143,7 +142,7 @@ class FE_Gate(FE_Base):
def render_POST(self, request: Request):
uri = request.uri.decode()
ip = request.getClientAddress().host
ip = Utils.get_ip_addr(request)
if uri == "/gate/gate.login":
access_code: str = request.args[b"access_code"][0].decode()

View File

@ -6,7 +6,7 @@ from twisted.web.http import Request
from datetime import datetime
import pytz
from core.config import CoreConfig
from core import CoreConfig
from core.utils import Utils
@ -47,11 +47,13 @@ class MuchaServlet:
self.mucha_registry.append(game_cd)
self.logger.info(
f"Serving {len(self.mucha_registry)} games on port {self.config.mucha.port}"
f"Serving {len(self.mucha_registry)} games"
)
def handle_boardauth(self, request: Request, _: Dict) -> bytes:
req_dict = self.mucha_preprocess(request.content.getvalue())
client_ip = Utils.get_ip_addr(request)
if req_dict is None:
self.logger.error(
f"Error processing mucha request {request.content.getvalue()}"
@ -61,7 +63,7 @@ class MuchaServlet:
req = MuchaAuthRequest(req_dict)
self.logger.debug(f"Mucha request {vars(req)}")
self.logger.info(
f"Boardauth request from {request.getClientAddress().host} for {req.gameVer}"
f"Boardauth request from {client_ip} for {req.gameVer}"
)
if req.gameCd not in self.mucha_registry:
@ -71,7 +73,7 @@ class MuchaServlet:
# TODO: Decrypt S/N
resp = MuchaAuthResponse(
f"{self.config.mucha.hostname}{':' + self.config.mucha.port if self.config.server.is_develop else ''}"
f"{self.config.mucha.hostname}{':' + str(self.config.allnet.port) if self.config.server.is_develop else ''}"
)
self.logger.debug(f"Mucha response {vars(resp)}")
@ -80,6 +82,8 @@ class MuchaServlet:
def handle_updatecheck(self, request: Request, _: Dict) -> bytes:
req_dict = self.mucha_preprocess(request.content.getvalue())
client_ip = Utils.get_ip_addr(request)
if req_dict is None:
self.logger.error(
f"Error processing mucha request {request.content.getvalue()}"
@ -89,7 +93,7 @@ class MuchaServlet:
req = MuchaUpdateRequest(req_dict)
self.logger.debug(f"Mucha request {vars(req)}")
self.logger.info(
f"Updatecheck request from {request.getClientAddress().host} for {req.gameVer}"
f"Updatecheck request from {client_ip} for {req.gameVer}"
)
if req.gameCd not in self.mucha_registry:
@ -132,24 +136,19 @@ class MuchaServlet:
class MuchaAuthRequest:
def __init__(self, request: Dict) -> None:
self.gameVer = (
"" if "gameVer" not in request else request["gameVer"]
) # gameCd + boardType + countryCd + version
self.sendDate = (
"" if "sendDate" not in request else request["sendDate"]
) # %Y%m%d
self.serialNum = "" if "serialNum" not in request else request["serialNum"]
self.gameCd = "" if "gameCd" not in request else request["gameCd"]
self.boardType = "" if "boardType" not in request else request["boardType"]
self.boardId = "" if "boardId" not in request else request["boardId"]
self.mac = "" if "mac" not in request else request["mac"]
self.placeId = "" if "placeId" not in request else request["placeId"]
self.storeRouterIp = (
"" if "storeRouterIp" not in request else request["storeRouterIp"]
)
self.countryCd = "" if "countryCd" not in request else request["countryCd"]
self.useToken = "" if "useToken" not in request else request["useToken"]
self.allToken = "" if "allToken" not in request else request["allToken"]
# gameCd + boardType + countryCd + version
self.gameVer = request.get("gameVer", "")
self.sendDate = request.get("sendDate", "") # %Y%m%d
self.serialNum = request.get("serialNum", "")
self.gameCd = request.get("gameCd", "")
self.boardType = request.get("boardType", "")
self.boardId = request.get("boardId", "")
self.mac = request.get("mac", "")
self.placeId = request.get("placeId", "")
self.storeRouterIp = request.get("storeRouterIp", "")
self.countryCd = request.get("countryCd", "")
self.useToken = request.get("useToken", "")
self.allToken = request.get("allToken", "")
class MuchaAuthResponse:
@ -199,14 +198,12 @@ class MuchaAuthResponse:
class MuchaUpdateRequest:
def __init__(self, request: Dict) -> None:
self.gameVer = "" if "gameVer" not in request else request["gameVer"]
self.gameCd = "" if "gameCd" not in request else request["gameCd"]
self.serialNum = "" if "serialNum" not in request else request["serialNum"]
self.countryCd = "" if "countryCd" not in request else request["countryCd"]
self.placeId = "" if "placeId" not in request else request["placeId"]
self.storeRouterIp = (
"" if "storeRouterIp" not in request else request["storeRouterIp"]
)
self.gameVer = request.get("gameVer", "")
self.gameCd = request.get("gameCd", "")
self.serialNum = request.get("serialNum", "")
self.countryCd = request.get("countryCd", "")
self.placeId = request.get("placeId", "")
self.storeRouterIp = request.get("storeRouterIp", "")
class MuchaUpdateResponse:

View File

@ -68,7 +68,7 @@ class TitleServlet:
self.logger.error(f"{folder} missing game_code or index in __init__.py")
self.logger.info(
f"Serving {len(self.title_registry)} game codes on port {core_cfg.title.port}"
f"Serving {len(self.title_registry)} game codes {'on port ' + str(core_cfg.title.port) if core_cfg.title.port > 0 else ''}"
)
def render_GET(self, request: Request, endpoints: dict) -> bytes:

View File

@ -1,5 +1,6 @@
from typing import Dict, Any
from types import ModuleType
from twisted.web.http import Request
import logging
import importlib
from os import walk
@ -21,3 +22,7 @@ class Utils:
logging.getLogger("core").error(f"get_all_titles: {dir} - {e}")
raise
return ret
@classmethod
def get_ip_addr(cls, req: Request) -> str:
return req.getAllHeaders()[b"x-forwarded-for"].decode() if b"x-forwarded-for" in req.getAllHeaders() else req.getClientAddress().host

View File

@ -48,6 +48,3 @@ mucha:
enable: False
hostname: "localhost"
loglevel: "info"
port: 8444
ssl_key: "cert/server.key"
ssl_cert: "cert/server.pem"

View File

@ -4,6 +4,8 @@ server {
server_name naominet.jp;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass_request_headers on;
proxy_pass http://localhost:8000/;
}
}
@ -14,6 +16,8 @@ server {
server_name your.hostname.here;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass_request_headers on;
proxy_pass http://localhost:8080/;
}
}
@ -75,6 +79,8 @@ server {
ssl_prefer_server_ciphers off;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass_request_headers on;
proxy_pass http://localhost:8080/;
}
}
@ -95,6 +101,8 @@ server {
ssl_prefer_server_ciphers off;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass_request_headers on;
proxy_pass http://localhost:8080/SDBT/104/;
}
}
@ -131,6 +139,8 @@ server {
add_header Strict-Transport-Security "max-age=63072000" always;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass_request_headers on;
proxy_pass http://localhost:8090/;
}
}

View File

@ -3,9 +3,6 @@ server:
enable: True
loglevel: "info"
port: 9000
port_matching: 9001
port_stun: 9002
port_turn: 9003
port_admission: 9004
ssl_cert: cert/pokken.crt
ssl_key: cert/pokken.key
port_stun: 9001
port_turn: 9002
port_admission: 9003

View File

@ -73,7 +73,7 @@ class HttpDispatcher(resource.Resource):
"mucha_updatacheck",
"/mucha/updatacheck.do",
controller="mucha",
action="handle_updatacheck",
action="handle_updatecheck",
conditions=dict(method=["POST"]),
)
@ -96,9 +96,11 @@ class HttpDispatcher(resource.Resource):
def render_GET(self, request: Request) -> bytes:
test = self.map_get.match(request.uri.decode())
client_ip = Utils.get_ip_addr(request)
if test is None:
self.logger.debug(
f"Unknown GET endpoint {request.uri.decode()} from {request.getClientAddress().host} to port {request.getHost().port}"
f"Unknown GET endpoint {request.uri.decode()} from {client_ip} to port {request.getHost().port}"
)
request.setResponseCode(404)
return b"Endpoint not found."
@ -107,9 +109,11 @@ class HttpDispatcher(resource.Resource):
def render_POST(self, request: Request) -> bytes:
test = self.map_post.match(request.uri.decode())
client_ip = Utils.get_ip_addr(request)
if test is None:
self.logger.debug(
f"Unknown POST endpoint {request.uri.decode()} from {request.getClientAddress().host} to port {request.getHost().port}"
f"Unknown POST endpoint {request.uri.decode()} from {client_ip} to port {request.getHost().port}"
)
request.setResponseCode(404)
return b"Endpoint not found."
@ -163,6 +167,9 @@ if __name__ == "__main__":
if path.exists(f"{args.config}/core.yaml"):
cfg.update(yaml.safe_load(open(f"{args.config}/core.yaml")))
if not path.exists(cfg.server.log_dir):
mkdir(cfg.server.log_dir)
logger = logging.getLogger("core")
log_fmt_str = "[%(asctime)s] Core | %(levelname)s | %(message)s"
log_fmt = logging.Formatter(log_fmt_str)
@ -182,9 +189,6 @@ if __name__ == "__main__":
logger.setLevel(log_lv)
coloredlogs.install(level=log_lv, logger=logger, fmt=log_fmt_str)
if not path.exists(cfg.server.log_dir):
mkdir(cfg.server.log_dir)
if not access(cfg.server.log_dir, W_OK):
logger.error(
f"Log directory {cfg.server.log_dir} NOT writable, please check permissions"

View File

@ -9,8 +9,7 @@ import logging, coloredlogs
from logging.handlers import TimedRotatingFileHandler
from typing import List, Optional
from core import CoreConfig
from core.utils import Utils
from core import CoreConfig, Utils
class BaseReader:

View File

@ -11,7 +11,7 @@ from Crypto.Util.Padding import pad
from os import path
from typing import Tuple
from core import CoreConfig
from core import CoreConfig, Utils
from titles.chuni.config import ChuniConfig
from titles.chuni.const import ChuniConstants
from titles.chuni.base import ChuniBase
@ -111,6 +111,7 @@ class ChuniServlet:
encrtped = False
internal_ver = 0
endpoint = url_split[len(url_split) - 1]
client_ip = Utils.get_ip_addr(request)
if version < 105: # 1.0
internal_ver = ChuniConstants.VER_CHUNITHM
@ -179,7 +180,7 @@ class ChuniServlet:
req_data = json.loads(unzip)
self.logger.info(
f"v{version} {endpoint} request from {request.getClientAddress().host}"
f"v{version} {endpoint} request from {client_ip}"
)
self.logger.debug(req_data)

View File

@ -60,6 +60,9 @@ class ChuniNew(ChuniBase):
"isAou": "false",
}
def handle_remove_token_api_request(self, data: Dict) -> Dict:
return { "returnCode": "1" }
def handle_delete_token_api_request(self, data: Dict) -> Dict:
return {"returnCode": "1"}

View File

@ -27,6 +27,8 @@ class CardMaker136(CardMakerBase):
ret["gameConnectList"][1]["titleUri"] = f"{uri}/SDEZ/125/"
ret["gameConnectList"][2]["titleUri"] = f"{uri}/SDDT/135/"
return ret
def handle_get_game_setting_api_request(self, data: Dict) -> Dict:
ret = super().handle_get_game_setting_api_request(data)
ret["gameSetting"]["dataVersion"] = "1.35.00"

View File

@ -98,11 +98,11 @@ class CxbServlet(resource.Resource):
).listen(server.Site(CxbServlet(self.core_cfg, self.cfg_dir)))
self.logger.info(
f"Crossbeats title server ready on port {self.game_cfg.server.port} & {self.game_cfg.server.port_secure}"
f"Ready on ports {self.game_cfg.server.port} & {self.game_cfg.server.port_secure}"
)
else:
self.logger.info(
f"Crossbeats title server ready on port {self.game_cfg.server.port}"
f"Ready on port {self.game_cfg.server.port}"
)
def render_POST(self, request: Request):

View File

@ -298,6 +298,6 @@ class DivaReader(BaseReader):
tree[key] = (
value
if len(vector) == 1
else self.add_branch(tree[key] if key in tree else {}, vector[1:], value)
else self.add_branch(tree.get(key, {}), vector[1:], value)
)
return tree

View File

@ -1,6 +1,6 @@
from datetime import datetime, timedelta
import json
from typing import Any
import json, logging
from typing import Any, Dict
from core.config import CoreConfig
from titles.pokken.config import PokkenConfig
@ -12,6 +12,7 @@ class PokkenBase:
self.core_cfg = core_cfg
self.game_cfg = game_cfg
self.version = 0
self.logger = logging.getLogger("pokken")
def handle_noop(self, request: Any) -> bytes:
res = jackal_pb2.Response()
@ -20,25 +21,26 @@ class PokkenBase:
return res.SerializeToString()
def handle_ping(self, request: jackal_pb2.PingRequestData) -> bytes:
def handle_ping(self, request: jackal_pb2.Request) -> bytes:
res = jackal_pb2.Response()
res.result = 1
res.type = jackal_pb2.MessageType.PING
return res.SerializeToString()
def handle_register_pcb(self, request: jackal_pb2.RegisterPcbRequestData) -> bytes:
def handle_register_pcb(self, request: jackal_pb2.Request) -> bytes:
res = jackal_pb2.Response()
res.result = 1
res.type = jackal_pb2.MessageType.REGISTER_PCB
self.logger.info(f"Register PCB {request.register_pcb.pcb_id}")
regist_pcb = jackal_pb2.RegisterPcbResponseData()
regist_pcb.server_time = int(datetime.now().timestamp() / 1000)
regist_pcb.server_time = int(datetime.now().timestamp())
biwa_setting = {
"MatchingServer": {
"host": f"https://{self.game_cfg.server.hostname}",
"port": self.game_cfg.server.port_matching,
"url": "/matching",
"port": self.game_cfg.server.port,
"url": "/SDAK/100/matching",
},
"StunServer": {
"addr": self.game_cfg.server.hostname,
@ -60,7 +62,7 @@ class PokkenBase:
return res.SerializeToString()
def handle_save_ads(self, request: jackal_pb2.SaveAdsRequestData) -> bytes:
def handle_save_ads(self, request: jackal_pb2.Request) -> bytes:
res = jackal_pb2.Response()
res.result = 1
res.type = jackal_pb2.MessageType.SAVE_ADS
@ -68,7 +70,7 @@ class PokkenBase:
return res.SerializeToString()
def handle_save_client_log(
self, request: jackal_pb2.SaveClientLogRequestData
self, request: jackal_pb2.Request
) -> bytes:
res = jackal_pb2.Response()
res.result = 1
@ -77,7 +79,7 @@ class PokkenBase:
return res.SerializeToString()
def handle_check_diagnosis(
self, request: jackal_pb2.CheckDiagnosisRequestData
self, request: jackal_pb2.Request
) -> bytes:
res = jackal_pb2.Response()
res.result = 1
@ -86,7 +88,7 @@ class PokkenBase:
return res.SerializeToString()
def handle_load_client_settings(
self, request: jackal_pb2.CheckDiagnosisRequestData
self, request: jackal_pb2.Request
) -> bytes:
res = jackal_pb2.Response()
res.result = 1
@ -108,3 +110,36 @@ class PokkenBase:
res.load_client_settings.CopyFrom(settings)
return res.SerializeToString()
def handle_load_ranking(self, request: jackal_pb2.Request) -> bytes:
res = jackal_pb2.Response()
res.result = 1
res.type = jackal_pb2.MessageType.LOAD_RANKING
ranking = jackal_pb2.LoadRankingResponseData()
ranking.ranking_id = 1
ranking.ranking_start = 0
ranking.ranking_end = 1
ranking.event_end = True
ranking.modify_date = int(datetime.now().timestamp() / 1000)
res.load_ranking.CopyFrom(ranking)
def handle_matching_noop(self, data: Dict = {}, client_ip: str = "127.0.0.1") -> Dict:
return {}
def handle_matching_start_matching(self, data: Dict = {}, client_ip: str = "127.0.0.1") -> Dict:
return {}
def handle_matching_is_matching(self, data: Dict = {}, client_ip: str = "127.0.0.1") -> Dict:
"""
"sessionId":"12345678",
"A":{
"pcb_id": data["data"]["must"]["pcb_id"],
"gip": client_ip
},
"list":[]
"""
return {}
def handle_matching_stop_matching(self, data: Dict = {}, client_ip: str = "127.0.0.1") -> Dict:
return {}

View File

@ -31,43 +31,24 @@ class PokkenServerConfig:
self.__config, "pokken", "server", "port", default=9000
)
@property
def port_matching(self) -> int:
return CoreConfig.get_config_field(
self.__config, "pokken", "server", "port_matching", default=9001
)
@property
def port_stun(self) -> int:
return CoreConfig.get_config_field(
self.__config, "pokken", "server", "port_stun", default=9002
self.__config, "pokken", "server", "port_stun", default=9001
)
@property
def port_turn(self) -> int:
return CoreConfig.get_config_field(
self.__config, "pokken", "server", "port_turn", default=9003
self.__config, "pokken", "server", "port_turn", default=9002
)
@property
def port_admission(self) -> int:
return CoreConfig.get_config_field(
self.__config, "pokken", "server", "port_admission", default=9004
self.__config, "pokken", "server", "port_admission", default=9003
)
@property
def ssl_cert(self) -> str:
return CoreConfig.get_config_field(
self.__config, "pokken", "server", "ssl_cert", default="cert/pokken.crt"
)
@property
def ssl_key(self) -> str:
return CoreConfig.get_config_field(
self.__config, "pokken", "server", "ssl_key", default="cert/pokken.key"
)
class PokkenConfig(dict):
def __init__(self) -> None:
self.server = PokkenServerConfig(self)

View File

@ -1,18 +1,20 @@
from typing import Tuple
from twisted.web.http import Request
from twisted.web import resource, server
from twisted.internet import reactor, endpoints
from twisted.web import resource
import json, ast
from datetime import datetime
import yaml
import logging, coloredlogs
from logging.handlers import TimedRotatingFileHandler
from titles.pokken.proto import jackal_pb2
import inflection
from os import path
from google.protobuf.message import DecodeError
from core.config import CoreConfig
from core import CoreConfig, Utils
from titles.pokken.config import PokkenConfig
from titles.pokken.base import PokkenBase
from titles.pokken.const import PokkenConstants
from titles.pokken.proto import jackal_pb2
class PokkenServlet(resource.Resource):
@ -65,17 +67,10 @@ class PokkenServlet(resource.Resource):
if not game_cfg.server.enable:
return (False, "", "")
if core_cfg.server.is_develop:
return (
True,
f"https://{game_cfg.server.hostname}:{game_cfg.server.port}/{game_code}/$v/",
f"{game_cfg.server.hostname}:{game_cfg.server.port}/",
)
return (
True,
f"https://{game_cfg.server.hostname}/{game_code}/$v/",
f"{game_cfg.server.hostname}/",
f"{game_cfg.server.hostname}/SDAK/$v/",
)
@classmethod
@ -90,46 +85,19 @@ class PokkenServlet(resource.Resource):
)
if not game_cfg.server.enable:
return (False, "", "")
return (False, "")
return (True, "PKFN")
return (True, "PKF2")
def setup(self):
"""
There's currently no point in having this server on because Twisted
won't play ball with both the fact that it's TLSv1.1, and because the
types of certs that pokken will accept are too flimsy for Twisted
so it will throw a fit. Currently leaving this here in case a bypass
is discovered in the future, but it's unlikly. For now, just use NGINX.
"""
if self.game_cfg.server.enable and self.core_cfg.server.is_develop:
key_exists = path.exists(self.game_cfg.server.ssl_key)
cert_exists = path.exists(self.game_cfg.server.ssl_cert)
if key_exists and cert_exists:
endpoints.serverFromString(
reactor,
f"ssl:{self.game_cfg.server.port}"
f":interface={self.core_cfg.server.listen_address}:privateKey={self.game_cfg.server.ssl_key}:"
f"certKey={self.game_cfg.server.ssl_cert}",
).listen(server.Site(self))
self.logger.info(
f"Pokken title server ready on port {self.game_cfg.server.port}"
)
else:
self.logger.error(
f"Could not find cert at {self.game_cfg.server.ssl_key} or key at {self.game_cfg.server.ssl_cert}, Pokken not running."
)
def setup(self) -> None:
# TODO: Setup stun, turn (UDP) and admission (WSS) servers
pass
def render_POST(
self, request: Request, version: int = 0, endpoints: str = ""
) -> bytes:
if endpoints == "":
endpoints = request.uri.decode()
if endpoints.startswith("/matching"):
self.logger.info("Matching request")
if endpoints == "matching":
return self.handle_matching(request)
content = request.content.getvalue()
if content == b"":
@ -143,12 +111,50 @@ class PokkenServlet(resource.Resource):
self.logger.warn(f"{e} {content}")
return b""
endpoint = jackal_pb2.MessageType(pokken_request.type).name.lower()
self.logger.info(f"{endpoint} request")
endpoint = jackal_pb2.MessageType.DESCRIPTOR.values_by_number[
pokken_request.type
].name.lower()
handler = getattr(self.base, f"handle_{endpoint}", None)
if handler is None:
self.logger.warn(f"No handler found for message type {endpoint}")
return self.base.handle_noop(pokken_request)
return handler(pokken_request)
self.logger.info(f"{endpoint} request from {Utils.get_ip_addr(request)}")
self.logger.debug(pokken_request)
ret = handler(pokken_request)
self.logger.debug(f"Response: {ret}")
return ret
def handle_matching(self, request: Request) -> bytes:
content = request.content.getvalue()
client_ip = Utils.get_ip_addr(request)
if content is None or content == b"":
self.logger.info("Empty matching request")
return json.dumps(self.base.handle_matching_noop()).encode()
json_content = ast.literal_eval(content.decode().replace('null', 'None').replace('true', 'True').replace('false', 'False'))
self.logger.info(f"Matching {json_content['call']} request")
self.logger.debug(json_content)
handler = getattr(self.base, f"handle_matching_{inflection.underscore(json_content['call'])}", None)
if handler is None:
self.logger.warn(f"No handler found for message type {json_content['call']}")
return json.dumps(self.base.handle_matching_noop()).encode()
ret = handler(json_content, client_ip)
if ret is None:
ret = {}
if "result" not in ret:
ret["result"] = "true"
if "data" not in ret:
ret["data"] = {}
if "timestamp" not in ret:
ret["timestamp"] = int(datetime.now().timestamp() * 1000)
self.logger.debug(f"Response {ret}")
return json.dumps(ret).encode()

View File

@ -1,6 +1,7 @@
import yaml
import jinja2
from twisted.web.http import Request
from os import path
from core.frontend import FE_Base
from core.config import CoreConfig
@ -16,7 +17,10 @@ class WaccaFrontend(FE_Base):
super().__init__(cfg, environment)
self.data = WaccaData(cfg)
self.game_cfg = WaccaConfig()
self.game_cfg.update(yaml.safe_load(open(f"{cfg_dir}/wacca.yaml")))
if path.exists(f"{cfg_dir}/{WaccaConstants.CONFIG_NAME}"):
self.game_cfg.update(
yaml.safe_load(open(f"{cfg_dir}/{WaccaConstants.CONFIG_NAME}"))
)
self.nav_name = "Wacca"
def render_GET(self, request: Request) -> bytes:

View File

@ -8,7 +8,7 @@ from twisted.web.http import Request
from typing import Dict, Tuple
from os import path
from core.config import CoreConfig
from core import CoreConfig, Utils
from titles.wacca.config import WaccaConfig
from titles.wacca.config import WaccaConfig
from titles.wacca.const import WaccaConstants
@ -89,25 +89,30 @@ class WaccaServlet:
request.responseHeaders.addRawHeader(b"X-Wacca-Hash", hash.hex().encode())
return json.dumps(resp).encode()
client_ip = Utils.get_ip_addr(request)
try:
req_json = json.loads(request.content.getvalue())
version_full = Version(req_json["appVersion"])
except:
self.logger.error(
f"Failed to parse request toi {request.uri} -> {request.content.getvalue()}"
f"Failed to parse request to {url_path} -> {request.content.getvalue()}"
)
resp = BaseResponse()
resp.status = 1
resp.message = "不正なリクエスト エラーです"
return end(resp.make())
url_split = url_path.split("/")
start_req_idx = url_split.index("api") + 1
if "/api/" in url_path:
func_to_find = (
"handle_" + url_path.partition("api/")[2].replace("/", "_") + "_request"
)
func_to_find = "handle_"
for x in range(len(url_split) - start_req_idx):
func_to_find += f"{url_split[x + start_req_idx]}_"
func_to_find += "request"
else:
self.logger.error(f"Malformed url {url_path}")
resp = BaseResponse()
resp.status = 1
resp.message = "Bad URL"
return end(resp.make())
ver_search = int(version_full)
@ -136,7 +141,7 @@ class WaccaServlet:
return end(resp.make())
self.logger.info(
f"v{req_json['appVersion']} {url_path} request from {request.getClientAddress().host} with chipId {req_json['chipId']}"
f"v{req_json['appVersion']} {url_path} request from {client_ip} with chipId {req_json['chipId']}"
)
self.logger.debug(req_json)