@vectorchat/mcp-server
Version:
VectorChat MCP Server - Encrypted AI-to-AI communication with hardware security (YubiKey/TPM). 45+ MCP tools for Windsurf, Claude, and AI assistants. Model-based identity with EMDM encryption. Dynamic AI playbook system, communication zones, message relay
877 lines (754 loc) ⢠31.6 kB
HTML
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Security - VectorChat Web</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
--primary-color: #667eea;
--secondary-color: #764ba2;
--success-color: #4caf50;
--warning-color: #ff9800;
--error-color: #f44336;
--surface-color: #ffffff;
--background-color: #f5f5f5;
--text-primary: #333333;
--text-secondary: #666666;
--border-color: #e0e0e0;
--shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: var(--background-color);
color: var(--text-primary);
line-height: 1.6;
padding: 20px;
}
.container {
max-width: 800px;
margin: 0 auto;
background: var(--surface-color);
border-radius: 12px;
box-shadow: var(--shadow);
overflow: hidden;
}
.header {
background: var(--primary-gradient);
color: white;
padding: 24px;
text-align: center;
}
.header h1 {
font-size: 1.8rem;
font-weight: 600;
margin-bottom: 8px;
}
.header p {
opacity: 0.9;
font-size: 1rem;
}
.content {
padding: 24px;
}
.security-card {
background: #f8f9fa;
border: 1px solid var(--border-color);
border-radius: 8px;
padding: 20px;
margin-bottom: 24px;
}
.security-card.secure {
border-color: var(--success-color);
background: rgba(76, 175, 80, 0.05);
}
.security-card.warning {
border-color: var(--warning-color);
background: rgba(255, 152, 0, 0.05);
}
.security-card-title {
font-size: 1.2rem;
font-weight: 600;
margin-bottom: 12px;
display: flex;
align-items: center;
gap: 8px;
}
.security-status {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 0.9rem;
padding: 4px 12px;
border-radius: 16px;
font-weight: 500;
}
.status-secure {
background: rgba(76, 175, 80, 0.1);
color: var(--success-color);
}
.status-warning {
background: rgba(255, 152, 0, 0.1);
color: var(--warning-color);
}
.status-error {
background: rgba(244, 67, 54, 0.1);
color: var(--error-color);
}
.security-details {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 16px;
margin-top: 16px;
}
.security-item {
padding: 12px;
background: white;
border-radius: 6px;
border: 1px solid #e0e0e0;
}
.security-label {
font-size: 0.85rem;
color: var(--text-secondary);
margin-bottom: 4px;
}
.security-value {
font-size: 1rem;
font-weight: 600;
font-family: monospace;
}
.control-section {
background: #f8f9fa;
border: 1px solid var(--border-color);
border-radius: 8px;
padding: 20px;
margin-bottom: 24px;
}
.control-section-title {
font-size: 1.2rem;
font-weight: 600;
margin-bottom: 16px;
color: var(--text-primary);
}
.control-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 12px;
}
.control-button {
padding: 12px 16px;
border: none;
border-radius: 8px;
cursor: pointer;
font-weight: 500;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 8px;
justify-content: center;
}
.control-button:hover:not(:disabled) {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.control-button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.control-secure {
background: var(--success-color);
color: white;
}
.control-warning {
background: var(--warning-color);
color: white;
}
.control-danger {
background: var(--error-color);
color: white;
}
.actions {
padding: 24px;
border-top: 1px solid var(--border-color);
display: flex;
gap: 12px;
justify-content: space-between;
}
.btn {
padding: 12px 24px;
border: none;
border-radius: 8px;
cursor: pointer;
font-weight: 500;
transition: all 0.3s ease;
font-size: 1rem;
display: flex;
align-items: center;
gap: 8px;
}
.btn-primary {
background: var(--primary-gradient);
color: white;
}
.btn-secondary {
background: #f5f5f5;
color: var(--text-primary);
border: 1px solid var(--border-color);
}
@media (max-width: 768px) {
.security-details {
grid-template-columns: 1fr;
}
.control-grid {
grid-template-columns: 1fr;
}
.actions {
flex-direction: column;
}
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>š”ļø Security Center</h1>
<p>Monitor and manage VectorChat security features</p>
</div>
<div class="content">
<!-- EMDM Status -->
<div class="security-card secure" id="emdmCard">
<div class="security-card-title">
š EMDM Encryption
<span class="security-status status-secure">
<span class="status-dot"></span>
Active
</span>
</div>
<div class="security-details">
<div class="security-item">
<div class="security-label">Key Space</div>
<div class="security-value" id="keySpace">496T</div>
</div>
<div class="security-item">
<div class="security-label">Model Fingerprint</div>
<div class="security-value" id="modelFingerprint">Qwen3-1.7B</div>
</div>
<div class="security-item">
<div class="security-label">Encryption Level</div>
<div class="security-value" id="encryptionLevel">Military Grade</div>
</div>
<div class="security-item">
<div class="security-label">Active Sessions</div>
<div class="security-value" id="activeSessions">0</div>
</div>
</div>
</div>
<!-- Identity Status -->
<div class="security-card secure" id="identityCard">
<div class="security-card-title">
š Identity Verification
<span class="security-status status-secure">
<span class="status-dot"></span>
Verified
</span>
</div>
<div class="security-details">
<div class="security-item">
<div class="security-label">Current Identity</div>
<div class="security-value" id="currentIdentity">Not set</div>
</div>
<div class="security-item">
<div class="security-label">Identity Hash</div>
<div class="security-value" id="identityHash">Not generated</div>
</div>
<div class="security-item">
<div class="security-label">Verification Status</div>
<div class="security-value" id="verificationStatus">Valid</div>
</div>
<div class="security-item">
<div class="security-label">Biometric Auth</div>
<div class="security-value" id="biometricStatus">Disabled</div>
</div>
</div>
</div>
<!-- Network Security -->
<div class="security-card warning" id="networkCard">
<div class="security-card-title">
š Network Security
<span class="security-status status-warning">
<span class="status-dot"></span>
Monitor
</span>
</div>
<div class="security-details">
<div class="security-item">
<div class="security-label">Connected Peers</div>
<div class="security-value" id="connectedPeers">0</div>
</div>
<div class="security-item">
<div class="security-label">IPFS Status</div>
<div class="security-value" id="ipfsStatus">Offline</div>
</div>
<div class="security-item">
<div class="security-label">WebSocket Security</div>
<div class="security-value" id="websocketSecurity">Active</div>
</div>
<div class="security-item">
<div class="security-label">Last Security Check</div>
<div class="security-value" id="lastSecurityCheck">Never</div>
</div>
</div>
</div>
<!-- Security Controls -->
<div class="control-section">
<div class="control-section-title">ā” Security Operations</div>
<div class="control-grid">
<button class="control-button control-secure" onclick="runSecurityScan()">
š Security Scan
</button>
<button class="control-button control-warning" onclick="regenerateKeys()">
š Regenerate Keys
</button>
<button class="control-button control-info" onclick="validateIdentity()">
ā
Validate Identity
</button>
<button class="control-button control-danger" onclick="emergencyLockdown()">
šØ Emergency Lock
</button>
</div>
</div>
<!-- Threat Detection -->
<div class="control-section">
<div class="control-section-title">š”ļø Threat Detection</div>
<div class="control-grid">
<button class="control-button control-info" onclick="checkForThreats()">
š Check Threats
</button>
<button class="control-button control-warning" onclick="reviewLogs()">
š Review Logs
</button>
<button class="control-button control-info" onclick="updateSecurity()">
š Update Security
</button>
<button class="control-button control-danger" onclick="reportIncident()">
šØ Report Incident
</button>
</div>
</div>
</div>
<div class="actions">
<button class="btn btn-secondary" onclick="goBack()">ā Back</button>
<div>
<button class="btn btn-secondary" onclick="refreshSecurity()">š Refresh</button>
<button class="btn btn-primary" onclick="openAdvancedSecurity()">āļø Advanced</button>
</div>
</div>
</div>
<script>
// Initialize
document.addEventListener('DOMContentLoaded', function() {
refreshSecurityStatus();
startSecurityUpdates();
});
async function refreshSecurityStatus() {
try {
// Check daemon status
const healthResponse = await fetch('http://localhost:3737/health');
const isDaemonOnline = healthResponse.ok;
if (isDaemonOnline) {
// Get detailed security status
const statusResponse = await fetch('http://localhost:3737/api/status');
const statusData = await statusResponse.json();
// Update EMDM status
updateSecurityCard('emdmCard',
statusData.emdm_active ? 'secure' : 'warning',
statusData.emdm_active ? 'Active' : 'Inactive');
if (statusData.emdm_active) {
document.getElementById('keySpace').textContent = '496T';
document.getElementById('encryptionLevel').textContent = 'Military Grade';
document.getElementById('activeSessions').textContent = statusData.active_sessions || 0;
}
// Update model info
if (statusData.model_status) {
document.getElementById('modelFingerprint').textContent =
statusData.model || 'Unknown';
}
// Update identity info
const identity = localStorage.getItem('vectorchat-identity');
if (identity) {
try {
const identityData = JSON.parse(identity);
document.getElementById('currentIdentity').textContent = identityData.username || 'Not set';
document.getElementById('identityHash').textContent =
generateIdentityHash(identityData.username, identityData.modelPath);
} catch (e) {
console.error('Error loading identity:', e);
}
}
// Update network status
updateSecurityCard('networkCard', 'warning', 'Monitor');
document.getElementById('connectedPeers').textContent = statusData.known_peers || 0;
document.getElementById('websocketSecurity').textContent =
statusData.transport === 'WebSocket' ? 'Active' : 'Inactive';
} else {
// Daemon offline
updateSecurityCard('emdmCard', 'warning', 'Offline');
updateSecurityCard('identityCard', 'warning', 'Offline');
updateSecurityCard('networkCard', 'warning', 'Offline');
}
document.getElementById('lastSecurityCheck').textContent =
new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
} catch (error) {
console.error('Error refreshing security status:', error);
updateSecurityCard('emdmCard', 'warning', 'Error');
updateSecurityCard('identityCard', 'warning', 'Error');
updateSecurityCard('networkCard', 'warning', 'Error');
}
}
function updateSecurityCard(cardId, className, statusText) {
const card = document.getElementById(cardId);
const statusElement = card.querySelector('.security-status');
// Remove existing classes
card.className = `security-card ${className}`;
statusElement.className = `security-status status-${className}`;
statusElement.querySelector('.status-dot').textContent = statusText;
}
function generateIdentityHash(username, modelPath) {
if (!username || !modelPath) return 'Not generated';
const input = `${username}-${modelPath}-${Date.now()}`;
let hash = 0;
for (let i = 0; i < input.length; i++) {
const char = input.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash;
}
return Math.abs(hash).toString(36).substring(0, 12).toUpperCase();
}
async function runSecurityScan() {
showNotification('Running security scan...', 'info');
try {
// Run comprehensive security checks
const checks = [
checkEMDMIntegrity(),
checkIdentityValidity(),
checkNetworkSecurity(),
checkModelIntegrity()
];
const results = await Promise.allSettled(checks);
let allPassed = true;
results.forEach((result, index) => {
if (result.status === 'rejected') {
allPassed = false;
showNotification(`Security check ${index + 1} failed: ${result.reason}`, 'error');
}
});
if (allPassed) {
showNotification('Security scan completed - All systems secure!', 'success');
} else {
showNotification('Security scan completed - Issues detected', 'warning');
}
// Refresh status
setTimeout(refreshSecurityStatus, 1000);
} catch (error) {
showNotification(`Security scan failed: ${error.message}`, 'error');
}
}
async function checkEMDMIntegrity() {
const response = await fetch('http://localhost:3737/api/status');
const data = await response.json();
if (!data.emdm_active) {
throw new Error('EMDM encryption is not active');
}
if (!data.model_status || data.model_status.status !== 'loaded') {
throw new Error('AI model is not properly loaded');
}
return true;
}
async function checkIdentityValidity() {
const identity = localStorage.getItem('vectorchat-identity');
if (!identity) {
throw new Error('No identity configured');
}
try {
const identityData = JSON.parse(identity);
if (!identityData.username || !identityData.modelPath) {
throw new Error('Identity is incomplete');
}
} catch (e) {
throw new Error('Identity data is corrupted');
}
return true;
}
async function checkNetworkSecurity() {
// Check for suspicious connections or unusual activity
const response = await fetch('http://localhost:3737/api/status');
const data = await response.json();
if (data.known_peers > 10) {
throw new Error('Unusually high number of connected peers');
}
return true;
}
async function checkModelIntegrity() {
// Verify model fingerprint matches expected
const response = await fetch('http://localhost:3737/api/status');
const data = await response.json();
if (!data.model) {
throw new Error('No model information available');
}
return true;
}
async function regenerateKeys() {
if (!confirm('Regenerate encryption keys? This will invalidate all existing encrypted data.')) {
return;
}
try {
const response = await fetch('http://localhost:3737/api/regenerate-keys', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
confirm: true
})
});
if (response.ok) {
showNotification('Encryption keys regenerated!', 'success');
// Refresh status
setTimeout(refreshSecurityStatus, 1000);
} else {
throw new Error(`HTTP ${response.status}`);
}
} catch (error) {
showNotification(`Failed to regenerate keys: ${error.message}`, 'error');
}
}
async function validateIdentity() {
showNotification('Validating identity...', 'info');
try {
const identity = localStorage.getItem('vectorchat-identity');
if (!identity) {
throw new Error('No identity found');
}
const identityData = JSON.parse(identity);
// Validate against daemon
const response = await fetch('http://localhost:3737/api/status');
const data = await response.json();
if (data.model_status && data.model) {
// Check if model matches
if (identityData.modelPath.includes(data.model)) {
showNotification('Identity validation successful!', 'success');
} else {
showNotification('Identity model mismatch detected', 'warning');
}
} else {
showNotification('Cannot validate identity - daemon offline', 'warning');
}
} catch (error) {
showNotification(`Identity validation failed: ${error.message}`, 'error');
}
}
async function emergencyLockdown() {
if (!confirm('EMERGENCY: Activate security lockdown? This will disconnect all users and require manual restart.')) {
return;
}
try {
// Emergency stop
const response = await fetch('http://localhost:3737/api/stop-daemon', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
confirm: true,
reason: 'Emergency security lockdown'
})
});
if (response.ok) {
showNotification('šØ EMERGENCY LOCKDOWN ACTIVATED', 'error');
addLogEntry('Emergency lockdown activated', 'error');
// Update UI
updateSecurityCard('emdmCard', 'warning', 'Locked');
updateSecurityCard('networkCard', 'warning', 'Locked');
// Disable controls
document.querySelectorAll('.control-button').forEach(btn => {
btn.disabled = true;
btn.textContent = 'š LOCKED';
});
} else {
throw new Error(`HTTP ${response.status}`);
}
} catch (error) {
showNotification(`Emergency lockdown failed: ${error.message}`, 'error');
}
}
async function checkForThreats() {
showNotification('Scanning for threats...', 'info');
try {
// Run threat detection
const response = await fetch('http://localhost:3737/api/status');
const data = await response.json();
// Check for suspicious patterns
const threats = [];
if (data.known_peers > 5) {
threats.push('High peer count detected');
}
if (data.active_sessions > 10) {
threats.push('Unusual session activity');
}
if (threats.length === 0) {
showNotification('No threats detected', 'success');
} else {
showNotification(`Threats detected: ${threats.join(', ')}`, 'warning');
}
} catch (error) {
showNotification(`Threat scan failed: ${error.message}`, 'error');
}
}
async function reviewLogs() {
try {
const response = await fetch('http://localhost:3737/api/get-logs', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
count: 50
})
});
if (response.ok) {
const logs = await response.json();
alert(`Recent logs (${logs.logs.length} entries):\n\n${logs.logs.join('\n')}`);
} else {
throw new Error(`HTTP ${response.status}`);
}
} catch (error) {
showNotification(`Failed to retrieve logs: ${error.message}`, 'error');
}
}
async function updateSecurity() {
showNotification('Updating security systems...', 'info');
try {
// Trigger security update
const response = await fetch('http://localhost:3737/api/reload-config', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
confirm: true
})
});
if (response.ok) {
showNotification('Security systems updated!', 'success');
// Refresh status
setTimeout(refreshSecurityStatus, 1000);
} else {
throw new Error(`HTTP ${response.status}`);
}
} catch (error) {
showNotification(`Security update failed: ${error.message}`, 'error');
}
}
async function reportIncident() {
const incidentType = prompt('Enter incident type (e.g., "Suspicious connection", "Data breach attempt", "Unauthorized access"):');
if (incidentType) {
try {
// Report to daemon
const response = await fetch('http://localhost:3737/api/report-incident', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
incident_type: incidentType,
timestamp: new Date().toISOString(),
details: 'Reported via web interface'
})
});
if (response.ok) {
showNotification('Incident reported to security system!', 'warning');
addLogEntry(`Security incident reported: ${incidentType}`, 'warning');
} else {
throw new Error(`HTTP ${response.status}`);
}
} catch (error) {
showNotification(`Failed to report incident: ${error.message}`, 'error');
}
}
}
function openAdvancedSecurity() {
alert('Advanced security features:\n\n⢠AI-powered threat detection\n⢠Behavioral analysis\n⢠Network anomaly detection\n⢠Automated response systems\n\nContact support for enterprise security features.');
}
function goBack() {
if (window.opener) {
window.close();
} else {
window.location.href = 'web-app.html';
}
}
function startSecurityUpdates() {
// Update security status every 10 seconds
setInterval(refreshSecurityStatus, 10000);
}
function addLogEntry(message, level = 'info') {
console.log(`[${level.toUpperCase()}] ${message}`);
}
function showNotification(message, type = 'info') {
// Create notification element
const notification = document.createElement('div');
notification.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
padding: 12px 20px;
border-radius: 8px;
color: white;
font-weight: 500;
z-index: 3000;
opacity: 0;
transform: translateX(100%);
transition: all 0.3s ease;
max-width: 400px;
`;
let backgroundColor;
switch (type) {
case 'error':
backgroundColor = '#f44336';
break;
case 'success':
backgroundColor = '#4caf50';
break;
case 'warning':
backgroundColor = '#ff9800';
break;
default:
backgroundColor = '#667eea';
}
notification.style.backgroundColor = backgroundColor;
notification.textContent = message;
document.body.appendChild(notification);
// Animate in
setTimeout(() => {
notification.style.opacity = '1';
notification.style.transform = 'translateX(0)';
}, 100);
// Animate out and remove
setTimeout(() => {
notification.style.opacity = '0';
notification.style.transform = 'translateX(100%)';
setTimeout(() => {
document.body.removeChild(notification);
}, 300);
}, 3000);
}
// Initial status update
setTimeout(refreshSecurityStatus, 1000);
</script>
</body>
</html>