UNPKG

browser-canvas-fingerprinting

Version:

A simple canvas fingerprinting implementation in browser with specific information used to generate fingerprint

163 lines (139 loc) 4.22 kB
// test/test-runner.js import { createServer } from 'http'; import { readFile } from 'fs/promises'; import { join, dirname } from 'path'; import { fileURLToPath } from 'url'; import { spawn } from 'child_process'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); class TestServer { constructor(port = 13879) { this.port = port; this.server = null; this.baseDir = join(__dirname, '..'); // 项目根目录 } async start() { return new Promise((resolve, reject) => { this.server = createServer(async (req, res) => { try { // 处理请求 let filePath = req.url === '/' ? '/test/index.html' : req.url; filePath = filePath.split('?')[0]; // 去掉查询参数 // 安全限制,只允许访问项目内的文件 if (filePath.includes('..')) { res.writeHead(403); res.end('Forbidden'); return; } const fullPath = join(this.baseDir, filePath); // 设置 MIME 类型 const mimeTypes = { '.html': 'text/html', '.js': 'text/javascript', '.css': 'text/css', '.json': 'application/json', '.png': 'image/png', '.jpg': 'image/jpg', '.gif': 'image/gif', '.ico': 'image/x-icon' }; const ext = filePath.substring(filePath.lastIndexOf('.')); const contentType = mimeTypes[ext] || 'application/octet-stream'; const content = await readFile(fullPath); res.writeHead(200, { 'Content-Type': contentType }); res.end(content, 'utf-8'); } catch (error) { if (error.code === 'ENOENT') { res.writeHead(404); res.end('File not found'); } else { res.writeHead(500); res.end('Server error: ' + error.message); } } }); this.server.listen(this.port, '127.0.0.1', (err) => { if (err) { reject(err); } else { console.log(`Test server running at http://127.0.0.1:${this.port}/test/`); resolve(); } }); // 设置超时自动关闭(10分钟后) this.timeout = setTimeout(() => { console.log('Test server timeout, shutting down...'); this.stop(); }, 60 * 60 * 1000); }); } stop() { return new Promise((resolve) => { if (this.timeout) { clearTimeout(this.timeout); } if (this.server) { this.server.close(() => { console.log('Test server stopped'); resolve(); }); } else { resolve(); } }); } } class TestRunner { constructor() { this.testServer = new TestServer(); this.isWindows = process.platform === 'win32'; } async run() { try { // 启动测试服务器 await this.testServer.start(); // 打开浏览器 await this.openBrowser(); console.log('Server started, time: 60min'); console.log('Ctrl+C to stop'); // 等待用户中断或超时 process.on('SIGINT', async () => { console.log('\nShutting down...'); await this.cleanup(); process.exit(0); }); } catch (error) { console.error('FAIL:', error); await this.cleanup(); process.exit(1); } } async openBrowser() { const url = `http://127.0.0.1:${this.testServer.port}/${process.argv[2] === 'production' ? 'test/production.html' : ''}`; if (this.isWindows) { // Windows spawn('cmd', ['/c', 'start', url], { stdio: 'inherit' }); } else { // Linux/macOS const commands = [ 'xdg-open', // Linux 'open' // macOS ]; for (const cmd of commands) { try { spawn(cmd, [url], { stdio: 'inherit' }); break; } catch (error) { continue; } } } console.log(`Browser launched: ${url}`); } async cleanup() { await this.testServer.stop(); } } // 运行测试 const runner = new TestRunner(); runner.run();