mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-08-23 03:44:08 +02:00
The body commands took a path from the client, so a token holder could read any file the process could. They now take a response id and resolve the location themselves, and the UI never sees a path at all: the desktop host asks the backend where the file is, and the bridge fetches /responses/:id/body. Ephemeral responses (GraphQL introspection) never reach the database, so resolution falls back to the path send writes them to.
40 lines
1010 B
TypeScript
40 lines
1010 B
TypeScript
import classNames from "classnames";
|
|
import { useEffect, useState } from "react";
|
|
|
|
type Props = { className?: string; mimeType?: string } & (
|
|
| {
|
|
/** A URL the host resolved, for a body it already stored. */
|
|
url: string;
|
|
}
|
|
| {
|
|
data: ArrayBuffer;
|
|
}
|
|
);
|
|
|
|
export function ImageViewer({ className, mimeType, ...props }: Props) {
|
|
const [src, setSrc] = useState<string>();
|
|
const url = "url" in props ? props.url : null;
|
|
const data = "data" in props ? props.data : null;
|
|
|
|
useEffect(() => {
|
|
if (url != null) {
|
|
setSrc(url);
|
|
} else if (data != null) {
|
|
const blob = new Blob([data], { type: mimeType ?? "image/png" });
|
|
const objectUrl = URL.createObjectURL(blob);
|
|
setSrc(objectUrl);
|
|
return () => URL.revokeObjectURL(objectUrl);
|
|
} else {
|
|
setSrc(undefined);
|
|
}
|
|
}, [url, data, mimeType]);
|
|
|
|
return (
|
|
<img
|
|
src={src}
|
|
alt="Response preview"
|
|
className={classNames(className, "max-w-full max-h-full")}
|
|
/>
|
|
);
|
|
}
|