diff --git a/example_config/nginx_example.conf b/example_config/nginx_example.conf index 3b8bf3c..096a072 100644 --- a/example_config/nginx_example.conf +++ b/example_config/nginx_example.conf @@ -18,7 +18,7 @@ server { } } -# SSL titles +# SSL titles, comment out if you don't plan on accepting SSL titles server { listen 443 ssl default_server; listen [::]:443 ssl default_server; @@ -57,4 +57,99 @@ server { location / { proxy_pass http://localhost:8444/; } +} + +# Pokken, comment this out if you don't plan on serving pokken. +server { + listen 443 ssl; + server_name pokken.hostname.here; + + ssl_certificate /path/to/cert/pokken.pem; + ssl_certificate_key /path/to/cert/pokken.key; + ssl_session_timeout 1d; + ssl_session_cache shared:MozSSL:10m; + ssl_session_tickets off; + + ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; + ssl_ciphers "ALL:@SECLEVEL=1"; + ssl_prefer_server_ciphers off; + + location / { + proxy_pass http://localhost:8080/; + } +} + +# CXB, comment this out if you don't plan on serving crossbeats. +server { + listen 443 ssl; + server_name cxb.hostname.here; + + ssl_certificate /path/to/cert/cxb.pem; + ssl_certificate_key /path/to/cert/cxb.key; + ssl_session_timeout 1d; + ssl_session_cache shared:MozSSL:10m; + ssl_session_tickets off; + + ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; + ssl_ciphers "ALL:@SECLEVEL=1"; + ssl_prefer_server_ciphers off; + + location / { + proxy_pass http://localhost:8080/SDBT/104/; + } +} + +# CXB, comment this out if you don't plan on serving crossbeats. +server { + listen 443 ssl; + server_name cxb.hostname.here; + + ssl_certificate /path/to/cert/cxb.pem; + ssl_certificate_key /path/to/cert/cxb.key; + ssl_session_timeout 1d; + ssl_session_cache shared:MozSSL:10m; + ssl_session_tickets off; + + ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; + ssl_ciphers "ALL:@SECLEVEL=1"; + ssl_prefer_server_ciphers off; + + location / { + proxy_pass http://localhost:8080/SDBT/104/; + } +} + +# Frontend, set to redirect to HTTPS. Comment out if you don't intend to use the frontend +server { + listen 80; + server_name frontend.hostname.here + + location / { + return 301 https://$host$request_uri; + # If you don't want https redirection, comment the line above and uncomment the line below + # proxy_pass http://localhost:8090/; + } +} + +# Frontend HTTPS. Comment out if you on't intend to use the frontend +server { + listen 443 ssl; + + ssl_certificate /path/to/cert/frontend.pem; + ssl_certificate_key /path/to/cert/frontend.key; + ssl_session_timeout 1d; + ssl_session_cache shared:MozSSL:10m; # about 40000 sessions + ssl_session_tickets off; + + # intermediate configuration + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; + ssl_prefer_server_ciphers off; + + # HSTS (ngx_http_headers_module is required) (63072000 seconds) + add_header Strict-Transport-Security "max-age=63072000" always; + + location / { + proxy_pass http://localhost:8090/; + } } \ No newline at end of file diff --git a/example_config/pokken.yaml b/example_config/pokken.yaml index 967cca6..5523996 100644 --- a/example_config/pokken.yaml +++ b/example_config/pokken.yaml @@ -1,8 +1,6 @@ server: enable: True loglevel: "info" - hostname: "localhost" - ssl_enable: False port: 9000 port_matching: 9001 ssl_cert: cert/pokken.crt diff --git a/titles/pokken/__init__.py b/titles/pokken/__init__.py index 5be8ac6..3b574fd 100644 --- a/titles/pokken/__init__.py +++ b/titles/pokken/__init__.py @@ -1,7 +1,9 @@ from titles.pokken.index import PokkenServlet from titles.pokken.const import PokkenConstants +from titles.pokken.database import PokkenData index = PokkenServlet +database = PokkenData use_default_title = True include_protocol = True diff --git a/titles/pokken/config.py b/titles/pokken/config.py index 4eb07c6..b6596f2 100644 --- a/titles/pokken/config.py +++ b/titles/pokken/config.py @@ -12,14 +12,6 @@ class PokkenServerConfig(): def loglevel(self) -> int: return CoreConfig.str_to_loglevel(CoreConfig.get_config_field(self.__config, 'pokken', 'server', 'loglevel', default="info")) - @property - def hostname(self) -> str: - return CoreConfig.get_config_field(self.__config, 'pokken', 'server', 'hostname', default="localhost") - - @property - def ssl_enable(self) -> bool: - return CoreConfig.get_config_field(self.__config, 'pokken', 'server', 'ssl_enable', default=False) - @property def port(self) -> int: return CoreConfig.get_config_field(self.__config, 'pokken', 'server', 'port', default=9000) diff --git a/titles/pokken/database.py b/titles/pokken/database.py new file mode 100644 index 0000000..eff928b --- /dev/null +++ b/titles/pokken/database.py @@ -0,0 +1,6 @@ +from core.data import Data +from core.config import CoreConfig + +class PokkenData(Data): + def __init__(self, cfg: CoreConfig) -> None: + super().__init__(cfg) \ No newline at end of file diff --git a/titles/pokken/index.py b/titles/pokken/index.py index facbd52..a47cac7 100644 --- a/titles/pokken/index.py +++ b/titles/pokken/index.py @@ -5,7 +5,8 @@ import yaml import logging, coloredlogs from logging.handlers import TimedRotatingFileHandler from titles.pokken.proto import jackal_pb2 -from google.protobuf import text_format +from os import path +from google.protobuf.message import DecodeError from core.config import CoreConfig from titles.pokken.config import PokkenConfig @@ -41,27 +42,46 @@ class PokkenServlet(resource.Resource): self.base = PokkenBase(core_cfg, self.game_cfg) def setup(self): - if self.game_cfg.server.enable: - if self.core_cfg.server.is_develop and self.game_cfg.server.ssl_enable: + """ + 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.game_cfg.server.hostname}:privateKey={self.game_cfg.server.ssl_key}:"\ + 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(PokkenServlet(self.core_cfg, self.config_dir))) + .listen(server.Site(self)) + + self.logger.info(f"Pokken title server ready on port {self.game_cfg.server.port}") else: - endpoints.serverFromString(reactor, f"tcp:{self.game_cfg.server.port}"\ - f":interface={self.game_cfg.server.hostname}")\ - .listen(server.Site(PokkenServlet(self.core_cfg, self.config_dir))) + 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.") - self.logger.info(f"Pokken title server ready on port {self.game_cfg.server.port}") - - def render_POST(self, request: Request, version: int, endpoints: str) -> bytes: - req_url = request.uri.decode() - if req_url == "/matching": + 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") + + content = request.content.getvalue() + if content == b"": + self.logger.info("Empty request") + return b"" pokken_request = jackal_pb2.Request() - pokken_request.ParseFromString(request.content.getvalue()) + try: + pokken_request.ParseFromString(content) + except DecodeError as e: + self.logger.warn(f"{e} {content}") + return b"" + endpoint = jackal_pb2.MessageType(pokken_request.type).name.lower() self.logger.info(f"{endpoint} request") diff --git a/titles/wacca/base.py b/titles/wacca/base.py index 815a841..5bb83ae 100644 --- a/titles/wacca/base.py +++ b/titles/wacca/base.py @@ -810,9 +810,9 @@ class WaccaBase(): if "always_vip" in profile and profile["always_vip"] or self.game_config.mods.always_vip: return UserVipStartResponse(int((self.srvtime + timedelta(days=req.days)).timestamp())).make() - profile["vip_expire_time"] = int((self.srvtime + timedelta(days=req.days)).timestamp()) - self.data.profile.update_vip_time(req.profileId, self.srvtime + timedelta(days=req.days)) - return UserVipStartResponse(profile["vip_expire_time"]).make() + vip_exp_time = (self.srvtime + timedelta(days=req.days)) + self.data.profile.update_vip_time(req.profileId, vip_exp_time) + return UserVipStartResponse(int(vip_exp_time.timestamp())).make() def util_put_items(self, profile_id: int, user_id: int, items_obtained: List[GenericItemRecv]) -> None: if user_id is None or profile_id <= 0: