execCommand corrupts multi-byte UTF-8 output split across channel data chunks

Đang mở Phù hợp với người mới
#487 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Đánh giá

Độ khó
2/5
Thời gian dự kiến
1-3 giờ
Mức phù hợp với người mới
78/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
nodejs, typescript
Lĩnh vực
networking

Hướng nghiên cứu

Lỗi nằm ở execCommand trong src/index.ts (dòng 394-401), nơi các trình xử lý data của channel và channel.stderr gọi chunk.toString(options.encoding) trên từng chunk riêng lẻ. Bắt đầu bằng cách chạy script tái hiện từ issue và đọc các trình xử lý đó cùng với wrapper exec gọi execCommand. Hoàn thành khi bản tái hiện in ra equal: true với độ dài 12000 và stdout không còn U+FFFD quanh điểm cắt.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

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/

Ngôn ngữ chính
TypeScript
Star
1k
Fork
94
Chỉ số merge pull request
Không có pull request nào được merge trong 30 ngày

Chuẩn bị môi trường

Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của steelbrain/node-ssh

Tất cả issue của steelbrain/node-ssh

Issue tương tự

Thêm issue về TypeScript

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.