| ${onlineStatus}` + data.DNSName;
row += ' | ' + tailscaleIp;
row += ' | ' + data.LastSeen;
row += ' | ' + data.OS;
@@ -114,7 +120,7 @@
- | {{ lang._('Name') }} |
+ {{ lang._('Peer') }} |
{{ lang._('Tailscale IPs') }} |
{{ lang._('Last Seen') }} |
{{ lang._('OS') }} |
diff --git a/security/tailscale/src/opnsense/www/js/widgets/Metadata/Tailscale.xml b/security/tailscale/src/opnsense/www/js/widgets/Metadata/Tailscale.xml
new file mode 100644
index 000000000..171aeddf9
--- /dev/null
+++ b/security/tailscale/src/opnsense/www/js/widgets/Metadata/Tailscale.xml
@@ -0,0 +1,25 @@
+
+
+ Tailscale.js
+
+ /api/tailscale/service/status
+ /api/tailscale/status/status
+
+
+ Tailscale
+ Tailscale service is not running
+ Backend State
+ DNS Name
+ Enabled
+ Exit Node
+ No
+ Could not fetch data
+ Online
+ Peers
+ Tailscale IP
+ Yes
+ Version
+
+
+
+
diff --git a/security/tailscale/src/opnsense/www/js/widgets/Tailscale.js b/security/tailscale/src/opnsense/www/js/widgets/Tailscale.js
new file mode 100644
index 000000000..5a68e9147
--- /dev/null
+++ b/security/tailscale/src/opnsense/www/js/widgets/Tailscale.js
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2024 Sheridan Computers
+ * 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 = $('');
+ let $tailscaleStatusTable = this.createTable('tailscaleStatusTable', {
+ headerPosition: 'left'
+ });
+
+ $container.append($tailscaleStatusTable);
+ return $container;
+ }
+
+ async onWidgetTick() {
+ // check if Tailscale is enabled
+ const ServiceStatusData = await this.ajaxCall('/api/tailscale/service/status');
+ if (!ServiceStatusData || ServiceStatusData.status !== 'running') {
+ this.displayError(this.translations.serviceDisabled);
+ return;
+ }
+
+ const tsData = await this.ajaxCall('/api/tailscale/status/status');
+ if (!tsData) {
+ this.displayError(this.translations.noData);
+ return;
+ }
+
+ let statusData = this.parseData(tsData);
+ if (!this.dataChanged('tailscale-data', statusData)) {
+ return;
+ }
+
+ this.updateWidgetTable(statusData);
+ }
+
+ parseData(data) {
+ let result = [];
+
+ result['version'] = data.Version;
+ result['backendState'] = data.BackendState;
+ result['dnsName'] = data.Self.DNSName;
+
+ result['online'] = (data.Self.Online === true) ?
+ this.translations.yes : this.translations.no;
+
+ result['exitNode'] = (data.Self.ExitNode === true) ?
+ this.translations.yes : this.translations.no;
+
+ result['peerCount'] = Object.keys(data.Peer).length;
+
+ let ipAddresses = [];
+ data.TailscaleIPs.forEach(ip => {
+ ipAddresses.push(ip);
+ });
+ result['ipAddresses'] = ipAddresses;
+
+ return result;
+ }
+
+ updateWidgetTable(data) {
+ let rows = [];
+
+ let color = "text-success";
+ if (data['online'] === false) {
+ color = "text-danger";
+ }
+
+ let row = [
+ ` ${this.translations.online} `,
+ `${data['online']} `
+ ];
+ rows.push(row);
+
+ // version
+ row = [
+ `${this.translations.version} `,
+ `${data['version']} `
+ ];
+ rows.push(row);
+
+ // backend state
+ row = [
+ `${this.translations.backendState} `,
+ `${data['backendState']} `
+ ];
+ rows.push(row);
+
+ // dns name
+ row = [
+ `${this.translations.dnsName} `,
+ `${data['dnsName']} `
+ ];
+ rows.push(row);
+
+ // ip addreses
+ row = [
+ `${this.translations.tailscaleIP} `,
+ `${data['ipAddresses'].join(' ')} `
+ ];
+ rows.push(row);
+
+ // exit node
+ row = [
+ `${this.translations.exitNode} `,
+ `${data['exitNode']} `
+ ];
+ rows.push(row);
+
+ // peers
+ row = [
+ `${this.translations.peers} `,
+ `${data['peerCount']} `
+ ];
+ rows.push(row);
+
+ super.updateTable('tailscaleStatusTable', rows);
+ }
+
+ displayError(message) {
+ $('#tailscaleStatusTable').empty().append(
+ $(`${message} `)
+ );
+ }
+}
+
|