fix for max file size

This commit is contained in:
onysd 2026-09-03 10:31:45 +03:00
parent a20f5b8b33
commit 508d120bd3
3 changed files with 33 additions and 12 deletions

View file

@ -23,7 +23,7 @@
})(); })();
</script> </script>
<script type="module" crossorigin src="/assets/index-_FsSjZOI.js"></script> <script type="module" crossorigin src="/assets/index-Cfyo2O3p.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-B7j2PW0q.css"> <link rel="stylesheet" crossorigin href="/assets/index-B7j2PW0q.css">
</head> </head>
<body> <body>

View file

@ -245,11 +245,20 @@ const BYTE_UNITS: { label: string; bytes: number }[] = [
{ label: "TB", bytes: 1024 ** 4 } { label: "TB", bytes: 1024 ** 4 }
]; ];
function bestByteUnit(bytes: number): { label: string; bytes: number } { // Max single file size can never usefully exceed the protocol's own per-file
for (let i = BYTE_UNITS.length - 1; i >= 0; i--) { // ceiling (PROTOCOL_UPLOAD_CEILING_BYTES, ~4000MiB) -- so its unit picker
if (bytes >= BYTE_UNITS[i].bytes) return BYTE_UNITS[i]; // drops TB entirely (a single file will never be measured in terabytes) and
// caps the amount at a round 4096MB/4GB (both the same byte value, since
// these units are binary) instead of letting the input accept an arbitrarily
// large number that Save would just reject anyway.
const MAX_FILE_SIZE_UNITS = BYTE_UNITS.filter((u) => u.label !== "TB");
const MAX_FILE_SIZE_CAP_BYTES = 4 * 1024 ** 3;
function bestByteUnit(bytes: number, units: { label: string; bytes: number }[] = BYTE_UNITS): { label: string; bytes: number } {
for (let i = units.length - 1; i >= 0; i--) {
if (bytes >= units[i].bytes) return units[i];
} }
return BYTE_UNITS[1]; // default to GB for small/zero values return units[Math.min(1, units.length - 1)]; // default to GB (or the 2nd unit) for small/zero values
} }
// parseDurationMinutes reads a Go-style duration string (e.g. "720h", "90m", // parseDurationMinutes reads a Go-style duration string (e.g. "720h", "90m",
@ -347,21 +356,28 @@ function DurationField({
// ByteSizeField edits one byte-count env value as a friendly // ByteSizeField edits one byte-count env value as a friendly
// "amount + unit" pair. bytes is the raw byte count as a string (what the // "amount + unit" pair. bytes is the raw byte count as a string (what the
// backend stores); an empty/zero value displays as "Unlimited". // backend stores); an empty/zero value displays as "Unlimited". units/maxBytes
// let a caller narrow this down for a field with its own hard ceiling (e.g.
// Max single file size, capped at the protocol's own ~4GB per-file limit --
// there's no point offering TB there, or letting MB/GB amounts go past it).
function ByteSizeField({ function ByteSizeField({
label, label,
help, help,
bytes, bytes,
onChange onChange,
units = BYTE_UNITS,
maxBytes
}: { }: {
label: string; label: string;
help: string; help: string;
bytes: string; bytes: string;
onChange: (bytes: string) => void; onChange: (bytes: string) => void;
units?: { label: string; bytes: number }[];
maxBytes?: number;
}) { }) {
const numericBytes = Number(bytes || "0"); const numericBytes = Number(bytes || "0");
const [unitLabel, setUnitLabel] = useState(() => bestByteUnit(numericBytes).label); const [unitLabel, setUnitLabel] = useState(() => bestByteUnit(numericBytes, units).label);
const unit = BYTE_UNITS.find((u) => u.label === unitLabel) ?? BYTE_UNITS[1]; const unit = units.find((u) => u.label === unitLabel) ?? units[0];
const amount = numericBytes > 0 ? numericBytes / unit.bytes : NaN; const amount = numericBytes > 0 ? numericBytes / unit.bytes : NaN;
function handleAmountChange(raw: string) { function handleAmountChange(raw: string) {
@ -370,7 +386,9 @@ function ByteSizeField({
onChange("0"); onChange("0");
return; return;
} }
onChange(String(Math.round(parsed * unit.bytes))); let value = Math.round(parsed * unit.bytes);
if (maxBytes && value > maxBytes) value = maxBytes;
onChange(String(value));
} }
return ( return (
@ -380,13 +398,14 @@ function ByteSizeField({
<input <input
type="number" type="number"
min="0" min="0"
max={maxBytes ? maxBytes / unit.bytes : undefined}
step="any" step="any"
value={Number.isNaN(amount) ? "" : amount} value={Number.isNaN(amount) ? "" : amount}
placeholder={"Unlimited"} placeholder={"Unlimited"}
onChange={(event) => handleAmountChange(event.target.value)} onChange={(event) => handleAmountChange(event.target.value)}
/> />
<select value={unitLabel} onChange={(event) => setUnitLabel(event.target.value)} style={{ maxWidth: 90 }}> <select value={unitLabel} onChange={(event) => setUnitLabel(event.target.value)} style={{ maxWidth: 90 }}>
{BYTE_UNITS.map((u) => ( {units.map((u) => (
<option key={u.label} value={u.label}>{u.label}</option> <option key={u.label} value={u.label}>{u.label}</option>
))} ))}
</select> </select>
@ -686,6 +705,8 @@ function LimitsRetentionSection() {
help={"Reject a single upload once its total assembled size exceeds this. Empty/0 = unlimited, bounded only by the protocol's own ~4GB per-file ceiling."} help={"Reject a single upload once its total assembled size exceeds this. Empty/0 = unlimited, bounded only by the protocol's own ~4GB per-file ceiling."}
bytes={maxUploadFileBytes} bytes={maxUploadFileBytes}
onChange={setMaxUploadFileBytes} onChange={setMaxUploadFileBytes}
units={MAX_FILE_SIZE_UNITS}
maxBytes={MAX_FILE_SIZE_CAP_BYTES}
/> />
{uploadCeilingExceeded && ( {uploadCeilingExceeded && (
<Alert>{"This exceeds the protocol's own ~4GB upload ceiling and will be refused when the server restarts."}</Alert> <Alert>{"This exceeds the protocol's own ~4GB upload ceiling and will be refused when the server restarts."}</Alert>