Group Mullvad exit nodes by country

This commit is contained in:
David Heinemeier Hansson
2026-05-28 21:21:33 +02:00
parent 007393387a
commit d3666c5e98
4 changed files with 382 additions and 15 deletions
+36 -2
View File
@@ -21,6 +21,9 @@ Item {
property string authUrl: ""
property var peers: []
property var exitNodes: []
property var tailnetExitNodes: []
property var mullvadExitNodes: []
property var mullvadCountries: []
property var accounts: []
property string selectedAccountId: ""
property string selectedAccountLabel: ""
@@ -31,13 +34,15 @@ Item {
property string lastError: ""
readonly property int refreshIntervalSec: intSetting("refreshIntervalSec", 30, 5, 3600)
readonly property bool busy: whichProcess.running || statusProcess.running || accountsProcess.running || actionProcess.running || loginProcess.running || switchProcess.running || operatorProcess.running || exitNodeProcess.running
readonly property bool busy: whichProcess.running || statusProcess.running || mullvadExitNodesProcess.running || accountsProcess.running || actionProcess.running || loginProcess.running || switchProcess.running || operatorProcess.running || exitNodeProcess.running
readonly property string userName: Quickshell.env("USER") || Quickshell.env("LOGNAME")
property string _statusOutput: ""
property string _statusError: ""
property string _accountsOutput: ""
property string _accountsError: ""
property string _mullvadExitNodesOutput: ""
property string _mullvadExitNodesError: ""
property string _actionOutput: ""
property string _actionError: ""
property string _loginOutput: ""
@@ -133,6 +138,12 @@ Item {
statusProcess.command = ["tailscale", "status", "--json"]
statusProcess.running = true
}
if (!mullvadExitNodesProcess.running) {
_mullvadExitNodesOutput = ""
_mullvadExitNodesError = ""
mullvadExitNodesProcess.command = ["tailscale", "exit-node", "list"]
mullvadExitNodesProcess.running = true
}
var now = Date.now()
var shouldRefreshAccounts = forceAccounts === true || accounts.length === 0 || now - _lastAccountsRefreshMs > 60000
if (shouldRefreshAccounts && !accountsProcess.running) {
@@ -160,6 +171,9 @@ Item {
authUrl = ""
peers = []
exitNodes = []
tailnetExitNodes = []
mullvadExitNodes = []
mullvadCountries = []
accounts = []
selectedAccountId = ""
selectedAccountLabel = ""
@@ -190,7 +204,8 @@ Item {
selfDnsName = parsed.selfDnsName
selfIp = parsed.selfIp
peers = parsed.running ? parsed.peers : []
exitNodes = parsed.running ? parsed.exitNodes : []
tailnetExitNodes = parsed.running ? parsed.exitNodes : []
exitNodes = parsed.running ? tailnetExitNodes.concat(mullvadCountries) : []
if (needsLogin) statusText = "Needs login"
else if (running) {
@@ -215,6 +230,12 @@ Item {
accountsAccessDenied = false
}
function parseMullvadExitNodes(raw) {
mullvadExitNodes = Model.parseExitNodeList(raw)
mullvadCountries = Model.mullvadCountryOptions(mullvadExitNodes)
exitNodes = running ? tailnetExitNodes.concat(mullvadCountries) : []
}
function toggleTailscale() {
if (!installed) return
if (running) runAction(["tailscale", "down"], "Turning Tailscale off…")
@@ -397,6 +418,19 @@ Item {
}
}
Process {
id: mullvadExitNodesProcess
running: false
command: []
stdout: StdioCollector { id: mullvadExitNodesStdout; waitForEnd: true; onStreamFinished: root._mullvadExitNodesOutput = text }
stderr: StdioCollector { id: mullvadExitNodesStderr; waitForEnd: true; onStreamFinished: root._mullvadExitNodesError = text }
onExited: function(exitCode) {
var stdout = String(mullvadExitNodesStdout.text || root._mullvadExitNodesOutput || "")
if (exitCode === 0) root.parseMullvadExitNodes(stdout)
else root.parseMullvadExitNodes("")
}
}
Process {
id: actionProcess
running: false