mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-23 08:45:50 +00:00
style: 完成所有文件的lint
This commit is contained in:
@@ -2,27 +2,27 @@
|
||||
* Self-signed certificate generation for HTTPS support
|
||||
*/
|
||||
|
||||
import { X509Certificate } from "node:crypto";
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
||||
import { homedir, networkInterfaces } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { generate } from "selfsigned";
|
||||
import { X509Certificate } from 'node:crypto'
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
|
||||
import { homedir, networkInterfaces } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
import { generate } from 'selfsigned'
|
||||
|
||||
/**
|
||||
* Get all LAN IPv4 addresses
|
||||
*/
|
||||
export function getLanIPs(): string[] {
|
||||
const ips: string[] = [];
|
||||
const nets = networkInterfaces();
|
||||
const ips: string[] = []
|
||||
const nets = networkInterfaces()
|
||||
for (const name of Object.keys(nets)) {
|
||||
for (const net of nets[name] || []) {
|
||||
// Skip internal (loopback) and non-IPv4 addresses
|
||||
if (!net.internal && net.family === "IPv4") {
|
||||
ips.push(net.address);
|
||||
if (!net.internal && net.family === 'IPv4') {
|
||||
ips.push(net.address)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ips;
|
||||
return ips
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -30,31 +30,31 @@ export function getLanIPs(): string[] {
|
||||
* SAN format: "IP Address:192.168.1.100, IP Address:127.0.0.1, DNS:localhost"
|
||||
*/
|
||||
function extractSanIPs(x509: X509Certificate): string[] {
|
||||
const san = x509.subjectAltName;
|
||||
if (!san) return [];
|
||||
const san = x509.subjectAltName
|
||||
if (!san) return []
|
||||
|
||||
const ips: string[] = [];
|
||||
const ips: string[] = []
|
||||
// Parse "IP Address:x.x.x.x" entries from SAN string
|
||||
const parts = san.split(", ");
|
||||
const parts = san.split(', ')
|
||||
for (const part of parts) {
|
||||
const match = part.match(/^IP Address:(.+)$/);
|
||||
const match = part.match(/^IP Address:(.+)$/)
|
||||
if (match && match[1]) {
|
||||
ips.push(match[1]);
|
||||
ips.push(match[1])
|
||||
}
|
||||
}
|
||||
return ips;
|
||||
return ips
|
||||
}
|
||||
|
||||
const CERT_DIR = join(homedir(), ".acp-proxy");
|
||||
const KEY_PATH = join(CERT_DIR, "key.pem");
|
||||
const CERT_PATH = join(CERT_DIR, "cert.pem");
|
||||
const CERT_DIR = join(homedir(), '.acp-proxy')
|
||||
const KEY_PATH = join(CERT_DIR, 'key.pem')
|
||||
const CERT_PATH = join(CERT_DIR, 'cert.pem')
|
||||
|
||||
// Certificate validity in days
|
||||
const CERT_VALIDITY_DAYS = 365;
|
||||
const CERT_VALIDITY_DAYS = 365
|
||||
|
||||
export interface TlsOptions {
|
||||
key: string;
|
||||
cert: string;
|
||||
key: string
|
||||
cert: string
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,111 +64,119 @@ export interface TlsOptions {
|
||||
export async function getOrCreateCertificate(): Promise<TlsOptions> {
|
||||
// Ensure directory exists
|
||||
if (!existsSync(CERT_DIR)) {
|
||||
mkdirSync(CERT_DIR, { recursive: true });
|
||||
mkdirSync(CERT_DIR, { recursive: true })
|
||||
}
|
||||
|
||||
// Check if certificates already exist and are still valid
|
||||
if (existsSync(KEY_PATH) && existsSync(CERT_PATH)) {
|
||||
const certPem = readFileSync(CERT_PATH, "utf-8");
|
||||
const keyPem = readFileSync(KEY_PATH, "utf-8");
|
||||
const certPem = readFileSync(CERT_PATH, 'utf-8')
|
||||
const keyPem = readFileSync(KEY_PATH, 'utf-8')
|
||||
|
||||
try {
|
||||
const x509 = new X509Certificate(certPem);
|
||||
const validTo = new Date(x509.validTo);
|
||||
const now = new Date();
|
||||
const x509 = new X509Certificate(certPem)
|
||||
const validTo = new Date(x509.validTo)
|
||||
const now = new Date()
|
||||
|
||||
// Check if cert is expired or will expire within 7 days
|
||||
const daysUntilExpiry = Math.floor((validTo.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
|
||||
const daysUntilExpiry = Math.floor(
|
||||
(validTo.getTime() - now.getTime()) / (1000 * 60 * 60 * 24),
|
||||
)
|
||||
|
||||
if (daysUntilExpiry <= 7) {
|
||||
// Certificate expired or expiring soon
|
||||
console.log(`⚠️ Certificate ${daysUntilExpiry <= 0 ? "expired" : `expires in ${daysUntilExpiry} days`}, regenerating...`);
|
||||
console.log(
|
||||
`⚠️ Certificate ${daysUntilExpiry <= 0 ? 'expired' : `expires in ${daysUntilExpiry} days`}, regenerating...`,
|
||||
)
|
||||
} else {
|
||||
// Check if current LAN IPs are in the certificate's SAN
|
||||
const currentLanIPs = getLanIPs();
|
||||
const certSanIPs = extractSanIPs(x509);
|
||||
const currentLanIPs = getLanIPs()
|
||||
const certSanIPs = extractSanIPs(x509)
|
||||
|
||||
// Check if all current LAN IPs are covered by the certificate
|
||||
const missingIPs = currentLanIPs.filter(ip => !certSanIPs.includes(ip));
|
||||
const missingIPs = currentLanIPs.filter(ip => !certSanIPs.includes(ip))
|
||||
|
||||
if (missingIPs.length === 0) {
|
||||
console.log(`🔐 Using existing certificate from ${CERT_DIR}`);
|
||||
console.log(` Valid for ${daysUntilExpiry} more days`);
|
||||
return { key: keyPem, cert: certPem };
|
||||
console.log(`🔐 Using existing certificate from ${CERT_DIR}`)
|
||||
console.log(` Valid for ${daysUntilExpiry} more days`)
|
||||
return { key: keyPem, cert: certPem }
|
||||
}
|
||||
|
||||
// LAN IP changed, regenerate
|
||||
console.log(`⚠️ LAN IP changed (missing: ${missingIPs.join(", ")}), regenerating certificate...`);
|
||||
console.log(
|
||||
`⚠️ LAN IP changed (missing: ${missingIPs.join(', ')}), regenerating certificate...`,
|
||||
)
|
||||
}
|
||||
} catch {
|
||||
// Failed to parse certificate, regenerate
|
||||
console.log(`⚠️ Invalid certificate, regenerating...`);
|
||||
console.log(`⚠️ Invalid certificate, regenerating...`)
|
||||
}
|
||||
}
|
||||
|
||||
// Generate new self-signed certificate
|
||||
console.log(`🔐 Generating self-signed certificate...`);
|
||||
console.log(`🔐 Generating self-signed certificate...`)
|
||||
|
||||
const attrs = [{ name: "commonName", value: "ACP Proxy Server" }];
|
||||
const attrs = [{ name: 'commonName', value: 'ACP Proxy Server' }]
|
||||
|
||||
// Calculate expiry date
|
||||
const notAfterDate = new Date();
|
||||
notAfterDate.setDate(notAfterDate.getDate() + CERT_VALIDITY_DAYS);
|
||||
const notAfterDate = new Date()
|
||||
notAfterDate.setDate(notAfterDate.getDate() + CERT_VALIDITY_DAYS)
|
||||
|
||||
// Build altNames: localhost + loopback + all LAN IPs
|
||||
const altNames: Array<{ type: 1 | 2 | 6 | 7; value?: string; ip?: string }> = [
|
||||
{ type: 2, value: "localhost" },
|
||||
{ type: 7, ip: "127.0.0.1" },
|
||||
{ type: 7, ip: "::1" },
|
||||
];
|
||||
const altNames: Array<{ type: 1 | 2 | 6 | 7; value?: string; ip?: string }> =
|
||||
[
|
||||
{ type: 2, value: 'localhost' },
|
||||
{ type: 7, ip: '127.0.0.1' },
|
||||
{ type: 7, ip: '::1' },
|
||||
]
|
||||
|
||||
// Add all current LAN IPs
|
||||
const lanIPs = getLanIPs();
|
||||
const lanIPs = getLanIPs()
|
||||
for (const ip of lanIPs) {
|
||||
altNames.push({ type: 7, ip });
|
||||
altNames.push({ type: 7, ip })
|
||||
}
|
||||
|
||||
if (lanIPs.length > 0) {
|
||||
console.log(` Including LAN IPs: ${lanIPs.join(", ")}`);
|
||||
console.log(` Including LAN IPs: ${lanIPs.join(', ')}`)
|
||||
}
|
||||
|
||||
const pems = await generate(attrs, {
|
||||
keySize: 2048,
|
||||
notAfterDate,
|
||||
algorithm: "sha256",
|
||||
algorithm: 'sha256',
|
||||
extensions: [
|
||||
{
|
||||
name: "basicConstraints",
|
||||
name: 'basicConstraints',
|
||||
cA: true,
|
||||
},
|
||||
{
|
||||
name: "keyUsage",
|
||||
name: 'keyUsage',
|
||||
keyCertSign: true,
|
||||
digitalSignature: true,
|
||||
keyEncipherment: true,
|
||||
},
|
||||
{
|
||||
name: "extKeyUsage",
|
||||
name: 'extKeyUsage',
|
||||
serverAuth: true,
|
||||
},
|
||||
{
|
||||
name: "subjectAltName",
|
||||
name: 'subjectAltName',
|
||||
altNames,
|
||||
},
|
||||
],
|
||||
});
|
||||
})
|
||||
|
||||
// Save certificates
|
||||
writeFileSync(KEY_PATH, pems.private);
|
||||
writeFileSync(CERT_PATH, pems.cert);
|
||||
writeFileSync(KEY_PATH, pems.private)
|
||||
writeFileSync(CERT_PATH, pems.cert)
|
||||
|
||||
console.log(`✅ Certificate saved to ${CERT_DIR}`);
|
||||
console.log(` Valid for ${CERT_VALIDITY_DAYS} days`);
|
||||
console.log(` ⚠️ First access will show a security warning - click "Advanced" → "Proceed"`);
|
||||
console.log(`✅ Certificate saved to ${CERT_DIR}`)
|
||||
console.log(` Valid for ${CERT_VALIDITY_DAYS} days`)
|
||||
console.log(
|
||||
` ⚠️ First access will show a security warning - click "Advanced" → "Proceed"`,
|
||||
)
|
||||
|
||||
return {
|
||||
key: pems.private,
|
||||
cert: pems.cert,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user