131 lines
5.2 KiB
HTML
131 lines
5.2 KiB
HTML
{% extends "layout.html" %}
|
|
{% set active_page = 'vpn_switcher' %}
|
|
{% block title %}VPN Switcher - {{ super() }}{% endblock %}
|
|
|
|
{% block extra_styles %}
|
|
<style>
|
|
.config-output {
|
|
background-color: #343a40;
|
|
border-radius: .25rem;
|
|
padding: 1rem;
|
|
font-size: 1.1em;
|
|
white-space: pre-wrap;
|
|
font-family: 'Courier New', Courier, monospace;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<h2 id="page-title" class="mb-0">VPN Switcher</h2>
|
|
</div>
|
|
<hr>
|
|
<div id="switcher-view">
|
|
<p>Enter a host IP to view and change its current VPN endpoint and system details.</p>
|
|
<div class="row align-items-end g-3">
|
|
<div class="col-md-6">
|
|
<label for="host-ip-input" class="form-label">Host IP Address</label>
|
|
<input type="text" class="form-control" id="host-ip-input" placeholder="IPv4 Addresses only">
|
|
</div>
|
|
<div class="col-auto">
|
|
<button class="btn btn-primary" id="getInfoBtn">Get Info</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="mt-4">
|
|
<h4>Result</h4>
|
|
<div id="spinner" class="d-none spinner-border text-primary" role="status"><span class="visually-hidden">Loading...</span></div>
|
|
<div id="results-output" class="p-3"></div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block extra_scripts %}
|
|
<script defer>
|
|
const hostIpInput = document.getElementById('host-ip-input');
|
|
const getInfoBtn = document.getElementById('getInfoBtn');
|
|
|
|
async function getInfo() {
|
|
const hostIp = hostIpInput.value;
|
|
if (!hostIp) {
|
|
alert('Please enter a host IP address.');
|
|
return;
|
|
}
|
|
|
|
history.pushState({}, '', `/vpn-switcher?ip=${hostIp}`);
|
|
|
|
const result = await apiCall('/api/vpn/get-config', { host_ip: hostIp });
|
|
|
|
if (result) {
|
|
const details = result.details;
|
|
const endpointInfo = result.vpn_endpoint;
|
|
const isUS = endpointInfo.region === 'US';
|
|
const isEU = endpointInfo.region === 'EU';
|
|
|
|
const detailHtml = `
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<strong>Current VPN Endpoint</strong>
|
|
</div>
|
|
<div class="card-body">
|
|
<p>Connected to: <strong>${endpointInfo.region} VPN</strong> (${endpointInfo.ip})</p>
|
|
<pre class="config-output"><code>${result.vpn_config}</code></pre>
|
|
<hr>
|
|
<p>Select a new endpoint:</p>
|
|
<button class="btn btn-primary me-2 switch-btn" data-region="US" ${isUS ? 'disabled' : ''}>Switch to US-VPN</button>
|
|
<button class="btn btn-primary switch-btn" data-region="EU" ${isEU ? 'disabled' : ''}>Switch to EU-VPN</button>
|
|
</div>
|
|
</div>
|
|
<hr>
|
|
<div class="row g-4">
|
|
<div class="col-md-6">
|
|
<h5>System Information</h5>
|
|
<dl class="row">
|
|
<dt class="col-sm-5">Hostname</dt><dd class="col-sm-7">${details.system.hostname}</dd>
|
|
<dt class="col-sm-5">Product</dt><dd class="col-sm-7">${details.system.product_name}</dd>
|
|
<dt class="col-sm-5">Version</dt><dd class="col-sm-7">${details.system.version}</dd>
|
|
</dl>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<h5>Site Information</h5>
|
|
<dl class="row">
|
|
<dt class="col-sm-4">Node Name</dt><dd class="col-sm-8">${details.site.current_node.name}</dd>
|
|
<dt class="col-sm-4">API Address</dt><dd class="col-sm-8">${details.site.current_node.api_address}</dd>
|
|
</dl>
|
|
</div>
|
|
</div>
|
|
`;
|
|
resultsOutput.innerHTML = detailHtml;
|
|
}
|
|
}
|
|
|
|
getInfoBtn.addEventListener('click', getInfo);
|
|
|
|
resultsOutput.addEventListener('click', async (event) => {
|
|
const switchButton = event.target.closest('.switch-btn');
|
|
if (switchButton) {
|
|
const hostIp = hostIpInput.value;
|
|
const region = switchButton.dataset.region;
|
|
|
|
switchButton.disabled = true;
|
|
switchButton.innerHTML = `<span class="spinner-border spinner-border-sm"></span> Switching...`;
|
|
|
|
const result = await apiCall('/api/vpn/set-endpoint', { host_ip: hostIp, region: region }, false);
|
|
|
|
if (result) {
|
|
alert(result.message);
|
|
getInfo(); // Refresh the info after a successful switch
|
|
} else {
|
|
getInfo(); // Also refresh on failure to restore the button state
|
|
}
|
|
}
|
|
});
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const ipFromUrl = '{{ ip_from_url|default("", True) }}';
|
|
if (ipFromUrl) {
|
|
hostIpInput.value = ipFromUrl;
|
|
getInfoBtn.click();
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %} |