mirror of
https://github.com/zotero/zotero.git
synced 2026-10-03 02:21:49 +00:00
Fix WebDAV download auth for usernames with special characters
HTTP.download() was rewritten in 0fe31b0f04 to use fetch() and build the
Basic auth header itself via btoa(username + ':' + password), but the
username and password come from nsIURI.username/password, which are
percent-encoded. As a result, a username like "user@example.com" was
sent as "user%40example.com", causing a 401 on every WebDAV download for
any user with @, :, space, etc. in their username. Other request types
were unaffected because they go through xmlhttp.open(method, url, true,
username, password), which decodes internally.
Decode username and password in _parseURI() so the values returned can
be used directly for Basic auth (and as a side effect, fix the other
display/use sites that were getting the percent-encoded form).
https://forums.zotero.org/discussion/131174/zotero-10-betas-1-2-3-cant-download-from-webdav-http-401
This commit is contained in:
parent
e13e85b2e5
commit
fd812070b6
2 changed files with 34 additions and 6 deletions
|
|
@ -15,8 +15,8 @@ Zotero.HTTP = new function () {
|
||||||
* Parse a URI (nsIURI or string), extract any embedded credentials, and
|
* Parse a URI (nsIURI or string), extract any embedded credentials, and
|
||||||
* return the URL as a credential-free string
|
* return the URL as a credential-free string
|
||||||
*
|
*
|
||||||
* Mozilla percent-encodes periods in the username component of nsIURIs (%2E), which is
|
* nsIURI returns the username and password percent-encoded, so we decode them so
|
||||||
* technically valid but breaks Basic auth against most servers, so we undo that here.
|
* callers can use them directly (e.g., when building a Basic auth header).
|
||||||
*
|
*
|
||||||
* @param {nsIURI|String} uri
|
* @param {nsIURI|String} uri
|
||||||
* @return {{ url: String, username: String|null, password: String|null }}
|
* @return {{ url: String, username: String|null, password: String|null }}
|
||||||
|
|
@ -30,11 +30,9 @@ Zotero.HTTP = new function () {
|
||||||
return { url: uri, username: null, password: null };
|
return { url: uri, username: null, password: null };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let username = uri.username || null;
|
let username = uri.username ? decodeURIComponent(uri.username) : null;
|
||||||
let password = null;
|
let password = uri.password ? decodeURIComponent(uri.password) : null;
|
||||||
if (username) {
|
if (username) {
|
||||||
username = username.replace(/%2E/, '.');
|
|
||||||
password = uri.password || null;
|
|
||||||
uri = uri.mutate().setUserPass('').finalize();
|
uri = uri.mutate().setUserPass('').finalize();
|
||||||
}
|
}
|
||||||
return { url: uri.spec, username, password };
|
return { url: uri.spec, username, password };
|
||||||
|
|
|
||||||
|
|
@ -421,6 +421,23 @@ describe("Zotero.HTTP", function () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
httpd.registerPathHandler(
|
||||||
|
'/download/auth',
|
||||||
|
{
|
||||||
|
handle: function (request, response) {
|
||||||
|
let val;
|
||||||
|
try {
|
||||||
|
val = request.getHeader("Authorization");
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
val = "";
|
||||||
|
}
|
||||||
|
response.setStatusLine(null, 200, "OK");
|
||||||
|
response.setHeader("X-Echo-Auth", val, false);
|
||||||
|
response.write("ok");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async function () {
|
beforeEach(async function () {
|
||||||
|
|
@ -551,6 +568,19 @@ describe("Zotero.HTTP", function () {
|
||||||
let stat = await IOUtils.stat(dest);
|
let stat = await IOUtils.stat(dest);
|
||||||
assert.equal(stat.size, 3 * 1024);
|
assert.equal(stat.size, 3 * 1024);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should decode percent-encoded credentials from URL for Basic auth", async function () {
|
||||||
|
let username = "user@example.com";
|
||||||
|
let password = "secret";
|
||||||
|
let expected = "Basic " + btoa(username + ":" + password);
|
||||||
|
let url = `http://${encodeURIComponent(username)}:${password}`
|
||||||
|
+ `@127.0.0.1:${port}/download/auth`;
|
||||||
|
let dest = PathUtils.join(tmpDir, "auth.bin");
|
||||||
|
let nsUri = Services.io.newURI(url);
|
||||||
|
let req = await Zotero.HTTP.download(nsUri, dest);
|
||||||
|
assert.equal(req.status, 200);
|
||||||
|
assert.equal(req.headers.get("X-Echo-Auth"), expected);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue