mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-16 07:16:38 +00:00
[client,signal,management] Add browser client support (#4415)
This commit is contained in:
@@ -18,6 +18,7 @@ import (
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"github.com/netbirdio/management-integrations/integrations"
|
||||
|
||||
"github.com/netbirdio/netbird/client/system"
|
||||
"github.com/netbirdio/netbird/encryption"
|
||||
"github.com/netbirdio/netbird/management/internals/server/config"
|
||||
@@ -27,6 +28,7 @@ import (
|
||||
"github.com/netbirdio/netbird/management/server/integrations/port_forwarding"
|
||||
"github.com/netbirdio/netbird/management/server/mock_server"
|
||||
"github.com/netbirdio/netbird/management/server/peers"
|
||||
"github.com/netbirdio/netbird/management/server/peers/ephemeral/manager"
|
||||
"github.com/netbirdio/netbird/management/server/permissions"
|
||||
"github.com/netbirdio/netbird/management/server/settings"
|
||||
"github.com/netbirdio/netbird/management/server/store"
|
||||
@@ -117,7 +119,7 @@ func startManagement(t *testing.T) (*grpc.Server, net.Listener) {
|
||||
groupsManager := groups.NewManagerMock()
|
||||
|
||||
secretsManager := mgmt.NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig, config.Relay, settingsMockManager, groupsManager)
|
||||
mgmtServer, err := mgmt.NewServer(context.Background(), config, accountManager, settingsMockManager, peersUpdateManager, secretsManager, nil, nil, nil, mgmt.MockIntegratedValidator{})
|
||||
mgmtServer, err := mgmt.NewServer(context.Background(), config, accountManager, settingsMockManager, peersUpdateManager, secretsManager, nil, &manager.EphemeralManager{}, nil, mgmt.MockIntegratedValidator{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -507,6 +507,48 @@ components:
|
||||
- serial_number
|
||||
- extra_dns_labels
|
||||
- ephemeral
|
||||
PeerTemporaryAccessRequest:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
description: Peer's hostname
|
||||
type: string
|
||||
example: temp-host-1
|
||||
wg_pub_key:
|
||||
description: Peer's WireGuard public key
|
||||
type: string
|
||||
example: "n0r3pL4c3h0ld3rK3y=="
|
||||
rules:
|
||||
description: List of temporary access rules
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
example: "tcp/80"
|
||||
required:
|
||||
- name
|
||||
- wg_pub_key
|
||||
- rules
|
||||
PeerTemporaryAccessResponse:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
description: Peer's hostname
|
||||
type: string
|
||||
example: temp-host-1
|
||||
id:
|
||||
description: Peer ID
|
||||
type: string
|
||||
example: chacbco6lnnbn6cg5s90
|
||||
rules:
|
||||
description: List of temporary access rules
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
example: "tcp/80"
|
||||
required:
|
||||
- name
|
||||
- id
|
||||
- rules
|
||||
AccessiblePeer:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/PeerMinimum'
|
||||
@@ -1404,7 +1446,8 @@ components:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/NetworkResourceType'
|
||||
- type: string
|
||||
example: host
|
||||
enum: ["peer"]
|
||||
example: peer
|
||||
NetworkRequest:
|
||||
type: object
|
||||
properties:
|
||||
@@ -2793,6 +2836,42 @@ paths:
|
||||
"$ref": "#/components/responses/forbidden"
|
||||
'500':
|
||||
"$ref": "#/components/responses/internal_error"
|
||||
/api/peers/{peerId}/temporary-access:
|
||||
post:
|
||||
summary: Create a Temporary Access Peer
|
||||
description: Creates a temporary access peer that can be used to access this peer and this peer only. The temporary access peer and its access policies will be automatically deleted after it disconnects.
|
||||
tags: [ Peers ]
|
||||
security:
|
||||
- BearerAuth: [ ]
|
||||
- TokenAuth: [ ]
|
||||
parameters:
|
||||
- in: path
|
||||
name: peerId
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
description: The unique identifier of a peer
|
||||
requestBody:
|
||||
description: Temporary Access Peer create request
|
||||
content:
|
||||
'application/json':
|
||||
schema:
|
||||
$ref: '#/components/schemas/PeerTemporaryAccessRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: Temporary Access Peer response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PeerTemporaryAccessResponse'
|
||||
'400':
|
||||
"$ref": "#/components/responses/bad_request"
|
||||
'401':
|
||||
"$ref": "#/components/responses/requires_authentication"
|
||||
'403':
|
||||
"$ref": "#/components/responses/forbidden"
|
||||
'500':
|
||||
"$ref": "#/components/responses/internal_error"
|
||||
/api/peers/{peerId}/ingress/ports:
|
||||
get:
|
||||
x-cloud-only: true
|
||||
|
||||
@@ -168,6 +168,7 @@ const (
|
||||
const (
|
||||
ResourceTypeDomain ResourceType = "domain"
|
||||
ResourceTypeHost ResourceType = "host"
|
||||
ResourceTypePeer ResourceType = "peer"
|
||||
ResourceTypeSubnet ResourceType = "subnet"
|
||||
)
|
||||
|
||||
@@ -1221,6 +1222,30 @@ type PeerRequest struct {
|
||||
SshEnabled bool `json:"ssh_enabled"`
|
||||
}
|
||||
|
||||
// PeerTemporaryAccessRequest defines model for PeerTemporaryAccessRequest.
|
||||
type PeerTemporaryAccessRequest struct {
|
||||
// Name Peer's hostname
|
||||
Name string `json:"name"`
|
||||
|
||||
// Rules List of temporary access rules
|
||||
Rules []string `json:"rules"`
|
||||
|
||||
// WgPubKey Peer's WireGuard public key
|
||||
WgPubKey string `json:"wg_pub_key"`
|
||||
}
|
||||
|
||||
// PeerTemporaryAccessResponse defines model for PeerTemporaryAccessResponse.
|
||||
type PeerTemporaryAccessResponse struct {
|
||||
// Id Peer ID
|
||||
Id string `json:"id"`
|
||||
|
||||
// Name Peer's hostname
|
||||
Name string `json:"name"`
|
||||
|
||||
// Rules List of temporary access rules
|
||||
Rules []string `json:"rules"`
|
||||
}
|
||||
|
||||
// PersonalAccessToken defines model for PersonalAccessToken.
|
||||
type PersonalAccessToken struct {
|
||||
// CreatedAt Date the token was created
|
||||
@@ -1949,6 +1974,9 @@ type PostApiPeersPeerIdIngressPortsJSONRequestBody = IngressPortAllocationReques
|
||||
// PutApiPeersPeerIdIngressPortsAllocationIdJSONRequestBody defines body for PutApiPeersPeerIdIngressPortsAllocationId for application/json ContentType.
|
||||
type PutApiPeersPeerIdIngressPortsAllocationIdJSONRequestBody = IngressPortAllocationRequest
|
||||
|
||||
// PostApiPeersPeerIdTemporaryAccessJSONRequestBody defines body for PostApiPeersPeerIdTemporaryAccess for application/json ContentType.
|
||||
type PostApiPeersPeerIdTemporaryAccessJSONRequestBody = PeerTemporaryAccessRequest
|
||||
|
||||
// PostApiPoliciesJSONRequestBody defines body for PostApiPolicies for application/json ContentType.
|
||||
type PostApiPoliciesJSONRequestBody = PolicyUpdate
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v4.24.3
|
||||
// protoc v6.32.0
|
||||
// source: management.proto
|
||||
|
||||
package proto
|
||||
|
||||
@@ -9,11 +9,8 @@ import (
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/netbirdio/netbird/client/iface"
|
||||
auth "github.com/netbirdio/netbird/shared/relay/auth/hmac"
|
||||
"github.com/netbirdio/netbird/shared/relay/client/dialer"
|
||||
"github.com/netbirdio/netbird/shared/relay/client/dialer/quic"
|
||||
"github.com/netbirdio/netbird/shared/relay/client/dialer/ws"
|
||||
"github.com/netbirdio/netbird/shared/relay/healthcheck"
|
||||
"github.com/netbirdio/netbird/shared/relay/messages"
|
||||
)
|
||||
@@ -296,14 +293,7 @@ func (c *Client) Close() error {
|
||||
}
|
||||
|
||||
func (c *Client) connect(ctx context.Context) (*RelayAddr, error) {
|
||||
// Force WebSocket for MTUs larger than default to avoid QUIC DATAGRAM frame size issues
|
||||
var dialers []dialer.DialeFn
|
||||
if c.mtu > 0 && c.mtu > iface.DefaultMTU {
|
||||
c.log.Infof("MTU %d exceeds default (%d), forcing WebSocket transport to avoid DATAGRAM frame size issues", c.mtu, iface.DefaultMTU)
|
||||
dialers = []dialer.DialeFn{ws.Dialer{}}
|
||||
} else {
|
||||
dialers = []dialer.DialeFn{quic.Dialer{}, ws.Dialer{}}
|
||||
}
|
||||
dialers := c.getDialers()
|
||||
|
||||
rd := dialer.NewRaceDial(c.log, dialer.DefaultConnectionTimeout, c.connectionURL, dialers...)
|
||||
conn, err := rd.Dial()
|
||||
|
||||
@@ -38,8 +38,7 @@ func (c *Conn) Read(b []byte) (n int, err error) {
|
||||
}
|
||||
|
||||
func (c *Conn) Write(b []byte) (n int, err error) {
|
||||
err = c.Conn.Write(c.ctx, websocket.MessageBinary, b)
|
||||
return 0, err
|
||||
return 0, c.Conn.Write(c.ctx, websocket.MessageBinary, b)
|
||||
}
|
||||
|
||||
func (c *Conn) RemoteAddr() net.Addr {
|
||||
|
||||
11
shared/relay/client/dialer/ws/dialopts_generic.go
Normal file
11
shared/relay/client/dialer/ws/dialopts_generic.go
Normal file
@@ -0,0 +1,11 @@
|
||||
//go:build !js
|
||||
|
||||
package ws
|
||||
|
||||
import "github.com/coder/websocket"
|
||||
|
||||
func createDialOptions() *websocket.DialOptions {
|
||||
return &websocket.DialOptions{
|
||||
HTTPClient: httpClientNbDialer(),
|
||||
}
|
||||
}
|
||||
10
shared/relay/client/dialer/ws/dialopts_js.go
Normal file
10
shared/relay/client/dialer/ws/dialopts_js.go
Normal file
@@ -0,0 +1,10 @@
|
||||
//go:build js
|
||||
|
||||
package ws
|
||||
|
||||
import "github.com/coder/websocket"
|
||||
|
||||
func createDialOptions() *websocket.DialOptions {
|
||||
// WASM version doesn't support HTTPClient
|
||||
return &websocket.DialOptions{}
|
||||
}
|
||||
@@ -32,9 +32,7 @@ func (d Dialer) Dial(ctx context.Context, address string) (net.Conn, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
opts := &websocket.DialOptions{
|
||||
HTTPClient: httpClientNbDialer(),
|
||||
}
|
||||
opts := createDialOptions()
|
||||
|
||||
parsedURL, err := url.Parse(wsURL)
|
||||
if err != nil {
|
||||
|
||||
19
shared/relay/client/dialers_generic.go
Normal file
19
shared/relay/client/dialers_generic.go
Normal file
@@ -0,0 +1,19 @@
|
||||
//go:build !js
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"github.com/netbirdio/netbird/client/iface"
|
||||
"github.com/netbirdio/netbird/shared/relay/client/dialer"
|
||||
"github.com/netbirdio/netbird/shared/relay/client/dialer/quic"
|
||||
"github.com/netbirdio/netbird/shared/relay/client/dialer/ws"
|
||||
)
|
||||
|
||||
// getDialers returns the list of dialers to use for connecting to the relay server.
|
||||
func (c *Client) getDialers() []dialer.DialeFn {
|
||||
if c.mtu > 0 && c.mtu > iface.DefaultMTU {
|
||||
c.log.Infof("MTU %d exceeds default (%d), forcing WebSocket transport to avoid DATAGRAM frame size issues", c.mtu, iface.DefaultMTU)
|
||||
return []dialer.DialeFn{ws.Dialer{}}
|
||||
}
|
||||
return []dialer.DialeFn{quic.Dialer{}, ws.Dialer{}}
|
||||
}
|
||||
13
shared/relay/client/dialers_js.go
Normal file
13
shared/relay/client/dialers_js.go
Normal file
@@ -0,0 +1,13 @@
|
||||
//go:build js
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"github.com/netbirdio/netbird/shared/relay/client/dialer"
|
||||
"github.com/netbirdio/netbird/shared/relay/client/dialer/ws"
|
||||
)
|
||||
|
||||
func (c *Client) getDialers() []dialer.DialeFn {
|
||||
// JS/WASM build only uses WebSocket transport
|
||||
return []dialer.DialeFn{ws.Dialer{}}
|
||||
}
|
||||
Reference in New Issue
Block a user