[Init] Initial commit - NetMesh terminal manager
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
This commit is contained in:
92
electron/bridges/cloudSyncBridge.webdavBasicAuth.test.cjs
Normal file
92
electron/bridges/cloudSyncBridge.webdavBasicAuth.test.cjs
Normal file
@@ -0,0 +1,92 @@
|
||||
const test = require("node:test");
|
||||
const assert = require("node:assert/strict");
|
||||
const http = require("node:http");
|
||||
|
||||
const {
|
||||
buildBasicAuthHeader,
|
||||
handleWebdavInitialize,
|
||||
} = require("./cloudSyncBridge.cjs");
|
||||
|
||||
// Per RFC 7617, Basic Auth credentials are UTF-8 encoded before base64.
|
||||
// The upstream `webdav` npm package (via `base-64`) encodes them as Latin1
|
||||
// instead, which silently corrupts non-ASCII characters like German umlauts
|
||||
// (ö, ä) — exactly the case reported by Hetzner Storage Box users (#891).
|
||||
//
|
||||
// `ö` (U+00F6):
|
||||
// Latin1 → 1 byte: F6
|
||||
// UTF-8 → 2 bytes: C3 B6
|
||||
const PASSWORD_WITH_UMLAUT = "6?G:ö9yZöäMF+H3";
|
||||
const USERNAME = "uHetzner1";
|
||||
|
||||
test("buildBasicAuthHeader UTF-8 encodes credentials (RFC 7617)", () => {
|
||||
const header = buildBasicAuthHeader("user", "ö");
|
||||
// UTF-8 base64 of "user:ö" = "user" + ":" + 0xC3 0xB6
|
||||
assert.equal(header, "Basic dXNlcjrDtg==");
|
||||
});
|
||||
|
||||
test("buildBasicAuthHeader stays compatible with pure-ASCII credentials", () => {
|
||||
// For ASCII, UTF-8 and Latin1 are byte-identical, so the header is unchanged.
|
||||
const header = buildBasicAuthHeader("user", "password");
|
||||
assert.equal(header, "Basic dXNlcjpwYXNzd29yZA==");
|
||||
});
|
||||
|
||||
function startUtf8BasicAuthServer({ username, password }) {
|
||||
const expected =
|
||||
"Basic " +
|
||||
Buffer.from(`${username}:${password}`, "utf8").toString("base64");
|
||||
|
||||
const server = http.createServer((req, res) => {
|
||||
const got = req.headers["authorization"];
|
||||
if (got !== expected) {
|
||||
res.writeHead(401, {
|
||||
"WWW-Authenticate": 'Basic realm="test", charset="UTF-8"',
|
||||
});
|
||||
res.end("Unauthorized");
|
||||
return;
|
||||
}
|
||||
// Minimal but parseable PROPFIND response so client.exists() resolves true.
|
||||
res.writeHead(207, { "Content-Type": "application/xml; charset=utf-8" });
|
||||
res.end(
|
||||
`<?xml version="1.0" encoding="utf-8"?>
|
||||
<D:multistatus xmlns:D="DAV:">
|
||||
<D:response>
|
||||
<D:href>${req.url}</D:href>
|
||||
<D:propstat>
|
||||
<D:prop>
|
||||
<D:displayname>netcatty-vault.json</D:displayname>
|
||||
<D:getlastmodified>Sat, 10 May 2026 00:00:00 GMT</D:getlastmodified>
|
||||
<D:getcontentlength>0</D:getcontentlength>
|
||||
<D:resourcetype/>
|
||||
</D:prop>
|
||||
<D:status>HTTP/1.1 200 OK</D:status>
|
||||
</D:propstat>
|
||||
</D:response>
|
||||
</D:multistatus>`,
|
||||
);
|
||||
});
|
||||
|
||||
return new Promise((resolve) => {
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
const { port } = server.address();
|
||||
resolve({ server, endpoint: `http://127.0.0.1:${port}` });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
test("handleWebdavInitialize sends UTF-8 Basic Auth (Hetzner umlaut password #891)", async () => {
|
||||
const { server, endpoint } = await startUtf8BasicAuthServer({
|
||||
username: USERNAME,
|
||||
password: PASSWORD_WITH_UMLAUT,
|
||||
});
|
||||
try {
|
||||
const result = await handleWebdavInitialize({
|
||||
endpoint,
|
||||
authType: "password",
|
||||
username: USERNAME,
|
||||
password: PASSWORD_WITH_UMLAUT,
|
||||
});
|
||||
assert.equal(result.resourceId, "/netcatty-vault.json");
|
||||
} finally {
|
||||
await new Promise((resolve) => server.close(resolve));
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user