From 59b111aaa37a9356feca053d7a64c05ef796b7d9 Mon Sep 17 00:00:00 2001 From: evan Date: Wed, 25 Mar 2026 07:54:10 -0700 Subject: [PATCH 1/8] remove nginx container from cleezy --- docker-compose.yml | 7 ------- nginx.conf | 41 ----------------------------------------- 2 files changed, 48 deletions(-) delete mode 100644 nginx.conf diff --git a/docker-compose.yml b/docker-compose.yml index 4d0b0dd..d347454 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,19 +14,12 @@ services: - -vvv volumes: - cleezy_data:/tmp/ - - nginx_data:/tmp/nginx/ - ./server.py:/app/server.py - ./modules:/app/modules - ./assets:/app/assets - nginx: - container_name: cleezy-nginx - image: nginx:alpine - volumes: - - ./nginx.conf:/etc/nginx/nginx.conf volumes: cleezy_data: - nginx_data: networks: default: diff --git a/nginx.conf b/nginx.conf deleted file mode 100644 index d11a36f..0000000 --- a/nginx.conf +++ /dev/null @@ -1,41 +0,0 @@ -http { - # Define the cache path for NGINX - # levels = number of characters in subdirectory names (/tmp/nginx/1/2a/) - # keys_zone = name of the cache : maximum size of the cache info (10mb) - # max_size = maximum size of the cache content (1gb) - # inactive = cache expiration time (60 minutes) - # use_temp_path = use extra space by writing to a temp directory before moving content --buito cache (off) - proxy_cache_path /tmp/nginx levels=1:2 keys_zone=shortener_cache:10m max_size=1g inactive=60m use_temp_path=off; - - server { - listen 80 default_server; - listen [::]:80 default_server; - server_name _; - - location ~ /s/(.*)$ { - resolver 127.0.0.11 valid=15s; - proxy_set_header Host $host; - set $upstream http://app:8000; - proxy_set_header X-Original-URL $http_x_original_url; - proxy_set_header X-Base-URL $http_x_base_url; - proxy_pass $upstream; - rewrite /s/(.*) /find/$1 break; - } - - location ~ /qr/(.*)$ { - proxy_cache shortener_cache; - proxy_cache_valid 200 60m; - add_header X-Cache-Status $upstream_cache_status; - - resolver 127.0.0.11 valid=15s; - proxy_set_header Host $host; - set $upstream http://app:8000; - proxy_set_header X-Original-URL $http_x_original_url; - proxy_set_header X-Base-URL $http_x_base_url; - proxy_pass $upstream; - rewrite /qr/(.*) /qr/$1 break; - } - } -} - -events { } From 79463bbb7c94c5aa7cb67b63a252e6f66bb83912 Mon Sep 17 00:00:00 2001 From: evan Date: Wed, 25 Mar 2026 08:27:30 -0700 Subject: [PATCH 2/8] retry embed --- server.py | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/server.py b/server.py index 044d0ac..3718b44 100644 --- a/server.py +++ b/server.py @@ -8,6 +8,7 @@ import uvicorn from queue import Queue from threading import Thread +import re from modules.args import get_args from modules.generate_alias import generate_alias @@ -157,7 +158,7 @@ async def delete_url(alias: str): raise HTTPException(status_code=HttpResponse.NOT_FOUND.code) @app.get("/qr/{alias}") -async def qr(alias: str): +async def qr(alias: str, request: Request, static: Optional[str] = None, user_agent: Optional[str] = Header(None)): logging.debug(f"/qr code generation called with alias: {alias}") with MetricsHandler.query_time.labels("qr").time(): maybe_image_data = qr_code_cache.find(alias) @@ -166,15 +167,32 @@ async def qr(alias: str): maybe_image_data, media_type='image/jpeg', ) - + url_output = sqlite_helpers.get_url(DATABASE_FILE, alias) if url_output is None: raise HTTPException(status_code=HttpResponse.NOT_FOUND.code) image_data = qr_code_cache.add(alias) - return FileResponse( - image_data, - media_type='image/jpeg', - ) + + if static: + return FileResponse(image_data, media_type='image/png') + + # try embedding the discord url + # We build the URL and add ?static=1 to prevent the loop + base_url = str(request.base_url).rstrip('/') + full_image_url = f"{base_url}/qr/{alias}?static=1" + + content = f""" + + + + + + + + + + """ + return HTMLResponse(content=content) @app.exception_handler(HTTPException) async def http_exception_handler(request, exc): From 52cb8059eabad4e08147e56211d83bae60f64098 Mon Sep 17 00:00:00 2001 From: evan Date: Wed, 25 Mar 2026 08:30:51 -0700 Subject: [PATCH 3/8] we were returning early --- server.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/server.py b/server.py index 3718b44..17953c1 100644 --- a/server.py +++ b/server.py @@ -162,19 +162,15 @@ async def qr(alias: str, request: Request, static: Optional[str] = None, user_ag logging.debug(f"/qr code generation called with alias: {alias}") with MetricsHandler.query_time.labels("qr").time(): maybe_image_data = qr_code_cache.find(alias) - if maybe_image_data is not None: - return FileResponse( - maybe_image_data, - media_type='image/jpeg', - ) + if maybe_image_data is None: + maybe_image_data = qr_code_cache.add(alias) url_output = sqlite_helpers.get_url(DATABASE_FILE, alias) if url_output is None: raise HTTPException(status_code=HttpResponse.NOT_FOUND.code) - image_data = qr_code_cache.add(alias) if static: - return FileResponse(image_data, media_type='image/png') + return FileResponse(maybe_image_data, media_type='image/png') # try embedding the discord url # We build the URL and add ?static=1 to prevent the loop From 29b76e039c41e3c702bab9a8b8f1f1e9e58284c9 Mon Sep 17 00:00:00 2001 From: evan Date: Wed, 25 Mar 2026 08:39:36 -0700 Subject: [PATCH 4/8] idk --- server.py | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/server.py b/server.py index 17953c1..3014479 100644 --- a/server.py +++ b/server.py @@ -159,22 +159,33 @@ async def delete_url(alias: str): @app.get("/qr/{alias}") async def qr(alias: str, request: Request, static: Optional[str] = None, user_agent: Optional[str] = Header(None)): - logging.debug(f"/qr code generation called with alias: {alias}") + logging.debug(f"/qr called with alias: {alias}, user_agent: {user_agent}, static: {static}") + with MetricsHandler.query_time.labels("qr").time(): + # 1. Ensure the alias exists in the DB first + url_output = sqlite_helpers.get_url(DATABASE_FILE, alias) + if url_output is None: + raise HTTPException(status_code=404) + + # 2. Get/Generate the image maybe_image_data = qr_code_cache.find(alias) if maybe_image_data is None: maybe_image_data = qr_code_cache.add(alias) - url_output = sqlite_helpers.get_url(DATABASE_FILE, alias) - if url_output is None: - raise HTTPException(status_code=HttpResponse.NOT_FOUND.code) - - if static: + # 3. Handle the "Trap Door" for the actual image file + # We also check if it's NOT a bot (like your curl/browser) + is_bot = user_agent and "Discordbot" in user_agent + + if static or not is_bot: + # Force PNG media type here return FileResponse(maybe_image_data, media_type='image/png') - # try embedding the discord url - # We build the URL and add ?static=1 to prevent the loop + # 4. If we reach here, it IS a bot and NOT static -> Send HTML Embed base_url = str(request.base_url).rstrip('/') + # Ensure we use https if you're behind an SSL proxy + if "https" in str(request.url): + base_url = base_url.replace("http://", "https://") + full_image_url = f"{base_url}/qr/{alias}?static=1" content = f""" From ca038c7e97df426dea87d30e1c2b9c3bac4bba56 Mon Sep 17 00:00:00 2001 From: evan Date: Wed, 25 Mar 2026 08:47:11 -0700 Subject: [PATCH 5/8] define header --- server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.py b/server.py index 3014479..fdcf923 100644 --- a/server.py +++ b/server.py @@ -1,5 +1,5 @@ from typing import Optional -from fastapi import FastAPI, Request, HTTPException, Response +from fastapi import FastAPI, Request, HTTPException, Response, Header from fastapi.responses import RedirectResponse, HTMLResponse, FileResponse from fastapi.middleware.cors import CORSMiddleware import logging From 3f978e0b98b8005c409be9a0c532753f0f2d70b9 Mon Sep 17 00:00:00 2001 From: evan Date: Wed, 25 Mar 2026 08:54:08 -0700 Subject: [PATCH 6/8] mention base url in log --- server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.py b/server.py index fdcf923..ed96f75 100644 --- a/server.py +++ b/server.py @@ -159,7 +159,7 @@ async def delete_url(alias: str): @app.get("/qr/{alias}") async def qr(alias: str, request: Request, static: Optional[str] = None, user_agent: Optional[str] = Header(None)): - logging.debug(f"/qr called with alias: {alias}, user_agent: {user_agent}, static: {static}") + logging.debug(f"/qr called with alias: {alias}, user_agent: {user_agent}, static: {static}, {request.base_url}") with MetricsHandler.query_time.labels("qr").time(): # 1. Ensure the alias exists in the DB first From 2c536e4bc479428996c882c97a8e9bda221947c8 Mon Sep 17 00:00:00 2001 From: evan Date: Wed, 25 Mar 2026 08:56:00 -0700 Subject: [PATCH 7/8] replace --- server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.py b/server.py index ed96f75..600868d 100644 --- a/server.py +++ b/server.py @@ -184,7 +184,7 @@ async def qr(alias: str, request: Request, static: Optional[str] = None, user_ag base_url = str(request.base_url).rstrip('/') # Ensure we use https if you're behind an SSL proxy if "https" in str(request.url): - base_url = base_url.replace("http://", "https://") + base_url = base_url.replace("http://sce.sjsu.edu/", "https://sce.sjsu.edu/") full_image_url = f"{base_url}/qr/{alias}?static=1" From 96521d0a73d2965b06a7b22ff1e720cd60353793 Mon Sep 17 00:00:00 2001 From: evan Date: Wed, 25 Mar 2026 09:15:39 -0700 Subject: [PATCH 8/8] will try embed later --- server.py | 57 ++++++++++++++++--------------------------------------- 1 file changed, 16 insertions(+), 41 deletions(-) diff --git a/server.py b/server.py index 600868d..044d0ac 100644 --- a/server.py +++ b/server.py @@ -1,5 +1,5 @@ from typing import Optional -from fastapi import FastAPI, Request, HTTPException, Response, Header +from fastapi import FastAPI, Request, HTTPException, Response from fastapi.responses import RedirectResponse, HTMLResponse, FileResponse from fastapi.middleware.cors import CORSMiddleware import logging @@ -8,7 +8,6 @@ import uvicorn from queue import Queue from threading import Thread -import re from modules.args import get_args from modules.generate_alias import generate_alias @@ -158,48 +157,24 @@ async def delete_url(alias: str): raise HTTPException(status_code=HttpResponse.NOT_FOUND.code) @app.get("/qr/{alias}") -async def qr(alias: str, request: Request, static: Optional[str] = None, user_agent: Optional[str] = Header(None)): - logging.debug(f"/qr called with alias: {alias}, user_agent: {user_agent}, static: {static}, {request.base_url}") - +async def qr(alias: str): + logging.debug(f"/qr code generation called with alias: {alias}") with MetricsHandler.query_time.labels("qr").time(): - # 1. Ensure the alias exists in the DB first - url_output = sqlite_helpers.get_url(DATABASE_FILE, alias) - if url_output is None: - raise HTTPException(status_code=404) - - # 2. Get/Generate the image maybe_image_data = qr_code_cache.find(alias) - if maybe_image_data is None: - maybe_image_data = qr_code_cache.add(alias) - - # 3. Handle the "Trap Door" for the actual image file - # We also check if it's NOT a bot (like your curl/browser) - is_bot = user_agent and "Discordbot" in user_agent - - if static or not is_bot: - # Force PNG media type here - return FileResponse(maybe_image_data, media_type='image/png') - - # 4. If we reach here, it IS a bot and NOT static -> Send HTML Embed - base_url = str(request.base_url).rstrip('/') - # Ensure we use https if you're behind an SSL proxy - if "https" in str(request.url): - base_url = base_url.replace("http://sce.sjsu.edu/", "https://sce.sjsu.edu/") - - full_image_url = f"{base_url}/qr/{alias}?static=1" + if maybe_image_data is not None: + return FileResponse( + maybe_image_data, + media_type='image/jpeg', + ) - content = f""" - - - - - - - - - - """ - return HTMLResponse(content=content) + url_output = sqlite_helpers.get_url(DATABASE_FILE, alias) + if url_output is None: + raise HTTPException(status_code=HttpResponse.NOT_FOUND.code) + image_data = qr_code_cache.add(alias) + return FileResponse( + image_data, + media_type='image/jpeg', + ) @app.exception_handler(HTTPException) async def http_exception_handler(request, exc):