chore(exposure): Remove obsolete view files replaced by KISS redesign
Delete overview.js, tor.js, ssl.js — all functionality is now in the single services.js view. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
9def2ad15a
commit
c6de8b2b1b
File diff suppressed because it is too large
Load Diff
@ -1,222 +0,0 @@
|
||||
'use strict';
|
||||
'require view';
|
||||
'require dom';
|
||||
'require ui';
|
||||
'require exposure/api as api';
|
||||
|
||||
return view.extend({
|
||||
load: function() {
|
||||
return Promise.all([
|
||||
api.sslList(),
|
||||
api.scan()
|
||||
]);
|
||||
},
|
||||
|
||||
render: function(data) {
|
||||
var sslResult = data[0] || {};
|
||||
var scanResult = data[1] || {};
|
||||
var sslBackends = Array.isArray(sslResult) ? sslResult : (sslResult.backends || []);
|
||||
var allServices = Array.isArray(scanResult) ? scanResult : (scanResult.services || []);
|
||||
var self = this;
|
||||
|
||||
// Inject CSS
|
||||
var cssLink = document.querySelector('link[href*="exposure/dashboard.css"]');
|
||||
if (!cssLink) {
|
||||
var link = document.createElement('link');
|
||||
link.rel = 'stylesheet';
|
||||
link.href = L.resource('exposure/dashboard.css');
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
|
||||
var view = E('div', { 'class': 'exposure-dashboard' }, [
|
||||
E('h2', {}, '\ud83d\udd12 HAProxy SSL Backends'),
|
||||
E('p', { 'style': 'color: #8892b0; margin-bottom: 1.5rem;' },
|
||||
'Configure HTTPS reverse proxy for your services'),
|
||||
|
||||
// Add new backend form
|
||||
E('div', { 'class': 'exposure-section' }, [
|
||||
E('div', { 'class': 'exposure-section-header' }, [
|
||||
E('div', { 'class': 'exposure-section-title' }, [
|
||||
E('span', { 'class': 'icon' }, '\u2795'),
|
||||
'Add SSL Backend'
|
||||
])
|
||||
]),
|
||||
E('div', { 'class': 'exposure-form' }, [
|
||||
E('div', { 'class': 'exposure-form-group' }, [
|
||||
E('label', {}, 'Service'),
|
||||
E('select', { 'id': 'new-ssl-service' },
|
||||
[E('option', { 'value': '' }, '-- Select --')].concat(
|
||||
allServices.filter(function(s) { return s.external; }).map(function(s) {
|
||||
var name = s.name || s.process;
|
||||
return E('option', {
|
||||
'value': s.process,
|
||||
'data-port': s.port,
|
||||
'data-name': name.toLowerCase().replace(/\s+/g, '')
|
||||
}, name + ' (:' + s.port + ')');
|
||||
})
|
||||
)
|
||||
)
|
||||
]),
|
||||
E('div', { 'class': 'exposure-form-group' }, [
|
||||
E('label', {}, 'Domain'),
|
||||
E('input', {
|
||||
'type': 'text',
|
||||
'id': 'new-ssl-domain',
|
||||
'placeholder': 'service.example.com'
|
||||
})
|
||||
]),
|
||||
E('div', { 'class': 'exposure-form-group' }, [
|
||||
E('label', {}, 'Backend Port'),
|
||||
E('input', { 'type': 'number', 'id': 'new-ssl-port', 'placeholder': '3000' })
|
||||
]),
|
||||
E('button', {
|
||||
'class': 'btn-action btn-primary',
|
||||
'click': ui.createHandlerFn(self, 'handleAdd')
|
||||
}, 'Add Backend')
|
||||
])
|
||||
]),
|
||||
|
||||
// Info box
|
||||
E('div', {
|
||||
'class': 'exposure-section',
|
||||
'style': 'background: rgba(0, 212, 255, 0.1); border-color: #00d4ff;'
|
||||
}, [
|
||||
E('p', { 'style': 'margin: 0; color: #ccd6f6;' }, [
|
||||
E('strong', {}, '\u2139\ufe0f SSL Certificate: '),
|
||||
'After adding a backend, upload the SSL certificate to ',
|
||||
E('code', {}, '/srv/lxc/haproxy/rootfs/etc/haproxy/certs/'),
|
||||
'. The certificate file should be named ',
|
||||
E('code', {}, 'domain.pem'),
|
||||
' and contain both the certificate and private key.'
|
||||
])
|
||||
]),
|
||||
|
||||
// Existing backends
|
||||
E('div', { 'class': 'exposure-section' }, [
|
||||
E('div', { 'class': 'exposure-section-header' }, [
|
||||
E('div', { 'class': 'exposure-section-title' }, [
|
||||
E('span', { 'class': 'icon' }, '\ud83d\udd12'),
|
||||
'Active SSL Backends (' + sslBackends.length + ')'
|
||||
]),
|
||||
E('button', {
|
||||
'class': 'btn-action btn-primary',
|
||||
'click': function() { location.reload(); }
|
||||
}, 'Refresh')
|
||||
]),
|
||||
|
||||
sslBackends.length > 0 ?
|
||||
E('table', { 'class': 'exposure-table' }, [
|
||||
E('thead', {}, [
|
||||
E('tr', {}, [
|
||||
E('th', {}, 'Service'),
|
||||
E('th', {}, 'Domain'),
|
||||
E('th', {}, 'Backend'),
|
||||
E('th', {}, 'Actions')
|
||||
])
|
||||
]),
|
||||
E('tbody', {},
|
||||
sslBackends.map(function(b) {
|
||||
return E('tr', {}, [
|
||||
E('td', { 'style': 'font-weight: 600;' }, b.service),
|
||||
E('td', {}, [
|
||||
E('a', {
|
||||
'href': 'https://' + b.domain,
|
||||
'target': '_blank',
|
||||
'style': 'color: #00d4ff;'
|
||||
}, b.domain),
|
||||
E('span', { 'style': 'margin-left: 0.5rem;' }, '\ud83d\udd17')
|
||||
]),
|
||||
E('td', { 'style': 'font-family: monospace;' }, b.backend || 'N/A'),
|
||||
E('td', {}, [
|
||||
E('button', {
|
||||
'class': 'btn-action btn-danger',
|
||||
'click': ui.createHandlerFn(self, 'handleRemove', b.service)
|
||||
}, 'Remove')
|
||||
])
|
||||
]);
|
||||
})
|
||||
)
|
||||
]) :
|
||||
E('div', { 'class': 'exposure-empty' }, [
|
||||
E('div', { 'class': 'icon' }, '\ud83d\udd12'),
|
||||
E('p', {}, 'No SSL backends configured'),
|
||||
E('p', { 'style': 'font-size: 0.85rem;' }, 'Select a service above to add HTTPS access')
|
||||
])
|
||||
])
|
||||
]);
|
||||
|
||||
// Wire up service selector
|
||||
setTimeout(function() {
|
||||
var sel = document.getElementById('new-ssl-service');
|
||||
var portInput = document.getElementById('new-ssl-port');
|
||||
var domainInput = document.getElementById('new-ssl-domain');
|
||||
if (sel && portInput) {
|
||||
sel.addEventListener('change', function() {
|
||||
var opt = sel.options[sel.selectedIndex];
|
||||
portInput.value = opt.dataset.port || '';
|
||||
if (opt.dataset.name) {
|
||||
domainInput.placeholder = opt.dataset.name + '.example.com';
|
||||
}
|
||||
});
|
||||
}
|
||||
}, 100);
|
||||
|
||||
return view;
|
||||
},
|
||||
|
||||
handleAdd: function(ev) {
|
||||
var service = document.getElementById('new-ssl-service').value;
|
||||
var domain = document.getElementById('new-ssl-domain').value;
|
||||
var port = parseInt(document.getElementById('new-ssl-port').value);
|
||||
|
||||
if (!service) {
|
||||
ui.addNotification(null, E('p', {}, 'Please select a service'), 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!domain) {
|
||||
ui.addNotification(null, E('p', {}, 'Please enter a domain'), 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!port) {
|
||||
ui.addNotification(null, E('p', {}, 'Please specify the backend port'), 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
api.sslAdd(service, domain, port).then(function(res) {
|
||||
if (res.success) {
|
||||
ui.addNotification(null, E('p', {}, [
|
||||
'SSL backend configured for ',
|
||||
E('strong', {}, domain),
|
||||
E('br'),
|
||||
'Remember to upload the SSL certificate!'
|
||||
]), 'success');
|
||||
location.reload();
|
||||
} else {
|
||||
ui.addNotification(null, E('p', {}, 'Error: ' + (res.error || 'Unknown error')), 'danger');
|
||||
}
|
||||
}).catch(function(err) {
|
||||
ui.addNotification(null, E('p', {}, 'Error: ' + err.message), 'danger');
|
||||
});
|
||||
},
|
||||
|
||||
handleRemove: function(service, ev) {
|
||||
if (!confirm('Remove SSL backend for ' + service + '?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
api.sslRemove(service).then(function(res) {
|
||||
if (res.success) {
|
||||
ui.addNotification(null, E('p', {}, 'SSL backend removed'), 'success');
|
||||
location.reload();
|
||||
} else {
|
||||
ui.addNotification(null, E('p', {}, 'Error: ' + (res.error || 'Unknown error')), 'danger');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
handleSaveApply: null,
|
||||
handleSave: null,
|
||||
handleReset: null
|
||||
});
|
||||
@ -1,201 +0,0 @@
|
||||
'use strict';
|
||||
'require view';
|
||||
'require dom';
|
||||
'require ui';
|
||||
'require exposure/api as api';
|
||||
|
||||
return view.extend({
|
||||
load: function() {
|
||||
return Promise.all([
|
||||
api.torList(),
|
||||
api.scan()
|
||||
]);
|
||||
},
|
||||
|
||||
render: function(data) {
|
||||
var torResult = data[0] || {};
|
||||
var scanResult = data[1] || {};
|
||||
var torServices = Array.isArray(torResult) ? torResult : (torResult.services || []);
|
||||
var allServices = Array.isArray(scanResult) ? scanResult : (scanResult.services || []);
|
||||
var self = this;
|
||||
|
||||
// Inject CSS
|
||||
var cssLink = document.querySelector('link[href*="exposure/dashboard.css"]');
|
||||
if (!cssLink) {
|
||||
var link = document.createElement('link');
|
||||
link.rel = 'stylesheet';
|
||||
link.href = L.resource('exposure/dashboard.css');
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
|
||||
var view = E('div', { 'class': 'exposure-dashboard' }, [
|
||||
E('h2', {}, '\ud83e\uddc5 Tor Hidden Services'),
|
||||
E('p', { 'style': 'color: #8892b0; margin-bottom: 1.5rem;' },
|
||||
'Expose services on the Tor network with .onion addresses'),
|
||||
|
||||
// Add new service form
|
||||
E('div', { 'class': 'exposure-section' }, [
|
||||
E('div', { 'class': 'exposure-section-header' }, [
|
||||
E('div', { 'class': 'exposure-section-title' }, [
|
||||
E('span', { 'class': 'icon' }, '\u2795'),
|
||||
'Add Hidden Service'
|
||||
])
|
||||
]),
|
||||
E('div', { 'class': 'exposure-form' }, [
|
||||
E('div', { 'class': 'exposure-form-group' }, [
|
||||
E('label', {}, 'Service'),
|
||||
E('select', { 'id': 'new-tor-service' },
|
||||
[E('option', { 'value': '' }, '-- Select --')].concat(
|
||||
allServices.filter(function(s) { return s.external; }).map(function(s) {
|
||||
var name = s.name || s.process;
|
||||
return E('option', { 'value': s.process, 'data-port': s.port },
|
||||
name + ' (:' + s.port + ')');
|
||||
})
|
||||
)
|
||||
)
|
||||
]),
|
||||
E('div', { 'class': 'exposure-form-group' }, [
|
||||
E('label', {}, 'Local Port'),
|
||||
E('input', { 'type': 'number', 'id': 'new-tor-port', 'placeholder': '3000' })
|
||||
]),
|
||||
E('div', { 'class': 'exposure-form-group' }, [
|
||||
E('label', {}, 'Onion Port'),
|
||||
E('input', { 'type': 'number', 'id': 'new-tor-onion-port', 'value': '80' })
|
||||
]),
|
||||
E('button', {
|
||||
'class': 'btn-action btn-primary',
|
||||
'click': ui.createHandlerFn(self, 'handleAdd')
|
||||
}, 'Create .onion')
|
||||
])
|
||||
]),
|
||||
|
||||
// Existing services
|
||||
E('div', { 'class': 'exposure-section' }, [
|
||||
E('div', { 'class': 'exposure-section-header' }, [
|
||||
E('div', { 'class': 'exposure-section-title' }, [
|
||||
E('span', { 'class': 'icon' }, '\ud83e\uddc5'),
|
||||
'Active Hidden Services (' + torServices.length + ')'
|
||||
]),
|
||||
E('button', {
|
||||
'class': 'btn-action btn-primary',
|
||||
'click': function() { location.reload(); }
|
||||
}, 'Refresh')
|
||||
]),
|
||||
|
||||
torServices.length > 0 ?
|
||||
E('table', { 'class': 'exposure-table' }, [
|
||||
E('thead', {}, [
|
||||
E('tr', {}, [
|
||||
E('th', {}, 'Service'),
|
||||
E('th', {}, 'Onion Address'),
|
||||
E('th', {}, 'Port'),
|
||||
E('th', {}, 'Backend'),
|
||||
E('th', {}, 'Actions')
|
||||
])
|
||||
]),
|
||||
E('tbody', {},
|
||||
torServices.map(function(svc) {
|
||||
return E('tr', {}, [
|
||||
E('td', { 'style': 'font-weight: 600;' }, svc.service),
|
||||
E('td', {}, [
|
||||
E('code', { 'class': 'onion-address' }, svc.onion),
|
||||
E('button', {
|
||||
'class': 'btn-action',
|
||||
'style': 'margin-left: 0.5rem; padding: 0.25rem 0.5rem;',
|
||||
'click': function() {
|
||||
navigator.clipboard.writeText(svc.onion);
|
||||
ui.addNotification(null, E('p', {}, 'Copied to clipboard'), 'info');
|
||||
}
|
||||
}, '\ud83d\udccb')
|
||||
]),
|
||||
E('td', {}, svc.port || '80'),
|
||||
E('td', { 'style': 'font-family: monospace;' }, svc.backend || 'N/A'),
|
||||
E('td', {}, [
|
||||
E('button', {
|
||||
'class': 'btn-action btn-danger',
|
||||
'click': ui.createHandlerFn(self, 'handleRemove', svc.service)
|
||||
}, 'Remove')
|
||||
])
|
||||
]);
|
||||
})
|
||||
)
|
||||
]) :
|
||||
E('div', { 'class': 'exposure-empty' }, [
|
||||
E('div', { 'class': 'icon' }, '\ud83e\uddc5'),
|
||||
E('p', {}, 'No Tor hidden services configured'),
|
||||
E('p', { 'style': 'font-size: 0.85rem;' }, 'Select a service above to create a .onion address')
|
||||
])
|
||||
])
|
||||
]);
|
||||
|
||||
// Wire up service selector
|
||||
setTimeout(function() {
|
||||
var sel = document.getElementById('new-tor-service');
|
||||
var portInput = document.getElementById('new-tor-port');
|
||||
if (sel && portInput) {
|
||||
sel.addEventListener('change', function() {
|
||||
var opt = sel.options[sel.selectedIndex];
|
||||
portInput.value = opt.dataset.port || '';
|
||||
});
|
||||
}
|
||||
}, 100);
|
||||
|
||||
return view;
|
||||
},
|
||||
|
||||
handleAdd: function(ev) {
|
||||
var service = document.getElementById('new-tor-service').value;
|
||||
var port = parseInt(document.getElementById('new-tor-port').value);
|
||||
var onionPort = parseInt(document.getElementById('new-tor-onion-port').value) || 80;
|
||||
|
||||
if (!service) {
|
||||
ui.addNotification(null, E('p', {}, 'Please select a service'), 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!port) {
|
||||
ui.addNotification(null, E('p', {}, 'Please specify the local port'), 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
ui.showModal('Creating Hidden Service...', [
|
||||
E('p', { 'class': 'spinning' }, 'Please wait, generating .onion address (this may take a moment)...')
|
||||
]);
|
||||
|
||||
api.torAdd(service, port, onionPort).then(function(res) {
|
||||
ui.hideModal();
|
||||
if (res.success) {
|
||||
ui.addNotification(null, E('p', {}, [
|
||||
'Hidden service created! ',
|
||||
E('br'),
|
||||
E('code', { 'style': 'word-break: break-all;' }, res.onion || 'Refresh to see address')
|
||||
]), 'success');
|
||||
location.reload();
|
||||
} else {
|
||||
ui.addNotification(null, E('p', {}, 'Error: ' + (res.error || 'Unknown error')), 'danger');
|
||||
}
|
||||
}).catch(function(err) {
|
||||
ui.hideModal();
|
||||
ui.addNotification(null, E('p', {}, 'Error: ' + err.message), 'danger');
|
||||
});
|
||||
},
|
||||
|
||||
handleRemove: function(service, ev) {
|
||||
if (!confirm('Remove hidden service for ' + service + '?\n\nThe .onion address will be permanently lost.')) {
|
||||
return;
|
||||
}
|
||||
|
||||
api.torRemove(service).then(function(res) {
|
||||
if (res.success) {
|
||||
ui.addNotification(null, E('p', {}, 'Hidden service removed'), 'success');
|
||||
location.reload();
|
||||
} else {
|
||||
ui.addNotification(null, E('p', {}, 'Error: ' + (res.error || 'Unknown error')), 'danger');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
handleSaveApply: null,
|
||||
handleSave: null,
|
||||
handleReset: null
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user