Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Advanced VPN Client</title> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
<style> | |
:root { | |
--primary: #4a6bff; | |
--primary-dark: #3a56cc; | |
--background: #1a1a2e; | |
--card-bg: #16213e; | |
--text: #e6e6e6; | |
--text-secondary: #b8b8b8; | |
--success: #2ecc71; | |
--danger: #e74c3c; | |
--warning: #f39c12; | |
} | |
* { | |
margin: 0; | |
padding: 0; | |
box-sizing: border-box; | |
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
} | |
body { | |
background-color: var(--background); | |
color: var(--text); | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
min-height: 100vh; | |
padding: 20px; | |
} | |
.vpn-client { | |
background-color: var(--card-bg); | |
border-radius: 16px; | |
width: 100%; | |
max-width: 500px; | |
padding: 30px; | |
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); | |
} | |
.header { | |
display: flex; | |
align-items: center; | |
margin-bottom: 20px; | |
} | |
.header i { | |
font-size: 28px; | |
color: var(--primary); | |
margin-right: 15px; | |
} | |
.header h1 { | |
font-size: 24px; | |
font-weight: 600; | |
} | |
.tabs { | |
display: flex; | |
margin-bottom: 20px; | |
border-bottom: 1px solid rgba(255, 255, 255, 0.1); | |
} | |
.tab { | |
padding: 10px 20px; | |
cursor: pointer; | |
font-size: 14px; | |
font-weight: 500; | |
color: var(--text-secondary); | |
border-bottom: 2px solid transparent; | |
transition: all 0.2s; | |
} | |
.tab.active { | |
color: var(--primary); | |
border-bottom: 2px solid var(--primary); | |
} | |
.tab-content { | |
display: none; | |
} | |
.tab-content.active { | |
display: block; | |
} | |
.connection-status { | |
display: flex; | |
align-items: center; | |
margin-bottom: 20px; | |
} | |
.status-indicator { | |
width: 12px; | |
height: 12px; | |
border-radius: 50%; | |
margin-right: 10px; | |
background-color: var(--danger); | |
} | |
.status-indicator.connected { | |
background-color: var(--success); | |
box-shadow: 0 0 10px var(--success); | |
} | |
.status-indicator.connecting { | |
background-color: var(--warning); | |
box-shadow: 0 0 10px var(--warning); | |
animation: pulse 1.5s infinite; | |
} | |
@keyframes pulse { | |
0% { opacity: 1; } | |
50% { opacity: 0.5; } | |
100% { opacity: 1; } | |
} | |
.status-text { | |
font-size: 16px; | |
color: var(--text-secondary); | |
} | |
.ip-info { | |
background-color: rgba(0, 0, 0, 0.2); | |
border-radius: 10px; | |
padding: 15px; | |
margin-bottom: 20px; | |
} | |
.ip-row { | |
display: flex; | |
justify-content: space-between; | |
margin-bottom: 10px; | |
} | |
.ip-row:last-child { | |
margin-bottom: 0; | |
} | |
.ip-label { | |
color: var(--text-secondary); | |
font-size: 14px; | |
} | |
.ip-value { | |
font-family: 'Courier New', Courier, monospace; | |
font-weight: 600; | |
} | |
.ping-info { | |
display: flex; | |
align-items: center; | |
margin-bottom: 20px; | |
} | |
.ping-icon { | |
margin-right: 10px; | |
color: var(--primary); | |
} | |
.ping-value { | |
font-size: 16px; | |
} | |
.server-list { | |
max-height: 300px; | |
overflow-y: auto; | |
margin-bottom: 20px; | |
border-radius: 8px; | |
background-color: rgba(0, 0, 0, 0.1); | |
} | |
.server-item { | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
padding: 12px 15px; | |
border-bottom: 1px solid rgba(255, 255, 255, 0.05); | |
cursor: pointer; | |
transition: all 0.2s; | |
} | |
.server-item:hover { | |
background-color: rgba(255, 255, 255, 0.05); | |
} | |
.server-item.active { | |
background-color: rgba(74, 107, 255, 0.2); | |
border-left: 3px solid var(--primary); | |
} | |
.server-info { | |
flex: 1; | |
} | |
.server-name { | |
font-weight: 500; | |
margin-bottom: 3px; | |
} | |
.server-location { | |
font-size: 12px; | |
color: var(--text-secondary); | |
} | |
.server-ping { | |
display: flex; | |
align-items: center; | |
font-family: 'Courier New', Courier, monospace; | |
font-weight: 600; | |
} | |
.server-ping.good { | |
color: var(--success); | |
} | |
.server-ping.medium { | |
color: var(--warning); | |
} | |
.server-ping.bad { | |
color: var(--danger); | |
} | |
.btn-group { | |
display: flex; | |
gap: 15px; | |
} | |
.btn { | |
flex: 1; | |
padding: 12px; | |
border-radius: 8px; | |
border: none; | |
font-weight: 600; | |
cursor: pointer; | |
transition: all 0.2s; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
gap: 8px; | |
} | |
.btn-connect { | |
background-color: var(--primary); | |
color: white; | |
} | |
.btn-connect:hover { | |
background-color: var(--primary-dark); | |
} | |
.btn-disconnect { | |
background-color: rgba(255, 255, 255, 0.1); | |
color: var(--text); | |
} | |
.btn-disconnect:hover { | |
background-color: rgba(255, 255, 255, 0.2); | |
} | |
.btn-find { | |
background-color: rgba(74, 107, 255, 0.1); | |
color: var(--primary); | |
margin-bottom: 20px; | |
} | |
.btn-find:hover { | |
background-color: rgba(74, 107, 255, 0.2); | |
} | |
.loading { | |
display: none; | |
width: 20px; | |
height: 20px; | |
border: 3px solid rgba(255, 255, 255, 0.3); | |
border-radius: 50%; | |
border-top-color: white; | |
animation: spin 1s ease-in-out infinite; | |
} | |
@keyframes spin { | |
to { transform: rotate(360deg); } | |
} | |
.btn.loading .loading { | |
display: block; | |
} | |
.btn.loading span { | |
display: none; | |
} | |
.search-proxy { | |
display: flex; | |
gap: 10px; | |
margin-bottom: 20px; | |
} | |
.search-input { | |
flex: 1; | |
padding: 10px 15px; | |
border-radius: 8px; | |
border: none; | |
background-color: rgba(0, 0, 0, 0.2); | |
color: var(--text); | |
} | |
.search-input:focus { | |
outline: 1px solid var(--primary); | |
} | |
.proxy-details { | |
background-color: rgba(0, 0, 0, 0.2); | |
border-radius: 10px; | |
padding: 15px; | |
margin-bottom: 20px; | |
display: none; | |
} | |
.proxy-details.active { | |
display: block; | |
} | |
.proxy-row { | |
display: flex; | |
margin-bottom: 8px; | |
} | |
.proxy-row:last-child { | |
margin-bottom: 0; | |
} | |
.proxy-label { | |
width: 100px; | |
color: var(--text-secondary); | |
font-size: 14px; | |
} | |
.proxy-value { | |
font-family: 'Courier New', Courier, monospace; | |
font-size: 14px; | |
} | |
.protocol-selector { | |
display: flex; | |
background-color: rgba(0, 0, 0, 0.2); | |
border-radius: 8px; | |
padding: 5px; | |
margin-bottom: 20px; | |
} | |
.protocol-option { | |
flex: 1; | |
text-align: center; | |
padding: 8px; | |
border-radius: 6px; | |
cursor: pointer; | |
font-size: 14px; | |
transition: all 0.2s; | |
} | |
.protocol-option.active { | |
background-color: var(--primary); | |
font-weight: 600; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="vpn-client"> | |
<div class="header"> | |
<i class="fas fa-shield-alt"></i> | |
<h1>Advanced VPN Client</h1> | |
</div> | |
<div class="tabs"> | |
<div class="tab active" data-tab="vpn">VPN Servers</div> | |
<div class="tab" data-tab="proxy">Proxy Servers</div> | |
<div class="tab" data-tab="routes">Routes</div> | |
</div> | |
<div class="tab-content active" id="vpn-tab"> | |
<div class="connection-status"> | |
<div class="status-indicator" id="statusIndicator"></div> | |
<div class="status-text" id="statusText">Disconnected</div> | |
</div> | |
<div class="ip-info"> | |
<div class="ip-row"> | |
<div class="ip-label">Original IP:</div> | |
<div class="ip-value" id="originalIp">192.168.1.105</div> | |
</div> | |
<div class="ip-row"> | |
<div class="ip-label">VPN IP:</div> | |
<div class="ip-value" id="vpnIp">Not connected</div> | |
</div> | |
</div> | |
<div class="ping-info"> | |
<i class="fas fa-bolt ping-icon"></i> | |
<div class="ping-value">Ping: <span id="pingValue">--</span> ms</div> | |
</div> | |
<button class="btn btn-find" id="findVpnBtn"> | |
<i class="fas fa-search"></i> | |
<span>Find VPN Servers</span> | |
<div class="loading"></div> | |
</button> | |
<div class="server-list" id="vpnServerList"> | |
<!-- VPN servers will be added here dynamically --> | |
</div> | |
<div class="btn-group"> | |
<button class="btn btn-connect" id="connectBtn"> | |
<span>Connect</span> | |
<div class="loading"></div> | |
</button> | |
<button class="btn btn-disconnect" id="disconnectBtn" disabled> | |
<span>Disconnect</span> | |
<div class="loading"></div> | |
</button> | |
</div> | |
</div> | |
<div class="tab-content" id="proxy-tab"> | |
<div class="search-proxy"> | |
<input type="text" class="search-input" id="proxySearch" placeholder="Search for proxy servers..."> | |
<button class="btn btn-find" id="findProxyBtn"> | |
<i class="fas fa-search"></i> | |
<span>Find</span> | |
<div class="loading"></div> | |
</button> | |
</div> | |
<div class="protocol-selector"> | |
<div class="protocol-option active" data-protocol="socks5">SOCKS5</div> | |
<div class="protocol-option" data-protocol="https">HTTPS</div> | |
<div class="protocol-option" data-protocol="http">HTTP</div> | |
</div> | |
<div class="server-list" id="proxyServerList"> | |
<!-- Proxy servers will be added here dynamically --> | |
</div> | |
<div class="proxy-details" id="proxyDetails"> | |
<div class="proxy-row"> | |
<div class="proxy-label">Address:</div> | |
<div class="proxy-value" id="proxyAddress">-</div> | |
</div> | |
<div class="proxy-row"> | |
<div class="proxy-label">Port:</div> | |
<div class="proxy-value" id="proxyPort">-</div> | |
</div> | |
<div class="proxy-row"> | |
<div class="proxy-label">Type:</div> | |
<div class="proxy-value" id="proxyType">-</div> | |
</div> | |
<div class="proxy-row"> | |
<div class="proxy-label">Country:</div> | |
<div class="proxy-value" id="proxyCountry">-</div> | |
</div> | |
<div class="proxy-row"> | |
<div class="proxy-label">Uptime:</div> | |
<div class="proxy-value" id="proxyUptime">-</div> | |
</div> | |
</div> | |
<div class="btn-group"> | |
<button class="btn btn-connect" id="connectProxyBtn" disabled> | |
<span>Connect Proxy</span> | |
<div class="loading"></div> | |
</button> | |
<button class="btn btn-disconnect" id="disconnectProxyBtn" disabled> | |
<span>Disconnect</span> | |
<div class="loading"></div> | |
</button> | |
</div> | |
</div> | |
<div class="tab-content" id="routes-tab"> | |
<div class="ip-info"> | |
<div class="ip-row"> | |
<div class="ip-label">Current Route:</div> | |
<div class="ip-value" id="currentRoute">Default</div> | |
</div> | |
<div class="ip-row"> | |
<div class="ip-label">Route Type:</div> | |
<div class="ip-value" id="routeType">Direct</div> | |
</div> | |
</div> | |
<button class="btn btn-find" id="findRoutesBtn"> | |
<i class="fas fa-route"></i> | |
<span>Find Optimal Routes</span> | |
<div class="loading"></div> | |
</button> | |
<div class="server-list" id="routesList"> | |
<!-- Routes will be added here dynamically --> | |
</div> | |
<div class="btn-group"> | |
<button class="btn btn-connect" id="applyRouteBtn" disabled> | |
<span>Apply Route</span> | |
<div class="loading"></div> | |
</button> | |
<button class="btn btn-disconnect" id="resetRouteBtn"> | |
<span>Reset to Default</span> | |
<div class="loading"></div> | |
</button> | |
</div> | |
</div> | |
</div> | |
<script> | |
document.addEventListener('DOMContentLoaded', function() { | |
// UI Elements | |
const tabs = document.querySelectorAll('.tab'); | |
const tabContents = document.querySelectorAll('.tab-content'); | |
const statusIndicator = document.getElementById('statusIndicator'); | |
const statusText = document.getElementById('statusText'); | |
const originalIp = document.getElementById('originalIp'); | |
const vpnIp = document.getElementById('vpnIp'); | |
const pingValue = document.getElementById('pingValue'); | |
const connectBtn = document.getElementById('connectBtn'); | |
const disconnectBtn = document.getElementById('disconnectBtn'); | |
const findVpnBtn = document.getElementById('findVpnBtn'); | |
const vpnServerList = document.getElementById('vpnServerList'); | |
const proxyServerList = document.getElementById('proxyServerList'); | |
const findProxyBtn = document.getElementById('findProxyBtn'); | |
const proxySearch = document.getElementById('proxySearch'); | |
const connectProxyBtn = document.getElementById('connectProxyBtn'); | |
const disconnectProxyBtn = document.getElementById('disconnectProxyBtn'); | |
const proxyDetails = document.getElementById('proxyDetails'); | |
const proxyAddress = document.getElementById('proxyAddress'); | |
const proxyPort = document.getElementById('proxyPort'); | |
const proxyType = document.getElementById('proxyType'); | |
const proxyCountry = document.getElementById('proxyCountry'); | |
const proxyUptime = document.getElementById('proxyUptime'); | |
const findRoutesBtn = document.getElementById('findRoutesBtn'); | |
const routesList = document.getElementById('routesList'); | |
const applyRouteBtn = document.getElementById('applyRouteBtn'); | |
const resetRouteBtn = document.getElementById('resetRouteBtn'); | |
const currentRoute = document.getElementById('currentRoute'); | |
const routeType = document.getElementById('routeType'); | |
const protocolOptions = document.querySelectorAll('.protocol-option'); | |
// State variables | |
let currentTab = 'vpn'; | |
let currentProtocol = 'socks5'; | |
let isConnected = false; | |
let isProxyConnected = false; | |
let pingInterval; | |
let selectedVpnServer = null; | |
let selectedProxy = null; | |
let selectedRoute = null; | |
// Tab switching | |
tabs.forEach(tab => { | |
tab.addEventListener('click', function() { | |
tabs.forEach(t => t.classList.remove('active')); | |
this.classList.add('active'); | |
currentTab = this.dataset.tab; | |
tabContents.forEach(content => { | |
content.classList.remove('active'); | |
if (content.id === `${currentTab}-tab`) { | |
content.classList.add('active'); | |
} | |
}); | |
}); | |
}); | |
// Protocol selection | |
protocolOptions.forEach(option => { | |
option.addEventListener('click', function() { | |
protocolOptions.forEach(opt => opt.classList.remove('active')); | |
this.classList.add('active'); | |
currentProtocol = this.dataset.protocol; | |
}); | |
}); | |
// Simulate getting original IP | |
function getOriginalIp() { | |
return '192.168.' + Math.floor(Math.random() * 255) + '.' + Math.floor(Math.random() * 255); | |
} | |
// Simulate getting VPN IP | |
function getVpnIp(server) { | |
const serverIps = { | |
'us1': '104.200.131.' + Math.floor(Math.random() * 255), | |
'us2': '45.33.15.' + Math.floor(Math.random() * 255), | |
'eu1': '185.243.56.' + Math.floor(Math.random() * 255), | |
'eu2': '94.230.90.' + Math.floor(Math.random() * 255), | |
'asia1': '45.76.178.' + Math.floor(Math.random() * 255), | |
'asia2': '45.32.100.' + Math.floor(Math.random() * 255) | |
}; | |
return serverIps[server]; | |
} | |
// Simulate getting ping | |
function getPing(server) { | |
const basePings = { | |
'us1': 45, | |
'us2': 75, | |
'eu1': 90, | |
'eu2': 110, | |
'asia1': 180, | |
'asia2': 220 | |
}; | |
return basePings[server] + Math.floor(Math.random() * 20) - 10; | |
} | |
// Update ping display | |
function updatePing() { | |
if (!isConnected || !selectedVpnServer) return; | |
const ping = getPing(selectedVpnServer.id); | |
pingValue.textContent = ping; | |
} | |
// Generate random VPN servers | |
function generateVpnServers() { | |
const servers = [ | |
{ id: 'us1', name: 'USA East', location: 'New York, USA', ping: getPing('us1') }, | |
{ id: 'us2', name: 'USA West', location: 'Los Angeles, USA', ping: getPing('us2') }, | |
{ id: 'eu1', name: 'Europe 1', location: 'Frankfurt, Germany', ping: getPing('eu1') }, | |
{ id: 'eu2', name: 'Europe 2', location: 'Amsterdam, Netherlands', ping: getPing('eu2') }, | |
{ id: 'asia1', name: 'Asia 1', location: 'Tokyo, Japan', ping: getPing('asia1') }, | |
{ id: 'asia2', name: 'Asia 2', location: 'Singapore', ping: getPing('asia2') } | |
]; | |
return servers; | |
} | |
// Generate random proxy servers | |
function generateProxyServers(type = 'all', search = '') { | |
const types = type === 'all' ? ['socks5', 'https', 'http'] : [type]; | |
const countries = ['USA', 'Germany', 'Netherlands', 'Japan', 'Singapore', 'UK', 'Canada', 'France']; | |
let proxies = []; | |
for (let i = 0; i < 15; i++) { | |
const proxyType = types[Math.floor(Math.random() * types.length)]; | |
const country = countries[Math.floor(Math.random() * countries.length)]; | |
if (search && !country.toLowerCase().includes(search.toLowerCase())) { | |
continue; | |
} | |
proxies.push({ | |
address: `${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}`, | |
port: Math.floor(Math.random() * 40000) + 10000, | |
type: proxyType, | |
country: country, | |
uptime: `${Math.floor(Math.random() * 90) + 10}%`, | |
ping: Math.floor(Math.random() * 300) + 50 | |
}); | |
} | |
return proxies; | |
} | |
// Generate random routes | |
function generateRoutes() { | |
return [ | |
{ id: 'route1', name: 'Fastest Route', type: 'Optimized', ping: 45 }, | |
{ id: 'route2', name: 'Secure Route', type: 'Encrypted', ping: 85 }, | |
{ id: 'route3', name: 'Geo-Specific', type: 'Country-based', ping: 120 }, | |
{ id: 'route4', name: 'Tor Network', type: 'Anonymous', ping: 250 } | |
]; | |
} | |
// Render VPN servers | |
function renderVpnServers(servers) { | |
vpnServerList.innerHTML = ''; | |
servers.forEach(server => { | |
const pingClass = server.ping < 100 ? 'good' : server.ping < 200 ? 'medium' : 'bad'; | |
const serverElement = document.createElement('div'); | |
serverElement.className = 'server-item'; | |
serverElement.dataset.id = server.id; | |
serverElement.innerHTML = ` | |
<div class="server-info"> | |
<div class="server-name">${server.name}</div> | |
<div class="server-location">${server.location}</div> | |
</div> | |
<div class="server-ping ${pingClass}">${server.ping} ms</div> | |
`; | |
serverElement.addEventListener('click', function() { | |
document.querySelectorAll('#vpnServerList .server-item').forEach(item => { | |
item.classList.remove('active'); | |
}); | |
this.classList.add('active'); | |
selectedVpnServer = server; | |
connectBtn.disabled = false; | |
}); | |
vpnServerList.appendChild(serverElement); | |
}); | |
} | |
// Render proxy servers | |
function renderProxyServers(proxies) { | |
proxyServerList.innerHTML = ''; | |
if (proxies.length === 0) { | |
const noResults = document.createElement('div'); | |
noResults.className = 'server-item'; | |
noResults.textContent = 'No proxy servers found'; | |
proxyServerList.appendChild(noResults); | |
return; | |
} | |
proxies.forEach(proxy => { | |
const pingClass = proxy.ping < 100 ? 'good' : proxy.ping < 200 ? 'medium' : 'bad'; | |
const proxyElement = document.createElement('div'); | |
proxyElement.className = 'server-item'; | |
proxyElement.innerHTML = ` | |
<div class="server-info"> | |
<div class="server-name">${proxy.address}:${proxy.port}</div> | |
<div class="server-location">${proxy.country} (${proxy.type.toUpperCase()})</div> | |
</div> | |
<div class="server-ping ${pingClass}">${proxy.ping} ms</div> | |
`; | |
proxyElement.addEventListener('click', function() { | |
document.querySelectorAll('#proxyServerList .server-item').forEach(item => { | |
item.classList.remove('active'); | |
}); | |
this.classList.add('active'); | |
selectedProxy = proxy; | |
connectProxyBtn.disabled = false; | |
// Show proxy details | |
proxyDetails.classList.add('active'); | |
proxyAddress.textContent = proxy.address; | |
proxyPort.textContent = proxy.port; | |
proxyType.textContent = proxy.type.toUpperCase(); | |
proxyCountry.textContent = proxy.country; | |
proxyUptime.textContent = proxy.uptime; | |
}); | |
proxyServerList.appendChild(proxyElement); | |
}); | |
} | |
// Render routes | |
function renderRoutes(routes) { | |
routesList.innerHTML = ''; | |
routes.forEach(route => { | |
const pingClass = route.ping < 100 ? 'good' : route.ping < 200 ? 'medium' : 'bad'; | |
const routeElement = document.createElement('div'); | |
routeElement.className = 'server-item'; | |
routeElement.dataset.id = route.id; | |
routeElement.innerHTML = ` | |
<div class="server-info"> | |
<div class="server-name">${route.name}</div> | |
<div class="server-location">${route.type}</div> | |
</div> | |
<div class="server-ping ${pingClass}">${route.ping} ms</div> | |
`; | |
routeElement.addEventListener('click', function() { | |
document.querySelectorAll('#routesList .server-item').forEach(item => { | |
item.classList.remove('active'); | |
}); | |
this.classList.add('active'); | |
selectedRoute = route; | |
applyRouteBtn.disabled = false; | |
}); | |
routesList.appendChild(routeElement); | |
}); | |
} | |
// Find VPN servers | |
findVpnBtn.addEventListener('click', function() { | |
findVpnBtn.classList.add('loading'); | |
setTimeout(() => { | |
const servers = generateVpnServers(); | |
renderVpnServers(servers); | |
findVpnBtn.classList.remove('loading'); | |
}, 1000); | |
}); | |
// Find proxy servers | |
findProxyBtn.addEventListener('click', function() { | |
findProxyBtn.classList.add('loading'); | |
const searchTerm = proxySearch.value.trim(); | |
setTimeout(() => { | |
const proxies = generateProxyServers(currentProtocol, searchTerm); | |
renderProxyServers(proxies); | |
findProxyBtn.classList.remove('loading'); | |
}, 1000); | |
}); | |
// Connect to VPN | |
connectBtn.addEventListener('click', function() { | |
if (isConnected || !selectedVpnServer) return; | |
connectBtn.classList.add('loading'); | |
statusIndicator.classList.add('connecting'); | |
statusText.textContent = 'Connecting...'; | |
setTimeout(() => { | |
statusIndicator.classList.remove('connecting'); | |
statusIndicator.classList.add('connected'); | |
statusText.textContent = `Connected to ${selectedVpnServer.name}`; | |
vpnIp.textContent = getVpnIp(selectedVpnServer.id); | |
isConnected = true; | |
connectBtn.disabled = true; | |
disconnectBtn.disabled = false; | |
updatePing(); | |
pingInterval = setInterval(updatePing, 3000); | |
connectBtn.classList.remove('loading'); | |
}, 2000); | |
}); | |
// Disconnect from VPN | |
disconnectBtn.addEventListener('click', function() { | |
if (!isConnected) return; | |
disconnectBtn.classList.add('loading'); | |
setTimeout(() => { | |
statusIndicator.classList.remove('connected'); | |
statusText.textContent = 'Disconnected'; | |
vpnIp.textContent = 'Not connected'; | |
pingValue.textContent = '--'; | |
isConnected = false; | |
connectBtn.disabled = false; | |
disconnectBtn.disabled = true; | |
clearInterval(pingInterval); | |
disconnectBtn.classList.remove('loading'); | |
}, 1000); | |
}); | |
// Connect to proxy | |
connectProxyBtn.addEventListener('click', function() { | |
if (isProxyConnected || !selectedProxy) return; | |
connectProxyBtn.classList.add('loading'); | |
setTimeout(() => { | |
isProxyConnected = true; | |
connectProxyBtn.disabled = true; | |
disconnectProxyBtn.disabled = false; | |
connectProxyBtn.classList.remove('loading'); | |
// Update status to show proxy connection | |
if (!isConnected) { | |
statusIndicator.classList.add('connected'); | |
statusText.textContent = `Connected to proxy (${selectedProxy.type.toUpperCase()})`; | |
} | |
}, 1500); | |
}); | |
// Disconnect from proxy | |
disconnectProxyBtn.addEventListener('click', function() { | |
if (!isProxyConnected) return; | |
disconnectProxyBtn.classList.add('loading'); | |
setTimeout(() => { | |
isProxyConnected = false; | |
connectProxyBtn.disabled = false; | |
disconnectProxyBtn.disabled = true; | |
disconnectProxyBtn.classList.remove('loading'); | |
// Update status if not connected to VPN | |
if (!isConnected) { | |
statusIndicator.classList.remove('connected'); | |
statusText.textContent = 'Disconnected'; | |
} | |
}, 1000); | |
}); | |
// Find routes | |
findRoutesBtn.addEventListener('click', function() { | |
findRoutesBtn.classList.add('loading'); | |
setTimeout(() => { | |
const routes = generateRoutes(); | |
renderRoutes(routes); | |
findRoutesBtn.classList.remove('loading'); | |
}, 1000); | |
}); | |
// Apply route | |
applyRouteBtn.addEventListener('click', function() { | |
if (!selectedRoute) return; | |
applyRouteBtn.classList.add('loading'); | |
setTimeout(() => { | |
currentRoute.textContent = selectedRoute.name; | |
routeType.textContent = selectedRoute.type; | |
applyRouteBtn.classList.remove('loading'); | |
}, 1000); | |
}); | |
// Reset route | |
resetRouteBtn.addEventListener('click', function() { | |
resetRouteBtn.classList.add('loading'); | |
setTimeout(() => { | |
currentRoute.textContent = 'Default'; | |
routeType.textContent = 'Direct'; | |
resetRouteBtn.classList.remove('loading'); | |
}, 800); | |
}); | |
// Initialize | |
originalIp.textContent = getOriginalIp(); | |
renderVpnServers(generateVpnServers()); | |
renderProxyServers(generateProxyServers()); | |
renderRoutes(generateRoutes()); | |
}); | |
</script> | |
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <a href="https://enzostvs-deepsite.hf.space" style="color: #fff;" target="_blank" >DeepSite</a> <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;"></p></body> | |
</html> |