Bild-Proxy (same-origin, defeats hotlink protection) + klareres Reset-Feedback
This commit is contained in:
+6
-5
@@ -1,4 +1,4 @@
|
||||
const C24 = u => u; // check24 proxy urls already absolute
|
||||
const IMG = u => '/img?u=' + encodeURIComponent(u); // route images through same-origin proxy
|
||||
const REG = {
|
||||
kroatien:{flag:'🇭🇷',name:'Kroatien',color:'var(--kro)',mk:'#e8643c'},
|
||||
kanaren:{flag:'🇮🇨',name:'Kanaren',color:'var(--kan)',mk:'#f1a23b'},
|
||||
@@ -119,7 +119,7 @@ let STATE = {votes:{}};
|
||||
|
||||
/* ---------- hero ---------- */
|
||||
document.getElementById('herobg').style.backgroundImage =
|
||||
"url('"+byId('bluesun').imgs[0]+"')";
|
||||
"url('"+IMG(byId('bluesun').imgs[0])+"')";
|
||||
|
||||
/* ---------- voter selector ---------- */
|
||||
const whoEl = document.getElementById('who');
|
||||
@@ -166,7 +166,7 @@ function avgFor(id){
|
||||
return {avg:n?sum/n:0,n,per};
|
||||
}
|
||||
function cardHTML(o){
|
||||
const imgs=o.imgs.map((s,i)=>`<img src="${s}" class="${i===0?'on':''}" loading="lazy" alt="${o.name}" onerror="this.remove()">`).join('');
|
||||
const imgs=o.imgs.map((s,i)=>`<img src="${IMG(s)}" class="${i===0?'on':''}" loading="lazy" alt="${o.name}" onerror="this.closest('.ph')&&this.remove()">`).join('');
|
||||
const dots=o.imgs.length>1?`<div class="dots">${o.imgs.map((_,i)=>`<span class="dot ${i===0?'on':''}"></span>`).join('')}</div>`:'';
|
||||
const nav=o.imgs.length>1?'<div class="nav l"></div><div class="nav r"></div>':'';
|
||||
const rate=o.rate?`<span class="crate"><b>${o.rate}</b> ${o.rlabel}${o.bew?(' · '+o.bew+' Bew.'):''}</span>`:(o.bew?`<span class="crate">${o.bew} Bewertungen</span>`:'');
|
||||
@@ -256,10 +256,11 @@ async function sendVote(option,stars){
|
||||
try{const r=await fetch('/api/vote',{method:'POST',headers:{'Content-Type':'application/json'},
|
||||
body:JSON.stringify({voter:me_,option,stars})});STATE=await r.json();renderVotes();}catch(e){}
|
||||
}
|
||||
function flashSaved(){const s=document.getElementById('saved');s.classList.add('on');setTimeout(()=>s.classList.remove('on'),1400);}
|
||||
function flashSaved(msg){const s=document.getElementById('saved');s.textContent=msg||'✓ gespeichert';s.classList.add('on');setTimeout(()=>s.classList.remove('on'),1800);}
|
||||
document.getElementById('resetBtn').onclick=async()=>{
|
||||
if(!confirm('Wirklich ALLE Bewertungen von Till, Lea und Astrid zurücksetzen?'))return;
|
||||
try{const r=await fetch('/api/reset',{method:'POST'});STATE=await r.json();renderVotes();flashSaved();}catch(e){}
|
||||
try{const r=await fetch('/api/reset',{method:'POST'});STATE=await r.json();renderVotes();flashSaved('✓ Alle Bewertungen gelöscht');}
|
||||
catch(e){alert('Zurücksetzen fehlgeschlagen – bitte nochmal versuchen.');}
|
||||
};
|
||||
|
||||
function renderAll(){renderWho();renderRecos();renderRegions();}
|
||||
|
||||
@@ -30,6 +30,12 @@ function saveState(state) {
|
||||
}
|
||||
let state = loadState();
|
||||
|
||||
// In-memory image cache for the proxy
|
||||
const imgCache = new Map();
|
||||
function hostAllowed(host) {
|
||||
return /(^|\.)urlaub\.check24\.de$/.test(host) || host === 'files.ahoi-schiff.de';
|
||||
}
|
||||
|
||||
const MIME = { '.html': 'text/html; charset=utf-8', '.js': 'text/javascript; charset=utf-8',
|
||||
'.css': 'text/css; charset=utf-8', '.json': 'application/json', '.svg': 'image/svg+xml',
|
||||
'.png': 'image/png', '.jpg': 'image/jpeg', '.ico': 'image/x-icon', '.webmanifest': 'application/manifest+json' };
|
||||
@@ -72,6 +78,34 @@ const server = http.createServer(async (req, res) => {
|
||||
}
|
||||
if (p === '/health') { return sendJSON(res, 200, { ok: true }); }
|
||||
|
||||
// ---- Image proxy (defeats hotlink/referrer protection, same-origin = always loads) ----
|
||||
if (p === '/img' && req.method === 'GET') {
|
||||
const u = url.searchParams.get('u');
|
||||
let host;
|
||||
try { host = new URL(u).host; } catch (e) { res.writeHead(400); return res.end('bad url'); }
|
||||
if (!hostAllowed(host)) { res.writeHead(403); return res.end('host not allowed'); }
|
||||
if (imgCache.has(u)) {
|
||||
const c = imgCache.get(u);
|
||||
res.writeHead(200, { 'Content-Type': c.type, 'Cache-Control': 'public, max-age=604800' });
|
||||
return res.end(c.buf);
|
||||
}
|
||||
try {
|
||||
const referer = host.endsWith('ahoi-schiff.de') ? 'https://www.ahoi-schiff.de/' : 'https://urlaub.check24.de/';
|
||||
const ac = new AbortController();
|
||||
const t = setTimeout(() => ac.abort(), 8000);
|
||||
const r = await fetch(u, { signal: ac.signal, headers: {
|
||||
'Referer': referer, 'User-Agent': 'Mozilla/5.0 (compatible; HeidrichReise/1.0)', 'Accept': 'image/*'
|
||||
}});
|
||||
clearTimeout(t);
|
||||
if (!r.ok) { res.writeHead(502); return res.end('upstream ' + r.status); }
|
||||
const type = r.headers.get('content-type') || 'image/jpeg';
|
||||
const buf = Buffer.from(await r.arrayBuffer());
|
||||
if (imgCache.size < 300) imgCache.set(u, { buf, type });
|
||||
res.writeHead(200, { 'Content-Type': type, 'Cache-Control': 'public, max-age=604800' });
|
||||
return res.end(buf);
|
||||
} catch (e) { res.writeHead(502); return res.end('proxy error'); }
|
||||
}
|
||||
|
||||
// ---- Static ----
|
||||
let file = p === '/' ? '/index.html' : decodeURIComponent(p);
|
||||
const full = path.join(PUBLIC, path.normalize(file).replace(/^(\.\.[\/\\])+/, ''));
|
||||
|
||||
Reference in New Issue
Block a user