fix: canonicalize Doodstream result links
CI / verify (push) Has been cancelled

Accept current Doodstream result domains while keeping returned download and embed URLs on doodstream.com. Add safe confirmation diagnostics and regression coverage.
This commit is contained in:
Sucukdeluxe
2026-08-12 02:43:36 +02:00
parent 238eeda24c
commit 4c970ec09e
4 changed files with 77 additions and 7 deletions
+43 -3
View File
@@ -7,19 +7,52 @@ const SUPPORTED_HOSTERS = new Set([
]); ]);
const FILE_CODE_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{2,127}$/; const FILE_CODE_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{2,127}$/;
const HOSTER_RESULT_DOMAINS = {
'doodstream.com': ['doodstream.com', 'dood.to', 'dood.la', 'dood.so', 'dsvplay.com']
};
function isExpectedHostUrl(value, expectedHost) { function isExpectedHostUrl(value, expectedHost) {
if (typeof value !== 'string' || value.trim() === '') return false; if (typeof value !== 'string' || value.trim() === '') return false;
try { try {
const url = new URL(value); const url = new URL(value);
const hostname = url.hostname.toLowerCase(); const hostname = url.hostname.toLowerCase();
const acceptedDomains = HOSTER_RESULT_DOMAINS[expectedHost] || [expectedHost];
return (url.protocol === 'http:' || url.protocol === 'https:') return (url.protocol === 'http:' || url.protocol === 'https:')
&& (hostname === expectedHost || hostname.endsWith(`.${expectedHost}`)); && acceptedDomains.some(domain => hostname === domain || hostname.endsWith(`.${domain}`));
} catch { } catch {
return false; return false;
} }
} }
function getUrlHost(value) {
try {
return new URL(value).hostname.toLowerCase();
} catch {
return 'invalid';
}
}
function normalizeDoodstreamUrl(value) {
if (typeof value !== 'string' || value.trim() === '') return value;
try {
const url = new URL(value);
const hostname = url.hostname.toLowerCase();
if (hostname !== 'doodstream.com' && HOSTER_RESULT_DOMAINS['doodstream.com'].includes(hostname)) {
url.hostname = 'doodstream.com';
return url.toString();
}
} catch {}
return value;
}
function normalizeConfirmedResult(result, hoster) {
if (hoster !== 'doodstream.com') return result;
const downloadUrl = normalizeDoodstreamUrl(result.download_url);
const embedUrl = normalizeDoodstreamUrl(result.embed_url);
if (downloadUrl === result.download_url && embedUrl === result.embed_url) return result;
return { ...result, download_url: downloadUrl, embed_url: embedUrl };
}
function assertUploadConfirmation(result, hoster) { function assertUploadConfirmation(result, hoster) {
const expectedHost = typeof hoster === 'string' ? hoster.trim().toLowerCase() : ''; const expectedHost = typeof hoster === 'string' ? hoster.trim().toLowerCase() : '';
const fileCode = typeof result?.file_code === 'string' ? result.file_code.trim() : ''; const fileCode = typeof result?.file_code === 'string' ? result.file_code.trim() : '';
@@ -31,9 +64,16 @@ function assertUploadConfirmation(result, hoster) {
if (SUPPORTED_HOSTERS.has(expectedHost) if (SUPPORTED_HOSTERS.has(expectedHost)
&& FILE_CODE_PATTERN.test(fileCode) && FILE_CODE_PATTERN.test(fileCode)
&& urls.every(value => isExpectedHostUrl(value, expectedHost))) { && urls.every(value => isExpectedHostUrl(value, expectedHost))) {
return result; return normalizeConfirmedResult(result, expectedHost);
} }
throw new Error(`Upload zu ${hoster || 'unbekanntem Hoster'} wurde nicht bestätigt`); const error = new Error(`Upload zu ${hoster || 'unbekanntem Hoster'} wurde nicht bestätigt`);
error.diagnostic = {
payloadSnippet: JSON.stringify({
fileCodeLength: fileCode.length,
urlHosts: urls.map(getUrlHost)
})
};
throw error;
} }
module.exports = { assertUploadConfirmation }; module.exports = { assertUploadConfirmation };
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "multi-hoster-uploader", "name": "multi-hoster-uploader",
"version": "2.1.13", "version": "2.1.14",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "multi-hoster-uploader", "name": "multi-hoster-uploader",
"version": "2.1.13", "version": "2.1.14",
"dependencies": { "dependencies": {
"chokidar": "^3.6.0", "chokidar": "^3.6.0",
"undici": "^7.29.0", "undici": "^7.29.0",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "multi-hoster-uploader", "name": "multi-hoster-uploader",
"version": "2.1.13", "version": "2.1.14",
"description": "Upload files to doodstream, voe, vidmoly, byse simultaneously", "description": "Upload files to doodstream, voe, vidmoly, byse simultaneously",
"main": "main.js", "main": "main.js",
"scripts": { "scripts": {
+31 -1
View File
@@ -22,6 +22,32 @@ test('accepts upload URLs for every supported hoster and its subdomains', () =>
} }
}); });
test('accepts Doodstream result links on its current public domains', () => {
const result = {
file_code: 'DOODCODE1234',
download_url: 'https://dood.to/d/DOODCODE1234',
embed_url: 'https://dood.la/e/DOODCODE1234'
};
assert.deepEqual(assertUploadConfirmation(result, 'doodstream.com'), {
...result,
download_url: 'https://doodstream.com/d/DOODCODE1234',
embed_url: 'https://doodstream.com/e/DOODCODE1234'
});
});
test('accepts the Doodstream result domain returned by the current upload service', () => {
const result = {
file_code: 'DOODCODE1234',
download_url: 'https://dsvplay.com/d/DOODCODE1234',
embed_url: 'https://dsvplay.com/e/DOODCODE1234'
};
assert.deepEqual(assertUploadConfirmation(result, 'doodstream.com'), {
...result,
download_url: 'https://doodstream.com/d/DOODCODE1234',
embed_url: 'https://doodstream.com/e/DOODCODE1234'
});
});
test('rejects an upload URL from a different domain', () => { test('rejects an upload URL from a different domain', () => {
assert.throws( assert.throws(
() => assertUploadConfirmation({ file_code: 'abc123', download_url: 'https://attacker.invalid/file/abc123' }, 'voe.sx'), () => assertUploadConfirmation({ file_code: 'abc123', download_url: 'https://attacker.invalid/file/abc123' }, 'voe.sx'),
@@ -39,7 +65,11 @@ test('rejects a syntactically invalid file code despite a valid hoster URL', ()
test('rejects a valid hoster URL without a file code', () => { test('rejects a valid hoster URL without a file code', () => {
assert.throws( assert.throws(
() => assertUploadConfirmation({ download_url: 'https://byse.sx/d/abc123' }, 'byse.sx'), () => assertUploadConfirmation({ download_url: 'https://byse.sx/d/abc123' }, 'byse.sx'),
/Upload zu byse\.sx wurde nicht bestätigt/ (err) => {
assert.match(err.message, /Upload zu byse\.sx wurde nicht bestätigt/);
assert.equal(err.diagnostic.payloadSnippet, '{"fileCodeLength":0,"urlHosts":["byse.sx"]}');
return true;
}
); );
}); });