execCommand corrupts multi-byte UTF-8 output split across channel data chunks
还没有人认领这个 Issue。
评估
- 难度
- 2/5
- 预计耗时
- 1-3 小时
- 新手友好度
- 78/100
- Issue 类型
- 缺陷
- 描述清晰度
- 描述清楚
- 活跃度
- 活跃
- 技术栈
- nodejs, typescript
- 领域
- networking
调研方向
该 bug 位于 src/index.ts 中的 execCommand(第 394-401 行),其中 data 处理器(作用于 channel 和 channel.stderr)对每个数据块分别调用 chunk.toString(options.encoding)。请先运行 issue 中的复现脚本,并结合调用 execCommand 的 exec 包装器阅读这些处理器。完成标准是复现脚本输出长度为 12000 的 equal: true,且 stdout 在拆分位置附近不再包含 U+FFFD。
由索引模型根据 Issue 内容生成。
描述
execCommand (and exec, which calls it) decodes each SSH channel data chunk on its own with chunk.toString(options.encoding), so any multi-byte UTF-8 character whose bytes straddle two SSH packets (for example at the default 32 KiB channel packet boundary) turns into U+FFFD replacement characters.
Save as repro.mjs and run npm install [email protected] && node repro.mjs:
import ssh2 from "ssh2";
import { NodeSSH } from "node-ssh";
const expected = "日".repeat(12000); // 36,000 UTF-8 bytes (> 32 KiB SSH packet size)
const hostKey = ssh2.utils.generateKeyPairSync("ed25519").private;
const server = new ssh2.Server({ hostKeys: [hostKey] }, (client) => {
client.on("authentication", (ctx) => ctx.accept());
client.on("session", (accept) => accept().on("exec", (accept) => {
const ch = accept();
ch.write(expected);
ch.exit(0);
ch.end();
}));
});
await new Promise((r) => server.listen(0, "127.0.0.1", r));
const ssh = new NodeSSH();
await ssh.connect({ host: "127.0.0.1", port: server.address().port, username: "u", password: "p" });
const { stdout } = await ssh.execCommand("cat file.txt");
console.log({
equal: stdout === expected,
length: stdout.length,
codePointsAroundSplit: [...stdout.slice(10921, 10925)].map((c) => c.codePointAt(0).toString(16)),
});
ssh.dispose();
server.close();
Actual:
{
equal: false,
length: 12001,
codePointsAroundSplit: [ '65e5', 'fffd', 'fffd', '65e5' ]
}
Expected:
{
equal: true,
length: 12000,
codePointsAroundSplit: [ '65e5', '65e5', '65e5', '65e5' ]
}
In src/index.ts lines 394-401, channel and channel.stderr convert each chunk via chunk.toString(options.encoding) instead of collecting the Buffer chunks for Buffer.concat(chunks).toString(options.encoding) (or using StringDecoder).
Version: [email protected] ([email protected]), also reproduced on main (fca27fa), Node.js v26.13.0.
Credit: https://ucsbplse.github.io/
- 主要语言
- TypeScript
- 星标
- 1k
- 派生
- 94
- PR 合并指标
- 30 天内没有已合并 PR
环境准备
这个项目没有提供开发容器、Dockerfile 或贡献指南,环境需要你自己搭建:先看它的 README,通用步骤见我们的新手贡献指南。
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
steelbrain/node-ssh 的其他 Issue
-
难度 5/5 一周以上 新手友好度 35/100
steelbrain/node-ssh#482 · 3 条评论 ·
-
难度 3/5 1-2 天 新手友好度 45/100
steelbrain/node-ssh#474 · 3 条评论 ·
-
难度 3/5 1-2 天 新手友好度 35/100
steelbrain/node-ssh#473 · 1 条评论 · 1 个 reaction ·
-
难度 4/5 3-5 天 新手友好度 20/100
steelbrain/node-ssh#472 ·
-
难度 4/5 3-5 天 新手友好度 35/100
steelbrain/node-ssh#471 · 1 条评论 ·
查看 steelbrain/node-ssh 的全部 Issue
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 82/100
-
cli: `execCargoMetadata` decodes stdout per chunk, corrupting non-ASCII paths across pipe boundaries未关闭
难度 2/5 1-3 小时 新手友好度 68/100
维护者通常 1 天内回复
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
难度 1/5 1 小时以内 新手友好度 62/100
lingdojo/kana-dojo#34127 · 1 条评论 · 5 个 reaction ·
维护者通常 1 天内回复
-
难度 1/5 1 小时以内 新手友好度 68/100
osmlab/name-suggestion-index#13104 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 72/100