From d55097284865037af792130b746fe479abe52ce4 Mon Sep 17 00:00:00 2001 From: Dicken Date: Sat, 13 Jun 2026 11:47:24 +0200 Subject: [PATCH] fix: Share-URL-Pfad korrigiert, PW 12 Stellen+Sonderzeichen sichtbar, Standard 1h, aktive Links in Dateiliste --- frontend/src/App.jsx | 8 +-- frontend/src/tools/dateien.jsx | 89 +++++++++++++++++++++++++++++----- 2 files changed, 81 insertions(+), 16 deletions(-) diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 45fc86c..fbe7708 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -2919,7 +2919,7 @@ function PublicFileShare({ token }) { }; useEffect(() => { - fetch('/api/public/file-share/public/' + token) + fetch('/api/public/file-share/' + token) .then(async r => { const d = await r.json(); if (!r.ok) { setErrMsg(d.error || 'Link ungültig'); setPhase('error'); return; } @@ -2931,7 +2931,7 @@ function PublicFileShare({ token }) { }, [token]); async function loadFolder(pw2) { - const res = await fetch('/api/public/file-share/public/' + token + '/folder', { + const res = await fetch('/api/public/file-share/' + token + '/folder', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({ password: pw2 }), }); @@ -2943,7 +2943,7 @@ function PublicFileShare({ token }) { async function handlePw() { if (!pw.trim()) return; - const res = await fetch('/api/public/file-share/public/' + token + (info?.is_folder ? '/folder' : '/download'), { + const res = await fetch('/api/public/file-share/' + token + (info?.is_folder ? '/folder' : '/download'), { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({ password: pw }), }); @@ -2959,7 +2959,7 @@ function PublicFileShare({ token }) { setDlLoading(fileId || 'single'); try { const res = await fetch( - '/api/public/file-share/public/' + token + (fileId ? '/folder/' + fileId : '/download'), + '/api/public/file-share/' + token + (fileId ? '/folder/' + fileId : '/download'), { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({ password }) } ); if (!res.ok) { const d = await res.json(); setErrMsg(d.error); return; } diff --git a/frontend/src/tools/dateien.jsx b/frontend/src/tools/dateien.jsx index 80b287f..4b55c96 100644 --- a/frontend/src/tools/dateien.jsx +++ b/frontend/src/tools/dateien.jsx @@ -29,8 +29,7 @@ const IconBtn = ({ onClick, color, title, children, stop }) => ( // ── Öffentlicher Link-Share Modal ───────────────────────────────────────────── function PublicShareModal({ item, itemType, onClose, toast }) { const [password, setPassword] = useState(() => genPw()); - const [showPw, setShowPw] = useState(false); - const [expiresH, setExpiresH] = useState(24); + const [expiresH, setExpiresH] = useState(1); const [label, setLabel] = useState(''); const [shares, setShares] = useState([]); const [creating, setCreating] = useState(false); @@ -41,8 +40,16 @@ function PublicShareModal({ item, itemType, onClose, toast }) { const base = '/tools/dateien/public-shares'; function genPw() { - const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789'; - return Array.from({length:10}, () => chars[Math.floor(Math.random()*chars.length)]).join(''); + const upper = 'ABCDEFGHJKLMNPQRSTUVWXYZ'; + const lower = 'abcdefghjkmnpqrstuvwxyz'; + const digits = '23456789'; + const special = '!@#$%&*-+?'; + const all = upper + lower + digits + special; + // Mindestens je 1 aus jeder Kategorie, Rest zufällig + const pick = s => s[Math.floor(Math.random()*s.length)]; + const base = [pick(upper), pick(lower), pick(digits), pick(special)]; + const rest = Array.from({length:8}, () => pick(all)); + return [...base, ...rest].sort(() => Math.random()-0.5).join(''); } useEffect(() => { @@ -120,18 +127,14 @@ function PublicShareModal({ item, itemType, onClose, toast }) { {/* Passwort Pflicht + Generator */}
-
+
setPassword(e.target.value)} placeholder="Passwort (Pflicht)" - style={{...S.inp, width:'100%', boxSizing:'border-box', paddingRight:36}} + style={{...S.inp, width:'100%', boxSizing:'border-box', fontFamily:'monospace', letterSpacing:1}} /> -
)} {shareItem && {setShareItem(null);load();}} toast={toast}/>} - {publicShareItem && setPublicShareItem(null)} toast={toast}/>} + {publicShareItem && {setPublicShareItem(null);load();}} toast={toast}/>} + + {/* ── Aktive öffentliche Links ──────────────────────────────────────── */} + {publicShares.length > 0 && tab === 'own' && ( +
+
setShowPublicLinks(v=>!v)}> +
+ 🔗 + + Aktive öffentliche Links + + + {publicShares.length} + +
+ {showPublicLinks ? '▲' : '▼'} +
+ {showPublicLinks && publicShares.map(s => { + const name = s.file_name || s.folder_name || s.label || '—'; + const isExp = s.expires_at && s.expires_at < Math.floor(Date.now()/1000); + const fmtExp = exp => { + if (!exp) return '∞'; + const d = new Date(exp*1000); + return d.toLocaleDateString('de-DE')+' '+d.toLocaleTimeString('de-DE',{hour:'2-digit',minute:'2-digit'}); + }; + return ( +
+ {s.file_id ? '📄' : '📁'} +
+
+ {name} + {s.label && s.label !== name && ({s.label})} +
+
+ {isExp?'⚠ Abgelaufen':'Ablauf: '}{!isExp&&fmtExp(s.expires_at)} · {s.download_count} Abrufe · 🔒 +
+
+ + +
+ ); + })} +
+ )} {pwPrompt && { setPwPrompt(null); download(pwPrompt, pw); }}