mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-06-18 00:55: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:
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -78,6 +79,63 @@ func TestHandleRefresh(t *testing.T) {
|
||||
assert.True(t, resp.Result.Success)
|
||||
}
|
||||
|
||||
func TestHandleActions(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
method string
|
||||
params map[string]any
|
||||
}{
|
||||
{"connect", "tailscale.connect", nil},
|
||||
{"disconnect", "tailscale.disconnect", nil},
|
||||
{"setExitNode", "tailscale.setExitNode", map[string]any{"id": "nABC123"}},
|
||||
{"clearExitNode", "tailscale.setExitNode", map[string]any{"id": ""}},
|
||||
{"setAllowLanAccess", "tailscale.setAllowLanAccess", map[string]any{"enabled": true}},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
m := handlerTestManager()
|
||||
defer m.Close()
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
conn := &mockConn{Buffer: buf}
|
||||
|
||||
req := models.Request{ID: 1, Method: tc.method, Params: tc.params}
|
||||
HandleRequest(conn, req, m)
|
||||
|
||||
var resp models.Response[models.SuccessResult]
|
||||
require.NoError(t, json.NewDecoder(buf).Decode(&resp))
|
||||
assert.Equal(t, 1, resp.ID)
|
||||
assert.Empty(t, resp.Error)
|
||||
require.NotNil(t, resp.Result)
|
||||
assert.True(t, resp.Result.Success)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleAction_BackendError(t *testing.T) {
|
||||
client := &mockClient{
|
||||
watchFn: blockingWatch,
|
||||
statusFn: func(ctx context.Context) (*ipnstate.Status, error) { return runningStatus(), nil },
|
||||
editPrefsFn: func(ctx context.Context, mp *ipn.MaskedPrefs) (*ipn.Prefs, error) {
|
||||
return nil, fmt.Errorf("backend rejected edit")
|
||||
},
|
||||
}
|
||||
m := newManager(client)
|
||||
defer m.Close()
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
conn := &mockConn{Buffer: buf}
|
||||
|
||||
req := models.Request{ID: 1, Method: "tailscale.connect"}
|
||||
HandleRequest(conn, req, m)
|
||||
|
||||
var resp models.Response[models.SuccessResult]
|
||||
require.NoError(t, json.NewDecoder(buf).Decode(&resp))
|
||||
assert.Nil(t, resp.Result)
|
||||
assert.Contains(t, resp.Error, "backend rejected edit")
|
||||
}
|
||||
|
||||
func TestHandleRequest_UnknownMethod(t *testing.T) {
|
||||
m := handlerTestManager()
|
||||
defer m.Close()
|
||||
|
||||
Reference in New Issue
Block a user