claude-opencode-viewer 2.6.6 → 2.6.7
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/package.json +1 -1
- package/server.js +103 -6
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -8,6 +8,7 @@ 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';
|
|
11
12
|
import { WebSocketServer } from 'ws';
|
|
12
13
|
import Database from 'better-sqlite3';
|
|
13
14
|
|
|
@@ -19,7 +20,7 @@ const PORT = parseInt(process.argv[2]) || 7008;
|
|
|
19
20
|
const IS_PC = process.argv.includes('--pc');
|
|
20
21
|
const USE_HTTPS = process.argv.includes('--https');
|
|
21
22
|
|
|
22
|
-
//
|
|
23
|
+
// 自签名证书生成(纯 Node.js,不依赖 openssl)
|
|
23
24
|
function getOrCreateCert() {
|
|
24
25
|
const certDir = join(homedir(), '.cov-certs');
|
|
25
26
|
const keyPath = join(certDir, 'key.pem');
|
|
@@ -31,12 +32,108 @@ function getOrCreateCert() {
|
|
|
31
32
|
|
|
32
33
|
console.log('🔐 首次使用 HTTPS,生成自签名证书...');
|
|
33
34
|
mkdirSync(certDir, { recursive: true });
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
|
|
36
|
+
const { publicKey, privateKey } = generateKeyPairSync('rsa', {
|
|
37
|
+
modulusLength: 2048,
|
|
38
|
+
publicKeyEncoding: { type: 'spki', format: 'der' },
|
|
39
|
+
privateKeyEncoding: { type: 'pkcs8', format: 'pem' },
|
|
40
|
+
});
|
|
41
|
+
|
|
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);
|
|
38
135
|
console.log(`📁 证书已保存到 ${certDir}`);
|
|
39
|
-
return { key:
|
|
136
|
+
return { key: privateKey, cert: certPem };
|
|
40
137
|
}
|
|
41
138
|
|
|
42
139
|
// OpenCode 数据库路径(支持环境变量覆盖,自动检测 /halo 环境)
|