Files

217 lines
8.6 KiB
HTML
Raw Permalink Normal View History

{% extends "base.html" %}
{% block title %}Settings{% endblock %}
{% block content %}
<h1>[%] Settings</h1>
<div class="grid grid-2">
<div class="card">
<div class="card-title">VPS Connection</div>
<label>Host</label>
<input type="text" id="s-host" style="width:100%">
<label>User</label>
<input type="text" id="s-user" style="width:100%">
<label>Port</label>
<input type="number" id="s-port" style="width:100%">
<label>SSH Key Path</label>
<input type="text" id="s-key" style="width:100%">
</div>
<div class="card">
<div class="card-title">Domain & Paths</div>
<label>Domain</label>
<input type="text" id="s-domain" style="width:100%">
<label>Web Root</label>
<input type="text" id="s-webroot" style="width:100%">
<label>Compose Path</label>
<input type="text" id="s-compose" style="width:100%">
</div>
</div>
<div class="card">
<div class="card-title">Hosting Provider API</div>
<p style="color:#888;font-size:11px;margin-bottom:10px">Select your hosting provider and enter API credentials for DNS management.</p>
<label>Provider</label>
<select id="s-provider" style="width:100%" onchange="providerChanged()">
<option value="">-- Select Provider --</option>
</select>
<div id="provider-notes" style="font-size:11px;color:#555;margin:5px 3px"></div>
<label id="lbl-apikey">API Key</label>
<input type="text" id="s-apikey" style="width:100%" placeholder="Enter API key">
<div id="provider-docs" style="font-size:11px;margin:5px 3px"></div>
</div>
<div class="card">
<div class="card-title">E2E SSH Encryption</div>
<p style="color:#888;font-size:11px;margin-bottom:10px">
Encrypts all SSH commands with AES-256-GCM before transport. Requires the setec-agent on the VPS.
</p>
<div id="e2e-status" style="margin-bottom:10px;font-size:12px;color:#555">Loading...</div>
<div class="toolbar" style="margin-bottom:0">
<button class="btn" id="btn-e2e-toggle" onclick="toggleE2E()">Enable E2E</button>
<button class="btn" onclick="deployE2E()">Deploy Agent</button>
<button class="btn" onclick="testE2E()">Test Tunnel</button>
</div>
<div class="output" id="e2e-output" style="margin-top:10px;display:none"></div>
</div>
<div class="toolbar">
<button class="btn" onclick="saveSettings()">Save Settings</button>
<button class="btn" onclick="loadSettings()">Reload</button>
<button class="btn" onclick="testConnection()">Test SSH Connection</button>
</div>
<div class="card">
<div class="card-title">Output</div>
<div class="output" id="output"><span class="info">Ready.</span></div>
</div>
{% endblock %}
{% block scripts %}
<script>
let providers = [];
async function loadProviders() {
const res = await apiGet('/api/hosting/providers');
if (!res.ok) return;
providers = res.data;
const sel = document.getElementById('s-provider');
providers.forEach(p => {
const opt = document.createElement('option');
opt.value = p.id;
opt.textContent = p.name;
sel.appendChild(opt);
});
}
function providerChanged() {
const id = document.getElementById('s-provider').value;
const p = providers.find(x => x.id === id);
if (p) {
document.getElementById('lbl-apikey').textContent = p.api_key_label || 'API Key';
document.getElementById('provider-notes').textContent = p.notes || '';
document.getElementById('provider-docs').innerHTML = p.docs ? '<a href="' + p.docs + '" target="_blank">' + p.docs + '</a>' : '';
} else {
document.getElementById('lbl-apikey').textContent = 'API Key';
document.getElementById('provider-notes').textContent = '';
document.getElementById('provider-docs').innerHTML = '';
}
}
async function loadSettings() {
const res = await apiGet('/api/settings');
if (!res.ok) { showResult(res); return; }
const d = res.data;
document.getElementById('s-host').value = d.vps_host || '';
document.getElementById('s-user').value = d.vps_user || '';
document.getElementById('s-port').value = d.vps_port || 22;
document.getElementById('s-key').value = d.ssh_key_path || '';
document.getElementById('s-domain').value = d.domain || '';
document.getElementById('s-apikey').value = d.hostinger_api_key || '';
document.getElementById('s-webroot').value = d.web_root || '';
document.getElementById('s-compose').value = d.compose_path || '';
if (d.hosting_provider) {
document.getElementById('s-provider').value = d.hosting_provider;
providerChanged();
}
document.getElementById('output').innerHTML = '<span class="info">Settings loaded.</span>';
}
async function saveSettings() {
const body = {
vps_host: document.getElementById('s-host').value,
vps_user: document.getElementById('s-user').value,
vps_port: parseInt(document.getElementById('s-port').value),
ssh_key_path: document.getElementById('s-key').value,
domain: document.getElementById('s-domain').value,
hostinger_api_key: document.getElementById('s-apikey').value,
hosting_provider: document.getElementById('s-provider').value,
web_root: document.getElementById('s-webroot').value,
compose_path: document.getElementById('s-compose').value,
};
const res = await apiPost('/api/settings', body);
showResult(res);
}
async function testConnection() {
document.getElementById('output').innerHTML = '<span class="info">Testing SSH...</span>';
const res = await apiGet('/api/ssh/test');
showResult(res);
}
// ── E2E Tunnel ──
async function loadE2EStatus() {
const res = await apiGet('/api/e2e/status');
const el = document.getElementById('e2e-status');
const btn = document.getElementById('btn-e2e-toggle');
if (!res.ok) { el.innerHTML = '<span class="error">Failed to load E2E status</span>'; return; }
const d = res.data;
const active = d.e2e_enabled && d.e2e_deployed;
let html = 'Status: ';
if (active) {
html += '<span class="status-ok">ACTIVE</span>';
btn.textContent = 'Disable E2E';
} else if (d.e2e_deployed) {
html += '<span class="status-warn">Deployed but disabled</span>';
btn.textContent = 'Enable E2E';
} else {
html += '<span class="status-err">Not deployed</span>';
btn.textContent = 'Enable E2E';
}
html += ' &nbsp;|&nbsp; Agent: <code>' + d.agent_path + '</code>';
el.innerHTML = html;
}
async function toggleE2E() {
const res = await apiGet('/api/e2e/status');
if (!res.ok) return;
const nowEnabled = res.data.e2e_enabled && res.data.e2e_deployed;
const out = document.getElementById('e2e-output');
out.style.display = 'block';
out.innerHTML = '<span class="info">' + (nowEnabled ? 'Disabling' : 'Enabling') + ' E2E...</span>';
const r = await apiPost('/api/e2e/toggle', {enabled: !nowEnabled});
if (r.ok) {
out.innerHTML = '<span class="status-ok">E2E ' + (!nowEnabled ? 'enabled' : 'disabled') + '</span>';
} else {
out.innerHTML = '<span class="error">' + (r.error || 'Failed') + '</span>';
}
loadE2EStatus();
}
async function deployE2E() {
const out = document.getElementById('e2e-output');
out.style.display = 'block';
out.innerHTML = '<span class="info">Deploying agent + tunnel key to VPS... this may take a moment.</span>';
const r = await apiPost('/api/e2e/deploy', {});
if (r.ok) {
let html = '<span class="status-ok">Deployment complete!</span><br>';
(r.data || []).forEach(s => {
html += (s.ok ? '<span class="status-ok">[OK]</span>' : '<span class="status-err">[FAIL]</span>') + ' ' + s.step + '<br>';
});
out.innerHTML = html;
} else {
let html = '<span class="error">' + (r.error || 'Deploy failed') + '</span><br>';
(r.data || []).forEach(s => {
html += (s.ok ? '<span class="status-ok">[OK]</span>' : '<span class="status-err">[FAIL]</span>') + ' ' + s.step + '<br>';
});
out.innerHTML = html;
}
loadE2EStatus();
}
async function testE2E() {
const out = document.getElementById('e2e-output');
out.style.display = 'block';
out.innerHTML = '<span class="info">Testing E2E tunnel...</span>';
const r = await apiPost('/api/e2e/test', {});
if (r.ok) {
out.innerHTML = '<span class="status-ok">E2E tunnel working!</span><br><pre>' + (r.data.output || '') + '</pre>';
} else {
out.innerHTML = '<span class="error">' + (r.error || 'Test failed') + '</span>';
}
}
loadProviders();
loadSettings();
loadE2EStatus();
</script>
{% endblock %}