mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-06-18 17:15:20 -04:00
feat(tailscale): add connect/disconnect, exit-node and LAN-access controls (#2644)
* feat(tailscale): add connect/disconnect/exit-node/LAN-access backend The Tailscale backend previously exposed only read-only status (tailscale.getStatus, tailscale.refresh). This adds write actions through the existing tailscale.com/client/local integration: - tailscale.connect / tailscale.disconnect (EditPrefs WantRunning) - tailscale.setExitNode (EditPrefs ExitNodeID; empty id clears it and any legacy ExitNodeIP, mirroring `tailscale set --exit-node`) - tailscale.setAllowLanAccess (EditPrefs ExitNodeAllowLANAccess) The manager's client interface gains GetPrefs/EditPrefs; fetchState merges ExitNodeAllowLANAccess from prefs, and Peer exposes ExitNodeOption so the UI can list exit-node-capable peers. * feat(tailscale): expose the new actions in TailscaleService Adds connectTailscale/disconnectTailscale, setExitNode/clearExitNode and setAllowLanAccess wrappers, plus derived exitNodeOptions/currentExitNode and the exitNodeAllowLanAccess state. Write-action errors surface via ToastService. * feat(tailscale): add connection, exit-node and LAN-access controls to the widget The control-center widget toggle was a no-op. It now connects/disconnects, and the detail panel gains a connection status row with a connect/disconnect button, an exit-node picker and a LAN-access toggle.
This commit is contained in:
@@ -41,6 +41,7 @@ Singleton {
|
||||
property string tailnetName: ""
|
||||
property var selfNode: null
|
||||
property var peers: []
|
||||
property bool exitNodeAllowLanAccess: false
|
||||
|
||||
property bool available: false
|
||||
property bool stateInitialized: false
|
||||
@@ -56,6 +57,19 @@ Singleton {
|
||||
|
||||
readonly property var onlinePeers: allPeersList.filter(p => p.online)
|
||||
|
||||
// Peers that may be used as an exit node (offered && approved). Self is
|
||||
// excluded: a node can never route through itself, and tailscaled rejects it.
|
||||
readonly property var exitNodeOptions: allPeersList.filter(p => p && p.exitNodeOption && p !== selfNode)
|
||||
|
||||
// The currently selected exit node, or null if none is in use.
|
||||
readonly property var currentExitNode: {
|
||||
for (const p of allPeersList) {
|
||||
if (p && p.exitNode)
|
||||
return p;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
readonly property var myPeers: {
|
||||
if (!selfNode)
|
||||
return allPeersList;
|
||||
@@ -141,6 +155,7 @@ Singleton {
|
||||
tailnetName = data.tailnetName || "";
|
||||
selfNode = data.self || null;
|
||||
peers = data.peers || [];
|
||||
exitNodeAllowLanAccess = data.exitNodeAllowLanAccess || false;
|
||||
}
|
||||
|
||||
function refresh(callback) {
|
||||
@@ -152,6 +167,45 @@ Singleton {
|
||||
});
|
||||
}
|
||||
|
||||
// sendAction issues a state-changing request. The backend refreshes and
|
||||
// broadcasts on success, so subscribers update without an extra getStatus.
|
||||
function sendAction(method, params, callback) {
|
||||
if (!available)
|
||||
return;
|
||||
DMSService.sendRequest(method, params, response => {
|
||||
if (response.error) {
|
||||
root.log.warn(method + " failed: " + response.error);
|
||||
ToastService.showError(I18n.tr("Tailscale action failed", "Toast shown when a Tailscale write action is rejected"), response.error);
|
||||
}
|
||||
if (callback)
|
||||
callback(response);
|
||||
});
|
||||
}
|
||||
|
||||
function connectTailscale(callback) {
|
||||
sendAction("tailscale.connect", null, callback);
|
||||
}
|
||||
|
||||
function disconnectTailscale(callback) {
|
||||
sendAction("tailscale.disconnect", null, callback);
|
||||
}
|
||||
|
||||
function setExitNode(id, callback) {
|
||||
sendAction("tailscale.setExitNode", {
|
||||
"id": id || ""
|
||||
}, callback);
|
||||
}
|
||||
|
||||
function clearExitNode(callback) {
|
||||
setExitNode("", callback);
|
||||
}
|
||||
|
||||
function setAllowLanAccess(enabled, callback) {
|
||||
sendAction("tailscale.setAllowLanAccess", {
|
||||
"enabled": enabled
|
||||
}, callback);
|
||||
}
|
||||
|
||||
function isMine(peer) {
|
||||
const myOwner = selfNode ? (selfNode.owner || "") : "";
|
||||
if (peer.owner === myOwner && myOwner !== "")
|
||||
|
||||
Reference in New Issue
Block a user