PdfDragButton: Drag nie abbrechen (Regression nach R131-Fix)
Der R131-Fix hatte den Drag per preventDefault() abgebrochen, wenn der 60s-Download-Token beim Griff noch nicht vorgewaermt war -> im Mail- Fenster kam gar keine Datei mehr an. Jetzt wird der Drag nie abgebrochen: bevorzugt der vorgewaermte Download-Token, im seltenen Rennen Fallback auf den Access-Token, aber weiterhin NUR in DownloadURL (kein text/plain) -> kein Klartext-Leak. DownloadURL ist ein Nativ-Format und wird bei Fehl-Drop in Web-Text- felder nicht als lesbarer Text ausgegeben, daher bleibt der R131-Fix (kein Token-Leak als Text) erhalten. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { GripVertical, FileDown, Info } from 'lucide-react';
|
import { GripVertical, FileDown, Info } from 'lucide-react';
|
||||||
import { fileUrl } from '../../utils/fileUrl';
|
import { fileUrl } from '../../utils/fileUrl';
|
||||||
import { authApi } from '../../services/api';
|
import { authApi, getAccessToken } from '../../services/api';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ziehbares Element, mit dem eine im Backend hinterlegte Datei (i.d.R. ein
|
* Ziehbares Element, mit dem eine im Backend hinterlegte Datei (i.d.R. ein
|
||||||
@@ -23,14 +23,18 @@ import { authApi } from '../../services/api';
|
|||||||
* Fallback (Datei im neuen Tab öffnen) bleibt aber nutzbar.
|
* Fallback (Datei im neuen Tab öffnen) bleibt aber nutzbar.
|
||||||
*
|
*
|
||||||
* SICHERHEIT (Pentest R131):
|
* SICHERHEIT (Pentest R131):
|
||||||
* - Für die Drag-URL wird ein KURZLEBIGER 60s-Download-Token
|
* - Es wird AUSSCHLIESSLICH `DownloadURL` gesetzt, KEINE `text/plain`-
|
||||||
|
* oder `text/uri-list`-Repräsentation. `DownloadURL` ist ein Chromium-
|
||||||
|
* internes Nativ-Format, das beim Fehl-Drop in ein Web-Textfeld nicht
|
||||||
|
* als lesbarer Text ankommt. Damit kann – anders als in der ersten
|
||||||
|
* Version – kein Token als Klartext in Chat/Ticket/URL-Leiste leaken.
|
||||||
|
* - In die URL wird bevorzugt ein KURZLEBIGER 60s-Download-Token
|
||||||
* (`authApi.getDownloadToken()`, `type:"download"`, nur `?token=`
|
* (`authApi.getDownloadToken()`, `type:"download"`, nur `?token=`
|
||||||
* nutzbar) verwendet – NICHT der 15-Minuten-Access-Token mit vollen
|
* nutzbar) geschrieben statt des 15-Min-Access-Tokens. Er wird
|
||||||
* Berechtigungen. Landet ein Drop versehentlich in einem Textfeld,
|
* proaktiv (mount + hover) vorgewärmt. Nur im seltenen Rennen „Drag
|
||||||
* kann bestenfalls ein 60s gültiger Downloads-only-Token auftauchen.
|
* bevor der Token da ist" fällt es auf den Access-Token zurück –
|
||||||
* - Es wird AUSSCHLIESSLICH `DownloadURL` gesetzt, keine `text/plain`-
|
* und auch dann nur innerhalb von DownloadURL, nie als Klartext.
|
||||||
* oder `text/uri-list`-Repräsentation. Ein Fehl-Drop in ein Text-/
|
* Der Drag wird NIE abgebrochen (sonst käme im Ziel keine Datei an).
|
||||||
* Chat-/URL-Feld erzeugt daher gar keinen sichtbaren Text.
|
|
||||||
*/
|
*/
|
||||||
interface PdfDragButtonProps {
|
interface PdfDragButtonProps {
|
||||||
/** Server-Pfad der Datei (`documentPath`). Ohne Pfad wird nichts gerendert. */
|
/** Server-Pfad der Datei (`documentPath`). Ohne Pfad wird nichts gerendert. */
|
||||||
@@ -110,21 +114,20 @@ export default function PdfDragButton({
|
|||||||
const name = safeBase.includes('.') ? safeBase : `${safeBase}${ext ? `.${ext}` : ''}`;
|
const name = safeBase.includes('.') ? safeBase : `${safeBase}${ext ? `.${ext}` : ''}`;
|
||||||
|
|
||||||
const handleDragStart = (e: React.DragEvent) => {
|
const handleDragStart = (e: React.DragEvent) => {
|
||||||
// Nur der kurzlebige Download-Token wird in die Drag-URL geschrieben.
|
// Bevorzugt den kurzlebigen 60s-Download-Token (auf mount+hover
|
||||||
// Ist noch keiner da (Netzwerk langsamer als der erste Griff), Drag
|
// vorgewärmt). Ist er im seltenen Rennen noch nicht da, fällt es auf den
|
||||||
// abbrechen und Token vorwärmen – lieber kein Drag als ein Access-Token-
|
// Access-Token zurück – NUR innerhalb von DownloadURL. Wichtig: der Drag
|
||||||
// Leak. Der nächste Versuch (nach Hover) hat den Token dann.
|
// wird NIE abgebrochen (sonst käme im Mail-Fenster gar keine Datei an).
|
||||||
const token = cachedToken;
|
const token = cachedToken || getAccessToken() || '';
|
||||||
if (!token) {
|
if (!cachedToken) warmDownloadToken(); // für den nächsten Drag vorwärmen
|
||||||
warmDownloadToken();
|
|
||||||
e.preventDefault();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const absolute = `${window.location.origin}${fileUrl(path, { token })}`;
|
const absolute = `${window.location.origin}${fileUrl(path, { token })}`;
|
||||||
try {
|
try {
|
||||||
// NUR DownloadURL – bewusst keine text/plain- oder text/uri-list-
|
// NUR DownloadURL setzen – bewusst KEINE text/plain- oder
|
||||||
// Repräsentation (sonst würde ein Fehl-Drop die volle URL als Text
|
// text/uri-list-Repräsentation. DownloadURL ist ein Chromium-internes
|
||||||
// ausgeben). Siehe Pentest R131.
|
// Nativ-Format und wird bei einem Fehl-Drop in ein Web-Textfeld nicht
|
||||||
|
// als lesbarer Text ausgegeben; so kann kein Token als Klartext leaken
|
||||||
|
// (Pentest R131). Für Explorer/Outlook ist DownloadURL das relevante
|
||||||
|
// Format – die entfernten Text-Formate waren dafür nie nötig.
|
||||||
e.dataTransfer.setData('DownloadURL', `${mime}:${name}:${absolute}`);
|
e.dataTransfer.setData('DownloadURL', `${mime}:${name}:${absolute}`);
|
||||||
} catch {
|
} catch {
|
||||||
/* manche Browser werfen bei DownloadURL – dann passiert einfach nichts */
|
/* manche Browser werfen bei DownloadURL – dann passiert einfach nichts */
|
||||||
|
|||||||
Reference in New Issue
Block a user