diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 60a79f88e..13d4fe2b3 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -3,3 +3,4 @@ v0.93.2 - CDSI: production enclave switch to 15637fa1 - SVR: New enclaves for 2026Q2 for staging, and configurations (but not use) for prod. - node: Expose SVR2-related functionality +- node: Support non-ASCII usernames and passwords in proxy URLs diff --git a/node/ts/net.ts b/node/ts/net.ts index f7d8a8fa4..1e5db933e 100644 --- a/node/ts/net.ts +++ b/node/ts/net.ts @@ -449,8 +449,10 @@ export class Net { // This does not distinguish between "https://proxy.example" and "https://@proxy.example". // This could be done by manually checking `url.href`. // But until someone complains about it, let's not worry about it. - const username = url.username != '' ? url.username : undefined; - const password = url.password != '' ? url.password : undefined; + const username = + url.username != '' ? decodeURIComponent(url.username) : undefined; + const password = + url.password != '' ? decodeURIComponent(url.password) : undefined; const host = url.hostname; const port = url.port != '' ? Number.parseInt(url.port, 10) : undefined; diff --git a/node/ts/test/NetTest.ts b/node/ts/test/NetTest.ts index 1137bc5f3..afff3edae 100644 --- a/node/ts/test/NetTest.ts +++ b/node/ts/test/NetTest.ts @@ -261,6 +261,28 @@ describe('chat service api', () => { port: undefined, }); + // Non-ASCII username and password + expect( + Net.proxyOptionsFromUrl('schm://ユーザ:パス@host.example') + ).deep.equals({ + scheme: 'schm', + host: 'host.example', + username: 'ユーザ', + password: 'パス', + port: undefined, + }); + expect( + Net.proxyOptionsFromUrl( + 'schm://%E3%83%A6%E3%83%BC%E3%82%B6:%E3%83%91%E3%82%B9@host.example' + ) + ).deep.equals({ + scheme: 'schm', + host: 'host.example', + username: 'ユーザ', + password: 'パス', + port: undefined, + }); + // Empty "fields" get dropped by Node's URL parser. expect(Net.proxyOptionsFromUrl('schm://host.example:')).deep.equals({ scheme: 'schm',