mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-13 00:42:49 -05:00
switch hto monorepo structure
This commit is contained in:
527
backend/internal/server/network/backend_networkmanager_vpn.go
Normal file
527
backend/internal/server/network/backend_networkmanager_vpn.go
Normal file
@@ -0,0 +1,527 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/AvengeMedia/DankMaterialShell/backend/internal/log"
|
||||
"github.com/Wifx/gonetworkmanager/v2"
|
||||
)
|
||||
|
||||
func (b *NetworkManagerBackend) ListVPNProfiles() ([]VPNProfile, error) {
|
||||
s := b.settings
|
||||
if s == nil {
|
||||
var err error
|
||||
s, err = gonetworkmanager.NewSettings()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get settings: %w", err)
|
||||
}
|
||||
b.settings = s
|
||||
}
|
||||
|
||||
settingsMgr := s.(gonetworkmanager.Settings)
|
||||
connections, err := settingsMgr.ListConnections()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get connections: %w", err)
|
||||
}
|
||||
|
||||
var profiles []VPNProfile
|
||||
for _, conn := range connections {
|
||||
settings, err := conn.GetSettings()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
connMeta, ok := settings["connection"]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
connType, _ := connMeta["type"].(string)
|
||||
if connType != "vpn" && connType != "wireguard" {
|
||||
continue
|
||||
}
|
||||
|
||||
connID, _ := connMeta["id"].(string)
|
||||
connUUID, _ := connMeta["uuid"].(string)
|
||||
|
||||
profile := VPNProfile{
|
||||
Name: connID,
|
||||
UUID: connUUID,
|
||||
Type: connType,
|
||||
}
|
||||
|
||||
if connType == "vpn" {
|
||||
if vpnSettings, ok := settings["vpn"]; ok {
|
||||
if svcType, ok := vpnSettings["service-type"].(string); ok {
|
||||
profile.ServiceType = svcType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
profiles = append(profiles, profile)
|
||||
}
|
||||
|
||||
sort.Slice(profiles, func(i, j int) bool {
|
||||
return strings.ToLower(profiles[i].Name) < strings.ToLower(profiles[j].Name)
|
||||
})
|
||||
|
||||
b.stateMutex.Lock()
|
||||
b.state.VPNProfiles = profiles
|
||||
b.stateMutex.Unlock()
|
||||
|
||||
return profiles, nil
|
||||
}
|
||||
|
||||
func (b *NetworkManagerBackend) ListActiveVPN() ([]VPNActive, error) {
|
||||
nm := b.nmConn.(gonetworkmanager.NetworkManager)
|
||||
|
||||
activeConns, err := nm.GetPropertyActiveConnections()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get active connections: %w", err)
|
||||
}
|
||||
|
||||
var active []VPNActive
|
||||
for _, activeConn := range activeConns {
|
||||
connType, err := activeConn.GetPropertyType()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if connType != "vpn" && connType != "wireguard" {
|
||||
continue
|
||||
}
|
||||
|
||||
uuid, _ := activeConn.GetPropertyUUID()
|
||||
id, _ := activeConn.GetPropertyID()
|
||||
state, _ := activeConn.GetPropertyState()
|
||||
|
||||
var stateStr string
|
||||
switch state {
|
||||
case 0:
|
||||
stateStr = "unknown"
|
||||
case 1:
|
||||
stateStr = "activating"
|
||||
case 2:
|
||||
stateStr = "activated"
|
||||
case 3:
|
||||
stateStr = "deactivating"
|
||||
case 4:
|
||||
stateStr = "deactivated"
|
||||
}
|
||||
|
||||
vpnActive := VPNActive{
|
||||
Name: id,
|
||||
UUID: uuid,
|
||||
State: stateStr,
|
||||
Type: connType,
|
||||
Plugin: "",
|
||||
}
|
||||
|
||||
if connType == "vpn" {
|
||||
conn, _ := activeConn.GetPropertyConnection()
|
||||
if conn != nil {
|
||||
connSettings, err := conn.GetSettings()
|
||||
if err == nil {
|
||||
if vpnSettings, ok := connSettings["vpn"]; ok {
|
||||
if svcType, ok := vpnSettings["service-type"].(string); ok {
|
||||
vpnActive.Plugin = svcType
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
active = append(active, vpnActive)
|
||||
}
|
||||
|
||||
b.stateMutex.Lock()
|
||||
b.state.VPNActive = active
|
||||
b.stateMutex.Unlock()
|
||||
|
||||
return active, nil
|
||||
}
|
||||
|
||||
func (b *NetworkManagerBackend) ConnectVPN(uuidOrName string, singleActive bool) error {
|
||||
if singleActive {
|
||||
active, err := b.ListActiveVPN()
|
||||
if err == nil && len(active) > 0 {
|
||||
alreadyConnected := false
|
||||
for _, vpn := range active {
|
||||
if vpn.UUID == uuidOrName || vpn.Name == uuidOrName {
|
||||
alreadyConnected = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !alreadyConnected {
|
||||
if err := b.DisconnectAllVPN(); err != nil {
|
||||
log.Warnf("Failed to disconnect existing VPNs: %v", err)
|
||||
}
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s := b.settings
|
||||
if s == nil {
|
||||
var err error
|
||||
s, err = gonetworkmanager.NewSettings()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get settings: %w", err)
|
||||
}
|
||||
b.settings = s
|
||||
}
|
||||
|
||||
settingsMgr := s.(gonetworkmanager.Settings)
|
||||
connections, err := settingsMgr.ListConnections()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get connections: %w", err)
|
||||
}
|
||||
|
||||
var targetConn gonetworkmanager.Connection
|
||||
for _, conn := range connections {
|
||||
settings, err := conn.GetSettings()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
connMeta, ok := settings["connection"]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
connType, _ := connMeta["type"].(string)
|
||||
if connType != "vpn" && connType != "wireguard" {
|
||||
continue
|
||||
}
|
||||
|
||||
connID, _ := connMeta["id"].(string)
|
||||
connUUID, _ := connMeta["uuid"].(string)
|
||||
|
||||
if connUUID == uuidOrName || connID == uuidOrName {
|
||||
targetConn = conn
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if targetConn == nil {
|
||||
return fmt.Errorf("VPN connection not found: %s", uuidOrName)
|
||||
}
|
||||
|
||||
targetSettings, err := targetConn.GetSettings()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get connection settings: %w", err)
|
||||
}
|
||||
|
||||
var targetUUID string
|
||||
if connMeta, ok := targetSettings["connection"]; ok {
|
||||
if uuid, ok := connMeta["uuid"].(string); ok {
|
||||
targetUUID = uuid
|
||||
}
|
||||
}
|
||||
|
||||
b.stateMutex.Lock()
|
||||
b.state.IsConnectingVPN = true
|
||||
b.state.ConnectingVPNUUID = targetUUID
|
||||
b.stateMutex.Unlock()
|
||||
|
||||
if b.onStateChange != nil {
|
||||
b.onStateChange()
|
||||
}
|
||||
|
||||
nm := b.nmConn.(gonetworkmanager.NetworkManager)
|
||||
activeConn, err := nm.ActivateConnection(targetConn, nil, nil)
|
||||
if err != nil {
|
||||
b.stateMutex.Lock()
|
||||
b.state.IsConnectingVPN = false
|
||||
b.state.ConnectingVPNUUID = ""
|
||||
b.stateMutex.Unlock()
|
||||
|
||||
if b.onStateChange != nil {
|
||||
b.onStateChange()
|
||||
}
|
||||
|
||||
return fmt.Errorf("failed to activate VPN: %w", err)
|
||||
}
|
||||
|
||||
if activeConn != nil {
|
||||
state, _ := activeConn.GetPropertyState()
|
||||
if state == 2 {
|
||||
b.stateMutex.Lock()
|
||||
b.state.IsConnectingVPN = false
|
||||
b.state.ConnectingVPNUUID = ""
|
||||
b.stateMutex.Unlock()
|
||||
b.ListActiveVPN()
|
||||
if b.onStateChange != nil {
|
||||
b.onStateChange()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *NetworkManagerBackend) DisconnectVPN(uuidOrName string) error {
|
||||
nm := b.nmConn.(gonetworkmanager.NetworkManager)
|
||||
|
||||
activeConns, err := nm.GetPropertyActiveConnections()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get active connections: %w", err)
|
||||
}
|
||||
|
||||
log.Debugf("[DisconnectVPN] Looking for VPN: %s", uuidOrName)
|
||||
|
||||
for _, activeConn := range activeConns {
|
||||
connType, err := activeConn.GetPropertyType()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if connType != "vpn" && connType != "wireguard" {
|
||||
continue
|
||||
}
|
||||
|
||||
uuid, _ := activeConn.GetPropertyUUID()
|
||||
id, _ := activeConn.GetPropertyID()
|
||||
state, _ := activeConn.GetPropertyState()
|
||||
|
||||
log.Debugf("[DisconnectVPN] Found active VPN: uuid=%s id=%s state=%d", uuid, id, state)
|
||||
|
||||
if uuid == uuidOrName || id == uuidOrName {
|
||||
log.Infof("[DisconnectVPN] Deactivating VPN: %s (state=%d)", id, state)
|
||||
if err := nm.DeactivateConnection(activeConn); err != nil {
|
||||
return fmt.Errorf("failed to deactivate VPN: %w", err)
|
||||
}
|
||||
b.ListActiveVPN()
|
||||
if b.onStateChange != nil {
|
||||
b.onStateChange()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
log.Warnf("[DisconnectVPN] VPN not found in active connections: %s", uuidOrName)
|
||||
|
||||
s := b.settings
|
||||
if s == nil {
|
||||
var err error
|
||||
s, err = gonetworkmanager.NewSettings()
|
||||
if err != nil {
|
||||
return fmt.Errorf("VPN connection not active and cannot access settings: %w", err)
|
||||
}
|
||||
b.settings = s
|
||||
}
|
||||
|
||||
settingsMgr := s.(gonetworkmanager.Settings)
|
||||
connections, err := settingsMgr.ListConnections()
|
||||
if err != nil {
|
||||
return fmt.Errorf("VPN connection not active: %s", uuidOrName)
|
||||
}
|
||||
|
||||
for _, conn := range connections {
|
||||
settings, err := conn.GetSettings()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
connMeta, ok := settings["connection"]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
connType, _ := connMeta["type"].(string)
|
||||
if connType != "vpn" && connType != "wireguard" {
|
||||
continue
|
||||
}
|
||||
|
||||
connID, _ := connMeta["id"].(string)
|
||||
connUUID, _ := connMeta["uuid"].(string)
|
||||
|
||||
if connUUID == uuidOrName || connID == uuidOrName {
|
||||
log.Infof("[DisconnectVPN] VPN connection exists but not active: %s", connID)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("VPN connection not found: %s", uuidOrName)
|
||||
}
|
||||
|
||||
func (b *NetworkManagerBackend) DisconnectAllVPN() error {
|
||||
nm := b.nmConn.(gonetworkmanager.NetworkManager)
|
||||
|
||||
activeConns, err := nm.GetPropertyActiveConnections()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get active connections: %w", err)
|
||||
}
|
||||
|
||||
var lastErr error
|
||||
var disconnected bool
|
||||
for _, activeConn := range activeConns {
|
||||
connType, err := activeConn.GetPropertyType()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if connType != "vpn" && connType != "wireguard" {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := nm.DeactivateConnection(activeConn); err != nil {
|
||||
lastErr = err
|
||||
log.Warnf("Failed to deactivate VPN connection: %v", err)
|
||||
} else {
|
||||
disconnected = true
|
||||
}
|
||||
}
|
||||
|
||||
if disconnected {
|
||||
b.ListActiveVPN()
|
||||
if b.onStateChange != nil {
|
||||
b.onStateChange()
|
||||
}
|
||||
}
|
||||
|
||||
return lastErr
|
||||
}
|
||||
|
||||
func (b *NetworkManagerBackend) ClearVPNCredentials(uuidOrName string) error {
|
||||
s := b.settings
|
||||
if s == nil {
|
||||
var err error
|
||||
s, err = gonetworkmanager.NewSettings()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get settings: %w", err)
|
||||
}
|
||||
b.settings = s
|
||||
}
|
||||
|
||||
settingsMgr := s.(gonetworkmanager.Settings)
|
||||
connections, err := settingsMgr.ListConnections()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get connections: %w", err)
|
||||
}
|
||||
|
||||
for _, conn := range connections {
|
||||
settings, err := conn.GetSettings()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
connMeta, ok := settings["connection"]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
connType, _ := connMeta["type"].(string)
|
||||
if connType != "vpn" && connType != "wireguard" {
|
||||
continue
|
||||
}
|
||||
|
||||
connID, _ := connMeta["id"].(string)
|
||||
connUUID, _ := connMeta["uuid"].(string)
|
||||
|
||||
if connUUID == uuidOrName || connID == uuidOrName {
|
||||
if connType == "vpn" {
|
||||
if vpnSettings, ok := settings["vpn"]; ok {
|
||||
delete(vpnSettings, "secrets")
|
||||
|
||||
if dataMap, ok := vpnSettings["data"].(map[string]string); ok {
|
||||
dataMap["password-flags"] = "1"
|
||||
vpnSettings["data"] = dataMap
|
||||
}
|
||||
|
||||
vpnSettings["password-flags"] = uint32(1)
|
||||
}
|
||||
|
||||
settings["vpn-secrets"] = make(map[string]interface{})
|
||||
}
|
||||
|
||||
if err := conn.Update(settings); err != nil {
|
||||
return fmt.Errorf("failed to update connection: %w", err)
|
||||
}
|
||||
|
||||
if err := conn.ClearSecrets(); err != nil {
|
||||
log.Warnf("ClearSecrets call failed (may not be critical): %v", err)
|
||||
}
|
||||
|
||||
log.Infof("Cleared credentials for VPN: %s", connID)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("VPN connection not found: %s", uuidOrName)
|
||||
}
|
||||
|
||||
func (b *NetworkManagerBackend) updateVPNConnectionState() {
|
||||
b.stateMutex.RLock()
|
||||
isConnectingVPN := b.state.IsConnectingVPN
|
||||
connectingVPNUUID := b.state.ConnectingVPNUUID
|
||||
b.stateMutex.RUnlock()
|
||||
|
||||
if !isConnectingVPN || connectingVPNUUID == "" {
|
||||
return
|
||||
}
|
||||
|
||||
nm := b.nmConn.(gonetworkmanager.NetworkManager)
|
||||
activeConns, err := nm.GetPropertyActiveConnections()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
foundConnection := false
|
||||
for _, activeConn := range activeConns {
|
||||
connType, err := activeConn.GetPropertyType()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if connType != "vpn" && connType != "wireguard" {
|
||||
continue
|
||||
}
|
||||
|
||||
uuid, err := activeConn.GetPropertyUUID()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
state, _ := activeConn.GetPropertyState()
|
||||
stateReason, _ := activeConn.GetPropertyStateFlags()
|
||||
|
||||
if uuid == connectingVPNUUID {
|
||||
foundConnection = true
|
||||
|
||||
switch state {
|
||||
case 2:
|
||||
log.Infof("[updateVPNConnectionState] VPN connection successful: %s", uuid)
|
||||
b.stateMutex.Lock()
|
||||
b.state.IsConnectingVPN = false
|
||||
b.state.ConnectingVPNUUID = ""
|
||||
b.state.LastError = ""
|
||||
b.stateMutex.Unlock()
|
||||
return
|
||||
case 4:
|
||||
log.Warnf("[updateVPNConnectionState] VPN connection failed/deactivated: %s (state=%d, flags=%d)", uuid, state, stateReason)
|
||||
b.stateMutex.Lock()
|
||||
b.state.IsConnectingVPN = false
|
||||
b.state.ConnectingVPNUUID = ""
|
||||
b.state.LastError = "VPN connection failed"
|
||||
b.stateMutex.Unlock()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !foundConnection {
|
||||
log.Warnf("[updateVPNConnectionState] VPN connection no longer exists: %s", connectingVPNUUID)
|
||||
b.stateMutex.Lock()
|
||||
b.state.IsConnectingVPN = false
|
||||
b.state.ConnectingVPNUUID = ""
|
||||
b.state.LastError = "VPN connection failed"
|
||||
b.stateMutex.Unlock()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user