diff --git a/Dockerfile b/Dockerfile index 90d20fc..46a8f22 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,8 @@ FROM python:3.10 +ENV TINI_VERSION v0.19.0 +ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini +RUN chmod +x /tini +ENTRYPOINT ["/tini", "--"] WORKDIR /app diff --git a/docker-compose.yml b/docker-compose.yml index 4cd019a..4a10424 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,5 +8,16 @@ services: environment: - IWM_SERVER="http://make.fangam.es" - IWM_THUMBNAILS="https://images.make.fangam.es" - - IMGPROXY_URL="http://127.0.0.1:8080" + - IMGPROXY_URL="http://127.0.0.1:5851" - IMGPROXY_PARAMS="{\"advanced\":[\"q:50\"]}" + - 'HTTP_PROXIES={"all://make.fangam.es": "http://squid:3128"}' + imgproxy: + image: 'darthsim/imgproxy' + ports: + - 5851:8080 + squid: + image: 'ubuntu/squid' + environment: + - TZ=UTC + volumes: + - ./squid.conf:/etc/squid/squid.conf diff --git a/iwm_browser/main.py b/iwm_browser/main.py index 6a0b0a7..3c6995d 100644 --- a/iwm_browser/main.py +++ b/iwm_browser/main.py @@ -1,7 +1,7 @@ from typing import Union from fastapi.staticfiles import StaticFiles from fastapi.middleware.gzip import GZipMiddleware -from fastapi.responses import HTMLResponse, PlainTextResponse +from fastapi.responses import HTMLResponse, PlainTextResponse, RedirectResponse from fastapi import FastAPI, Form, Response from typing import Optional import urllib.parse @@ -28,7 +28,6 @@ template_env = jinja2.Environment( error_template = template_env.get_template("error.html") - template_env.globals["builtins"] = __builtins__ template_env.globals["convert_times"] = utils.convert_times template_env.globals["json_dumps"] = json.dumps @@ -46,6 +45,8 @@ utils.global_imgproxy_params = json.loads(utils.config_value("IMGPROXY_PARAMS", "advanced": ["q:50"], }''')) # Set it to None to disable the proxy params +PROXIES = utils.config_value("HTTP_PROXIES", '{}') + # Matches level code. # \S[A-Z0-9]{4}\-[A-Z0-9]{4} = With dash, no whitespace # \S[A-Z0-9]{8} = without dash, no whitespace @@ -76,6 +77,7 @@ async def root(): @app.get("/search", response_class=HTMLResponse) async def search( request: starlette.requests.Request, + response: Response, q: Union[str, None] = None, p: int = 0, sort: str = "average_rating", @@ -133,6 +135,9 @@ async def search( searchValue = q try: + headers = {} + if sort == "random": + headers["Cache-Control"] = "no-cache" rq = httpx.get( BASE_URL + "/api/v1/map", params={ @@ -146,6 +151,8 @@ async def search( **author, }, timeout=10, + proxies=PROXIES, + headers=headers ) if rq.status_code == 503: return error_template.render( @@ -174,11 +181,31 @@ async def search( QueryValues=QueryValues, ) +@app.get("/playlist/featured") +async def get_featured_list(): + try: + rq = httpx.get(BASE_URL + "/api/v1/featuredlist", timeout=10, proxies=PROXIES) + if rq.status_code == 503: + return error_template.render(reason="Server is unavailable right now") + response = rq.json() + + except httpx.ReadTimeout: + return error_template.render(reason="Server timed out") + except json.decoder.JSONDecodeError: + return error_template.render( + reason="Failed to parse server response.", details=rq.text + ) + except Exception as exc: + return error_template.render(reason="Uncaught exception", details=exc) + + + return RedirectResponse("/playlist/" + str(response["ListID"])) + @app.get("/playlist/{playlist_id}", response_class=HTMLResponse) async def showList(request: starlette.requests.Request, playlist_id: int): template = template_env.get_template("playlist.html") try: - rq = httpx.get(BASE_URL + "/api/v1/list/" + str(playlist_id), timeout=10) + rq = httpx.get(BASE_URL + "/api/v1/list/" + str(playlist_id), timeout=10, proxies=PROXIES) if rq.status_code == 503: return error_template.render(reason="Server is unavailable right now") response = rq.json() @@ -205,7 +232,7 @@ async def showLevel(level_id: int): template = template_env.get_template("levelInfo.html") try: - rq = httpx.get(BASE_URL + "/api/v1/map/" + str(level_id), timeout=10) + rq = httpx.get(BASE_URL + "/api/v1/map/" + str(level_id), timeout=10, proxies=PROXIES) if rq.status_code == 503: return error_template.render(reason="Server is unavailable right now") searchResults = rq.json() @@ -230,7 +257,7 @@ async def showUser(user_id: int): template = template_env.get_template("userInfo.html") try: - rq = httpx.get(BASE_URL + "/api/v1/user/" + str(user_id), timeout=10) + rq = httpx.get(BASE_URL + "/api/v1/user/" + str(user_id), timeout=10, proxies=PROXIES) if rq.status_code == 503: return error_template.render(reason="Server is unavailable right now") searchResults = rq.json() diff --git a/iwm_browser/templates/playlist.html b/iwm_browser/templates/playlist.html index df053b7..d1ef9d8 100644 --- a/iwm_browser/templates/playlist.html +++ b/iwm_browser/templates/playlist.html @@ -27,7 +27,7 @@
ID: {{ response.ID }}
Maps: {{ response.MapCount }}
diff --git a/squid.conf b/squid.conf new file mode 100644 index 0000000..5c9e997 --- /dev/null +++ b/squid.conf @@ -0,0 +1,88 @@ +# +# Recommended minimum configuration: +# + +# Example rule allowing access from your local networks. +# Adapt to list your (internal) IP networks from where browsing +# should be allowed +acl localnet src 0.0.0.1-0.255.255.255 # RFC 1122 "this" network (LAN) +acl localnet src 10.0.0.0/8 # RFC 1918 local private network (LAN) +acl localnet src 100.64.0.0/10 # RFC 6598 shared address space (CGN) +acl localnet src 169.254.0.0/16 # RFC 3927 link-local (directly plugged) machines +acl localnet src 172.16.0.0/12 # RFC 1918 local private network (LAN) +acl localnet src 192.168.0.0/16 # RFC 1918 local private network (LAN) +acl localnet src fc00::/7 # RFC 4193 local private network range +acl localnet src fe80::/10 # RFC 4291 link-local (directly plugged) machines + +acl SSL_ports port 443 +acl Safe_ports port 80 # http +# acl Safe_ports port 21 # ftp +acl Safe_ports port 443 # https +# acl Safe_ports port 70 # gopher +# acl Safe_ports port 210 # wais +# acl Safe_ports port 1025-65535 # unregistered ports +# acl Safe_ports port 280 # http-mgmt +# acl Safe_ports port 488 # gss-http +# acl Safe_ports port 591 # filemaker +# acl Safe_ports port 777 # multiling http + +# +# Recommended minimum Access Permission configuration: +# +# Deny requests to certain unsafe ports +http_access deny !Safe_ports + +# Deny CONNECT to other than secure SSL ports +http_access deny CONNECT !SSL_ports + +# Only allow cachemgr access from localhost +http_access allow localhost manager +http_access deny manager + +# This default configuration only allows localhost requests because a more +# permissive Squid installation could introduce new attack vectors into the +# network by proxying external TCP connections to unprotected services. +http_access allow localhost + +# The two deny rules below are unnecessary in this default configuration +# because they are followed by a "deny all" rule. However, they may become +# critically important when you start allowing external requests below them. + +# Protect web applications running on the same server as Squid. They often +# assume that only local users can access them at "localhost" ports. +http_access deny to_localhost + +# Protect cloud servers that provide local users with sensitive info about +# their server via certain well-known link-local (a.k.a. APIPA) addresses. +# http_access deny to_linklocal + +# +# INSERT YOUR OWN RULE(S) HERE TO ALLOW ACCESS FROM YOUR CLIENTS +# + +http_access allow localnet + +# For example, to allow access from your local networks, you may uncomment the +# following rule (and/or add rules that match your definition of "local"): +# http_access allow localnet + +# And finally deny all other access to this proxy +http_access deny all + +# Squid normally listens to port 3128 +http_port 3128 + +# Uncomment and adjust the following to add a disk cache directory. +#cache_dir ufs /var/cache/squid 100 16 256 + +# Leave coredumps in the first cache dir +coredump_dir /var/cache/squid + +max_filedescriptors 16384 +# +# Add any of your own refresh_pattern entries above these. +# +refresh_pattern ^ftp: 1440 20% 10080 +refresh_pattern ^gopher: 1440 0% 1440 +refresh_pattern -i (\?) 1 0% 10 +refresh_pattern . 0 20% 4320