Guard upload when info hash is unavailable

This commit is contained in:
thePR0M3TH3AN committed 2026-01-14 21:38:27 -05:00
1 parent f52da2581b
commit a3374f0569
3 files changed
+66 -11

No files matched your search

+2 -2
View File
@@ -209,12 +209,12 @@
<div class="space-y-2">
<label for="input-url" class="block text-sm font-medium text-text">Video URL</label>
<input id="input-url" type="url" class="input" placeholder="https://example.com/video.mp4" />
<p class="text-xs text-muted">Direct link to a hosted video file.</p>
<p class="text-xs text-muted">Primary hosted video source (URL-first playback).</p>
</div>
<div class="space-y-2">
<label for="input-magnet" class="block text-sm font-medium text-text">Magnet Link</label>
<input id="input-magnet" type="text" class="input" placeholder="magnet:?xt=urn:btih:..." />
<p class="text-xs text-muted">Optional P2P fallback or primary source.</p>
<p class="text-xs text-muted">Optional WebTorrent fallback when the URL is unavailable.</p>
</div>
</div>
+30 -8
View File
@@ -31,6 +31,15 @@ import {
} from "./videoNotePayload.js";
const STATUS_VARIANTS = new Set(["info", "success", "error", "warning"]);
const INFO_HASH_PATTERN = /^[a-f0-9]{40}$/;
function normalizeInfoHash(value) {
return typeof value === "string" ? value.trim().toLowerCase() : "";
}
function isValidInfoHash(value) {
return INFO_HASH_PATTERN.test(value);
}
function createDefaultSettings() {
return {
@@ -187,10 +196,10 @@ class R2Service {
primaryVariant.m = mimeType;
}
const normalizedHash =
typeof infoHash === "string" ? infoHash.trim().toLowerCase() : "";
const normalizedHash = normalizeInfoHash(infoHash);
if (
normalizedHash &&
isValidInfoHash(normalizedHash) &&
(!primaryVariant.x || !String(primaryVariant.x).trim())
) {
primaryVariant.x = normalizedHash;
@@ -705,14 +714,27 @@ class R2Service {
} else {
// Construct the Magnet Link
// magnet:?xt=urn:btih:<infoHash>&dn=<filename>&ws=<publicUrl>
const normalizedInfoHash = normalizeInfoHash(infoHash);
const hasValidInfoHash = isValidInfoHash(normalizedInfoHash);
let generatedMagnet = "";
let generatedWs = "";
if (infoHash) {
const encodedDn = encodeURIComponent(file.name);
const encodedWs = encodeURIComponent(publicUrl);
generatedMagnet = `magnet:?xt=urn:btih:${infoHash}&dn=${encodedDn}&ws=${encodedWs}`;
generatedWs = publicUrl;
if (hasValidInfoHash) {
const encodedDn = encodeURIComponent(file.name);
const encodedWs = encodeURIComponent(publicUrl);
generatedMagnet = `magnet:?xt=urn:btih:${normalizedInfoHash}&dn=${encodedDn}&ws=${encodedWs}`;
generatedWs = publicUrl;
} else {
if (infoHash) {
userLogger.warn(
"Invalid info hash provided. Skipping magnet and webseed generation.",
infoHash
);
}
this.setCloudflareUploadStatus(
"Info hash missing or invalid. Publishing URL-first without WebTorrent fallback.",
"warning"
);
}
const rawVideoPayload = {
@@ -731,7 +753,7 @@ class R2Service {
const mergedNip71 = this.buildNip71MetadataForUpload(metadata?.nip71, {
publicUrl,
file,
infoHash,
infoHash: hasValidInfoHash ? normalizedInfoHash : "",
});
if (mergedNip71 && Object.keys(mergedNip71).length) {
rawVideoPayload.nip71 = mergedNip71;
+34 -1
View File
@@ -10,6 +10,16 @@ import {
import { createTorrentMetadata } from "../../utils/torrentHash.js";
import { sanitizeBucketName } from "../../storage/r2-mgmt.js";
const INFO_HASH_PATTERN = /^[a-f0-9]{40}$/;
function normalizeInfoHash(value) {
return typeof value === "string" ? value.trim().toLowerCase() : "";
}
function isValidInfoHash(value) {
return INFO_HASH_PATTERN.test(value);
}
export class UploadModal {
constructor({
authService,
@@ -671,6 +681,29 @@ export class UploadModal {
userLogger.warn("Failed to calculate info hash:", hashErr);
}
const normalizedInfoHash = normalizeInfoHash(infoHash);
const hasValidInfoHash = isValidInfoHash(normalizedInfoHash);
if (!hasValidInfoHash) {
const proceed = confirm(
"We couldn't calculate a valid info hash. Publishing will continue with URL-first playback only, and WebTorrent fallback will be unavailable. Continue?"
);
if (!proceed) {
this.updateUploadStatus(
"Upload canceled. A valid info hash is required for WebTorrent fallback.",
"warning"
);
this.isUploading = false;
this.submitButton.disabled = false;
this.updateProgress(null);
return;
}
this.updateUploadStatus(
"Continuing without WebTorrent fallback (info hash unavailable).",
"warning"
);
}
// 2. Upload
await this.r2Service.uploadVideo({
npub,
@@ -678,7 +711,7 @@ export class UploadModal {
thumbnailFile,
torrentFile,
metadata,
infoHash,
infoHash: hasValidInfoHash ? normalizedInfoHash : "",
settingsInput: this.collectSettingsForm(),
publishVideoNote: this.publishVideoNote,
onReset: () => this.resetForm(),