claude-opencode-viewer 2.6.7 → 2.6.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index-pc.html CHANGED
@@ -1036,7 +1036,8 @@
1036
1036
  if (!b64 || b64 === '?') return false;
1037
1037
  if (isBufferReplay) return true;
1038
1038
  try {
1039
- var text = atob(b64);
1039
+ var bytes = Uint8Array.from(atob(b64), function(c) { return c.charCodeAt(0); });
1040
+ var text = new TextDecoder().decode(bytes);
1040
1041
  if (navigator.clipboard && navigator.clipboard.writeText) {
1041
1042
  navigator.clipboard.writeText(text).then(function() {
1042
1043
  showCopyToast();
package/index.html CHANGED
@@ -1026,7 +1026,8 @@
1026
1026
  var b64 = data.substring(idx + 1);
1027
1027
  if (!b64 || b64 === '?') return false;
1028
1028
  try {
1029
- var text = atob(b64);
1029
+ var bytes = Uint8Array.from(atob(b64), function(c) { return c.charCodeAt(0); });
1030
+ var text = new TextDecoder().decode(bytes);
1030
1031
  if (navigator.clipboard && navigator.clipboard.writeText) {
1031
1032
  navigator.clipboard.writeText(text).then(function() {
1032
1033
  showCopyToast();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-opencode-viewer",
3
- "version": "2.6.7",
3
+ "version": "2.6.9",
4
4
  "description": "A unified terminal viewer for Claude Code and OpenCode with seamless switching",
5
5
  "type": "module",
6
6
  "main": "server.js",
@@ -35,6 +35,7 @@
35
35
  "dependencies": {
36
36
  "better-sqlite3": "^11.8.1",
37
37
  "node-pty": "^1.1.0",
38
+ "selfsigned": "^5.5.0",
38
39
  "ws": "^8.19.0"
39
40
  },
40
41
  "engines": {
package/server.js CHANGED
@@ -8,7 +8,6 @@ import { networkInterfaces, platform, arch, homedir } from 'node:os';
8
8
  import { chmodSync, statSync } from 'node:fs';
9
9
  import { execSync, execFile } from 'child_process';
10
10
  import { promisify } from 'node:util';
11
- import { generateKeyPairSync, createSign, randomBytes } from 'node:crypto';
12
11
  import { WebSocketServer } from 'ws';
13
12
  import Database from 'better-sqlite3';
14
13
 
@@ -20,8 +19,8 @@ const PORT = parseInt(process.argv[2]) || 7008;
20
19
  const IS_PC = process.argv.includes('--pc');
21
20
  const USE_HTTPS = process.argv.includes('--https');
22
21
 
23
- // 自签名证书生成(纯 Node.js,不依赖 openssl)
24
- function getOrCreateCert() {
22
+ // 自签名证书生成(使用 selfsigned 库,不依赖 openssl)
23
+ async function getOrCreateCert() {
25
24
  const certDir = join(homedir(), '.cov-certs');
26
25
  const keyPath = join(certDir, 'key.pem');
27
26
  const certPath = join(certDir, 'cert.pem');
@@ -33,107 +32,23 @@ function getOrCreateCert() {
33
32
  console.log('🔐 首次使用 HTTPS,生成自签名证书...');
34
33
  mkdirSync(certDir, { recursive: true });
35
34
 
36
- const { publicKey, privateKey } = generateKeyPairSync('rsa', {
37
- modulusLength: 2048,
38
- publicKeyEncoding: { type: 'spki', format: 'der' },
39
- privateKeyEncoding: { type: 'pkcs8', format: 'pem' },
35
+ const { default: selfsigned } = await import('selfsigned');
36
+ const attrs = [{ name: 'commonName', value: 'cov-self-signed' }];
37
+ const pems = await selfsigned.generate(attrs, {
38
+ days: 365,
39
+ keySize: 2048,
40
+ extensions: [
41
+ { name: 'subjectAltName', altNames: [
42
+ { type: 7, ip: '127.0.0.1' },
43
+ { type: 2, value: 'localhost' },
44
+ ]}
45
+ ],
40
46
  });
41
47
 
42
- // 构建自签名 X.509 v3 证书(DER 编码)
43
- const serial = randomBytes(8);
44
- const now = new Date();
45
- const expire = new Date(now.getTime() + 365 * 24 * 3600 * 1000);
46
-
47
- function encodeLength(len) {
48
- if (len < 128) return Buffer.from([len]);
49
- if (len < 256) return Buffer.from([0x81, len]);
50
- return Buffer.from([0x82, (len >> 8) & 0xff, len & 0xff]);
51
- }
52
-
53
- function derSequence(buffers) {
54
- const body = Buffer.concat(buffers);
55
- return Buffer.concat([Buffer.from([0x30]), encodeLength(body.length), body]);
56
- }
57
-
58
- function derSet(buffers) {
59
- const body = Buffer.concat(buffers);
60
- return Buffer.concat([Buffer.from([0x31]), encodeLength(body.length), body]);
61
- }
62
-
63
- function derOid(oid) {
64
- const parts = oid.split('.').map(Number);
65
- const bytes = [40 * parts[0] + parts[1]];
66
- for (let i = 2; i < parts.length; i++) {
67
- let v = parts[i];
68
- if (v < 128) { bytes.push(v); }
69
- else {
70
- const enc = [];
71
- enc.push(v & 0x7f); v >>= 7;
72
- while (v > 0) { enc.push(0x80 | (v & 0x7f)); v >>= 7; }
73
- bytes.push(...enc.reverse());
74
- }
75
- }
76
- const buf = Buffer.from(bytes);
77
- return Buffer.concat([Buffer.from([0x06]), encodeLength(buf.length), buf]);
78
- }
79
-
80
- function derUtf8(str) {
81
- const buf = Buffer.from(str, 'utf8');
82
- return Buffer.concat([Buffer.from([0x0c]), encodeLength(buf.length), buf]);
83
- }
84
-
85
- function derInt(buf) {
86
- if (buf[0] & 0x80) buf = Buffer.concat([Buffer.from([0x00]), buf]);
87
- return Buffer.concat([Buffer.from([0x02]), encodeLength(buf.length), buf]);
88
- }
89
-
90
- function derBitString(buf) {
91
- const body = Buffer.concat([Buffer.from([0x00]), buf]);
92
- return Buffer.concat([Buffer.from([0x03]), encodeLength(body.length), body]);
93
- }
94
-
95
- function derTime(date) {
96
- const s = date.toISOString().replace(/[-:T]/g, '').slice(0, 14) + 'Z';
97
- const buf = Buffer.from(s, 'ascii');
98
- return Buffer.concat([Buffer.from([0x17]), encodeLength(buf.length), buf]);
99
- }
100
-
101
- function derExplicit(tag, content) {
102
- return Buffer.concat([Buffer.from([0xa0 | tag]), encodeLength(content.length), content]);
103
- }
104
-
105
- const issuer = derSequence([derSet([derSequence([derOid('2.5.4.3'), derUtf8('cov-self-signed')])])]);
106
- const validity = derSequence([derTime(now), derTime(expire)]);
107
- const spki = Buffer.from(publicKey);
108
-
109
- const tbs = derSequence([
110
- derExplicit(0, derInt(Buffer.from([0x02]))), // version v3
111
- derInt(serial),
112
- derSequence([derOid('1.2.840.113549.1.1.11'), Buffer.from([0x05, 0x00])]), // sha256WithRSA
113
- issuer,
114
- validity,
115
- issuer, // subject = issuer (self-signed)
116
- spki,
117
- ]);
118
-
119
- const sign = createSign('SHA256');
120
- sign.update(tbs);
121
- const signature = sign.sign(privateKey);
122
-
123
- const cert = derSequence([
124
- tbs,
125
- derSequence([derOid('1.2.840.113549.1.1.11'), Buffer.from([0x05, 0x00])]),
126
- derBitString(signature),
127
- ]);
128
-
129
- const certPem = '-----BEGIN CERTIFICATE-----\n' +
130
- cert.toString('base64').match(/.{1,64}/g).join('\n') +
131
- '\n-----END CERTIFICATE-----\n';
132
-
133
- writeFileSync(keyPath, privateKey);
134
- writeFileSync(certPath, certPem);
48
+ writeFileSync(keyPath, pems.private);
49
+ writeFileSync(certPath, pems.cert);
135
50
  console.log(`📁 证书已保存到 ${certDir}`);
136
- return { key: privateKey, cert: certPem };
51
+ return { key: pems.private, cert: pems.cert };
137
52
  }
138
53
 
139
54
  // OpenCode 数据库路径(支持环境变量覆盖,自动检测 /halo 环境)
@@ -679,7 +594,7 @@ const requestHandler = async (req, res) => {
679
594
  };
680
595
 
681
596
  const server = USE_HTTPS
682
- ? createHttpsServer(getOrCreateCert(), requestHandler)
597
+ ? createHttpsServer(await getOrCreateCert(), requestHandler)
683
598
  : createServer(requestHandler);
684
599
 
685
600
  const wss = new WebSocketServer({ server, path: '/ws' });