diff --git a/lib/upload-confirmation.js b/lib/upload-confirmation.js index 4de4655..05fd840 100644 --- a/lib/upload-confirmation.js +++ b/lib/upload-confirmation.js @@ -32,6 +32,17 @@ function getUrlHost(value) { } } +function selectPublicUploadUrl(result) { + for (const value of [result?.download_url, result?.embed_url]) { + if (typeof value !== 'string' || value.trim() === '') continue; + try { + const url = new URL(value.trim()); + if (url.protocol === 'https:') return url.href; + } catch {} + } + return ''; +} + function assertUploadConfirmation(result, hoster) { const expectedHost = typeof hoster === 'string' ? hoster.trim().toLowerCase() : ''; const fileCode = typeof result?.file_code === 'string' ? result.file_code.trim() : ''; @@ -63,4 +74,4 @@ function assertUploadConfirmation(result, hoster) { throw error; } -module.exports = { assertUploadConfirmation }; +module.exports = { assertUploadConfirmation, selectPublicUploadUrl }; diff --git a/main.js b/main.js index 618c62b..c868313 100644 --- a/main.js +++ b/main.js @@ -40,6 +40,7 @@ const { createCollectors } = require('./lib/diagnostics-collectors'); const { createAgent } = require('./lib/diagnostics-agent'); const { buildSessionReport, buildSessionReportCsv } = require('./lib/session-report'); const { buildTerminalJobSnapshots } = require('./lib/upload-recovery'); +const { selectPublicUploadUrl } = require('./lib/upload-confirmation'); const _eventLoopDelay = monitorEventLoopDelay({ resolution: 10 }); _eventLoopDelay.enable(); @@ -982,8 +983,7 @@ function flattenHistoryForExport(history) { for (const result of results) { // Only accept real URLs. file_code alone is just an opaque ID and // ends up looking like "nur sone Nummerierung" in the CSV. - const rawLink = result && (result.download_url || result.embed_url) || ''; - const link = /^https?:\/\//i.test(String(rawLink)) ? String(rawLink) : ''; + const link = selectPublicUploadUrl(result); rows.push({ batchId, batchTimestamp, @@ -2158,7 +2158,7 @@ ipcMain.handle('start-upload', async (_event, payload) => { }); } if (data.status === 'done' && data.result) { - const link = data.result.download_url || data.result.embed_url || data.result.file_code || ''; + const link = selectPublicUploadUrl(data.result); if (link) { if (shouldLogHosterToFile(data.hoster)) { appendUploadLog(data.hoster || '', link, data.fileName || ''); diff --git a/scripts/verify-public-release.mjs b/scripts/verify-public-release.mjs index 387964f..6432b60 100644 --- a/scripts/verify-public-release.mjs +++ b/scripts/verify-public-release.mjs @@ -30,6 +30,7 @@ const sourceFiles = [ 'lib/file-discovery.js', 'lib/folder-monitor.js', 'lib/hosters.js', + 'lib/hoster-transport-error.js', 'lib/ip-allowlist.js', 'lib/log-mode.js', 'lib/log-policy.js', @@ -111,6 +112,7 @@ const sourceFiles = [ 'tests/history-status.test.js', 'tests/history-retention.test.js', 'tests/hosters.test.js', + 'tests/hoster-recovery-provenance.test.js', 'tests/i18n.test.js', 'tests/ip-allowlist.test.js', 'tests/log-mode.test.js', diff --git a/tests/upload-confirmation.test.js b/tests/upload-confirmation.test.js index 9bcbeba..b480143 100644 --- a/tests/upload-confirmation.test.js +++ b/tests/upload-confirmation.test.js @@ -1,7 +1,14 @@ const test = require('node:test'); const assert = require('node:assert/strict'); -const { assertUploadConfirmation } = require('../lib/upload-confirmation'); +const { assertUploadConfirmation, selectPublicUploadUrl } = require('../lib/upload-confirmation'); + +test('selects only a real public URL for logs and exports', () => { + assert.equal(selectPublicUploadUrl({ download_url: 'https://doodstream.com/d/abc123', file_code: 'abc123' }), 'https://doodstream.com/d/abc123'); + assert.equal(selectPublicUploadUrl({ embed_url: 'https://voe.sx/e/abc123', file_code: 'abc123' }), 'https://voe.sx/e/abc123'); + assert.equal(selectPublicUploadUrl({ download_url: 'javascript:alert(1)', file_code: 'abc123' }), ''); + assert.equal(selectPublicUploadUrl({ file_code: 'abc123' }), ''); +}); test('materializes canonical Doodstream URLs from a confirmed file code', () => { assert.deepEqual(