%PDF- %PDF-
| Direktori : /proc/thread-self/root/backups/router/usr/local/opnsense/www/js/widgets/ |
| Current File : //proc/thread-self/root/backups/router/usr/local/opnsense/www/js/widgets/Wireguard.js |
/**
* Copyright (C) 2024 Deciso B.V.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
export default class Wireguard extends BaseTableWidget {
constructor() {
super();
}
getGridOptions() {
return {
// Automatically triggers vertical scrolling after reaching 650px in height
sizeToContent: 650
};
}
getMarkup() {
let $container = $('<div></div>');
let $wgTunnelTable = this.createTable('wgTunnelTable', {
headerPosition: 'left'
});
$container.append($wgTunnelTable);
return $container;
}
async onWidgetTick() {
const wg = await this.ajaxCall('/api/wireguard/general/get');
if (!wg.general || !wg.general.enabled) {
this.displayError(`${this.translations.unconfigured}`);
return;
}
const response = await this.ajaxCall('/api/wireguard/service/show');
if (!response || !response.rows || response.rows.length === 0) {
this.displayError(`${this.translations.notunnels}`);
return;
}
if (!this.dataChanged('wg-tunnels', response.rows)) {
return; // No changes detected, do not update the UI
}
this.processTunnels(response.rows);
}
displayError(message) {
$('#wgTunnelTable'). empty().append(
$(`<div class="error-message"><a href="/ui/wireguard/general">${message}</a></div>`)
);
}
processTunnels(newTunnels) {
$('.wireguard-interface').tooltip('hide');
let now = moment().unix(); // Current time in seconds
let tunnels = newTunnels.filter(row => row.type == 'peer').map(row => ({
ifname: row.ifname ? row.if + ' (' + row.ifname + ') ' : row.if,
name: row.name,
allowed_ips: row['allowed-ips'] || this.translations.notavailable,
rx: row['transfer-rx'] ? this._formatBytes(row['transfer-rx']) : this.translations.notavailable,
tx: row['transfer-tx'] ? this._formatBytes(row['transfer-tx']) : this.translations.notavailable,
latest_handshake: row['latest-handshake'], // No fallback since we handle if 0
latest_handshake_fmt: row['latest-handshake'] ? moment.unix(row['latest-handshake']).local().format('YYYY-MM-DD HH:mm:ss') : null,
connected: row['latest-handshake'] && (now - row['latest-handshake']) <= 180, // Considered online if last handshake was within 3 minutes
statusIcon: row['latest-handshake'] && (now - row['latest-handshake']) <= 180 ? 'fa-exchange text-success' : 'fa-exchange text-danger',
publicKey: row['public-key'],
uniqueId: row.if + row['public-key']
}));
tunnels.sort((a, b) => a.connected === b.connected ? 0 : a.connected ? -1 : 1);
let onlineCount = tunnels.filter(tunnel => tunnel.connected).length;
let offlineCount = tunnels.length - onlineCount;
let summaryRow = `
<div>
<span>${this.translations.total}: ${tunnels.length} | ${this.translations.online}: ${onlineCount} | ${this.translations.offline}: ${offlineCount}</span>
</div>`;
super.updateTable('wgTunnelTable', [[summaryRow, '']], 'wg-summary');
// Generate HTML for each tunnel
tunnels.forEach(tunnel => {
let header = `
<div style="display: flex; justify-content: space-between; align-items: center;">
<div style="display: flex; align-items: center;">
<i class="fa ${tunnel.statusIcon} wireguard-interface" style="cursor: pointer;"
data-toggle="tooltip" title="${tunnel.connected ? this.translations.online : this.translations.offline}">
</i>
<span><b>${tunnel.ifname}</b></span>
</div>
</div>`;
let row = `
<div>
<span>
<a href="/ui/wireguard/general#peers&search=${encodeURIComponent(tunnel.name)}" target="_blank" rel="noopener noreferrer">
${tunnel.name}
</a> | ${tunnel.allowed_ips}
</span>
</div>
<div>
${tunnel.latest_handshake_fmt
? `<span>${tunnel.latest_handshake_fmt}</span>
<div style="padding-bottom: 10px;">
<i class="fa fa-arrow-down" style="font-size: 13px;"></i>
${tunnel.rx}
|
<i class="fa fa-arrow-up" style="font-size: 13px;"></i>
${tunnel.tx}
</div>`
: `<span>${this.translations.disconnected}</span>`}
</div>`;
// Update the HTML table with the sorted rows
super.updateTable('wgTunnelTable', [[header, row]], tunnel.uniqueId);
});
// Activate tooltips for new dynamic elements
$('.wireguard-interface').tooltip({container: 'body'});
}
}