commit d6071a60f1450e0fceb98780615d0005b52767df
parent 56f728f9a05c19ec3af63d538fd7b24ed20a75cb
Author: Amit Dutta <mail@amit.is-a.dev>
Date: Thu, 3 Sep 2026 18:40:58 +0530
Merge pull request #6 from notamitgamer/patch
Refactor raw file handling and update links for subdomain support
Diffstat:
3 files changed, 44 insertions(+), 33 deletions(-)
diff --git a/app/main.py b/app/main.py
@@ -4,7 +4,7 @@ import uuid
import mimetypes
import httpx
from fastapi import FastAPI, Request, File, UploadFile, Depends, HTTPException
-from fastapi.responses import StreamingResponse, HTMLResponse, PlainTextResponse
+from fastapi.responses import StreamingResponse, HTMLResponse, PlainTextResponse, RedirectResponse
from fastapi.templating import Jinja2Templates
from .storage import is_file, list_directory, upload_temp_file, HF_REPO_ID
@@ -15,6 +15,8 @@ app = FastAPI()
templates = Jinja2Templates(directory="app/templates")
CDN_BASE_URL = os.getenv("CDN_BASE_URL", "https://cdn-zt7p.onrender.com")
+RAW_DOMAIN = os.getenv("RAW_DOMAIN", "raw.cdn.amit.is-a.dev")
+RAW_BASE_URL = os.getenv("RAW_BASE_URL", f"https://{RAW_DOMAIN}")
RAW_PREFIX = "raw/"
async def stream_raw(path: str):
@@ -28,27 +30,27 @@ async def stream_raw(path: str):
raise HTTPException(status_code=404, detail="File not found")
filename = path.split("/")[-1].lower()
+ guessed_type, _ = mimetypes.guess_type(filename)
- raw_no_ext_files = {"dockerfile", "makefile", "license", "readme", "cname"}
-
- if filename in raw_no_ext_files:
- content_type = "text/plain"
+ # Allow media and PDFs to render in-browser securely
+ if guessed_type and (
+ guessed_type.startswith("image/") or
+ guessed_type.startswith("video/") or
+ guessed_type.startswith("audio/") or
+ guessed_type == "application/pdf"
+ ):
+ content_type = guessed_type
else:
- guessed_type, _ = mimetypes.guess_type(filename)
-
- if guessed_type:
- if guessed_type.startswith("text/"):
- content_type = "text/plain"
- else:
- content_type = guessed_type
- else:
- content_type = "text/plain"
+ # Force all other files (code, HTML, JSON, unknown) to plain text
+ # This prevents XSS attacks on the raw domain
+ content_type = "text/plain; charset=utf-8"
headers = {
"Access-Control-Allow-Origin": "*",
"Cache-Control": "public, max-age=31536000",
"Content-Type": content_type,
- "Content-Disposition": "inline"
+ "Content-Disposition": "inline",
+ "X-Content-Type-Options": "nosniff"
}
async def stream_generator():
@@ -103,7 +105,7 @@ async def handle_upload(files: list[UploadFile] = File(...), _ = Depends(verify_
results.append({
"filename": file.filename,
"cdn_url": f"{CDN_BASE_URL}/{hf_path}",
- "raw_url": f"{CDN_BASE_URL}/{RAW_PREFIX}{hf_path}"
+ "raw_url": f"{RAW_BASE_URL}/{hf_path}" # Updated to use new raw subdomain
})
return {"files": results}
@@ -116,11 +118,18 @@ async def ping():
async def serve(request: Request, path: str):
clean_path = path.strip("/")
+ # 1. Intercept requests coming to the raw subdomain
+ if request.url.hostname == RAW_DOMAIN:
+ if not clean_path:
+ return HTMLResponse("Specify a file path.", status_code=200)
+ return await stream_raw(clean_path)
+
+ # 2. Keep old /raw/ prefix working on main domain by redirecting to subdomain
if clean_path == RAW_PREFIX.rstrip("/") or clean_path.startswith(RAW_PREFIX):
raw_path = clean_path[len(RAW_PREFIX):]
if not raw_path:
return HTMLResponse("/raw/ — specify a file path after this prefix.", status_code=200)
- return await stream_raw(raw_path)
+ return RedirectResponse(f"{RAW_BASE_URL}/{raw_path}")
if clean_path == "upload":
return templates.TemplateResponse(request, "index.html", {"page": "upload"})
@@ -130,7 +139,8 @@ async def serve(request: Request, path: str):
return templates.TemplateResponse(request, "index.html", {
"page": "file",
"path": clean_path,
- "filename": filename
+ "filename": filename,
+ "raw_base_url": RAW_BASE_URL
})
items = list_directory(clean_path)
@@ -140,5 +150,6 @@ async def serve(request: Request, path: str):
return templates.TemplateResponse(request, "index.html", {
"page": "listing",
"path": clean_path,
- "items": items
+ "items": items,
+ "raw_base_url": RAW_BASE_URL
})
diff --git a/app/templates/index.html b/app/templates/index.html
@@ -98,7 +98,6 @@
}
.filter-input::placeholder { color: var(--text-dim); }
- /* Updated list-item so only the links are clickable */
.list-item {
display: flex;
align-items: center;
@@ -232,7 +231,6 @@
<div id="file-list">
{% if path %}
- <!-- Note the change: list-item is now a div, only the '..' is an a tag -->
<div class="list-item" data-name="..">
<div class="item-name">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 14l-4-4 4-4"/><path d="M5 10h11a4 4 0 1 1 0 8h-1"/></svg>
@@ -249,8 +247,8 @@
<a href="/{{ item.path }}">{{ item.name }}/</a>
{% else %}
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><polyline points="13 2 13 9 20 9"/></svg>
- <!-- Routes directly to raw for files -->
- <a href="/raw/{{ item.path }}">{{ item.name }}</a>
+ <!-- Updated to link directly to the new raw subdomain -->
+ <a href="{{ raw_base_url }}/{{ item.path }}">{{ item.name }}</a>
{% endif %}
</div>
<div class="item-meta">
@@ -281,7 +279,7 @@
const term = e.target.value.toLowerCase();
fileList.forEach(item => {
const name = item.getAttribute('data-name').toLowerCase();
- if (name === '..') return; // Always show parent dir link
+ if (name === '..') return;
item.style.display = name.includes(term) ? 'flex' : 'none';
});
});
@@ -296,18 +294,18 @@
<div style="display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap;">
<a href="/api/download/{{ path }}" class="btn">Download</a>
- <a href="/raw/{{ path }}" class="btn">Open Raw</a>
+ <!-- Updated links to utilize raw_base_url -->
+ <a href="{{ raw_base_url }}/{{ path }}" class="btn">Open Raw</a>
<button onclick="copyToClipboard(window.location.origin + '/' + '{{ path }}')" class="btn">Copy Link</button>
- <button onclick="copyToClipboard(window.location.origin + '/raw/' + '{{ path }}')" class="btn">Copy Raw Link</button>
+ <button onclick="copyToClipboard('{{ raw_base_url }}/{{ path }}')" class="btn">Copy Raw Link</button>
</div>
</div>
{% elif page == 'upload' %}
<blockquote>
- If you do not remember the link, go to the <a href="/uploads">uploads folder</a>to find your file.
+ If you do not remember the link, go to the <a href="/uploads">uploads folder</a> to find your file.
</blockquote>
- <!-- Hidden token field containing the hardcoded password -->
<input type="hidden" id="token" value="Amitthehack2006">
<div id="dropzone">
@@ -344,7 +342,6 @@
function handleFiles(fileList) {
errorBox.style.display = 'none';
- // Grabbing the hidden hardcoded password
const token = tokenInput.value;
const files = Array.from(fileList);
@@ -363,7 +360,6 @@
const xhr = new XMLHttpRequest();
xhr.open('POST', '/api/upload', true);
- // Automatically append the Bearer prefix and token for backend authentication
xhr.setRequestHeader('Authorization', 'Bearer ' + token);
xhr.upload.onprogress = (e) => {
@@ -380,7 +376,8 @@
const row = rows[item.filename];
if (!row) return;
row.classList.add('done');
- const rawPath = item.raw_url.substring(item.raw_url.indexOf('/raw/'));
+ // Updated to grab the full raw_url since it now points to the subdomain
+ const rawPath = item.raw_url;
row.innerHTML = `
<div style="overflow:hidden; text-overflow:ellipsis; white-space:nowrap; padding-right:1rem; color: #2ea043;">${item.filename}</div>
<div style="white-space:nowrap; display:flex; gap:0.75rem;">
diff --git a/render.yaml b/render.yaml
@@ -9,4 +9,8 @@ services:
- key: HF_TOKEN
sync: false
- key: ADMIN_TOKEN
- sync: false-
\ No newline at end of file
+ sync: false
+ - key: RAW_DOMAIN
+ value: raw.cdn.amit.is-a.dev
+ - key: RAW_BASE_URL
+ value: https://raw.cdn.amit.is-a.dev