From 0f03c612d10981f166423487a536cf945b6852a7 Mon Sep 17 00:00:00 2001 From: Viktor Liu Date: Fri, 22 May 2026 12:01:18 +0200 Subject: [PATCH] Lower CreateTemporaryAccess complexity and emit VncAuth for session pubkeys --- .../internals/shared/grpc/conversion.go | 8 +++-- .../http/handlers/peers/peers_handler.go | 31 ++++++++++++------- shared/management/http/api/types.gen.go | 2 +- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/management/internals/shared/grpc/conversion.go b/management/internals/shared/grpc/conversion.go index a33b75d2c..1ecb7306b 100644 --- a/management/internals/shared/grpc/conversion.go +++ b/management/internals/shared/grpc/conversion.go @@ -183,8 +183,12 @@ func ToSyncResponse(ctx context.Context, config *nbconfig.Config, httpConfig *nb response.NetworkMap.SshAuth = &proto.SSHAuth{AuthorizedUsers: hashedUsers, MachineUsers: machineUsers, UserIDClaim: userIDClaim} } - if networkMap.VNCAuthorizedUsers != nil { - hashedUsers, machineUsers := buildAuthorizedUsersProto(ctx, networkMap.VNCAuthorizedUsers) + if networkMap.VNCAuthorizedUsers != nil || len(networkMap.VNCSessionPubKeys) > 0 { + var hashedUsers [][]byte + var machineUsers map[string]*proto.MachineUserIndexes + if networkMap.VNCAuthorizedUsers != nil { + hashedUsers, machineUsers = buildAuthorizedUsersProto(ctx, networkMap.VNCAuthorizedUsers) + } response.NetworkMap.VncAuth = &proto.VNCAuth{ AuthorizedUsers: hashedUsers, MachineUsers: machineUsers, diff --git a/management/server/http/handlers/peers/peers_handler.go b/management/server/http/handlers/peers/peers_handler.go index e6f218f0d..45ec2556c 100644 --- a/management/server/http/handlers/peers/peers_handler.go +++ b/management/server/http/handlers/peers/peers_handler.go @@ -519,20 +519,12 @@ func (h *Handler) CreateTemporaryAccess(w http.ResponseWriter, r *http.Request) policy.Rules[0].AuthorizedUser = userAuth.UserId } if protocol == types.PolicyRuleProtocolNetbirdVNC { - if req.SessionPubKey == nil || *req.SessionPubKey == "" { - util.WriteError(r.Context(), status.Errorf(status.InvalidArgument, "session_pub_key is required for VNC temporary access"), w) - return - } - pub, err := base64.StdEncoding.DecodeString(*req.SessionPubKey) + pubKey, err := validateVNCSessionPubKey(req.SessionPubKey) if err != nil { - util.WriteError(r.Context(), status.Errorf(status.InvalidArgument, "session_pub_key is not valid base64: %v", err), w) + util.WriteError(r.Context(), err, w) return } - if len(pub) != 32 { - util.WriteError(r.Context(), status.Errorf(status.InvalidArgument, "session_pub_key must decode to 32 bytes, got %d", len(pub)), w) - return - } - policy.Rules[0].SessionPubKey = *req.SessionPubKey + policy.Rules[0].SessionPubKey = pubKey } _, err = h.accountManager.SavePolicy(r.Context(), userAuth.AccountId, userAuth.UserId, policy, true) @@ -552,6 +544,23 @@ func (h *Handler) CreateTemporaryAccess(w http.ResponseWriter, r *http.Request) util.WriteJSONObject(r.Context(), w, resp) } +// validateVNCSessionPubKey ensures the request carries a base64-encoded +// 32-byte X25519 public key for VNC temporary access. Returns the original +// base64 string on success. +func validateVNCSessionPubKey(raw *string) (string, error) { + if raw == nil || *raw == "" { + return "", status.Errorf(status.InvalidArgument, "session_pub_key is required for VNC temporary access") + } + pub, err := base64.StdEncoding.DecodeString(*raw) + if err != nil { + return "", status.Errorf(status.InvalidArgument, "session_pub_key is not valid base64: %v", err) + } + if len(pub) != 32 { + return "", status.Errorf(status.InvalidArgument, "session_pub_key must decode to 32 bytes, got %d", len(pub)) + } + return *raw, nil +} + func toAccessiblePeers(netMap *types.NetworkMap, dnsDomain string) []api.AccessiblePeer { accessiblePeers := make([]api.AccessiblePeer, 0, len(netMap.Peers)+len(netMap.OfflinePeers)) for _, p := range netMap.Peers { diff --git a/shared/management/http/api/types.gen.go b/shared/management/http/api/types.gen.go index e7447a7c6..5832be29b 100644 --- a/shared/management/http/api/types.gen.go +++ b/shared/management/http/api/types.gen.go @@ -3391,7 +3391,7 @@ type PeerTemporaryAccessRequest struct { // Rules List of temporary access rules Rules []string `json:"rules"` - // SessionPubKey Ephemeral Ed25519 public key the requester will sign session-binding challenges with. Required for VNC rules; ignored for SSH and L4. + // SessionPubKey Ephemeral base64-encoded X25519 public key used with Noise_IK to bind the VNC session. Required for VNC rules; ignored for SSH and L4. SessionPubKey *string `json:"session_pub_key,omitempty"` // WgPubKey Peer's WireGuard public key