Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restart norduser/tray when user switches from GUI interface to text only #487

Merged
merged 4 commits into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions cmd/daemon/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ func main() {
log.Fatalln(err)
}

var norduserService norduserservice.NorduserService
var norduserService norduserservice.Service
if snapconf.IsUnderSnap() {
norduserService = norduserservice.NewNorduserSnapService()
} else {
Expand Down Expand Up @@ -488,10 +488,16 @@ func main() {
grpc.Creds(internal.NewUnixSocketCredentials(internal.NewDaemonAuthenticator())),
}

norduserMonitor := norduser.NewNordVPNGroupMonitor(norduserService)
norduserMonitor := norduser.NewNorduserProcessMonitor(norduserService)
go func() {
if err := norduserMonitor.Start(); err != nil {
log.Println("Error when starting norduser monitor: ", err.Error())
if snapconf.IsUnderSnap() {
if err := norduserMonitor.StartSnap(); err != nil {
log.Println(internal.ErrorPrefix, "Error when starting norduser monitor for snap:", err.Error())
}
} else {
if err := norduserMonitor.Start(); err != nil {
log.Println(internal.ErrorPrefix, "Error when starting norduser monitor:", err.Error())
}
}
}()

Expand Down
4 changes: 2 additions & 2 deletions daemon/rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ type RPC struct {
nameservers dns.Getter
ncClient nc.NotificationClient
analytics events.Analytics
norduser service.NorduserService
norduser service.Service
meshRegistry mesh.Registry
systemShutdown atomic.Bool
pb.UnimplementedDaemonServer
Expand All @@ -77,7 +77,7 @@ func NewRPC(
nameservers dns.Getter,
ncClient nc.NotificationClient,
analytics events.Analytics,
norduser service.NorduserService,
norduser service.Service,
meshRegistry mesh.Registry,
) *RPC {
scheduler, _ := gocron.NewScheduler(gocron.WithLocation(time.UTC))
Expand Down
39 changes: 39 additions & 0 deletions norduser/environ.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package norduser

import (
"fmt"
"os"
"strings"
)

func findVariable(name string, environment string) string {
variables := strings.Split(environment, "\000")
for _, variable := range variables {
split := strings.Split(variable, "=")
if len(split) < 1 {
continue
}

if split[0] != name {
continue
}

if len(split) != 2 {
return ""
}

return split[1]
}

return ""
}

func findEnvVariableForPID(pid uint32, name string) (string, error) {
path := fmt.Sprintf("/proc/%d/environ", pid)
environment, err := os.ReadFile(path)
if err != nil {
return "", fmt.Errorf("reading file: %w", err)
}

return findVariable(name, string(environment)), nil
}
55 changes: 55 additions & 0 deletions norduser/environ_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package norduser

import (
"fmt"
"testing"

"github.com/NordSecurity/nordvpn-linux/test/category"
"github.com/stretchr/testify/assert"
)

func Test_findVariable(t *testing.T) {
category.Set(t, category.Unit)

const variable1 string = "VAR_1"
const value1 string = "val_1"

const variable2 string = "VAR_2"
const value2 string = "val_2"

const emptyVariable string = "VAR_3"

environment := fmt.Sprintf("%s=%s\000%s=%s\000%s=",
variable1, value1,
variable2, value2,
emptyVariable)

tests := []struct {
name string
variableName string
expectedValue string
}{
{
name: "normal variable",
variableName: variable1,
expectedValue: value1,
},
{
name: "empty variable",
variableName: emptyVariable,
expectedValue: "",
},
{
name: "variable doesnt exist",
variableName: "NO_VARIABLE",
expectedValue: "",
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
variableValue := findVariable(test.variableName, environment)
assert.Equal(t, test.expectedValue, variableValue)
})
}
}
93 changes: 93 additions & 0 deletions norduser/group.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package norduser

import (
"fmt"
"os/user"
"regexp"
"strconv"
"strings"

"github.com/NordSecurity/nordvpn-linux/internal"
)

func findGroupEntry(groups string, groupName string) string {
r, _ := regexp.Compile(fmt.Sprintf("^%s:", groupName))

for _, groupEntry := range strings.Split(groups, "\n") {
if r.MatchString(groupEntry) {
return groupEntry
}
}

return ""
}

func getGroupEntry(groupName string) (string, error) {
file, err := internal.FileRead(groupFilePath)
if err != nil {
return "", fmt.Errorf("failed to read group file: %w", err)
}

groupEntry := findGroupEntry(string(file), groupName)
if groupEntry == "" {
return "", fmt.Errorf("group entry not found: %w", err)
}

return groupEntry, nil
}

func getGroupMembers(groupEntry string) []string {
groupEntry = strings.TrimSuffix(groupEntry, "\n")
sepIndex := strings.LastIndex(groupEntry, ":")
groupMembers := groupEntry[sepIndex+1:]

if groupMembers == "" {
return []string{}
}

return strings.Split(groupMembers, ",")
}

func getNordVPNGroupMembers() ([]string, error) {
groupEntry, err := getGroupEntry(internal.NordvpnGroup)
if err != nil {
return nil, fmt.Errorf("getting group entry: %w", err)
}

return getGroupMembers(groupEntry), nil
}

type userIDs struct {
uid uint32
gid uint32
home string
}

type userIDGetter interface {
getUserID(username string) (userIDs, error)
}

type osGetter struct{}

func (osGetter) getUserID(username string) (userIDs, error) {
user, err := user.Lookup(username)
if err != nil {
return userIDs{}, fmt.Errorf("looking up user: %w", err)
}

uid, err := strconv.Atoi(user.Uid)
if err != nil {
return userIDs{}, fmt.Errorf("converting uid string to int: %w", err)
}

gid, err := strconv.Atoi(user.Gid)
if err != nil {
return userIDs{}, fmt.Errorf("converting uid string to int: %w", err)
}

return userIDs{
uid: uint32(uid),
gid: uint32(gid),
home: user.HomeDir,
}, nil
}
Loading
Loading