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

LVPN-5407: Change notification settings only for members of the NordVPN group #748

Merged
merged 3 commits into from
Mar 4, 2025
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
2 changes: 0 additions & 2 deletions cli/cli_set_notify.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package cli
import (
"context"
"fmt"
"os"

"github.com/NordSecurity/nordvpn-linux/daemon/pb"
filesharepb "github.com/NordSecurity/nordvpn-linux/fileshare/pb"
Expand All @@ -28,7 +27,6 @@ func (c *cmd) SetNotify(ctx *cli.Context) error {
}

daemonResp, err := c.client.SetNotify(context.Background(), &pb.SetNotifyRequest{
Uid: int64(os.Getuid()),
Notify: flag,
})
if err != nil {
Expand Down
213 changes: 102 additions & 111 deletions daemon/pb/set.pb.go

Large diffs are not rendered by default.

23 changes: 20 additions & 3 deletions daemon/rpc_set_notify.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,32 @@ import (
"github.com/NordSecurity/nordvpn-linux/config"
"github.com/NordSecurity/nordvpn-linux/daemon/pb"
"github.com/NordSecurity/nordvpn-linux/internal"
"google.golang.org/grpc/peer"
)

func (r *RPC) SetNotify(ctx context.Context, in *pb.SetNotifyRequest) (*pb.Payload, error) {
peer, ok := peer.FromContext(ctx)
if !ok {
log.Println(internal.ErrorPrefix, "failed to retrieve gRPC peer information from the context")
return &pb.Payload{
Type: internal.CodeInternalError,
}, nil
}

cred, ok := peer.AuthInfo.(internal.UcredAuth)
if !ok {
log.Println(internal.ErrorPrefix, "failed to extract ucred out of gRPC peer info")
return &pb.Payload{
Type: internal.CodeInternalError,
}, nil
}

var cfg config.Config
if err := r.cm.Load(&cfg); err != nil {
log.Println(internal.ErrorPrefix, err)
}

notifyStatus := !cfg.UsersData.NotifyOff[in.GetUid()]
notifyStatus := !cfg.UsersData.NotifyOff[int64(cred.Uid)]

if in.GetNotify() == notifyStatus {
getBool := func(label bool) string {
Expand All @@ -32,7 +49,7 @@ func (r *RPC) SetNotify(ctx context.Context, in *pb.SetNotifyRequest) (*pb.Paylo

if !in.GetNotify() {
if err := r.cm.SaveWith(func(c config.Config) config.Config {
c.UsersData.NotifyOff[in.GetUid()] = true
c.UsersData.NotifyOff[int64(cred.Uid)] = true
return c
}); err != nil {
log.Println(internal.ErrorPrefix, err)
Expand All @@ -42,7 +59,7 @@ func (r *RPC) SetNotify(ctx context.Context, in *pb.SetNotifyRequest) (*pb.Paylo
}
} else {
if err := r.cm.SaveWith(func(c config.Config) config.Config {
delete(c.UsersData.NotifyOff, in.GetUid())
delete(c.UsersData.NotifyOff, int64(cred.Uid))
return c
}); err != nil {
log.Println(internal.ErrorPrefix, err)
Expand Down
1 change: 1 addition & 0 deletions internal/codes.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const (
CodePqWithoutNordlynx int64 = 3049
CodeFeatureHidden int64 = 3050
CodeTechnologyDisabled int64 = 3051
CodeNotInNordVPNGroup int64 = 3052
)

type ErrorWithCode struct {
Expand Down
36 changes: 36 additions & 0 deletions internal/permissions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package internal

import (
"fmt"
"os/user"
)

var allowedGroups []string = []string{"nordvpn"}
var ErrNoPermission error = fmt.Errorf("requesting user does not have permissions")

// IsInAllowedGroup returns true if user with the given UID is in nordvpn privileged group
func IsInAllowedGroup(uid uint32) (bool, error) {
userInfo, err := user.LookupId(fmt.Sprintf("%d", uid))
if err != nil {
return false, fmt.Errorf("authenticate user, lookup user info: %s", err)
}
// user belongs to the allowed group?
groups, err := userInfo.GroupIds()
if err != nil {
return false, fmt.Errorf("authenticate user, check user groups: %s", err)
}

for _, groupId := range groups {
groupInfo, err := user.LookupGroupId(groupId)
if err != nil {
return false, fmt.Errorf("authenticate user, check user group: %s", err)
}
for _, allowGroupName := range allowedGroups {
if groupInfo.Name == allowGroupName {
return true, nil
}
}
}

return false, nil
}
32 changes: 1 addition & 31 deletions internal/socket.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"fmt"
"net"
"os/user"
"reflect"
"strconv"
"strings"
Expand All @@ -14,35 +13,6 @@ import (
"google.golang.org/grpc/credentials"
)

var allowedGroups []string = []string{"nordvpn"}
var ErrNoPermission error = fmt.Errorf("requesting user does not have permissions")

func isInAllowedGroup(ucred *unix.Ucred) (bool, error) {
userInfo, err := user.LookupId(fmt.Sprintf("%d", ucred.Uid))
if err != nil {
return false, fmt.Errorf("authenticate user, lookup user info: %s", err)
}
// user belongs to the allowed group?
groups, err := userInfo.GroupIds()
if err != nil {
return false, fmt.Errorf("authenticate user, check user groups: %s", err)
}

for _, groupId := range groups {
groupInfo, err := user.LookupGroupId(groupId)
if err != nil {
return false, fmt.Errorf("authenticate user, check user group: %s", err)
}
for _, allowGroupName := range allowedGroups {
if groupInfo.Name == allowGroupName {
return true, nil
}
}
}

return false, nil
}

// getUnixCreds returns info from unix socket connection about the process on the other end.
func getUnixCreds(conn net.Conn, authenticator SocketAuthenticator) (*unix.Ucred, error) {
conn2 := extractConnection(conn)
Expand Down Expand Up @@ -96,7 +66,7 @@ func (DaemonAuthenticator) Authenticate(ucred *unix.Ucred) error {
return nil
}

isGroup, err := isInAllowedGroup(ucred)
isGroup, err := IsInAllowedGroup(ucred.Uid)
if err != nil {
return err
}
Expand Down
1 change: 0 additions & 1 deletion protobuf/daemon/set.proto
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ message SetKillSwitchRequest {
}

message SetNotifyRequest {
int64 uid = 2;
bool notify = 3;
}

Expand Down
64 changes: 32 additions & 32 deletions test/qa/lib/protobuf/daemon/set_pb2.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 2 additions & 4 deletions test/qa/lib/protobuf/daemon/set_pb2.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,10 @@ class SetKillSwitchRequest(_message.Message):
def __init__(self, kill_switch: bool = ...) -> None: ...

class SetNotifyRequest(_message.Message):
__slots__ = ("uid", "notify")
UID_FIELD_NUMBER: _ClassVar[int]
__slots__ = ("notify",)
NOTIFY_FIELD_NUMBER: _ClassVar[int]
uid: int
notify: bool
def __init__(self, uid: _Optional[int] = ..., notify: bool = ...) -> None: ...
def __init__(self, notify: bool = ...) -> None: ...

class SetTrayRequest(_message.Message):
__slots__ = ("uid", "tray")
Expand Down
1 change: 0 additions & 1 deletion tray/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,6 @@ func (ti *Instance) setNotify(flag bool) bool {
flagText = "on"
}
resp, err := ti.client.SetNotify(context.Background(), &pb.SetNotifyRequest{
Uid: int64(os.Getuid()),
Notify: flag,
})
if err != nil {
Expand Down
Loading