ui布局自适应

This commit is contained in:
tianmo committed 2026-11-09 10:08:29 +08:00
1 parent 98f44890f8
commit 3587129b90
40 files changed
+929 -142

No files matched your search

+110
View File
@@ -0,0 +1,110 @@
import { execFile } from 'node:child_process'
import { access, chmod, mkdir, rm, writeFile } from 'node:fs/promises'
import { constants } from 'node:fs'
import { homedir, platform } from 'node:os'
import { dirname, join } from 'node:path'
import { promisify } from 'node:util'
import { configPath } from './connector-config.mjs'
const run = promisify(execFile)
export function certificateDirectory() {
return process.env.SPINE_CONNECTOR_TLS_DIR || join(dirname(configPath()), 'tls')
}
export function certificatePaths(directory = certificateDirectory()) {
return {
directory,
caKey: join(directory, 'ca-key.pem'),
ca: join(directory, 'ca.pem'),
serverKey: join(directory, 'server-key.pem'),
serverCertificate: join(directory, 'server.pem'),
identity: join(directory, 'identity.p12'),
request: join(directory, 'server.csr'),
extensions: join(directory, 'server.ext'),
}
}
async function certificateIsUsable(path) {
try {
await access(path, constants.R_OK)
await run('/usr/bin/openssl', ['x509', '-checkend', '2592000', '-noout', '-in', path])
return true
} catch {
return false
}
}
async function identityIsUsable(path) {
try {
await access(path, constants.R_OK)
return true
} catch {
return false
}
}
async function runOpenSSL(args) {
try {
await run('/usr/bin/openssl', args)
} catch (error) {
const detail = String(error?.stderr || error?.message || error).trim()
throw new Error(`无法生成本机 HTTPS 证书:${detail}`)
}
}
export async function ensureLocalCertificate() {
if (platform() !== 'darwin') throw new Error('Safari 本机 HTTPS 证书仅支持 macOS')
const paths = certificatePaths()
if (await certificateIsUsable(paths.serverCertificate) && await identityIsUsable(paths.identity)) return paths
await mkdir(paths.directory, { recursive: true, mode: 0o700 })
await runOpenSSL(['genrsa', '-out', paths.caKey, '2048'])
await runOpenSSL([
'req', '-x509', '-new', '-key', paths.caKey, '-sha256', '-days', '3650',
'-subj', '/CN=Spine Particle Connector Local CA', '-out', paths.ca,
])
await runOpenSSL(['genrsa', '-out', paths.serverKey, '2048'])
await runOpenSSL(['req', '-new', '-key', paths.serverKey, '-subj', '/CN=127.0.0.1', '-out', paths.request])
await writeFile(paths.extensions, 'subjectAltName=IP:127.0.0.1,DNS:localhost\nextendedKeyUsage=serverAuth\nbasicConstraints=CA:FALSE\n', 'utf8')
await runOpenSSL([
'x509', '-req', '-in', paths.request, '-CA', paths.ca, '-CAkey', paths.caKey,
'-CAcreateserial', '-out', paths.serverCertificate, '-days', '825', '-sha256',
'-extfile', paths.extensions,
])
await runOpenSSL([
'pkcs12', '-export', '-out', paths.identity, '-inkey', paths.serverKey,
'-in', paths.serverCertificate, '-passout', 'pass:spine-connector-local',
])
await Promise.all([paths.serverKey, paths.identity].map((path) => chmod(path, 0o600)))
await rm(paths.caKey, { force: true })
return paths
}
export async function localCertificateTrusted() {
const paths = certificatePaths()
try {
await run('/usr/bin/security', [
'verify-cert', '-c', paths.serverCertificate, '-n', '127.0.0.1', '-p', 'ssl', '-L', '-q',
])
return true
} catch {
return false
}
}
export async function trustLocalCertificate() {
if (platform() !== 'darwin') throw new Error('Safari 本机 HTTPS 证书仅支持 macOS')
const paths = await ensureLocalCertificate()
const loginKeychain = join(homedir(), 'Library', 'Keychains', 'login.keychain-db')
try {
await run('/usr/bin/security', [
'add-trusted-cert', '-r', 'trustRoot', '-p', 'ssl', '-k', loginKeychain, paths.ca,
])
} catch (error) {
const detail = String(error?.stderr || error?.message || error).trim()
throw new Error(detail || '无法把本机证书加入信任列表')
}
if (!(await localCertificateTrusted())) throw new Error('证书已安装,但系统仍未信任它')
return paths
}