From 4bc2f85da82894c6a5d28ab1b610ca6e6ffc29ba Mon Sep 17 00:00:00 2001 From: tokisaki galaxy Date: Mon, 28 Sep 2026 12:27:01 +0000 Subject: [PATCH] luci-app-tailscale-community: fix status parsing and TUNMode type - Return TUNMode as an actual boolean instead of string - Safely extract first health message from Health array - Add null-safety checks and fallbacks for peer properties - Initialize default peers data structure as an object - Ensure tailscale.uc retains executable file mode (0755) Signed-off-by: tokisaki galaxy --- .../root/usr/share/rpcd/ucode/tailscale.uc | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/applications/luci-app-tailscale-community/root/usr/share/rpcd/ucode/tailscale.uc b/applications/luci-app-tailscale-community/root/usr/share/rpcd/ucode/tailscale.uc index b7bf94b0ba..ca00d44708 100755 --- a/applications/luci-app-tailscale-community/root/usr/share/rpcd/ucode/tailscale.uc +++ b/applications/luci-app-tailscale-community/root/usr/share/rpcd/ucode/tailscale.uc @@ -40,12 +40,12 @@ methods.get_status = { let data = { status: '', version: '', - TUNMode: '', + TUNMode: false, health: '', ipv4: "Not running", - ipv6: null, + ipv6: "", domain_name: '', - peers: [] + peers: {} }; if (access('/usr/sbin/tailscale')==true || access('/usr/bin/tailscale')==true){ }else{ data.status = 'not_installed'; @@ -56,32 +56,34 @@ methods.get_status = { let peer_map = {}; if (status_json_output.code == 0 && length(status_json_output.stdout) > 0) { try { - let status_data = json(join('',status_json_output.stdout)); + let status_data = json(join('', status_json_output.stdout)); data.version = status_data?.Version || 'Unknown'; - data.health = status_data?.Health || ''; - data.TUNMode = status_data?.TUN || 'true'; + data.health = (status_data?.Health && length(status_data.Health) > 0) ? status_data.Health[0] : ''; + data.TUNMode = (status_data?.TUN == true); if (status_data?.BackendState == 'Running') { data.status = 'running'; } if (status_data?.BackendState == 'NeedsLogin') { data.status = 'logout'; } data.ipv4 = status_data?.Self?.TailscaleIPs?.[0] || 'No IP assigned'; - data.ipv6 = status_data?.Self?.TailscaleIPs?.[1] || null; + data.ipv6 = status_data?.Self?.TailscaleIPs?.[1] || ''; data.domain_name = status_data?.CurrentTailnet?.Name || ''; // peers list - for (let p in status_data?.Peer) { - p = status_data.Peer[p]; - peer_map[p.ID] = { - ip: join('
', p?.TailscaleIPs) || '', - hostname: split(p?.DNSName || '','.')[0] || '', - ostype: p?.OS, - online: p?.Online, - linkadress: (!p?.CurAddr) ? p?.Relay : p?.CurAddr, - lastseen: p?.LastSeen, - exit_node: !!p?.ExitNode, - exit_node_option: !!p?.ExitNodeOption, - tx: p?.TxBytes || '', - rx: p?.RxBytes || '' - }; + if (status_data?.Peer) { + for (let p in status_data.Peer) { + let peer = status_data.Peer[p]; + peer_map[peer.ID] = { + ip: join('
', peer?.TailscaleIPs || []), + hostname: split(peer?.DNSName || '', '.')[0] || peer?.HostName || '', + ostype: peer?.OS || '', + online: !!peer?.Online, + linkadress: (!peer?.CurAddr) ? (peer?.Relay || '') : peer?.CurAddr, + lastseen: peer?.LastSeen || '', + exit_node: !!peer?.ExitNode, + exit_node_option: !!peer?.ExitNodeOption, + tx: peer?.TxBytes || 0, + rx: peer?.RxBytes || 0 + }; + } } } catch (e) { /* ignore */ } }