fix(doodstream): use current page format (form action + matching sess_id)
The 3.3.25 diagnostics captured the live upload page: doodstream moved the upload server from a `srv_url` JS variable into the multipart form's action, e.g. action="https://xxx.cloudatacdn.com/upload/01?SESSID", with a per-page session token in the query that matches the page's hidden sess_id input. The old parser found neither and fell through to the stale hardcoded node, which returns an empty filecode. - Parse the upload server from the form action (matched via the /upload/ path), un-escaping & in the query string. - Refresh this.sessId from the SAME page (only on action match) so the multipart sess_id field matches the node URL's token; login-time and node tokens otherwise diverge. Keep the existing sessId if the input is absent. - Keep the legacy ?op=upload_server JSON and srv_url paths as fallbacks; the fail-fast throw from 3.3.25 stays as the last resort. - Tests: form-action parse, sess_id refresh, & un-escape (9 total). Whether this fully resolves the uploads is for the next server logs to confirm; both the node and sess_id fixes are individually correct. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
1e6bb27404
commit
18a875a764
@ -210,6 +210,31 @@ class DoodstreamUploader {
|
||||
// Fallback: try fetching from upload page HTML
|
||||
const pageRes = await this._fetch(BASE_URL + '/?op=upload');
|
||||
const html = await pageRes.text();
|
||||
|
||||
// Current doodstream format: the upload server is the action of the
|
||||
// multipart upload form, e.g.
|
||||
// <form name="file" enctype="multipart/form-data"
|
||||
// action="https://xxx.cloudatacdn.com/upload/01?SESSID" ...>
|
||||
// <input type="hidden" name="sess_id" value="SESSID">
|
||||
// The node is assigned per page-load and the action carries a session token
|
||||
// in its query string that matches the page's hidden sess_id. We refresh
|
||||
// this.sessId from THIS page so the multipart sess_id field matches the node
|
||||
// URL — login-time and node tokens otherwise diverge and the upload comes
|
||||
// back with an empty filecode.
|
||||
const actionMatch = html.match(/action=["'](https?:\/\/[^"']+\/upload\/[^"']*)["']/i);
|
||||
if (actionMatch) {
|
||||
const url = actionMatch[1].replace(/&/g, '&'); // un-escape HTML entities in query
|
||||
const freshSess = html.match(/name=["']sess_id["'][^>]*value=["']([a-zA-Z0-9]+)["']/);
|
||||
if (freshSess) {
|
||||
this.sessId = freshSess[1];
|
||||
} else {
|
||||
_debugLog('upload_server: form action found but no sess_id on page; keeping existing sessId');
|
||||
}
|
||||
_debugLog(`upload_server: using form action node=${url} sess=${this.sessId}`);
|
||||
return url;
|
||||
}
|
||||
|
||||
// Legacy fallback: srv_url JS variable (older doodstream theme).
|
||||
const srvMatch = html.match(/srv_url['":\s]+['"]?(https?:\/\/[^'">\s]+)['"]?/i);
|
||||
if (srvMatch) return srvMatch[1];
|
||||
|
||||
|
||||
@ -87,6 +87,27 @@ test('getUploadServer: falls back to srv_url in upload-page HTML', async () => {
|
||||
assert.equal(await up._getUploadServer(), 'https://node7.cloudatacdn.com/upload/01');
|
||||
});
|
||||
|
||||
test('getUploadServer: parses current form-action node and refreshes sess_id from the same page', async () => {
|
||||
const up = new DoodstreamUploader();
|
||||
up.sessId = 'stale-from-login';
|
||||
up._fetch = async (url) => {
|
||||
if (/op=upload_server/.test(url)) return fakeRes('<html>not json</html>');
|
||||
return fakeRes('<form name="file" enctype="multipart/form-data" action="https://n9.cloudatacdn.com/upload/01?FRESH123" method="post"><input type="hidden" name="sess_id" value="FRESH123"></form>');
|
||||
};
|
||||
const url = await up._getUploadServer();
|
||||
assert.equal(url, 'https://n9.cloudatacdn.com/upload/01?FRESH123');
|
||||
assert.equal(up.sessId, 'FRESH123'); // critical: form-field token must match the node URL token
|
||||
});
|
||||
|
||||
test('getUploadServer: un-escapes & in the form-action query string', async () => {
|
||||
const up = new DoodstreamUploader();
|
||||
up._fetch = async (url) => {
|
||||
if (/op=upload_server/.test(url)) return fakeRes('<html>not json</html>');
|
||||
return fakeRes('<form name="file" enctype="multipart/form-data" action="https://n9.cloudatacdn.com/upload/01?a=1&b=2" method="post"></form>');
|
||||
};
|
||||
assert.equal(await up._getUploadServer(), 'https://n9.cloudatacdn.com/upload/01?a=1&b=2');
|
||||
});
|
||||
|
||||
test('getUploadServer: throws (no silent dead fallback) when discovery fails', async () => {
|
||||
const up = new DoodstreamUploader();
|
||||
up._fetch = async () => fakeRes('<html><body>login required</body></html>', { status: 200 });
|
||||
|
||||
Loading…
Reference in New Issue
Block a user