Initial commit
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
'use strict';
|
||||
'require view';
|
||||
'require rpc';
|
||||
'require poll';
|
||||
'require dom';
|
||||
'require ui';
|
||||
|
||||
|
||||
var callGetWgInstances = rpc.declare({
|
||||
object: 'luci.amneziawg',
|
||||
method: 'getWgInstances'
|
||||
});
|
||||
|
||||
function timestampToStr(timestamp) {
|
||||
if (timestamp < 1)
|
||||
return _('Never', 'No AmneziaWG peer handshake yet');
|
||||
|
||||
var seconds = (Date.now() / 1000) - timestamp;
|
||||
var ago;
|
||||
|
||||
if (seconds < 60)
|
||||
ago = _('%ds ago').format(seconds);
|
||||
else if (seconds < 3600)
|
||||
ago = _('%dm ago').format(seconds / 60);
|
||||
else if (seconds < 86401)
|
||||
ago = _('%dh ago').format(seconds / 3600);
|
||||
else
|
||||
ago = _('over a day ago');
|
||||
|
||||
return (new Date(timestamp * 1000)).toUTCString() + ' (' + ago + ')';
|
||||
}
|
||||
|
||||
function handleInterfaceDetails(iface) {
|
||||
ui.showModal(_('Instance Details'), [
|
||||
ui.itemlist(E([]), [
|
||||
_('Name'), iface.name,
|
||||
_('Public Key'), E('code', [ iface.public_key ]),
|
||||
_('Listen Port'), iface.listen_port,
|
||||
_('Firewall Mark'), iface.fwmark != 'off' ? iface.fwmark : E('em', _('none'))
|
||||
]),
|
||||
E('div', { 'class': 'right' }, [
|
||||
E('button', {
|
||||
'class': 'btn cbi-button',
|
||||
'click': ui.hideModal
|
||||
}, [ _('Dismiss') ])
|
||||
])
|
||||
]);
|
||||
}
|
||||
|
||||
function handlePeerDetails(peer) {
|
||||
ui.showModal(_('Peer Details'), [
|
||||
ui.itemlist(E([]), [
|
||||
_('Description'), peer.name,
|
||||
_('Public Key'), E('code', [ peer.public_key ]),
|
||||
_('Endpoint'), peer.endpoint,
|
||||
_('Allowed IPs'), (Array.isArray(peer.allowed_ips) && peer.allowed_ips.length) ? peer.allowed_ips.join(', ') : E('em', _('none')),
|
||||
_('Received Data'), '%1024mB'.format(peer.transfer_rx),
|
||||
_('Transmitted Data'), '%1024mB'.format(peer.transfer_tx),
|
||||
_('Latest Handshake'), timestampToStr(+peer.latest_handshake),
|
||||
_('Keep-Alive'), (peer.persistent_keepalive != 'off') ? _('every %ds', 'AmneziaWG keep alive interval').format(+peer.persistent_keepalive) : E('em', _('none')),
|
||||
]),
|
||||
E('div', { 'class': 'right' }, [
|
||||
E('button', {
|
||||
'class': 'btn cbi-button',
|
||||
'click': ui.hideModal
|
||||
}, [ _('Dismiss') ])
|
||||
])
|
||||
]);
|
||||
}
|
||||
|
||||
function renderPeerTable(instanceName, peers) {
|
||||
var t = new L.ui.Table(
|
||||
[
|
||||
_('Peer'),
|
||||
_('Endpoint'),
|
||||
_('Data Received'),
|
||||
_('Data Transmitted'),
|
||||
_('Latest Handshake')
|
||||
],
|
||||
{
|
||||
id: 'peers-' + instanceName
|
||||
},
|
||||
E('em', [
|
||||
_('No peers connected')
|
||||
])
|
||||
);
|
||||
|
||||
t.update(peers.map(function(peer) {
|
||||
return [
|
||||
[
|
||||
peer.name || '',
|
||||
E('div', {
|
||||
'style': 'cursor:pointer',
|
||||
'click': ui.createHandlerFn(this, handlePeerDetails, peer)
|
||||
}, [
|
||||
E('p', [
|
||||
peer.name ? E('span', [ peer.name ]) : E('em', [ _('Untitled peer') ])
|
||||
]),
|
||||
E('span', {
|
||||
'class': 'ifacebadge hide-sm',
|
||||
'data-tooltip': _('Public key: %h', 'Tooltip displaying full AmneziaWG peer public key').format(peer.public_key)
|
||||
}, [
|
||||
E('code', [ peer.public_key.replace(/^(.{5}).+(.{6})$/, '$1…$2') ])
|
||||
])
|
||||
])
|
||||
],
|
||||
peer.endpoint,
|
||||
[ +peer.transfer_rx, '%1024mB'.format(+peer.transfer_rx) ],
|
||||
[ +peer.transfer_tx, '%1024mB'.format(+peer.transfer_tx) ],
|
||||
[ +peer.latest_handshake, timestampToStr(+peer.latest_handshake) ]
|
||||
];
|
||||
}));
|
||||
|
||||
return t.render();
|
||||
}
|
||||
|
||||
return view.extend({
|
||||
renderIfaces: function(ifaces) {
|
||||
var res = [
|
||||
E('h2', [ _('AmneziaWG Status') ])
|
||||
];
|
||||
|
||||
for (var instanceName in ifaces) {
|
||||
res.push(
|
||||
E('h3', [ _('Instance "%h"', 'AmneziaWG instance heading').format(instanceName) ]),
|
||||
E('p', {
|
||||
'style': 'cursor:pointer',
|
||||
'click': ui.createHandlerFn(this, handleInterfaceDetails, ifaces[instanceName])
|
||||
}, [
|
||||
E('span', { 'class': 'ifacebadge' }, [
|
||||
E('img', { 'src': L.resource('icons', 'tunnel.png') }),
|
||||
'\xa0',
|
||||
instanceName
|
||||
]),
|
||||
E('span', { 'style': 'opacity:.8' }, [
|
||||
' · ',
|
||||
_('Port %d', 'AmneziaWG listen port').format(ifaces[instanceName].listen_port),
|
||||
' · ',
|
||||
E('code', { 'click': '' }, [ ifaces[instanceName].public_key ])
|
||||
])
|
||||
]),
|
||||
renderPeerTable(instanceName, ifaces[instanceName].peers)
|
||||
);
|
||||
}
|
||||
|
||||
if (res.length == 1)
|
||||
res.push(E('p', { 'class': 'center', 'style': 'margin-top:5em' }, [
|
||||
E('em', [ _('No AmneziaWG interfaces configured.') ])
|
||||
]));
|
||||
|
||||
return E([], res);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
poll.add(L.bind(function () {
|
||||
return callGetWgInstances().then(L.bind(function(ifaces) {
|
||||
dom.content(
|
||||
document.querySelector('#view'),
|
||||
this.renderIfaces(ifaces)
|
||||
);
|
||||
}, this));
|
||||
}, this), 5);
|
||||
|
||||
return E([], [
|
||||
E('h2', [ _('AmneziaWG Status') ]),
|
||||
E('p', { 'class': 'center', 'style': 'margin-top:5em' }, [
|
||||
E('em', [ _('Loading data…') ])
|
||||
])
|
||||
]);
|
||||
},
|
||||
|
||||
handleReset: null,
|
||||
handleSaveApply: null,
|
||||
handleSave: null
|
||||
});
|
||||
Reference in New Issue
Block a user