mirror of
https://github.com/simplex-chat/simplexmq.git
synced 2026-06-03 08:47:32 +00:00
115 lines
3.8 KiB
TypeScript
115 lines
3.8 KiB
TypeScript
import {defineConfig, type Plugin} from 'vite'
|
|
import {readFileSync} from 'fs'
|
|
import {createHash} from 'crypto'
|
|
import {resolve, join} from 'path'
|
|
import {tmpdir} from 'os'
|
|
import presets from './web/servers.json'
|
|
|
|
const PORT_FILE = join(tmpdir(), 'xftp-test-server.port')
|
|
const FIXTURES = resolve(import.meta.dirname, '../tests/fixtures')
|
|
|
|
const __dirname = import.meta.dirname
|
|
|
|
function parseHost(addr: string): string {
|
|
const m = addr.match(/@(.+)$/)
|
|
if (!m) throw new Error('bad server address: ' + addr)
|
|
const host = m[1].split(',')[0]
|
|
return host.includes(':') ? host : host + ':443'
|
|
}
|
|
|
|
function cspPlugin(servers: string[], isDev: boolean): Plugin {
|
|
const origins = servers.map(s => 'https://' + parseHost(s)).join(' ')
|
|
return {
|
|
name: 'csp-connect-src',
|
|
transformIndexHtml: {
|
|
order: 'pre',
|
|
handler(html) {
|
|
if (isDev) {
|
|
return html.replace(/<meta\s[^>]*?Content-Security-Policy[\s\S]*?>/i, '')
|
|
}
|
|
// Auto-compute SHA-256 hashes for inline scripts (CSP script-src)
|
|
const scriptHashes: string[] = []
|
|
html.replace(/<script>(.+?)<\/script>/gs, (_m: string, content: string) => {
|
|
scriptHashes.push("'sha256-" + createHash('sha256').update(content, 'utf-8').digest('base64') + "'")
|
|
return _m
|
|
})
|
|
return html
|
|
.replace('__CSP_CONNECT_SRC__', origins)
|
|
.replace('__CSP_SCRIPT_HASHES__', scriptHashes.join(' '))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Compute fingerprint from ca.crt (SHA-256 of DER)
|
|
function getFingerprint(): string {
|
|
const pem = readFileSync(join(FIXTURES, 'ca.crt'), 'utf-8')
|
|
const der = Buffer.from(pem.replace(/-----[^-]+-----/g, '').replace(/\s/g, ''), 'base64')
|
|
return createHash('sha256').update(der).digest('base64')
|
|
.replace(/\+/g, '-').replace(/\//g, '_')
|
|
}
|
|
|
|
// Plugin to inject __XFTP_SERVERS__ via Vite define (reads PORT_FILE written by test/runSetup.ts)
|
|
function xftpServersPlugin(): Plugin {
|
|
const fp = getFingerprint()
|
|
return {
|
|
name: 'xftp-servers-define',
|
|
config() {
|
|
const port = readFileSync(PORT_FILE, 'utf-8').trim()
|
|
const serverAddr = `xftp://${fp}@localhost:${port}`
|
|
return {define: {__XFTP_SERVERS__: JSON.stringify([serverAddr])}}
|
|
}
|
|
}
|
|
}
|
|
|
|
export default defineConfig(({mode}) => {
|
|
const define: Record<string, string> = {}
|
|
let servers: string[]
|
|
const plugins: Plugin[] = []
|
|
|
|
if (mode === 'development') {
|
|
// In development mode, use the test server (port from globalSetup)
|
|
plugins.push(xftpServersPlugin())
|
|
define['__XFTP_PROXY_PORT__'] = JSON.stringify(null)
|
|
// For CSP plugin, use localhost placeholder (CSP stripped in dev server anyway)
|
|
servers = ['xftp://fp@localhost:443']
|
|
} else {
|
|
// In production mode, use the preset servers
|
|
servers = [...presets.simplex]
|
|
define['__XFTP_SERVERS__'] = JSON.stringify(servers)
|
|
define['__XFTP_PROXY_PORT__'] = JSON.stringify(null)
|
|
}
|
|
|
|
plugins.push(cspPlugin(servers, mode === 'development'))
|
|
|
|
const httpsConfig = mode === 'development' ? {
|
|
key: readFileSync(join(FIXTURES, 'web.key')),
|
|
cert: readFileSync(join(FIXTURES, 'web.crt')),
|
|
} : undefined
|
|
|
|
return {
|
|
base: './',
|
|
root: 'web',
|
|
build: {
|
|
outDir: resolve(__dirname, 'dist-web'),
|
|
emptyOutDir: true,
|
|
target: 'esnext',
|
|
minify: false,
|
|
chunkSizeWarningLimit: 1200,
|
|
rollupOptions: {
|
|
external: ['node:http2', 'url'],
|
|
output: {
|
|
entryFileNames: 'assets/[name].js',
|
|
chunkFileNames: 'assets/[name].js',
|
|
assetFileNames: 'assets/[name][extname]',
|
|
},
|
|
},
|
|
},
|
|
server: httpsConfig ? {https: httpsConfig} : {},
|
|
preview: {host: true, https: false},
|
|
define,
|
|
worker: {format: 'es' as const, rollupOptions: {external: ['node:http2', 'url'], output: {entryFileNames: 'assets/[name].js'}}},
|
|
plugins,
|
|
}
|
|
})
|