mirror of
https://github.com/netbirdio/netbird.git
synced 2026-07-19 06:59:56 +02:00
Merge branch 'main' into userspace-router
This commit is contained in:
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -12,7 +12,7 @@ env:
|
||||
SIGN_PIPE_VER: "v0.0.18"
|
||||
GORELEASER_VER: "v2.3.2"
|
||||
PRODUCT_NAME: "NetBird"
|
||||
COPYRIGHT: "Wiretrustee UG (haftungsbeschreankt)"
|
||||
COPYRIGHT: "NetBird GmbH"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.head_ref || github.actor_id }}
|
||||
|
||||
2
AUTHORS
2
AUTHORS
@@ -1,3 +1,3 @@
|
||||
Mikhail Bragin (https://github.com/braginini)
|
||||
Maycon Santos (https://github.com/mlsmaycon)
|
||||
Wiretrustee UG (haftungsbeschränkt)
|
||||
NetBird GmbH
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
We are incredibly thankful for the contributions we receive from the community.
|
||||
We require our external contributors to sign a Contributor License Agreement ("CLA") in
|
||||
order to ensure that our projects remain licensed under Free and Open Source licenses such
|
||||
as BSD-3 while allowing Wiretrustee to build a sustainable business.
|
||||
as BSD-3 while allowing NetBird to build a sustainable business.
|
||||
|
||||
Wiretrustee is committed to having a true Open Source Software ("OSS") license for
|
||||
our software. A CLA enables Wiretrustee to safely commercialize our products
|
||||
NetBird is committed to having a true Open Source Software ("OSS") license for
|
||||
our software. A CLA enables NetBird to safely commercialize our products
|
||||
while keeping a standard OSS license with all the rights that license grants to users: the
|
||||
ability to use the project in their own projects or businesses, to republish modified
|
||||
source, or to completely fork the project.
|
||||
@@ -20,11 +20,11 @@ This is a human-readable summary of (and not a substitute for) the full agreemen
|
||||
This highlights only some of key terms of the CLA. It has no legal value and you should
|
||||
carefully review all the terms of the actual CLA before agreeing.
|
||||
|
||||
<li>Grant of copyright license. You give Wiretrustee permission to use your copyrighted work
|
||||
<li>Grant of copyright license. You give NetBird permission to use your copyrighted work
|
||||
in commercial products.
|
||||
</li>
|
||||
|
||||
<li>Grant of patent license. If your contributed work uses a patent, you give Wiretrustee a
|
||||
<li>Grant of patent license. If your contributed work uses a patent, you give NetBird a
|
||||
license to use that patent including within commercial products. You also agree that you
|
||||
have permission to grant this license.
|
||||
</li>
|
||||
@@ -45,7 +45,7 @@ more.
|
||||
# Why require a CLA?
|
||||
|
||||
Agreeing to a CLA explicitly states that you are entitled to provide a contribution, that you cannot withdraw permission
|
||||
to use your contribution at a later date, and that Wiretrustee has permission to use your contribution in our commercial
|
||||
to use your contribution at a later date, and that NetBird has permission to use your contribution in our commercial
|
||||
products.
|
||||
|
||||
This removes any ambiguities or uncertainties caused by not having a CLA and allows users and customers to confidently
|
||||
@@ -65,25 +65,25 @@ Follow the steps given by the bot to sign the CLA. This will require you to log
|
||||
information from your account) and to fill in a few additional details such as your name and email address. We will only
|
||||
use this information for CLA tracking; none of your submitted information will be used for marketing purposes.
|
||||
|
||||
You only have to sign the CLA once. Once you've signed the CLA, future contributions to any Wiretrustee project will not
|
||||
You only have to sign the CLA once. Once you've signed the CLA, future contributions to any NetBird project will not
|
||||
require you to sign again.
|
||||
|
||||
# Legal Terms and Agreement
|
||||
|
||||
In order to clarify the intellectual property license granted with Contributions from any person or entity, Wiretrustee
|
||||
UG (haftungsbeschränkt) ("Wiretrustee") must have a Contributor License Agreement ("CLA") on file that has been signed
|
||||
In order to clarify the intellectual property license granted with Contributions from any person or entity, NetBird
|
||||
GmbH ("NetBird") must have a Contributor License Agreement ("CLA") on file that has been signed
|
||||
by each Contributor, indicating agreement to the license terms below. This license does not change your rights to use
|
||||
your own Contributions for any other purpose.
|
||||
|
||||
You accept and agree to the following terms and conditions for Your present and future Contributions submitted to
|
||||
Wiretrustee. Except for the license granted herein to Wiretrustee and recipients of software distributed by Wiretrustee,
|
||||
NetBird. Except for the license granted herein to NetBird and recipients of software distributed by NetBird,
|
||||
You reserve all right, title, and interest in and to Your Contributions.
|
||||
|
||||
1. Definitions.
|
||||
|
||||
```
|
||||
"You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner
|
||||
that is making this Agreement with Wiretrustee. For legal entities, the entity making a Contribution and all other
|
||||
that is making this Agreement with NetBird. For legal entities, the entity making a Contribution and all other
|
||||
entities that control, are controlled by, or are under common control with that entity are considered
|
||||
to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect,
|
||||
to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty
|
||||
@@ -91,23 +91,23 @@ You reserve all right, title, and interest in and to Your Contributions.
|
||||
```
|
||||
```
|
||||
"Contribution" shall mean any original work of authorship, including any modifications or additions to
|
||||
an existing work, that is or previously has been intentionally submitted by You to Wiretrustee for inclusion in,
|
||||
or documentation of, any of the products owned or managed by Wiretrustee (the "Work").
|
||||
an existing work, that is or previously has been intentionally submitted by You to NetBird for inclusion in,
|
||||
or documentation of, any of the products owned or managed by NetBird (the "Work").
|
||||
For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication
|
||||
sent to Wiretrustee or its representatives, including but not limited to communication on electronic mailing lists,
|
||||
sent to NetBird or its representatives, including but not limited to communication on electronic mailing lists,
|
||||
source code control systems, and issue tracking systems that are managed by, or on behalf of,
|
||||
Wiretrustee for the purpose of discussing and improving the Work, but excluding communication that is conspicuously
|
||||
NetBird for the purpose of discussing and improving the Work, but excluding communication that is conspicuously
|
||||
marked or otherwise designated in writing by You as "Not a Contribution."
|
||||
```
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to Wiretrustee
|
||||
and to recipients of software distributed by Wiretrustee a perpetual, worldwide, non-exclusive, no-charge,
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to NetBird
|
||||
and to recipients of software distributed by NetBird a perpetual, worldwide, non-exclusive, no-charge,
|
||||
royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly
|
||||
perform, sublicense, and distribute Your Contributions and such derivative works.
|
||||
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to Wiretrustee and
|
||||
to recipients of software distributed by Wiretrustee a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
3. Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to NetBird and
|
||||
to recipients of software distributed by NetBird a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import,
|
||||
and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are
|
||||
necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which
|
||||
@@ -121,8 +121,8 @@ You reserve all right, title, and interest in and to Your Contributions.
|
||||
intellectual property that you create that includes your Contributions, you represent that you have received
|
||||
permission to make Contributions on behalf of that employer, that you will have received permission from your current
|
||||
and future employers for all future Contributions, that your applicable employer has waived such rights for all of
|
||||
your current and future Contributions to Wiretrustee, or that your employer has executed a separate Corporate CLA
|
||||
with Wiretrustee.
|
||||
your current and future Contributions to NetBird, or that your employer has executed a separate Corporate CLA
|
||||
with NetBird.
|
||||
|
||||
|
||||
5. You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of
|
||||
@@ -138,11 +138,11 @@ You reserve all right, title, and interest in and to Your Contributions.
|
||||
MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
|
||||
7. Should You wish to submit work that is not Your original creation, You may submit it to Wiretrustee separately from
|
||||
7. Should You wish to submit work that is not Your original creation, You may submit it to NetBird separately from
|
||||
any Contribution, identifying the complete details of its source and of any license or other restriction (including,
|
||||
but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and
|
||||
conspicuously marking the work as "Submitted on behalf of a third-party: [named here]".
|
||||
|
||||
|
||||
8. You agree to notify Wiretrustee of any facts or circumstances of which you become aware that would make these
|
||||
representations inaccurate in any respect.
|
||||
8. You agree to notify NetBird of any facts or circumstances of which you become aware that would make these
|
||||
representations inaccurate in any respect.
|
||||
|
||||
4
LICENSE
4
LICENSE
@@ -1,6 +1,6 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2022 Wiretrustee UG (haftungsbeschränkt) & AUTHORS
|
||||
Copyright (c) 2022 NetBird GmbH & AUTHORS
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
@@ -10,4 +10,4 @@ Redistribution and use in source and binary forms, with or without modification,
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
package configurer
|
||||
|
||||
// WgInterfaceDefault is a default interface name of Wiretrustee
|
||||
// WgInterfaceDefault is a default interface name of Netbird
|
||||
const WgInterfaceDefault = "wt0"
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
package configurer
|
||||
|
||||
// WgInterfaceDefault is a default interface name of Wiretrustee
|
||||
// WgInterfaceDefault is a default interface name of Netbird
|
||||
const WgInterfaceDefault = "utun100"
|
||||
|
||||
@@ -63,7 +63,7 @@ func (t *WGTunDevice) Create(routes []string, dns string, searchDomains []string
|
||||
t.filteredDevice = newDeviceFilter(tunDevice)
|
||||
|
||||
log.Debugf("attaching to interface %v", name)
|
||||
t.device = device.NewDevice(t.filteredDevice, t.iceBind, device.NewLogger(wgLogLevel(), "[wiretrustee] "))
|
||||
t.device = device.NewDevice(t.filteredDevice, t.iceBind, device.NewLogger(wgLogLevel(), "[netbird] "))
|
||||
// without this property mobile devices can discover remote endpoints if the configured one was wrong.
|
||||
// this helps with support for the older NetBird clients that had a hardcoded direct mode
|
||||
// t.device.DisableSomeRoamingForBrokenMobileSemantics()
|
||||
|
||||
@@ -64,7 +64,7 @@ func (t *TunDevice) Create() (WGConfigurer, error) {
|
||||
|
||||
t.filteredDevice = newDeviceFilter(tunDevice)
|
||||
log.Debug("Attaching to interface")
|
||||
t.device = device.NewDevice(t.filteredDevice, t.iceBind, device.NewLogger(wgLogLevel(), "[wiretrustee] "))
|
||||
t.device = device.NewDevice(t.filteredDevice, t.iceBind, device.NewLogger(wgLogLevel(), "[netbird] "))
|
||||
// without this property mobile devices can discover remote endpoints if the configured one was wrong.
|
||||
// this helps with support for the older NetBird clients that had a hardcoded direct mode
|
||||
// t.device.DisableSomeRoamingForBrokenMobileSemantics()
|
||||
|
||||
@@ -268,7 +268,7 @@ func (d *DefaultManager) protoRuleToFirewallRule(
|
||||
}
|
||||
|
||||
var port *firewall.Port
|
||||
if r.PortInfo != nil {
|
||||
if !portInfoEmpty(r.PortInfo) {
|
||||
port = convertPortInfo(r.PortInfo)
|
||||
} else if r.Port != "" {
|
||||
// old version of management, single port
|
||||
@@ -305,6 +305,22 @@ func (d *DefaultManager) protoRuleToFirewallRule(
|
||||
return ruleID, rules, nil
|
||||
}
|
||||
|
||||
func portInfoEmpty(portInfo *mgmProto.PortInfo) bool {
|
||||
if portInfo == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
switch portInfo.GetPortSelection().(type) {
|
||||
case *mgmProto.PortInfo_Port:
|
||||
return portInfo.GetPort() == 0
|
||||
case *mgmProto.PortInfo_Range_:
|
||||
r := portInfo.GetRange()
|
||||
return r == nil || r.Start == 0 || r.End == 0
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DefaultManager) addInRules(
|
||||
ip net.IP,
|
||||
protocol firewall.Protocol,
|
||||
@@ -491,7 +507,7 @@ func (d *DefaultManager) squashAcceptRules(
|
||||
|
||||
// getRuleGroupingSelector takes all rule properties except IP address to build selector
|
||||
func (d *DefaultManager) getRuleGroupingSelector(rule *mgmProto.FirewallRule) string {
|
||||
return fmt.Sprintf("%v:%v:%v:%s", strconv.Itoa(int(rule.Direction)), rule.Action, rule.Protocol, rule.Port)
|
||||
return fmt.Sprintf("%v:%v:%v:%s:%v", strconv.Itoa(int(rule.Direction)), rule.Action, rule.Protocol, rule.Port, rule.PortInfo)
|
||||
}
|
||||
|
||||
func (d *DefaultManager) rollBack(newRulePairs map[id.RuleID][]firewall.Rule) {
|
||||
|
||||
@@ -2,6 +2,8 @@ package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -11,7 +13,10 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/netbirdio/netbird/client/internal"
|
||||
"github.com/netbirdio/netbird/util/embeddedroots"
|
||||
)
|
||||
|
||||
// HostedGrantType grant type for device flow on Hosted
|
||||
@@ -56,6 +61,18 @@ func NewDeviceAuthorizationFlow(config internal.DeviceAuthProviderConfig) (*Devi
|
||||
httpTransport := http.DefaultTransport.(*http.Transport).Clone()
|
||||
httpTransport.MaxIdleConns = 5
|
||||
|
||||
certPool, err := x509.SystemCertPool()
|
||||
if err != nil || certPool == nil {
|
||||
log.Debugf("System cert pool not available; falling back to embedded cert, error: %v", err)
|
||||
certPool = embeddedroots.Get()
|
||||
} else {
|
||||
log.Debug("Using system certificate pool.")
|
||||
}
|
||||
|
||||
httpTransport.TLSClientConfig = &tls.Config{
|
||||
RootCAs: certPool,
|
||||
}
|
||||
|
||||
httpClient := &http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
Transport: httpTransport,
|
||||
|
||||
@@ -177,7 +177,7 @@ func (c *ConnectClient) run(mobileDependency MobileDependency, runningChan chan
|
||||
}
|
||||
}()
|
||||
|
||||
// connect (just a connection, no stream yet) and login to Management Service to get an initial global Wiretrustee config
|
||||
// connect (just a connection, no stream yet) and login to Management Service to get an initial global Netbird config
|
||||
loginResp, err := loginToManagement(engineCtx, mgmClient, publicSSHKey, c.config)
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
@@ -199,8 +199,8 @@ func (c *ConnectClient) run(mobileDependency MobileDependency, runningChan chan
|
||||
c.statusRecorder.UpdateLocalPeerState(localPeerState)
|
||||
|
||||
signalURL := fmt.Sprintf("%s://%s",
|
||||
strings.ToLower(loginResp.GetWiretrusteeConfig().GetSignal().GetProtocol().String()),
|
||||
loginResp.GetWiretrusteeConfig().GetSignal().GetUri(),
|
||||
strings.ToLower(loginResp.GetNetbirdConfig().GetSignal().GetProtocol().String()),
|
||||
loginResp.GetNetbirdConfig().GetSignal().GetUri(),
|
||||
)
|
||||
|
||||
c.statusRecorder.UpdateSignalAddress(signalURL)
|
||||
@@ -211,8 +211,8 @@ func (c *ConnectClient) run(mobileDependency MobileDependency, runningChan chan
|
||||
c.statusRecorder.MarkSignalDisconnected(err)
|
||||
}()
|
||||
|
||||
// with the global Wiretrustee config in hand connect (just a connection, no stream yet) Signal
|
||||
signalClient, err := connectToSignal(engineCtx, loginResp.GetWiretrusteeConfig(), myPrivateKey)
|
||||
// with the global Netbird config in hand connect (just a connection, no stream yet) Signal
|
||||
signalClient, err := connectToSignal(engineCtx, loginResp.GetNetbirdConfig(), myPrivateKey)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return wrapErr(err)
|
||||
@@ -311,7 +311,7 @@ func (c *ConnectClient) run(mobileDependency MobileDependency, runningChan chan
|
||||
}
|
||||
|
||||
func parseRelayInfo(loginResp *mgmProto.LoginResponse) ([]string, *hmac.Token) {
|
||||
relayCfg := loginResp.GetWiretrusteeConfig().GetRelay()
|
||||
relayCfg := loginResp.GetNetbirdConfig().GetRelay()
|
||||
if relayCfg == nil {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -440,7 +440,7 @@ func createEngineConfig(key wgtypes.Key, config *Config, peerConfig *mgmProto.Pe
|
||||
}
|
||||
|
||||
// connectToSignal creates Signal Service client and established a connection
|
||||
func connectToSignal(ctx context.Context, wtConfig *mgmProto.WiretrusteeConfig, ourPrivateKey wgtypes.Key) (*signal.GrpcClient, error) {
|
||||
func connectToSignal(ctx context.Context, wtConfig *mgmProto.NetbirdConfig, ourPrivateKey wgtypes.Key) (*signal.GrpcClient, error) {
|
||||
var sigTLSEnabled bool
|
||||
if wtConfig.Signal.Protocol == mgmProto.HostConfig_HTTPS {
|
||||
sigTLSEnabled = true
|
||||
@@ -457,7 +457,7 @@ func connectToSignal(ctx context.Context, wtConfig *mgmProto.WiretrusteeConfig,
|
||||
return signalClient, nil
|
||||
}
|
||||
|
||||
// loginToManagement creates Management Services client, establishes a connection, logs-in and gets a global Wiretrustee config (signal, turn, stun hosts, etc)
|
||||
// loginToManagement creates Management Services client, establishes a connection, logs-in and gets a global Netbird config (signal, turn, stun hosts, etc)
|
||||
func loginToManagement(ctx context.Context, client mgm.Client, pubSSHKey []byte, config *Config) (*mgmProto.LoginResponse, error) {
|
||||
|
||||
serverPublicKey, err := client.GetServerPublicKey()
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
@@ -146,7 +145,7 @@ type Engine struct {
|
||||
STUNs []*stun.URI
|
||||
// TURNs is a list of STUN servers used by ICE
|
||||
TURNs []*stun.URI
|
||||
stunTurn atomic.Value
|
||||
stunTurn icemaker.StunTurn
|
||||
|
||||
clientCtx context.Context
|
||||
clientCancel context.CancelFunc
|
||||
@@ -612,8 +611,8 @@ func (e *Engine) handleSync(update *mgmProto.SyncResponse) error {
|
||||
e.syncMsgMux.Lock()
|
||||
defer e.syncMsgMux.Unlock()
|
||||
|
||||
if update.GetWiretrusteeConfig() != nil {
|
||||
wCfg := update.GetWiretrusteeConfig()
|
||||
if update.GetNetbirdConfig() != nil {
|
||||
wCfg := update.GetNetbirdConfig()
|
||||
err := e.updateTURNs(wCfg.GetTurns())
|
||||
if err != nil {
|
||||
return fmt.Errorf("update TURNs: %w", err)
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package peer
|
||||
|
||||
import (
|
||||
"github.com/magiconair/properties/assert"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestConnStatus_String(t *testing.T) {
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/magiconair/properties/assert"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/netbirdio/netbird/client/iface"
|
||||
"github.com/netbirdio/netbird/client/internal/peer/guard"
|
||||
|
||||
22
client/internal/peer/ice/StunTurn.go
Normal file
22
client/internal/peer/ice/StunTurn.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package ice
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/pion/stun/v2"
|
||||
)
|
||||
|
||||
type StunTurn atomic.Value
|
||||
|
||||
func (s *StunTurn) Load() []*stun.URI {
|
||||
v := (*atomic.Value)(s).Load()
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return v.([]*stun.URI)
|
||||
}
|
||||
|
||||
func (s *StunTurn) Store(value []*stun.URI) {
|
||||
(*atomic.Value)(s).Store(value)
|
||||
}
|
||||
13
client/internal/peer/ice/StunTurn_test.go
Normal file
13
client/internal/peer/ice/StunTurn_test.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package ice
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStunTurn_LoadEmpty(t *testing.T) {
|
||||
var stStunTurn StunTurn
|
||||
got := stStunTurn.Load()
|
||||
if len(got) != 0 {
|
||||
t.Errorf("StunTurn.Load() = %v, want %v", got, nil)
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
"github.com/pion/ice/v3"
|
||||
"github.com/pion/randutil"
|
||||
"github.com/pion/stun/v2"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/netbirdio/netbird/client/internal/stdnet"
|
||||
@@ -39,7 +38,7 @@ func NewAgent(iFaceDiscover stdnet.ExternalIFaceDiscover, config Config, candida
|
||||
agentConfig := &ice.AgentConfig{
|
||||
MulticastDNSMode: ice.MulticastDNSModeDisabled,
|
||||
NetworkTypes: []ice.NetworkType{ice.NetworkTypeUDP4, ice.NetworkTypeUDP6},
|
||||
Urls: config.StunTurn.Load().([]*stun.URI),
|
||||
Urls: config.StunTurn.Load(),
|
||||
CandidateTypes: candidateTypes,
|
||||
InterfaceFilter: stdnet.InterfaceFilter(config.InterfaceBlackList),
|
||||
UDPMux: config.UDPMux,
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
package ice
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/pion/ice/v3"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
// StunTurn is a list of STUN and TURN URLs
|
||||
StunTurn *atomic.Value // []*stun.URI
|
||||
StunTurn *StunTurn // []*stun.URI
|
||||
|
||||
// InterfaceBlackList is a list of machine interfaces that should be filtered out by ICE Candidate gathering
|
||||
// (e.g. if eth0 is in the list, host candidate of this interface won't be used)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Wix
|
||||
xmlns="http://wixtoolset.org/schemas/v4/wxs">
|
||||
<Package Name="NetBird" Version="$(env.NETBIRD_VERSION)" Manufacturer="Wiretrustee UG (haftungsbeschreankt)" Language="1033" UpgradeCode="6456ec4e-3ad6-4b9b-a2be-98e81cb21ccf"
|
||||
<Package Name="NetBird" Version="$(env.NETBIRD_VERSION)" Manufacturer="NetBird GmbH" Language="1033" UpgradeCode="6456ec4e-3ad6-4b9b-a2be-98e81cb21ccf"
|
||||
InstallerVersion="500" Compressed="yes" Codepage="utf-8" >
|
||||
|
||||
<MediaTemplate EmbedCab="yes" />
|
||||
@@ -75,4 +75,4 @@
|
||||
<Property Id="ARPPRODUCTICON" Value="NetbirdIcon" />
|
||||
|
||||
</Package>
|
||||
</Wix>
|
||||
</Wix>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.26.0
|
||||
// protoc v4.23.4
|
||||
// protoc v4.24.3
|
||||
// source: daemon.proto
|
||||
|
||||
package proto
|
||||
@@ -92,7 +92,7 @@ type LoginRequest struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// setupKey wiretrustee setup key.
|
||||
// setupKey netbird setup key.
|
||||
SetupKey string `protobuf:"bytes,1,opt,name=setupKey,proto3" json:"setupKey,omitempty"`
|
||||
// This is the old PreSharedKey field which will be deprecated in favor of optionalPreSharedKey field that is defined as optional
|
||||
// to allow clearing of preshared key while being able to persist in the config file.
|
||||
|
||||
@@ -63,7 +63,7 @@ service DaemonService {
|
||||
|
||||
|
||||
message LoginRequest {
|
||||
// setupKey wiretrustee setup key.
|
||||
// setupKey netbird setup key.
|
||||
string setupKey = 1;
|
||||
|
||||
// This is the old PreSharedKey field which will be deprecated in favor of optionalPreSharedKey field that is defined as optional
|
||||
|
||||
@@ -50,7 +50,7 @@ type Info struct {
|
||||
OSVersion string
|
||||
Hostname string
|
||||
CPUs int
|
||||
WiretrusteeVersion string
|
||||
NetbirdVersion string
|
||||
UIVersion string
|
||||
KernelVersion string
|
||||
NetworkAddresses []NetworkAddress
|
||||
|
||||
@@ -36,7 +36,7 @@ func GetInfo(ctx context.Context) *Info {
|
||||
OSVersion: osVersion(),
|
||||
Hostname: extractDeviceName(ctx, "android"),
|
||||
CPUs: runtime.NumCPU(),
|
||||
WiretrusteeVersion: version.NetbirdVersion(),
|
||||
NetbirdVersion: version.NetbirdVersion(),
|
||||
UIVersion: extractUIVersion(ctx),
|
||||
KernelVersion: kernelVersion,
|
||||
SystemSerialNumber: serial(),
|
||||
|
||||
@@ -63,7 +63,7 @@ func GetInfo(ctx context.Context) *Info {
|
||||
|
||||
systemHostname, _ := os.Hostname()
|
||||
gio.Hostname = extractDeviceName(ctx, systemHostname)
|
||||
gio.WiretrusteeVersion = version.NetbirdVersion()
|
||||
gio.NetbirdVersion = version.NetbirdVersion()
|
||||
gio.UIVersion = extractUserAgent(ctx)
|
||||
|
||||
return gio
|
||||
|
||||
@@ -39,17 +39,17 @@ func GetInfo(ctx context.Context) *Info {
|
||||
systemHostname, _ := os.Hostname()
|
||||
|
||||
return &Info{
|
||||
GoOS: runtime.GOOS,
|
||||
Kernel: osInfo[0],
|
||||
Platform: runtime.GOARCH,
|
||||
OS: osName,
|
||||
OSVersion: osVersion,
|
||||
Hostname: extractDeviceName(ctx, systemHostname),
|
||||
CPUs: runtime.NumCPU(),
|
||||
WiretrusteeVersion: version.NetbirdVersion(),
|
||||
UIVersion: extractUserAgent(ctx),
|
||||
KernelVersion: osInfo[1],
|
||||
Environment: env,
|
||||
GoOS: runtime.GOOS,
|
||||
Kernel: osInfo[0],
|
||||
Platform: runtime.GOARCH,
|
||||
OS: osName,
|
||||
OSVersion: osVersion,
|
||||
Hostname: extractDeviceName(ctx, systemHostname),
|
||||
CPUs: runtime.NumCPU(),
|
||||
NetbirdVersion: version.NetbirdVersion(),
|
||||
UIVersion: extractUserAgent(ctx),
|
||||
KernelVersion: osInfo[1],
|
||||
Environment: env,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ func GetInfo(ctx context.Context) *Info {
|
||||
|
||||
gio := &Info{Kernel: sysName, OSVersion: swVersion, Platform: "unknown", OS: sysName, GoOS: runtime.GOOS, CPUs: runtime.NumCPU(), KernelVersion: swVersion}
|
||||
gio.Hostname = extractDeviceName(ctx, "hostname")
|
||||
gio.WiretrusteeVersion = version.NetbirdVersion()
|
||||
gio.NetbirdVersion = version.NetbirdVersion()
|
||||
gio.UIVersion = extractUserAgent(ctx)
|
||||
|
||||
return gio
|
||||
|
||||
@@ -61,7 +61,7 @@ func GetInfo(ctx context.Context) *Info {
|
||||
Hostname: extractDeviceName(ctx, systemHostname),
|
||||
GoOS: runtime.GOOS,
|
||||
CPUs: runtime.NumCPU(),
|
||||
WiretrusteeVersion: version.NetbirdVersion(),
|
||||
NetbirdVersion: version.NetbirdVersion(),
|
||||
UIVersion: extractUserAgent(ctx),
|
||||
KernelVersion: osInfo[1],
|
||||
NetworkAddresses: addrs,
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
func Test_LocalWTVersion(t *testing.T) {
|
||||
got := GetInfo(context.TODO())
|
||||
want := "development"
|
||||
assert.Equal(t, want, got.WiretrusteeVersion)
|
||||
assert.Equal(t, want, got.NetbirdVersion)
|
||||
}
|
||||
|
||||
func Test_UIVersion(t *testing.T) {
|
||||
|
||||
@@ -64,7 +64,7 @@ func GetInfo(ctx context.Context) *Info {
|
||||
|
||||
systemHostname, _ := os.Hostname()
|
||||
gio.Hostname = extractDeviceName(ctx, systemHostname)
|
||||
gio.WiretrusteeVersion = version.NetbirdVersion()
|
||||
gio.NetbirdVersion = version.NetbirdVersion()
|
||||
gio.UIVersion = extractUserAgent(ctx)
|
||||
|
||||
return gio
|
||||
|
||||
4
go.mod
4
go.mod
@@ -36,6 +36,7 @@ require (
|
||||
github.com/c-robinson/iplib v1.0.3
|
||||
github.com/caddyserver/certmagic v0.21.3
|
||||
github.com/cilium/ebpf v0.15.0
|
||||
github.com/coder/websocket v1.8.12
|
||||
github.com/coreos/go-iptables v0.7.0
|
||||
github.com/creack/pty v1.1.18
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
@@ -54,7 +55,6 @@ require (
|
||||
github.com/hashicorp/go-version v1.6.0
|
||||
github.com/libdns/route53 v1.5.0
|
||||
github.com/libp2p/go-netroute v0.2.1
|
||||
github.com/magiconair/properties v1.8.7
|
||||
github.com/mattn/go-sqlite3 v1.14.22
|
||||
github.com/mdlayher/socket v0.5.1
|
||||
github.com/miekg/dns v1.1.59
|
||||
@@ -103,7 +103,6 @@ require (
|
||||
gorm.io/driver/sqlite v1.5.7
|
||||
gorm.io/gorm v1.25.12
|
||||
gvisor.dev/gvisor v0.0.0-20231020174304-b8a429915ff1
|
||||
nhooyr.io/websocket v1.8.11
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -186,6 +185,7 @@ require (
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||
github.com/libdns/libdns v0.2.2 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mdlayher/genetlink v1.3.2 // indirect
|
||||
github.com/mdlayher/netlink v1.7.2 // indirect
|
||||
github.com/mholt/acmez/v2 v2.0.1 // indirect
|
||||
|
||||
4
go.sum
4
go.sum
@@ -137,6 +137,8 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo=
|
||||
github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs=
|
||||
github.com/containerd/containerd v1.7.16 h1:7Zsfe8Fkj4Wi2My6DXGQ87hiqIrmOXolm72ZEkFU5Mg=
|
||||
github.com/containerd/containerd v1.7.16/go.mod h1:NL49g7A/Fui7ccmxV6zkBWwqMgmMxFWzujYCc+JLt7k=
|
||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||
@@ -1264,8 +1266,6 @@ k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8
|
||||
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
||||
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
|
||||
nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0=
|
||||
nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
||||
@@ -273,8 +273,8 @@ func TestClient_Sync(t *testing.T) {
|
||||
if resp.GetPeerConfig() == nil {
|
||||
t.Error("expecting non nil PeerConfig got nil")
|
||||
}
|
||||
if resp.GetWiretrusteeConfig() == nil {
|
||||
t.Error("expecting non nil WiretrusteeConfig got nil")
|
||||
if resp.GetNetbirdConfig() == nil {
|
||||
t.Error("expecting non nil NetbirdConfig got nil")
|
||||
}
|
||||
if len(resp.GetRemotePeers()) != 1 {
|
||||
t.Errorf("expecting RemotePeers size %d got %d", 1, len(resp.GetRemotePeers()))
|
||||
@@ -366,15 +366,15 @@ func Test_SystemMetaDataFromClient(t *testing.T) {
|
||||
}
|
||||
|
||||
expectedMeta := &mgmtProto.PeerSystemMeta{
|
||||
Hostname: info.Hostname,
|
||||
GoOS: info.GoOS,
|
||||
Kernel: info.Kernel,
|
||||
Platform: info.Platform,
|
||||
OS: info.OS,
|
||||
Core: info.OSVersion,
|
||||
OSVersion: info.OSVersion,
|
||||
WiretrusteeVersion: info.WiretrusteeVersion,
|
||||
KernelVersion: info.KernelVersion,
|
||||
Hostname: info.Hostname,
|
||||
GoOS: info.GoOS,
|
||||
Kernel: info.Kernel,
|
||||
Platform: info.Platform,
|
||||
OS: info.OS,
|
||||
Core: info.OSVersion,
|
||||
OSVersion: info.OSVersion,
|
||||
NetbirdVersion: info.NetbirdVersion,
|
||||
KernelVersion: info.KernelVersion,
|
||||
|
||||
NetworkAddresses: protoNetAddr,
|
||||
SysSerialNumber: info.SystemSerialNumber,
|
||||
@@ -417,7 +417,7 @@ func isEqual(a, b *mgmtProto.PeerSystemMeta) bool {
|
||||
a.GetPlatform() == b.GetPlatform() &&
|
||||
a.GetOS() == b.GetOS() &&
|
||||
a.GetOSVersion() == b.GetOSVersion() &&
|
||||
a.GetWiretrusteeVersion() == b.GetWiretrusteeVersion() &&
|
||||
a.GetNetbirdVersion() == b.GetNetbirdVersion() &&
|
||||
a.GetUiVersion() == b.GetUiVersion() &&
|
||||
a.GetSysSerialNumber() == b.GetSysSerialNumber() &&
|
||||
a.GetSysProductName() == b.GetSysProductName() &&
|
||||
|
||||
@@ -521,20 +521,20 @@ func infoToMetaData(info *system.Info) *proto.PeerSystemMeta {
|
||||
}
|
||||
|
||||
return &proto.PeerSystemMeta{
|
||||
Hostname: info.Hostname,
|
||||
GoOS: info.GoOS,
|
||||
OS: info.OS,
|
||||
Core: info.OSVersion,
|
||||
OSVersion: info.OSVersion,
|
||||
Platform: info.Platform,
|
||||
Kernel: info.Kernel,
|
||||
WiretrusteeVersion: info.WiretrusteeVersion,
|
||||
UiVersion: info.UIVersion,
|
||||
KernelVersion: info.KernelVersion,
|
||||
NetworkAddresses: addresses,
|
||||
SysSerialNumber: info.SystemSerialNumber,
|
||||
SysManufacturer: info.SystemManufacturer,
|
||||
SysProductName: info.SystemProductName,
|
||||
Hostname: info.Hostname,
|
||||
GoOS: info.GoOS,
|
||||
OS: info.OS,
|
||||
Core: info.OSVersion,
|
||||
OSVersion: info.OSVersion,
|
||||
Platform: info.Platform,
|
||||
Kernel: info.Kernel,
|
||||
NetbirdVersion: info.NetbirdVersion,
|
||||
UiVersion: info.UIVersion,
|
||||
KernelVersion: info.KernelVersion,
|
||||
NetworkAddresses: addresses,
|
||||
SysSerialNumber: info.SystemSerialNumber,
|
||||
SysManufacturer: info.SystemManufacturer,
|
||||
SysProductName: info.SystemProductName,
|
||||
Environment: &proto.Environment{
|
||||
Cloud: info.Environment.Cloud,
|
||||
Platform: info.Environment.Platform,
|
||||
|
||||
54
management/client/rest/accounts.go
Normal file
54
management/client/rest/accounts.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
)
|
||||
|
||||
// AccountsAPI APIs for accounts, do not use directly
|
||||
type AccountsAPI struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// List list all accounts, only returns one account always
|
||||
// See more: https://docs.netbird.io/api/resources/accounts#list-all-accounts
|
||||
func (a *AccountsAPI) List(ctx context.Context) ([]api.Account, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/accounts", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[[]api.Account](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Update update account settings
|
||||
// See more: https://docs.netbird.io/api/resources/accounts#update-an-account
|
||||
func (a *AccountsAPI) Update(ctx context.Context, accountID string, request api.PutApiAccountsAccountIdJSONRequestBody) (*api.Account, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.newRequest(ctx, "PUT", "/api/accounts/"+accountID, bytes.NewReader(requestBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.Account](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Delete delete account
|
||||
// See more: https://docs.netbird.io/api/resources/accounts#delete-an-account
|
||||
func (a *AccountsAPI) Delete(ctx context.Context, accountID string) error {
|
||||
resp, err := a.c.newRequest(ctx, "DELETE", "/api/accounts/"+accountID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
169
management/client/rest/accounts_test.go
Normal file
169
management/client/rest/accounts_test.go
Normal file
@@ -0,0 +1,169 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
"github.com/netbirdio/netbird/management/server/http/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
testAccount = api.Account{
|
||||
Id: "Test",
|
||||
Settings: api.AccountSettings{
|
||||
Extra: &api.AccountExtraSettings{
|
||||
PeerApprovalEnabled: ptr(false),
|
||||
},
|
||||
GroupsPropagationEnabled: ptr(true),
|
||||
JwtGroupsEnabled: ptr(false),
|
||||
PeerInactivityExpiration: 7,
|
||||
PeerInactivityExpirationEnabled: true,
|
||||
PeerLoginExpiration: 24,
|
||||
PeerLoginExpirationEnabled: true,
|
||||
RegularUsersViewBlocked: false,
|
||||
RoutingPeerDnsResolutionEnabled: ptr(false),
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func TestAccounts_List_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/accounts", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal([]api.Account{testAccount})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Accounts.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testAccount, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccounts_List_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/accounts", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Accounts.List(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccounts_Update_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/accounts/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "PUT", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PutApiAccountsAccountIdJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, *req.Settings.RoutingPeerDnsResolutionEnabled)
|
||||
retBytes, _ := json.Marshal(testAccount)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Accounts.Update(context.Background(), "Test", api.PutApiAccountsAccountIdJSONRequestBody{
|
||||
Settings: api.AccountSettings{
|
||||
RoutingPeerDnsResolutionEnabled: ptr(true),
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testAccount, *ret)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestAccounts_Update_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/accounts/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Accounts.Update(context.Background(), "Test", api.PutApiAccountsAccountIdJSONRequestBody{
|
||||
Settings: api.AccountSettings{
|
||||
RoutingPeerDnsResolutionEnabled: ptr(true),
|
||||
},
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccounts_Delete_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/accounts/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.Accounts.Delete(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccounts_Delete_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/accounts/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.Accounts.Delete(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccounts_Integration_List(t *testing.T) {
|
||||
withBlackBoxServer(t, func(c *Client) {
|
||||
accounts, err := c.Accounts.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, accounts, 1)
|
||||
assert.Equal(t, "bf1c8084-ba50-4ce7-9439-34653001fc3b", accounts[0].Id)
|
||||
assert.Equal(t, false, *accounts[0].Settings.Extra.PeerApprovalEnabled)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccounts_Integration_Update(t *testing.T) {
|
||||
withBlackBoxServer(t, func(c *Client) {
|
||||
accounts, err := c.Accounts.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, accounts, 1)
|
||||
accounts[0].Settings.JwtAllowGroups = ptr([]string{"test"})
|
||||
account, err := c.Accounts.Update(context.Background(), accounts[0].Id, api.AccountRequest{
|
||||
Settings: accounts[0].Settings,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, accounts[0].Id, account.Id)
|
||||
assert.Equal(t, []string{"test"}, *account.Settings.JwtAllowGroups)
|
||||
})
|
||||
}
|
||||
|
||||
// Account deletion on MySQL and PostgreSQL databases causes unknown errors
|
||||
// func TestAccounts_Integration_Delete(t *testing.T) {
|
||||
// withBlackBoxServer(t, func(c *Client) {
|
||||
// accounts, err := c.Accounts.List(context.Background())
|
||||
// require.NoError(t, err)
|
||||
// assert.Len(t, accounts, 1)
|
||||
// err = c.Accounts.Delete(context.Background(), accounts[0].Id)
|
||||
// require.NoError(t, err)
|
||||
// _, err = c.Accounts.List(context.Background())
|
||||
// assert.Error(t, err)
|
||||
// })
|
||||
// }
|
||||
133
management/client/rest/client.go
Normal file
133
management/client/rest/client.go
Normal file
@@ -0,0 +1,133 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/util"
|
||||
)
|
||||
|
||||
// Client Management service HTTP REST API Client
|
||||
type Client struct {
|
||||
managementURL string
|
||||
authHeader string
|
||||
|
||||
// Accounts NetBird account APIs
|
||||
// see more: https://docs.netbird.io/api/resources/accounts
|
||||
Accounts *AccountsAPI
|
||||
|
||||
// Users NetBird users APIs
|
||||
// see more: https://docs.netbird.io/api/resources/users
|
||||
Users *UsersAPI
|
||||
|
||||
// Tokens NetBird tokens APIs
|
||||
// see more: https://docs.netbird.io/api/resources/tokens
|
||||
Tokens *TokensAPI
|
||||
|
||||
// Peers NetBird peers APIs
|
||||
// see more: https://docs.netbird.io/api/resources/peers
|
||||
Peers *PeersAPI
|
||||
|
||||
// SetupKeys NetBird setup keys APIs
|
||||
// see more: https://docs.netbird.io/api/resources/setup-keys
|
||||
SetupKeys *SetupKeysAPI
|
||||
|
||||
// Groups NetBird groups APIs
|
||||
// see more: https://docs.netbird.io/api/resources/groups
|
||||
Groups *GroupsAPI
|
||||
|
||||
// Policies NetBird policies APIs
|
||||
// see more: https://docs.netbird.io/api/resources/policies
|
||||
Policies *PoliciesAPI
|
||||
|
||||
// PostureChecks NetBird posture checks APIs
|
||||
// see more: https://docs.netbird.io/api/resources/posture-checks
|
||||
PostureChecks *PostureChecksAPI
|
||||
|
||||
// Networks NetBird networks APIs
|
||||
// see more: https://docs.netbird.io/api/resources/networks
|
||||
Networks *NetworksAPI
|
||||
|
||||
// Routes NetBird routes APIs
|
||||
// see more: https://docs.netbird.io/api/resources/routes
|
||||
Routes *RoutesAPI
|
||||
|
||||
// DNS NetBird DNS APIs
|
||||
// see more: https://docs.netbird.io/api/resources/routes
|
||||
DNS *DNSAPI
|
||||
|
||||
// GeoLocation NetBird Geo Location APIs
|
||||
// see more: https://docs.netbird.io/api/resources/geo-locations
|
||||
GeoLocation *GeoLocationAPI
|
||||
|
||||
// Events NetBird Events APIs
|
||||
// see more: https://docs.netbird.io/api/resources/events
|
||||
Events *EventsAPI
|
||||
}
|
||||
|
||||
// New initialize new Client instance
|
||||
func New(managementURL, token string) *Client {
|
||||
client := &Client{
|
||||
managementURL: managementURL,
|
||||
authHeader: "Token " + token,
|
||||
}
|
||||
client.Accounts = &AccountsAPI{client}
|
||||
client.Users = &UsersAPI{client}
|
||||
client.Tokens = &TokensAPI{client}
|
||||
client.Peers = &PeersAPI{client}
|
||||
client.SetupKeys = &SetupKeysAPI{client}
|
||||
client.Groups = &GroupsAPI{client}
|
||||
client.Policies = &PoliciesAPI{client}
|
||||
client.PostureChecks = &PostureChecksAPI{client}
|
||||
client.Networks = &NetworksAPI{client}
|
||||
client.Routes = &RoutesAPI{client}
|
||||
client.DNS = &DNSAPI{client}
|
||||
client.GeoLocation = &GeoLocationAPI{client}
|
||||
client.Events = &EventsAPI{client}
|
||||
return client
|
||||
}
|
||||
|
||||
func (c *Client) newRequest(ctx context.Context, method, path string, body io.Reader) (*http.Response, error) {
|
||||
req, err := http.NewRequestWithContext(ctx, method, c.managementURL+path, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Add("Authorization", c.authHeader)
|
||||
req.Header.Add("Accept", "application/json")
|
||||
if body != nil {
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
}
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resp.StatusCode > 299 {
|
||||
parsedErr, pErr := parseResponse[util.ErrorResponse](resp)
|
||||
if pErr != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, errors.New(parsedErr.Message)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func parseResponse[T any](resp *http.Response) (T, error) {
|
||||
var ret T
|
||||
if resp.Body == nil {
|
||||
return ret, errors.New("No body")
|
||||
}
|
||||
bs, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
err = json.Unmarshal(bs, &ret)
|
||||
|
||||
return ret, err
|
||||
}
|
||||
30
management/client/rest/client_test.go
Normal file
30
management/client/rest/client_test.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/testing/testing_tools"
|
||||
)
|
||||
|
||||
func withMockClient(callback func(*Client, *http.ServeMux)) {
|
||||
mux := &http.ServeMux{}
|
||||
server := httptest.NewServer(mux)
|
||||
defer server.Close()
|
||||
c := New(server.URL, "ABC")
|
||||
callback(c, mux)
|
||||
}
|
||||
|
||||
func ptr[T any, PT *T](x T) PT {
|
||||
return &x
|
||||
}
|
||||
|
||||
func withBlackBoxServer(t *testing.T, callback func(*Client)) {
|
||||
t.Helper()
|
||||
handler, _, _ := testing_tools.BuildApiBlackBoxWithDBState(t, "../../server/testdata/store.sql", nil, false)
|
||||
server := httptest.NewServer(handler)
|
||||
defer server.Close()
|
||||
c := New(server.URL, "nbp_apTmlmUXHSC4PKmHwtIZNaGr8eqcVI2gMURp")
|
||||
callback(c)
|
||||
}
|
||||
110
management/client/rest/dns.go
Normal file
110
management/client/rest/dns.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
)
|
||||
|
||||
// DNSAPI APIs for DNS Management, do not use directly
|
||||
type DNSAPI struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// ListNameserverGroups list all nameserver groups
|
||||
// See more: https://docs.netbird.io/api/resources/dns#list-all-nameserver-groups
|
||||
func (a *DNSAPI) ListNameserverGroups(ctx context.Context) ([]api.NameserverGroup, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/dns/nameservers", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[[]api.NameserverGroup](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// GetNameserverGroup get nameserver group info
|
||||
// See more: https://docs.netbird.io/api/resources/dns#retrieve-a-nameserver-group
|
||||
func (a *DNSAPI) GetNameserverGroup(ctx context.Context, nameserverGroupID string) (*api.NameserverGroup, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/dns/nameservers/"+nameserverGroupID, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.NameserverGroup](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// CreateNameserverGroup create new nameserver group
|
||||
// See more: https://docs.netbird.io/api/resources/dns#create-a-nameserver-group
|
||||
func (a *DNSAPI) CreateNameserverGroup(ctx context.Context, request api.PostApiDnsNameserversJSONRequestBody) (*api.NameserverGroup, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.newRequest(ctx, "POST", "/api/dns/nameservers", bytes.NewReader(requestBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.NameserverGroup](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// UpdateNameserverGroup update nameserver group info
|
||||
// See more: https://docs.netbird.io/api/resources/dns#update-a-nameserver-group
|
||||
func (a *DNSAPI) UpdateNameserverGroup(ctx context.Context, nameserverGroupID string, request api.PutApiDnsNameserversNsgroupIdJSONRequestBody) (*api.NameserverGroup, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.newRequest(ctx, "PUT", "/api/dns/nameservers/"+nameserverGroupID, bytes.NewReader(requestBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.NameserverGroup](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// DeleteNameserverGroup delete nameserver group
|
||||
// See more: https://docs.netbird.io/api/resources/dns#delete-a-nameserver-group
|
||||
func (a *DNSAPI) DeleteNameserverGroup(ctx context.Context, nameserverGroupID string) error {
|
||||
resp, err := a.c.newRequest(ctx, "DELETE", "/api/dns/nameservers/"+nameserverGroupID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSettings get DNS settings
|
||||
// See more: https://docs.netbird.io/api/resources/dns#retrieve-dns-settings
|
||||
func (a *DNSAPI) GetSettings(ctx context.Context) (*api.DNSSettings, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/dns/settings", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.DNSSettings](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// UpdateSettings update DNS settings
|
||||
// See more: https://docs.netbird.io/api/resources/dns#update-dns-settings
|
||||
func (a *DNSAPI) UpdateSettings(ctx context.Context, request api.PutApiDnsSettingsJSONRequestBody) (*api.DNSSettings, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.newRequest(ctx, "PUT", "/api/dns/settings", bytes.NewReader(requestBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.DNSSettings](resp)
|
||||
return &ret, err
|
||||
}
|
||||
295
management/client/rest/dns_test.go
Normal file
295
management/client/rest/dns_test.go
Normal file
@@ -0,0 +1,295 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
"github.com/netbirdio/netbird/management/server/http/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
testNameserverGroup = api.NameserverGroup{
|
||||
Id: "Test",
|
||||
Name: "wow",
|
||||
}
|
||||
|
||||
testSettings = api.DNSSettings{
|
||||
DisabledManagementGroups: []string{"gone"},
|
||||
}
|
||||
)
|
||||
|
||||
func TestDNSNameserverGroup_List_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/dns/nameservers", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal([]api.NameserverGroup{testNameserverGroup})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.DNS.ListNameserverGroups(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testNameserverGroup, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestDNSNameserverGroup_List_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/dns/nameservers", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.DNS.ListNameserverGroups(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDNSNameserverGroup_Get_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/dns/nameservers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(testNameserverGroup)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.DNS.GetNameserverGroup(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testNameserverGroup, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDNSNameserverGroup_Get_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/dns/nameservers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.DNS.GetNameserverGroup(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDNSNameserverGroup_Create_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/dns/nameservers", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PostApiDnsNameserversJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "weaw", req.Name)
|
||||
retBytes, _ := json.Marshal(testNameserverGroup)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.DNS.CreateNameserverGroup(context.Background(), api.PostApiDnsNameserversJSONRequestBody{
|
||||
Name: "weaw",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testNameserverGroup, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDNSNameserverGroup_Create_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/dns/nameservers", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.DNS.CreateNameserverGroup(context.Background(), api.PostApiDnsNameserversJSONRequestBody{
|
||||
Name: "weaw",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDNSNameserverGroup_Update_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/dns/nameservers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "PUT", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PutApiDnsNameserversNsgroupIdJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "weaw", req.Name)
|
||||
retBytes, _ := json.Marshal(testNameserverGroup)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.DNS.UpdateNameserverGroup(context.Background(), "Test", api.PutApiDnsNameserversNsgroupIdJSONRequestBody{
|
||||
Name: "weaw",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testNameserverGroup, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDNSNameserverGroup_Update_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/dns/nameservers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.DNS.UpdateNameserverGroup(context.Background(), "Test", api.PutApiDnsNameserversNsgroupIdJSONRequestBody{
|
||||
Name: "weaw",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDNSNameserverGroup_Delete_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/dns/nameservers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.DNS.DeleteNameserverGroup(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDNSNameserverGroup_Delete_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/dns/nameservers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.DNS.DeleteNameserverGroup(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestDNSSettings_Get_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/dns/settings", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(testSettings)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.DNS.GetSettings(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testSettings, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDNSSettings_Get_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/dns/settings", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.DNS.GetSettings(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDNSSettings_Update_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/dns/settings", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "PUT", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PutApiDnsSettingsJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []string{"test"}, req.DisabledManagementGroups)
|
||||
retBytes, _ := json.Marshal(testSettings)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.DNS.UpdateSettings(context.Background(), api.PutApiDnsSettingsJSONRequestBody{
|
||||
DisabledManagementGroups: []string{"test"},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testSettings, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDNSSettings_Update_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/dns/settings", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.DNS.UpdateSettings(context.Background(), api.PutApiDnsSettingsJSONRequestBody{
|
||||
DisabledManagementGroups: []string{"test"},
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDNS_Integration(t *testing.T) {
|
||||
nsGroupReq := api.NameserverGroupRequest{
|
||||
Description: "Test",
|
||||
Enabled: true,
|
||||
Groups: []string{"cs1tnh0hhcjnqoiuebeg"},
|
||||
Name: "test",
|
||||
Nameservers: []api.Nameserver{
|
||||
{
|
||||
Ip: "8.8.8.8",
|
||||
NsType: api.NameserverNsTypeUdp,
|
||||
Port: 53,
|
||||
},
|
||||
},
|
||||
Primary: true,
|
||||
SearchDomainsEnabled: false,
|
||||
}
|
||||
withBlackBoxServer(t, func(c *Client) {
|
||||
// Create
|
||||
nsGroup, err := c.DNS.CreateNameserverGroup(context.Background(), nsGroupReq)
|
||||
require.NoError(t, err)
|
||||
|
||||
// List
|
||||
nsGroups, err := c.DNS.ListNameserverGroups(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, *nsGroup, nsGroups[0])
|
||||
|
||||
// Update
|
||||
nsGroupReq.Description = "TestUpdate"
|
||||
nsGroup, err = c.DNS.UpdateNameserverGroup(context.Background(), nsGroup.Id, nsGroupReq)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "TestUpdate", nsGroup.Description)
|
||||
|
||||
// Delete
|
||||
err = c.DNS.DeleteNameserverGroup(context.Background(), nsGroup.Id)
|
||||
require.NoError(t, err)
|
||||
|
||||
// List again to ensure deletion
|
||||
nsGroups, err = c.DNS.ListNameserverGroups(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, nsGroups, 0)
|
||||
})
|
||||
}
|
||||
24
management/client/rest/events.go
Normal file
24
management/client/rest/events.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
)
|
||||
|
||||
// EventsAPI APIs for Events, do not use directly
|
||||
type EventsAPI struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// List list all events
|
||||
// See more: https://docs.netbird.io/api/resources/events#list-all-events
|
||||
func (a *EventsAPI) List(ctx context.Context) ([]api.Event, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/events", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[[]api.Event](resp)
|
||||
return ret, err
|
||||
}
|
||||
65
management/client/rest/events_test.go
Normal file
65
management/client/rest/events_test.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
"github.com/netbirdio/netbird/management/server/http/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
testEvent = api.Event{
|
||||
Activity: "AccountCreate",
|
||||
ActivityCode: api.EventActivityCodeAccountCreate,
|
||||
}
|
||||
)
|
||||
|
||||
func TestEvents_List_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/events", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal([]api.Event{testEvent})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Events.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testEvent, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestEvents_List_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/events", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Events.List(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEvents_Integration(t *testing.T) {
|
||||
withBlackBoxServer(t, func(c *Client) {
|
||||
// Do something that would trigger any event
|
||||
_, err := c.SetupKeys.Create(context.Background(), api.CreateSetupKeyRequest{
|
||||
Ephemeral: ptr(true),
|
||||
Name: "TestSetupKey",
|
||||
Type: "reusable",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
events, err := c.Events.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, events)
|
||||
})
|
||||
}
|
||||
36
management/client/rest/geo.go
Normal file
36
management/client/rest/geo.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
)
|
||||
|
||||
// GeoLocationAPI APIs for Geo-Location, do not use directly
|
||||
type GeoLocationAPI struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// ListCountries list all country codes
|
||||
// See more: https://docs.netbird.io/api/resources/geo-locations#list-all-country-codes
|
||||
func (a *GeoLocationAPI) ListCountries(ctx context.Context) ([]api.Country, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/locations/countries", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[[]api.Country](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// ListCountryCities Get a list of all English city names for a given country code
|
||||
// See more: https://docs.netbird.io/api/resources/geo-locations#list-all-city-names-by-country
|
||||
func (a *GeoLocationAPI) ListCountryCities(ctx context.Context, countryCode string) ([]api.City, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/locations/countries/"+countryCode+"/cities", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[[]api.City](resp)
|
||||
return ret, err
|
||||
}
|
||||
96
management/client/rest/geo_test.go
Normal file
96
management/client/rest/geo_test.go
Normal file
@@ -0,0 +1,96 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
"github.com/netbirdio/netbird/management/server/http/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
testCountry = api.Country{
|
||||
CountryCode: "DE",
|
||||
CountryName: "Germany",
|
||||
}
|
||||
|
||||
testCity = api.City{
|
||||
CityName: "Berlin",
|
||||
GeonameId: 2950158,
|
||||
}
|
||||
)
|
||||
|
||||
func TestGeo_ListCountries_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/locations/countries", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal([]api.Country{testCountry})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.GeoLocation.ListCountries(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testCountry, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestGeo_ListCountries_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/locations/countries", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.GeoLocation.ListCountries(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGeo_ListCountryCities_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/locations/countries/Test/cities", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal([]api.City{testCity})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.GeoLocation.ListCountryCities(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testCity, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestGeo_ListCountryCities_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/locations/countries/Test/cities", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.GeoLocation.ListCountryCities(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGeo_Integration(t *testing.T) {
|
||||
// Blackbox is initialized with empty GeoLocations
|
||||
withBlackBoxServer(t, func(c *Client) {
|
||||
countries, err := c.GeoLocation.ListCountries(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, countries)
|
||||
|
||||
cities, err := c.GeoLocation.ListCountryCities(context.Background(), "DE")
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, cities)
|
||||
})
|
||||
}
|
||||
82
management/client/rest/groups.go
Normal file
82
management/client/rest/groups.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
)
|
||||
|
||||
// GroupsAPI APIs for Groups, do not use directly
|
||||
type GroupsAPI struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// List list all groups
|
||||
// See more: https://docs.netbird.io/api/resources/groups#list-all-groups
|
||||
func (a *GroupsAPI) List(ctx context.Context) ([]api.Group, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/groups", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[[]api.Group](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get get group info
|
||||
// See more: https://docs.netbird.io/api/resources/groups#retrieve-a-group
|
||||
func (a *GroupsAPI) Get(ctx context.Context, groupID string) (*api.Group, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/groups/"+groupID, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.Group](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Create create new group
|
||||
// See more: https://docs.netbird.io/api/resources/groups#create-a-group
|
||||
func (a *GroupsAPI) Create(ctx context.Context, request api.PostApiGroupsJSONRequestBody) (*api.Group, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.newRequest(ctx, "POST", "/api/groups", bytes.NewReader(requestBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.Group](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Update update group info
|
||||
// See more: https://docs.netbird.io/api/resources/groups#update-a-group
|
||||
func (a *GroupsAPI) Update(ctx context.Context, groupID string, request api.PutApiGroupsGroupIdJSONRequestBody) (*api.Group, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.newRequest(ctx, "PUT", "/api/groups/"+groupID, bytes.NewReader(requestBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.Group](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Delete delete group
|
||||
// See more: https://docs.netbird.io/api/resources/groups#delete-a-group
|
||||
func (a *GroupsAPI) Delete(ctx context.Context, groupID string) error {
|
||||
resp, err := a.c.newRequest(ctx, "DELETE", "/api/groups/"+groupID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
210
management/client/rest/groups_test.go
Normal file
210
management/client/rest/groups_test.go
Normal file
@@ -0,0 +1,210 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
"github.com/netbirdio/netbird/management/server/http/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
testGroup = api.Group{
|
||||
Id: "Test",
|
||||
Name: "wow",
|
||||
PeersCount: 0,
|
||||
}
|
||||
)
|
||||
|
||||
func TestGroups_List_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/groups", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal([]api.Group{testGroup})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Groups.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testGroup, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestGroups_List_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/groups", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Groups.List(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGroups_Get_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/groups/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(testGroup)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Groups.Get(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testGroup, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGroups_Get_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/groups/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Groups.Get(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGroups_Create_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/groups", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PostApiGroupsJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "weaw", req.Name)
|
||||
retBytes, _ := json.Marshal(testGroup)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Groups.Create(context.Background(), api.PostApiGroupsJSONRequestBody{
|
||||
Name: "weaw",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testGroup, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGroups_Create_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/groups", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Groups.Create(context.Background(), api.PostApiGroupsJSONRequestBody{
|
||||
Name: "weaw",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGroups_Update_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/groups/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "PUT", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PutApiGroupsGroupIdJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "weaw", req.Name)
|
||||
retBytes, _ := json.Marshal(testGroup)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Groups.Update(context.Background(), "Test", api.PutApiGroupsGroupIdJSONRequestBody{
|
||||
Name: "weaw",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testGroup, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGroups_Update_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/groups/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Groups.Update(context.Background(), "Test", api.PutApiGroupsGroupIdJSONRequestBody{
|
||||
Name: "weaw",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGroups_Delete_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/groups/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.Groups.Delete(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGroups_Delete_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/groups/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.Groups.Delete(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestGroups_Integration(t *testing.T) {
|
||||
withBlackBoxServer(t, func(c *Client) {
|
||||
groups, err := c.Groups.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, groups, 1)
|
||||
|
||||
group, err := c.Groups.Create(context.Background(), api.GroupRequest{
|
||||
Name: "Test",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "Test", group.Name)
|
||||
assert.NotEmpty(t, group.Id)
|
||||
|
||||
group, err = c.Groups.Update(context.Background(), group.Id, api.GroupRequest{
|
||||
Name: "Testnt",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "Testnt", group.Name)
|
||||
|
||||
err = c.Groups.Delete(context.Background(), group.Id)
|
||||
require.NoError(t, err)
|
||||
|
||||
groups, err = c.Groups.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, groups, 1)
|
||||
})
|
||||
}
|
||||
246
management/client/rest/networks.go
Normal file
246
management/client/rest/networks.go
Normal file
@@ -0,0 +1,246 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
)
|
||||
|
||||
// NetworksAPI APIs for Networks, do not use directly
|
||||
type NetworksAPI struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// List list all networks
|
||||
// See more: https://docs.netbird.io/api/resources/networks#list-all-networks
|
||||
func (a *NetworksAPI) List(ctx context.Context) ([]api.Network, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/networks", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[[]api.Network](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get get network info
|
||||
// See more: https://docs.netbird.io/api/resources/networks#retrieve-a-network
|
||||
func (a *NetworksAPI) Get(ctx context.Context, networkID string) (*api.Network, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/networks/"+networkID, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.Network](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Create create new network
|
||||
// See more: https://docs.netbird.io/api/resources/networks#create-a-network
|
||||
func (a *NetworksAPI) Create(ctx context.Context, request api.PostApiNetworksJSONRequestBody) (*api.Network, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.newRequest(ctx, "POST", "/api/networks", bytes.NewReader(requestBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.Network](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Update update network
|
||||
// See more: https://docs.netbird.io/api/resources/networks#update-a-network
|
||||
func (a *NetworksAPI) Update(ctx context.Context, networkID string, request api.PutApiNetworksNetworkIdJSONRequestBody) (*api.Network, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.newRequest(ctx, "PUT", "/api/networks/"+networkID, bytes.NewReader(requestBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.Network](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Delete delete network
|
||||
// See more: https://docs.netbird.io/api/resources/networks#delete-a-network
|
||||
func (a *NetworksAPI) Delete(ctx context.Context, networkID string) error {
|
||||
resp, err := a.c.newRequest(ctx, "DELETE", "/api/networks/"+networkID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NetworkResourcesAPI APIs for Network Resources, do not use directly
|
||||
type NetworkResourcesAPI struct {
|
||||
c *Client
|
||||
networkID string
|
||||
}
|
||||
|
||||
// Resources APIs for network resources
|
||||
func (a *NetworksAPI) Resources(networkID string) *NetworkResourcesAPI {
|
||||
return &NetworkResourcesAPI{
|
||||
c: a.c,
|
||||
networkID: networkID,
|
||||
}
|
||||
}
|
||||
|
||||
// List list all resources in networks
|
||||
// See more: https://docs.netbird.io/api/resources/networks#list-all-network-resources
|
||||
func (a *NetworkResourcesAPI) List(ctx context.Context) ([]api.NetworkResource, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/networks/"+a.networkID+"/resources", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[[]api.NetworkResource](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get get network resource info
|
||||
// See more: https://docs.netbird.io/api/resources/networks#retrieve-a-network-resource
|
||||
func (a *NetworkResourcesAPI) Get(ctx context.Context, networkResourceID string) (*api.NetworkResource, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/networks/"+a.networkID+"/resources/"+networkResourceID, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.NetworkResource](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Create create new network resource
|
||||
// See more: https://docs.netbird.io/api/resources/networks#create-a-network-resource
|
||||
func (a *NetworkResourcesAPI) Create(ctx context.Context, request api.PostApiNetworksNetworkIdResourcesJSONRequestBody) (*api.NetworkResource, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.newRequest(ctx, "POST", "/api/networks/"+a.networkID+"/resources", bytes.NewReader(requestBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.NetworkResource](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Update update network resource
|
||||
// See more: https://docs.netbird.io/api/resources/networks#update-a-network-resource
|
||||
func (a *NetworkResourcesAPI) Update(ctx context.Context, networkResourceID string, request api.PutApiNetworksNetworkIdResourcesResourceIdJSONRequestBody) (*api.NetworkResource, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.newRequest(ctx, "PUT", "/api/networks/"+a.networkID+"/resources/"+networkResourceID, bytes.NewReader(requestBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.NetworkResource](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Delete delete network resource
|
||||
// See more: https://docs.netbird.io/api/resources/networks#delete-a-network-resource
|
||||
func (a *NetworkResourcesAPI) Delete(ctx context.Context, networkResourceID string) error {
|
||||
resp, err := a.c.newRequest(ctx, "DELETE", "/api/networks/"+a.networkID+"/resources/"+networkResourceID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NetworkRoutersAPI APIs for Network Routers, do not use directly
|
||||
type NetworkRoutersAPI struct {
|
||||
c *Client
|
||||
networkID string
|
||||
}
|
||||
|
||||
// Routers APIs for network routers
|
||||
func (a *NetworksAPI) Routers(networkID string) *NetworkRoutersAPI {
|
||||
return &NetworkRoutersAPI{
|
||||
c: a.c,
|
||||
networkID: networkID,
|
||||
}
|
||||
}
|
||||
|
||||
// List list all routers in networks
|
||||
// See more: https://docs.netbird.io/api/routers/networks#list-all-network-routers
|
||||
func (a *NetworkRoutersAPI) List(ctx context.Context) ([]api.NetworkRouter, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/networks/"+a.networkID+"/routers", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[[]api.NetworkRouter](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get get network router info
|
||||
// See more: https://docs.netbird.io/api/routers/networks#retrieve-a-network-router
|
||||
func (a *NetworkRoutersAPI) Get(ctx context.Context, networkRouterID string) (*api.NetworkRouter, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/networks/"+a.networkID+"/routers/"+networkRouterID, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.NetworkRouter](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Create create new network router
|
||||
// See more: https://docs.netbird.io/api/routers/networks#create-a-network-router
|
||||
func (a *NetworkRoutersAPI) Create(ctx context.Context, request api.PostApiNetworksNetworkIdRoutersJSONRequestBody) (*api.NetworkRouter, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.newRequest(ctx, "POST", "/api/networks/"+a.networkID+"/routers", bytes.NewReader(requestBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.NetworkRouter](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Update update network router
|
||||
// See more: https://docs.netbird.io/api/routers/networks#update-a-network-router
|
||||
func (a *NetworkRoutersAPI) Update(ctx context.Context, networkRouterID string, request api.PutApiNetworksNetworkIdRoutersRouterIdJSONRequestBody) (*api.NetworkRouter, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.newRequest(ctx, "PUT", "/api/networks/"+a.networkID+"/routers/"+networkRouterID, bytes.NewReader(requestBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.NetworkRouter](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Delete delete network router
|
||||
// See more: https://docs.netbird.io/api/routers/networks#delete-a-network-router
|
||||
func (a *NetworkRoutersAPI) Delete(ctx context.Context, networkRouterID string) error {
|
||||
resp, err := a.c.newRequest(ctx, "DELETE", "/api/networks/"+a.networkID+"/routers/"+networkRouterID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
589
management/client/rest/networks_test.go
Normal file
589
management/client/rest/networks_test.go
Normal file
@@ -0,0 +1,589 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
"github.com/netbirdio/netbird/management/server/http/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
testNetwork = api.Network{
|
||||
Id: "Test",
|
||||
Name: "wow",
|
||||
}
|
||||
|
||||
testNetworkResource = api.NetworkResource{
|
||||
Description: ptr("meaw"),
|
||||
Id: "awa",
|
||||
}
|
||||
|
||||
testNetworkRouter = api.NetworkRouter{
|
||||
Id: "ouch",
|
||||
}
|
||||
)
|
||||
|
||||
func TestNetworks_List_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal([]api.Network{testNetwork})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Networks.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testNetwork, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworks_List_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Networks.List(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworks_Get_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(testNetwork)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Networks.Get(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testNetwork, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworks_Get_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Networks.Get(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworks_Create_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PostApiNetworksJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "weaw", req.Name)
|
||||
retBytes, _ := json.Marshal(testNetwork)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Networks.Create(context.Background(), api.PostApiNetworksJSONRequestBody{
|
||||
Name: "weaw",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testNetwork, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworks_Create_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Networks.Create(context.Background(), api.PostApiNetworksJSONRequestBody{
|
||||
Name: "weaw",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworks_Update_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "PUT", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PutApiNetworksNetworkIdJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "weaw", req.Name)
|
||||
retBytes, _ := json.Marshal(testNetwork)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Networks.Update(context.Background(), "Test", api.PutApiNetworksNetworkIdJSONRequestBody{
|
||||
Name: "weaw",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testNetwork, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworks_Update_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Networks.Update(context.Background(), "Test", api.PutApiNetworksNetworkIdJSONRequestBody{
|
||||
Name: "weaw",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworks_Delete_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.Networks.Delete(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworks_Delete_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.Networks.Delete(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworks_Integration(t *testing.T) {
|
||||
withBlackBoxServer(t, func(c *Client) {
|
||||
network, err := c.Networks.Create(context.Background(), api.NetworkRequest{
|
||||
Description: ptr("TestNetwork"),
|
||||
Name: "Test",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "Test", network.Name)
|
||||
|
||||
networks, err := c.Networks.List(context.Background())
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, networks)
|
||||
|
||||
network, err = c.Networks.Update(context.Background(), "TestID", api.NetworkRequest{
|
||||
Description: ptr("TestNetwork?"),
|
||||
Name: "Test",
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "TestNetwork?", *network.Description)
|
||||
|
||||
err = c.Networks.Delete(context.Background(), "TestID")
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworkResources_List_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Meow/resources", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal([]api.NetworkResource{testNetworkResource})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Networks.Resources("Meow").List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testNetworkResource, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworkResources_List_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Meow/resources", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Networks.Resources("Meow").List(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworkResources_Get_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Meow/resources/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(testNetworkResource)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Networks.Resources("Meow").Get(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testNetworkResource, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworkResources_Get_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Meow/resources/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Networks.Resources("Meow").Get(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworkResources_Create_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Meow/resources", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PostApiNetworksNetworkIdResourcesJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "weaw", req.Name)
|
||||
retBytes, _ := json.Marshal(testNetworkResource)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Networks.Resources("Meow").Create(context.Background(), api.PostApiNetworksNetworkIdResourcesJSONRequestBody{
|
||||
Name: "weaw",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testNetworkResource, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworkResources_Create_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Meow/resources", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Networks.Resources("Meow").Create(context.Background(), api.PostApiNetworksNetworkIdResourcesJSONRequestBody{
|
||||
Name: "weaw",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworkResources_Update_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Meow/resources/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "PUT", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PutApiNetworksNetworkIdResourcesResourceIdJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "weaw", req.Name)
|
||||
retBytes, _ := json.Marshal(testNetworkResource)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Networks.Resources("Meow").Update(context.Background(), "Test", api.PutApiNetworksNetworkIdResourcesResourceIdJSONRequestBody{
|
||||
Name: "weaw",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testNetworkResource, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworkResources_Update_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Meow/resources/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Networks.Resources("Meow").Update(context.Background(), "Test", api.PutApiNetworksNetworkIdResourcesResourceIdJSONRequestBody{
|
||||
Name: "weaw",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworkResources_Delete_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Meow/resources/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.Networks.Resources("Meow").Delete(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworkResources_Delete_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Meow/resources/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.Networks.Resources("Meow").Delete(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworkResources_Integration(t *testing.T) {
|
||||
withBlackBoxServer(t, func(c *Client) {
|
||||
_, err := c.Networks.Resources("TestNetwork").Create(context.Background(), api.NetworkResourceRequest{
|
||||
Address: "test.com",
|
||||
Description: ptr("Description"),
|
||||
Enabled: false,
|
||||
Groups: []string{"test"},
|
||||
Name: "test",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = c.Networks.Resources("TestNetwork").List(context.Background())
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = c.Networks.Resources("TestNetwork").Get(context.Background(), "TestResource")
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = c.Networks.Resources("TestNetwork").Update(context.Background(), "TestResource", api.NetworkResourceRequest{
|
||||
Address: "testnt.com",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = c.Networks.Resources("TestNetwork").Delete(context.Background(), "TestResource")
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworkRouters_List_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Meow/routers", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal([]api.NetworkRouter{testNetworkRouter})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Networks.Routers("Meow").List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testNetworkRouter, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworkRouters_List_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Meow/routers", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Networks.Routers("Meow").List(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworkRouters_Get_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Meow/routers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(testNetworkRouter)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Networks.Routers("Meow").Get(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testNetworkRouter, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworkRouters_Get_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Meow/routers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Networks.Routers("Meow").Get(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworkRouters_Create_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Meow/routers", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PostApiNetworksNetworkIdRoutersJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "test", *req.Peer)
|
||||
retBytes, _ := json.Marshal(testNetworkRouter)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Networks.Routers("Meow").Create(context.Background(), api.PostApiNetworksNetworkIdRoutersJSONRequestBody{
|
||||
Peer: ptr("test"),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testNetworkRouter, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworkRouters_Create_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Meow/routers", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Networks.Routers("Meow").Create(context.Background(), api.PostApiNetworksNetworkIdRoutersJSONRequestBody{
|
||||
Peer: ptr("test"),
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworkRouters_Update_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Meow/routers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "PUT", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PutApiNetworksNetworkIdRoutersRouterIdJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "test", *req.Peer)
|
||||
retBytes, _ := json.Marshal(testNetworkRouter)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Networks.Routers("Meow").Update(context.Background(), "Test", api.PutApiNetworksNetworkIdRoutersRouterIdJSONRequestBody{
|
||||
Peer: ptr("test"),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testNetworkRouter, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworkRouters_Update_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Meow/routers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Networks.Routers("Meow").Update(context.Background(), "Test", api.PutApiNetworksNetworkIdRoutersRouterIdJSONRequestBody{
|
||||
Peer: ptr("test"),
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworkRouters_Delete_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Meow/routers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.Networks.Routers("Meow").Delete(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworkRouters_Delete_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/networks/Meow/routers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.Networks.Routers("Meow").Delete(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestNetworkRouters_Integration(t *testing.T) {
|
||||
withBlackBoxServer(t, func(c *Client) {
|
||||
_, err := c.Networks.Routers("TestNetwork").Create(context.Background(), api.NetworkRouterRequest{
|
||||
Enabled: false,
|
||||
Masquerade: false,
|
||||
Metric: 9999,
|
||||
PeerGroups: ptr([]string{"test"}),
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = c.Networks.Routers("TestNetwork").List(context.Background())
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = c.Networks.Routers("TestNetwork").Get(context.Background(), "TestRouter")
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = c.Networks.Routers("TestNetwork").Update(context.Background(), "TestRouter", api.NetworkRouterRequest{
|
||||
Enabled: true,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = c.Networks.Routers("TestNetwork").Delete(context.Background(), "TestRouter")
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
78
management/client/rest/peers.go
Normal file
78
management/client/rest/peers.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
)
|
||||
|
||||
// PeersAPI APIs for peers, do not use directly
|
||||
type PeersAPI struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// List list all peers
|
||||
// See more: https://docs.netbird.io/api/resources/peers#list-all-peers
|
||||
func (a *PeersAPI) List(ctx context.Context) ([]api.Peer, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/peers", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[[]api.Peer](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get retrieve a peer
|
||||
// See more: https://docs.netbird.io/api/resources/peers#retrieve-a-peer
|
||||
func (a *PeersAPI) Get(ctx context.Context, peerID string) (*api.Peer, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/peers/"+peerID, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.Peer](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Update update information for a peer
|
||||
// See more: https://docs.netbird.io/api/resources/peers#update-a-peer
|
||||
func (a *PeersAPI) Update(ctx context.Context, peerID string, request api.PutApiPeersPeerIdJSONRequestBody) (*api.Peer, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.newRequest(ctx, "PUT", "/api/peers/"+peerID, bytes.NewReader(requestBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.Peer](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Delete delete a peer
|
||||
// See more: https://docs.netbird.io/api/resources/peers#delete-a-peer
|
||||
func (a *PeersAPI) Delete(ctx context.Context, peerID string) error {
|
||||
resp, err := a.c.newRequest(ctx, "DELETE", "/api/peers/"+peerID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListAccessiblePeers list all peers that the specified peer can connect to within the network
|
||||
// See more: https://docs.netbird.io/api/resources/peers#list-accessible-peers
|
||||
func (a *PeersAPI) ListAccessiblePeers(ctx context.Context, peerID string) ([]api.Peer, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/peers/"+peerID+"/accessible-peers", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[[]api.Peer](resp)
|
||||
return ret, err
|
||||
}
|
||||
203
management/client/rest/peers_test.go
Normal file
203
management/client/rest/peers_test.go
Normal file
@@ -0,0 +1,203 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
"github.com/netbirdio/netbird/management/server/http/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
testPeer = api.Peer{
|
||||
ApprovalRequired: false,
|
||||
Connected: false,
|
||||
ConnectionIp: "127.0.0.1",
|
||||
DnsLabel: "test",
|
||||
Id: "Test",
|
||||
}
|
||||
)
|
||||
|
||||
func TestPeers_List_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal([]api.Peer{testPeer})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Peers.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testPeer, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeers_List_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Peers.List(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeers_Get_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(testPeer)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Peers.Get(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testPeer, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeers_Get_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Peers.Get(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeers_Update_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "PUT", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PutApiPeersPeerIdJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, req.InactivityExpirationEnabled)
|
||||
retBytes, _ := json.Marshal(testPeer)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Peers.Update(context.Background(), "Test", api.PutApiPeersPeerIdJSONRequestBody{
|
||||
InactivityExpirationEnabled: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testPeer, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeers_Update_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Peers.Update(context.Background(), "Test", api.PutApiPeersPeerIdJSONRequestBody{
|
||||
InactivityExpirationEnabled: false,
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeers_Delete_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.Peers.Delete(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeers_Delete_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.Peers.Delete(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeers_ListAccessiblePeers_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/Test/accessible-peers", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal([]api.Peer{testPeer})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Peers.ListAccessiblePeers(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testPeer, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeers_ListAccessiblePeers_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/peers/Test/accessible-peers", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Peers.ListAccessiblePeers(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPeers_Integration(t *testing.T) {
|
||||
withBlackBoxServer(t, func(c *Client) {
|
||||
peers, err := c.Peers.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, peers)
|
||||
|
||||
peer, err := c.Peers.Get(context.Background(), peers[0].Id)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, peers[0].Id, peer.Id)
|
||||
|
||||
peer, err = c.Peers.Update(context.Background(), peer.Id, api.PeerRequest{
|
||||
LoginExpirationEnabled: true,
|
||||
Name: "Test",
|
||||
SshEnabled: false,
|
||||
ApprovalRequired: ptr(false),
|
||||
InactivityExpirationEnabled: false,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, peer.LoginExpirationEnabled)
|
||||
|
||||
accessiblePeers, err := c.Peers.ListAccessiblePeers(context.Background(), peer.Id)
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, accessiblePeers)
|
||||
|
||||
err = c.Peers.Delete(context.Background(), peer.Id)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
82
management/client/rest/policies.go
Normal file
82
management/client/rest/policies.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
)
|
||||
|
||||
// PoliciesAPI APIs for Policies, do not use directly
|
||||
type PoliciesAPI struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// List list all policies
|
||||
// See more: https://docs.netbird.io/api/resources/policies#list-all-policies
|
||||
func (a *PoliciesAPI) List(ctx context.Context) ([]api.Policy, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/policies", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[[]api.Policy](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get get policy info
|
||||
// See more: https://docs.netbird.io/api/resources/policies#retrieve-a-policy
|
||||
func (a *PoliciesAPI) Get(ctx context.Context, policyID string) (*api.Policy, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/policies/"+policyID, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.Policy](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Create create new policy
|
||||
// See more: https://docs.netbird.io/api/resources/policies#create-a-policy
|
||||
func (a *PoliciesAPI) Create(ctx context.Context, request api.PostApiPoliciesJSONRequestBody) (*api.Policy, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.newRequest(ctx, "POST", "/api/policies", bytes.NewReader(requestBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.Policy](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Update update policy info
|
||||
// See more: https://docs.netbird.io/api/resources/policies#update-a-policy
|
||||
func (a *PoliciesAPI) Update(ctx context.Context, policyID string, request api.PutApiPoliciesPolicyIdJSONRequestBody) (*api.Policy, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.newRequest(ctx, "PUT", "/api/policies/"+policyID, bytes.NewReader(requestBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.Policy](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Delete delete policy
|
||||
// See more: https://docs.netbird.io/api/resources/policies#delete-a-policy
|
||||
func (a *PoliciesAPI) Delete(ctx context.Context, policyID string) error {
|
||||
resp, err := a.c.newRequest(ctx, "DELETE", "/api/policies/"+policyID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
236
management/client/rest/policies_test.go
Normal file
236
management/client/rest/policies_test.go
Normal file
@@ -0,0 +1,236 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
"github.com/netbirdio/netbird/management/server/http/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
testPolicy = api.Policy{
|
||||
Name: "wow",
|
||||
Id: ptr("Test"),
|
||||
Enabled: false,
|
||||
}
|
||||
)
|
||||
|
||||
func TestPolicies_List_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/policies", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal([]api.Policy{testPolicy})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Policies.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testPolicy, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestPolicies_List_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/policies", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Policies.List(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPolicies_Get_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/policies/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(testPolicy)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Policies.Get(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testPolicy, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPolicies_Get_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/policies/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Policies.Get(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPolicies_Create_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/policies", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PutApiPoliciesPolicyIdJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "weaw", req.Name)
|
||||
retBytes, _ := json.Marshal(testPolicy)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Policies.Create(context.Background(), api.PostApiPoliciesJSONRequestBody{
|
||||
Name: "weaw",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testPolicy, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPolicies_Create_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/policies", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Policies.Create(context.Background(), api.PostApiPoliciesJSONRequestBody{
|
||||
Name: "weaw",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPolicies_Update_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/policies/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "PUT", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PutApiPoliciesPolicyIdJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "weaw", req.Name)
|
||||
retBytes, _ := json.Marshal(testPolicy)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Policies.Update(context.Background(), "Test", api.PutApiPoliciesPolicyIdJSONRequestBody{
|
||||
Name: "weaw",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testPolicy, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPolicies_Update_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/policies/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Policies.Update(context.Background(), "Test", api.PutApiPoliciesPolicyIdJSONRequestBody{
|
||||
Name: "weaw",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPolicies_Delete_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/policies/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.Policies.Delete(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPolicies_Delete_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/policies/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.Policies.Delete(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestPolicies_Integration(t *testing.T) {
|
||||
withBlackBoxServer(t, func(c *Client) {
|
||||
policies, err := c.Policies.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, policies)
|
||||
|
||||
policy, err := c.Policies.Get(context.Background(), *policies[0].Id)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, *policies[0].Id, *policy.Id)
|
||||
|
||||
policy, err = c.Policies.Update(context.Background(), *policy.Id, api.PolicyCreate{
|
||||
Description: ptr("Test Policy"),
|
||||
Enabled: false,
|
||||
Name: "Test",
|
||||
Rules: []api.PolicyRuleUpdate{
|
||||
{
|
||||
Action: api.PolicyRuleUpdateAction(policy.Rules[0].Action),
|
||||
Bidirectional: true,
|
||||
Description: ptr("Test Policy"),
|
||||
Sources: ptr([]string{(*policy.Rules[0].Sources)[0].Id}),
|
||||
Destinations: ptr([]string{(*policy.Rules[0].Destinations)[0].Id}),
|
||||
Enabled: false,
|
||||
Protocol: api.PolicyRuleUpdateProtocolAll,
|
||||
},
|
||||
},
|
||||
SourcePostureChecks: nil,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "Test Policy", *policy.Rules[0].Description)
|
||||
|
||||
policy, err = c.Policies.Create(context.Background(), api.PolicyUpdate{
|
||||
Description: ptr("Test Policy 2"),
|
||||
Enabled: false,
|
||||
Name: "Test",
|
||||
Rules: []api.PolicyRuleUpdate{
|
||||
{
|
||||
Action: api.PolicyRuleUpdateAction(policy.Rules[0].Action),
|
||||
Bidirectional: true,
|
||||
Description: ptr("Test Policy 2"),
|
||||
Sources: ptr([]string{(*policy.Rules[0].Sources)[0].Id}),
|
||||
Destinations: ptr([]string{(*policy.Rules[0].Destinations)[0].Id}),
|
||||
Enabled: false,
|
||||
Protocol: api.PolicyRuleUpdateProtocolAll,
|
||||
},
|
||||
},
|
||||
SourcePostureChecks: nil,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = c.Policies.Delete(context.Background(), *policy.Id)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
82
management/client/rest/posturechecks.go
Normal file
82
management/client/rest/posturechecks.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
)
|
||||
|
||||
// PostureChecksAPI APIs for PostureChecks, do not use directly
|
||||
type PostureChecksAPI struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// List list all posture checks
|
||||
// See more: https://docs.netbird.io/api/resources/posture-checks#list-all-posture-checks
|
||||
func (a *PostureChecksAPI) List(ctx context.Context) ([]api.PostureCheck, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/posture-checks", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[[]api.PostureCheck](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get get posture check info
|
||||
// See more: https://docs.netbird.io/api/resources/posture-checks#retrieve-a-posture-check
|
||||
func (a *PostureChecksAPI) Get(ctx context.Context, postureCheckID string) (*api.PostureCheck, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/posture-checks/"+postureCheckID, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.PostureCheck](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Create create new posture check
|
||||
// See more: https://docs.netbird.io/api/resources/posture-checks#create-a-posture-check
|
||||
func (a *PostureChecksAPI) Create(ctx context.Context, request api.PostApiPostureChecksJSONRequestBody) (*api.PostureCheck, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.newRequest(ctx, "POST", "/api/posture-checks", bytes.NewReader(requestBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.PostureCheck](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Update update posture check info
|
||||
// See more: https://docs.netbird.io/api/resources/posture-checks#update-a-posture-check
|
||||
func (a *PostureChecksAPI) Update(ctx context.Context, postureCheckID string, request api.PutApiPostureChecksPostureCheckIdJSONRequestBody) (*api.PostureCheck, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.newRequest(ctx, "PUT", "/api/posture-checks/"+postureCheckID, bytes.NewReader(requestBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.PostureCheck](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Delete delete posture check
|
||||
// See more: https://docs.netbird.io/api/resources/posture-checks#delete-a-posture-check
|
||||
func (a *PostureChecksAPI) Delete(ctx context.Context, postureCheckID string) error {
|
||||
resp, err := a.c.newRequest(ctx, "DELETE", "/api/posture-checks/"+postureCheckID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
228
management/client/rest/posturechecks_test.go
Normal file
228
management/client/rest/posturechecks_test.go
Normal file
@@ -0,0 +1,228 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
"github.com/netbirdio/netbird/management/server/http/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
testPostureCheck = api.PostureCheck{
|
||||
Id: "Test",
|
||||
Name: "wow",
|
||||
}
|
||||
)
|
||||
|
||||
func TestPostureChecks_List_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/posture-checks", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal([]api.PostureCheck{testPostureCheck})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.PostureChecks.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testPostureCheck, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestPostureChecks_List_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/posture-checks", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.PostureChecks.List(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPostureChecks_Get_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/posture-checks/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(testPostureCheck)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.PostureChecks.Get(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testPostureCheck, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPostureChecks_Get_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/posture-checks/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.PostureChecks.Get(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPostureChecks_Create_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/posture-checks", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PostureCheckUpdate
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "weaw", req.Name)
|
||||
retBytes, _ := json.Marshal(testPostureCheck)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.PostureChecks.Create(context.Background(), api.PostureCheckUpdate{
|
||||
Name: "weaw",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testPostureCheck, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPostureChecks_Create_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/posture-checks", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.PostureChecks.Create(context.Background(), api.PostureCheckUpdate{
|
||||
Name: "weaw",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPostureChecks_Update_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/posture-checks/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "PUT", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PostureCheckUpdate
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "weaw", req.Name)
|
||||
retBytes, _ := json.Marshal(testPostureCheck)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.PostureChecks.Update(context.Background(), "Test", api.PostureCheckUpdate{
|
||||
Name: "weaw",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testPostureCheck, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPostureChecks_Update_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/posture-checks/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.PostureChecks.Update(context.Background(), "Test", api.PostureCheckUpdate{
|
||||
Name: "weaw",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPostureChecks_Delete_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/posture-checks/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.PostureChecks.Delete(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestPostureChecks_Delete_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/posture-checks/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.PostureChecks.Delete(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestPostureChecks_Integration(t *testing.T) {
|
||||
withBlackBoxServer(t, func(c *Client) {
|
||||
check, err := c.PostureChecks.Create(context.Background(), api.PostureCheckUpdate{
|
||||
Name: "Test",
|
||||
Description: "Testing",
|
||||
Checks: &api.Checks{
|
||||
OsVersionCheck: &api.OSVersionCheck{
|
||||
Windows: &api.MinKernelVersionCheck{
|
||||
MinKernelVersion: "0.0.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "Test", check.Name)
|
||||
|
||||
checks, err := c.PostureChecks.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, checks, 1)
|
||||
|
||||
check, err = c.PostureChecks.Update(context.Background(), check.Id, api.PostureCheckUpdate{
|
||||
Name: "Tests",
|
||||
Description: "Testings",
|
||||
Checks: &api.Checks{
|
||||
GeoLocationCheck: &api.GeoLocationCheck{
|
||||
Action: api.GeoLocationCheckActionAllow, Locations: []api.Location{
|
||||
{
|
||||
CityName: ptr("Cairo"),
|
||||
CountryCode: "EG",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "Testings", *check.Description)
|
||||
|
||||
check, err = c.PostureChecks.Get(context.Background(), check.Id)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "Tests", check.Name)
|
||||
|
||||
err = c.PostureChecks.Delete(context.Background(), check.Id)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
82
management/client/rest/routes.go
Normal file
82
management/client/rest/routes.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
)
|
||||
|
||||
// RoutesAPI APIs for Routes, do not use directly
|
||||
type RoutesAPI struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// List list all routes
|
||||
// See more: https://docs.netbird.io/api/resources/routes#list-all-routes
|
||||
func (a *RoutesAPI) List(ctx context.Context) ([]api.Route, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/routes", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[[]api.Route](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get get route info
|
||||
// See more: https://docs.netbird.io/api/resources/routes#retrieve-a-route
|
||||
func (a *RoutesAPI) Get(ctx context.Context, routeID string) (*api.Route, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/routes/"+routeID, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.Route](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Create create new route
|
||||
// See more: https://docs.netbird.io/api/resources/routes#create-a-route
|
||||
func (a *RoutesAPI) Create(ctx context.Context, request api.PostApiRoutesJSONRequestBody) (*api.Route, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.newRequest(ctx, "POST", "/api/routes", bytes.NewReader(requestBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.Route](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Update update route info
|
||||
// See more: https://docs.netbird.io/api/resources/routes#update-a-route
|
||||
func (a *RoutesAPI) Update(ctx context.Context, routeID string, request api.PutApiRoutesRouteIdJSONRequestBody) (*api.Route, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.newRequest(ctx, "PUT", "/api/routes/"+routeID, bytes.NewReader(requestBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.Route](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Delete delete route
|
||||
// See more: https://docs.netbird.io/api/resources/routes#delete-a-route
|
||||
func (a *RoutesAPI) Delete(ctx context.Context, routeID string) error {
|
||||
resp, err := a.c.newRequest(ctx, "DELETE", "/api/routes/"+routeID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
226
management/client/rest/routes_test.go
Normal file
226
management/client/rest/routes_test.go
Normal file
@@ -0,0 +1,226 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
"github.com/netbirdio/netbird/management/server/http/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
testRoute = api.Route{
|
||||
Id: "Test",
|
||||
Domains: ptr([]string{"google.com"}),
|
||||
}
|
||||
)
|
||||
|
||||
func TestRoutes_List_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/routes", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal([]api.Route{testRoute})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Routes.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testRoute, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestRoutes_List_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/routes", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Routes.List(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRoutes_Get_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/routes/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(testRoute)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Routes.Get(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testRoute, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRoutes_Get_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/routes/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Routes.Get(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRoutes_Create_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/routes", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PostApiRoutesJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "meow", req.Description)
|
||||
retBytes, _ := json.Marshal(testRoute)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Routes.Create(context.Background(), api.PostApiRoutesJSONRequestBody{
|
||||
Description: "meow",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testRoute, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRoutes_Create_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/routes", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Routes.Create(context.Background(), api.PostApiRoutesJSONRequestBody{
|
||||
Description: "meow",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRoutes_Update_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/routes/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "PUT", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PutApiRoutesRouteIdJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "meow", req.Description)
|
||||
retBytes, _ := json.Marshal(testRoute)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Routes.Update(context.Background(), "Test", api.PutApiRoutesRouteIdJSONRequestBody{
|
||||
Description: "meow",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testRoute, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRoutes_Update_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/routes/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Routes.Update(context.Background(), "Test", api.PutApiRoutesRouteIdJSONRequestBody{
|
||||
Description: "meow",
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRoutes_Delete_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/routes/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.Routes.Delete(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRoutes_Delete_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/routes/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.Routes.Delete(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestRoutes_Integration(t *testing.T) {
|
||||
withBlackBoxServer(t, func(c *Client) {
|
||||
route, err := c.Routes.Create(context.Background(), api.RouteRequest{
|
||||
Description: "Meow",
|
||||
Enabled: false,
|
||||
Groups: []string{"cs1tnh0hhcjnqoiuebeg"},
|
||||
PeerGroups: ptr([]string{"cs1tnh0hhcjnqoiuebeg"}),
|
||||
Domains: ptr([]string{"google.com"}),
|
||||
Masquerade: true,
|
||||
Metric: 9999,
|
||||
KeepRoute: false,
|
||||
NetworkId: "Test",
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "Test", route.NetworkId)
|
||||
|
||||
routes, err := c.Routes.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, routes, 1)
|
||||
|
||||
route, err = c.Routes.Update(context.Background(), route.Id, api.RouteRequest{
|
||||
Description: "Testings",
|
||||
Enabled: false,
|
||||
Groups: []string{"cs1tnh0hhcjnqoiuebeg"},
|
||||
PeerGroups: ptr([]string{"cs1tnh0hhcjnqoiuebeg"}),
|
||||
Domains: ptr([]string{"google.com"}),
|
||||
Masquerade: true,
|
||||
Metric: 9999,
|
||||
KeepRoute: false,
|
||||
NetworkId: "Tests",
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "Testings", route.Description)
|
||||
|
||||
route, err = c.Routes.Get(context.Background(), route.Id)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "Tests", route.NetworkId)
|
||||
|
||||
err = c.Routes.Delete(context.Background(), route.Id)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
82
management/client/rest/setupkeys.go
Normal file
82
management/client/rest/setupkeys.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
)
|
||||
|
||||
// SetupKeysAPI APIs for Setup keys, do not use directly
|
||||
type SetupKeysAPI struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// List list all setup keys
|
||||
// See more: https://docs.netbird.io/api/resources/setup-keys#list-all-setup-keys
|
||||
func (a *SetupKeysAPI) List(ctx context.Context) ([]api.SetupKey, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/setup-keys", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[[]api.SetupKey](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get get setup key info
|
||||
// See more: https://docs.netbird.io/api/resources/setup-keys#retrieve-a-setup-key
|
||||
func (a *SetupKeysAPI) Get(ctx context.Context, setupKeyID string) (*api.SetupKey, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/setup-keys/"+setupKeyID, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.SetupKey](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Create generate new Setup Key
|
||||
// See more: https://docs.netbird.io/api/resources/setup-keys#create-a-setup-key
|
||||
func (a *SetupKeysAPI) Create(ctx context.Context, request api.PostApiSetupKeysJSONRequestBody) (*api.SetupKeyClear, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.newRequest(ctx, "POST", "/api/setup-keys", bytes.NewReader(requestBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.SetupKeyClear](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Update generate new Setup Key
|
||||
// See more: https://docs.netbird.io/api/resources/setup-keys#update-a-setup-key
|
||||
func (a *SetupKeysAPI) Update(ctx context.Context, setupKeyID string, request api.PutApiSetupKeysKeyIdJSONRequestBody) (*api.SetupKey, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.newRequest(ctx, "PUT", "/api/setup-keys/"+setupKeyID, bytes.NewReader(requestBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.SetupKey](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Delete delete setup key
|
||||
// See more: https://docs.netbird.io/api/resources/setup-keys#delete-a-setup-key
|
||||
func (a *SetupKeysAPI) Delete(ctx context.Context, setupKeyID string) error {
|
||||
resp, err := a.c.newRequest(ctx, "DELETE", "/api/setup-keys/"+setupKeyID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
227
management/client/rest/setupkeys_test.go
Normal file
227
management/client/rest/setupkeys_test.go
Normal file
@@ -0,0 +1,227 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
"github.com/netbirdio/netbird/management/server/http/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
testSetupKey = api.SetupKey{
|
||||
Id: "Test",
|
||||
Name: "wow",
|
||||
AutoGroups: []string{"meow"},
|
||||
Ephemeral: true,
|
||||
}
|
||||
|
||||
testSteupKeyGenerated = api.SetupKeyClear{
|
||||
Id: "Test",
|
||||
Name: "wow",
|
||||
AutoGroups: []string{"meow"},
|
||||
Ephemeral: true,
|
||||
Key: "shhh",
|
||||
}
|
||||
)
|
||||
|
||||
func TestSetupKeys_List_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/setup-keys", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal([]api.SetupKey{testSetupKey})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.SetupKeys.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testSetupKey, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestSetupKeys_List_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/setup-keys", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.SetupKeys.List(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSetupKeys_Get_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/setup-keys/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(testSetupKey)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.SetupKeys.Get(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testSetupKey, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSetupKeys_Get_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/setup-keys/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.SetupKeys.Get(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSetupKeys_Create_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/setup-keys", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PostApiSetupKeysJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 5, req.ExpiresIn)
|
||||
retBytes, _ := json.Marshal(testSteupKeyGenerated)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.SetupKeys.Create(context.Background(), api.PostApiSetupKeysJSONRequestBody{
|
||||
ExpiresIn: 5,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testSteupKeyGenerated, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSetupKeys_Create_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/setup-keys", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.SetupKeys.Create(context.Background(), api.PostApiSetupKeysJSONRequestBody{
|
||||
ExpiresIn: 5,
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSetupKeys_Update_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/setup-keys/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "PUT", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PutApiSetupKeysKeyIdJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, req.Revoked)
|
||||
retBytes, _ := json.Marshal(testSetupKey)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.SetupKeys.Update(context.Background(), "Test", api.PutApiSetupKeysKeyIdJSONRequestBody{
|
||||
Revoked: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testSetupKey, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSetupKeys_Update_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/setup-keys/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.SetupKeys.Update(context.Background(), "Test", api.PutApiSetupKeysKeyIdJSONRequestBody{
|
||||
Revoked: true,
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSetupKeys_Delete_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/setup-keys/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.SetupKeys.Delete(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSetupKeys_Delete_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/setup-keys/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.SetupKeys.Delete(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestSetupKeys_Integration(t *testing.T) {
|
||||
withBlackBoxServer(t, func(c *Client) {
|
||||
group, err := c.Groups.Create(context.Background(), api.GroupRequest{
|
||||
Name: "Test",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
skClear, err := c.SetupKeys.Create(context.Background(), api.CreateSetupKeyRequest{
|
||||
AutoGroups: []string{group.Id},
|
||||
Ephemeral: ptr(false),
|
||||
Name: "test",
|
||||
Type: "reusable",
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, skClear.Valid)
|
||||
|
||||
keys, err := c.SetupKeys.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, keys, 2)
|
||||
|
||||
sk, err := c.SetupKeys.Update(context.Background(), skClear.Id, api.SetupKeyRequest{
|
||||
Revoked: true,
|
||||
AutoGroups: []string{group.Id},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
sk, err = c.SetupKeys.Get(context.Background(), sk.Id)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, false, sk.Valid)
|
||||
|
||||
err = c.SetupKeys.Delete(context.Background(), sk.Id)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
66
management/client/rest/tokens.go
Normal file
66
management/client/rest/tokens.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
)
|
||||
|
||||
// TokensAPI APIs for PATs, do not use directly
|
||||
type TokensAPI struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// List list user tokens
|
||||
// See more: https://docs.netbird.io/api/resources/tokens#list-all-tokens
|
||||
func (a *TokensAPI) List(ctx context.Context, userID string) ([]api.PersonalAccessToken, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/users/"+userID+"/tokens", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[[]api.PersonalAccessToken](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Get get user token info
|
||||
// See more: https://docs.netbird.io/api/resources/tokens#retrieve-a-token
|
||||
func (a *TokensAPI) Get(ctx context.Context, userID, tokenID string) (*api.PersonalAccessToken, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/users/"+userID+"/tokens/"+tokenID, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.PersonalAccessToken](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Create generate new PAT for user
|
||||
// See more: https://docs.netbird.io/api/resources/tokens#create-a-token
|
||||
func (a *TokensAPI) Create(ctx context.Context, userID string, request api.PostApiUsersUserIdTokensJSONRequestBody) (*api.PersonalAccessTokenGenerated, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.newRequest(ctx, "POST", "/api/users/"+userID+"/tokens", bytes.NewReader(requestBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.PersonalAccessTokenGenerated](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Delete delete user token
|
||||
// See more: https://docs.netbird.io/api/resources/tokens#delete-a-token
|
||||
func (a *TokensAPI) Delete(ctx context.Context, userID, tokenID string) error {
|
||||
resp, err := a.c.newRequest(ctx, "DELETE", "/api/users/"+userID+"/tokens/"+tokenID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
175
management/client/rest/tokens_test.go
Normal file
175
management/client/rest/tokens_test.go
Normal file
@@ -0,0 +1,175 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
"github.com/netbirdio/netbird/management/server/http/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
testToken = api.PersonalAccessToken{
|
||||
Id: "Test",
|
||||
CreatedAt: time.Time{},
|
||||
CreatedBy: "meow",
|
||||
ExpirationDate: time.Time{},
|
||||
LastUsed: nil,
|
||||
Name: "wow",
|
||||
}
|
||||
|
||||
testTokenGenerated = api.PersonalAccessTokenGenerated{
|
||||
PersonalAccessToken: testToken,
|
||||
PlainToken: "shhh",
|
||||
}
|
||||
)
|
||||
|
||||
func TestTokens_List_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/meow/tokens", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal([]api.PersonalAccessToken{testToken})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Tokens.List(context.Background(), "meow")
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testToken, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestTokens_List_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/meow/tokens", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Tokens.List(context.Background(), "meow")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestTokens_Get_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/meow/tokens/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(testToken)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Tokens.Get(context.Background(), "meow", "Test")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testToken, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestTokens_Get_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/meow/tokens/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Tokens.Get(context.Background(), "meow", "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestTokens_Create_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/meow/tokens", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PostApiUsersUserIdTokensJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 5, req.ExpiresIn)
|
||||
retBytes, _ := json.Marshal(testTokenGenerated)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Tokens.Create(context.Background(), "meow", api.PostApiUsersUserIdTokensJSONRequestBody{
|
||||
ExpiresIn: 5,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testTokenGenerated, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestTokens_Create_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/meow/tokens", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Tokens.Create(context.Background(), "meow", api.PostApiUsersUserIdTokensJSONRequestBody{
|
||||
ExpiresIn: 5,
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestTokens_Delete_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/meow/tokens/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.Tokens.Delete(context.Background(), "meow", "Test")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestTokens_Delete_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/meow/tokens/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.Tokens.Delete(context.Background(), "meow", "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestTokens_Integration(t *testing.T) {
|
||||
withBlackBoxServer(t, func(c *Client) {
|
||||
tokenClear, err := c.Tokens.Create(context.Background(), "a23efe53-63fb-11ec-90d6-0242ac120003", api.PersonalAccessTokenRequest{
|
||||
Name: "Test",
|
||||
ExpiresIn: 365,
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "Test", tokenClear.PersonalAccessToken.Name)
|
||||
|
||||
tokens, err := c.Tokens.List(context.Background(), "a23efe53-63fb-11ec-90d6-0242ac120003")
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, tokens, 2)
|
||||
|
||||
token, err := c.Tokens.Get(context.Background(), "a23efe53-63fb-11ec-90d6-0242ac120003", tokenClear.PersonalAccessToken.Id)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "Test", token.Name)
|
||||
|
||||
err = c.Tokens.Delete(context.Background(), "a23efe53-63fb-11ec-90d6-0242ac120003", token.Id)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
82
management/client/rest/users.go
Normal file
82
management/client/rest/users.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
)
|
||||
|
||||
// UsersAPI APIs for users, do not use directly
|
||||
type UsersAPI struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// List list all users, only returns one user always
|
||||
// See more: https://docs.netbird.io/api/resources/users#list-all-users
|
||||
func (a *UsersAPI) List(ctx context.Context) ([]api.User, error) {
|
||||
resp, err := a.c.newRequest(ctx, "GET", "/api/users", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[[]api.User](resp)
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Create create user
|
||||
// See more: https://docs.netbird.io/api/resources/users#create-a-user
|
||||
func (a *UsersAPI) Create(ctx context.Context, request api.PostApiUsersJSONRequestBody) (*api.User, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.newRequest(ctx, "POST", "/api/users", bytes.NewReader(requestBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.User](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Update update user settings
|
||||
// See more: https://docs.netbird.io/api/resources/users#update-a-user
|
||||
func (a *UsersAPI) Update(ctx context.Context, userID string, request api.PutApiUsersUserIdJSONRequestBody) (*api.User, error) {
|
||||
requestBytes, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := a.c.newRequest(ctx, "PUT", "/api/users/"+userID, bytes.NewReader(requestBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
ret, err := parseResponse[api.User](resp)
|
||||
return &ret, err
|
||||
}
|
||||
|
||||
// Delete delete user
|
||||
// See more: https://docs.netbird.io/api/resources/users#delete-a-user
|
||||
func (a *UsersAPI) Delete(ctx context.Context, userID string) error {
|
||||
resp, err := a.c.newRequest(ctx, "DELETE", "/api/users/"+userID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResendInvitation resend user invitation
|
||||
// See more: https://docs.netbird.io/api/resources/users#resend-user-invitation
|
||||
func (a *UsersAPI) ResendInvitation(ctx context.Context, userID string) error {
|
||||
resp, err := a.c.newRequest(ctx, "POST", "/api/users/"+userID+"/invite", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
222
management/client/rest/users_test.go
Normal file
222
management/client/rest/users_test.go
Normal file
@@ -0,0 +1,222 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
"github.com/netbirdio/netbird/management/server/http/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
testUser = api.User{
|
||||
Id: "Test",
|
||||
AutoGroups: []string{"test-group"},
|
||||
Email: "test@test.com",
|
||||
IsBlocked: false,
|
||||
IsCurrent: ptr(false),
|
||||
IsServiceUser: ptr(false),
|
||||
Issued: ptr("api"),
|
||||
LastLogin: &time.Time{},
|
||||
Name: "M. Essam",
|
||||
Permissions: &api.UserPermissions{
|
||||
DashboardView: ptr(api.UserPermissionsDashboardViewFull),
|
||||
},
|
||||
Role: "user",
|
||||
Status: api.UserStatusActive,
|
||||
}
|
||||
)
|
||||
|
||||
func TestUsers_List_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal([]api.User{testUser})
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Users.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, ret, 1)
|
||||
assert.Equal(t, testUser, ret[0])
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_List_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Users.List(context.Background())
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Empty(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_Create_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PostApiUsersJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []string{"meow"}, req.AutoGroups)
|
||||
retBytes, _ := json.Marshal(testUser)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Users.Create(context.Background(), api.PostApiUsersJSONRequestBody{
|
||||
AutoGroups: []string{"meow"},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testUser, *ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_Create_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Users.Create(context.Background(), api.PostApiUsersJSONRequestBody{
|
||||
AutoGroups: []string{"meow"},
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_Update_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "PUT", r.Method)
|
||||
reqBytes, err := io.ReadAll(r.Body)
|
||||
require.NoError(t, err)
|
||||
var req api.PutApiUsersUserIdJSONRequestBody
|
||||
err = json.Unmarshal(reqBytes, &req)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, req.IsBlocked)
|
||||
retBytes, _ := json.Marshal(testUser)
|
||||
_, err = w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Users.Update(context.Background(), "Test", api.PutApiUsersUserIdJSONRequestBody{
|
||||
IsBlocked: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testUser, *ret)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestUsers_Update_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||
w.WriteHeader(400)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
ret, err := c.Users.Update(context.Background(), "Test", api.PutApiUsersUserIdJSONRequestBody{
|
||||
IsBlocked: true,
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "No", err.Error())
|
||||
assert.Nil(t, ret)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_Delete_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "DELETE", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.Users.Delete(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_Delete_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/Test", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.Users.Delete(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_ResendInvitation_200(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/Test/invite", func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "POST", r.Method)
|
||||
w.WriteHeader(200)
|
||||
})
|
||||
err := c.Users.ResendInvitation(context.Background(), "Test")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_ResendInvitation_Err(t *testing.T) {
|
||||
withMockClient(func(c *Client, mux *http.ServeMux) {
|
||||
mux.HandleFunc("/api/users/Test/invite", func(w http.ResponseWriter, r *http.Request) {
|
||||
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "Not found", Code: 404})
|
||||
w.WriteHeader(404)
|
||||
_, err := w.Write(retBytes)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
err := c.Users.ResendInvitation(context.Background(), "Test")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "Not found", err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
func TestUsers_Integration(t *testing.T) {
|
||||
withBlackBoxServer(t, func(c *Client) {
|
||||
user, err := c.Users.Create(context.Background(), api.UserCreateRequest{
|
||||
AutoGroups: []string{},
|
||||
Email: ptr("test@example.com"),
|
||||
IsServiceUser: true,
|
||||
Name: ptr("Nobody"),
|
||||
Role: "user",
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "Nobody", user.Name)
|
||||
|
||||
users, err := c.Users.List(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, users)
|
||||
|
||||
user, err = c.Users.Update(context.Background(), user.Id, api.UserRequest{
|
||||
AutoGroups: []string{},
|
||||
Role: "admin",
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "admin", user.Role)
|
||||
|
||||
err = c.Users.Delete(context.Background(), user.Id)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -52,7 +52,7 @@ message EncryptedMessage {
|
||||
|
||||
// encrypted message Body
|
||||
bytes body = 2;
|
||||
// Version of the Wiretrustee Management Service protocol
|
||||
// Version of the Netbird Management Service protocol
|
||||
int32 version = 3;
|
||||
}
|
||||
|
||||
@@ -61,11 +61,11 @@ message SyncRequest {
|
||||
PeerSystemMeta meta = 1;
|
||||
}
|
||||
|
||||
// SyncResponse represents a state that should be applied to the local peer (e.g. Wiretrustee servers config as well as local peer and remote peers configs)
|
||||
// SyncResponse represents a state that should be applied to the local peer (e.g. Netbird servers config as well as local peer and remote peers configs)
|
||||
message SyncResponse {
|
||||
|
||||
// Global config
|
||||
WiretrusteeConfig wiretrusteeConfig = 1;
|
||||
NetbirdConfig netbirdConfig = 1;
|
||||
|
||||
// Deprecated. Use NetworkMap.PeerConfig
|
||||
PeerConfig peerConfig = 2;
|
||||
@@ -146,7 +146,7 @@ message PeerSystemMeta {
|
||||
string core = 4;
|
||||
string platform = 5;
|
||||
string OS = 6;
|
||||
string wiretrusteeVersion = 7;
|
||||
string netbirdVersion = 7;
|
||||
string uiVersion = 8;
|
||||
string kernelVersion = 9;
|
||||
string OSVersion = 10;
|
||||
@@ -161,7 +161,7 @@ message PeerSystemMeta {
|
||||
|
||||
message LoginResponse {
|
||||
// Global config
|
||||
WiretrusteeConfig wiretrusteeConfig = 1;
|
||||
NetbirdConfig netbirdConfig = 1;
|
||||
// Peer local config
|
||||
PeerConfig peerConfig = 2;
|
||||
// Posture checks to be evaluated by client
|
||||
@@ -173,14 +173,14 @@ message ServerKeyResponse {
|
||||
string key = 1;
|
||||
// Key expiration timestamp after which the key should be fetched again by the client
|
||||
google.protobuf.Timestamp expiresAt = 2;
|
||||
// Version of the Wiretrustee Management Service protocol
|
||||
// Version of the Netbird Management Service protocol
|
||||
int32 version = 3;
|
||||
}
|
||||
|
||||
message Empty {}
|
||||
|
||||
// WiretrusteeConfig is a common configuration of any Wiretrustee peer. It contains STUN, TURN, Signal and Management servers configurations
|
||||
message WiretrusteeConfig {
|
||||
// NetbirdConfig is a common configuration of any Netbird peer. It contains STUN, TURN, Signal and Management servers configurations
|
||||
message NetbirdConfig {
|
||||
// a list of STUN servers
|
||||
repeated HostConfig stuns = 1;
|
||||
// a list of TURN servers
|
||||
@@ -194,7 +194,7 @@ message WiretrusteeConfig {
|
||||
|
||||
// HostConfig describes connection properties of some server (e.g. STUN, Signal, Management)
|
||||
message HostConfig {
|
||||
// URI of the resource e.g. turns://stun.wiretrustee.com:4430 or signal.wiretrustee.com:10000
|
||||
// URI of the resource e.g. turns://stun.netbird.io:4430 or signal.netbird.io:10000
|
||||
string uri = 1;
|
||||
Protocol protocol = 2;
|
||||
|
||||
@@ -224,9 +224,9 @@ message ProtectedHostConfig {
|
||||
// PeerConfig represents a configuration of a "our" peer.
|
||||
// The properties are used to configure local Wireguard
|
||||
message PeerConfig {
|
||||
// Peer's virtual IP address within the Wiretrustee VPN (a Wireguard address config)
|
||||
// Peer's virtual IP address within the Netbird VPN (a Wireguard address config)
|
||||
string address = 1;
|
||||
// Wiretrustee DNS server (a Wireguard DNS config)
|
||||
// Netbird DNS server (a Wireguard DNS config)
|
||||
string dns = 2;
|
||||
|
||||
// SSHConfig of the peer.
|
||||
|
||||
@@ -106,10 +106,10 @@ type HttpServerConfig struct {
|
||||
ExtraAuthAudience string
|
||||
}
|
||||
|
||||
// Host represents a Wiretrustee host (e.g. STUN, TURN, Signal)
|
||||
// Host represents a Netbird host (e.g. STUN, TURN, Signal)
|
||||
type Host struct {
|
||||
Proto Protocol
|
||||
// URI e.g. turns://stun.wiretrustee.com:4430 or signal.wiretrustee.com:10000
|
||||
// URI e.g. turns://stun.netbird.io:4430 or signal.netbird.io:10000
|
||||
URI string
|
||||
Username string
|
||||
Password string
|
||||
|
||||
@@ -381,7 +381,7 @@ func extractPeerMeta(ctx context.Context, meta *proto.PeerSystemMeta) nbpeer.Pee
|
||||
Platform: meta.GetPlatform(),
|
||||
OS: meta.GetOS(),
|
||||
OSVersion: osVersion,
|
||||
WtVersion: meta.GetWiretrusteeVersion(),
|
||||
WtVersion: meta.GetNetbirdVersion(),
|
||||
UIVersion: meta.GetUiVersion(),
|
||||
KernelVersion: meta.GetKernelVersion(),
|
||||
NetworkAddresses: networkAddresses,
|
||||
@@ -489,9 +489,9 @@ func (s *GRPCServer) Login(ctx context.Context, req *proto.EncryptedMessage) (*p
|
||||
|
||||
// if peer has reached this point then it has logged in
|
||||
loginResp := &proto.LoginResponse{
|
||||
WiretrusteeConfig: toWiretrusteeConfig(s.config, nil, relayToken),
|
||||
PeerConfig: toPeerConfig(peer, netMap.Network, s.accountManager.GetDNSDomain(), false),
|
||||
Checks: toProtocolChecks(ctx, postureChecks),
|
||||
NetbirdConfig: toNetbirdConfig(s.config, nil, relayToken),
|
||||
PeerConfig: toPeerConfig(peer, netMap.Network, s.accountManager.GetDNSDomain(), false),
|
||||
Checks: toProtocolChecks(ctx, postureChecks),
|
||||
}
|
||||
encryptedResp, err := encryption.EncryptMessage(peerKey, s.wgKey, loginResp)
|
||||
if err != nil {
|
||||
@@ -547,7 +547,7 @@ func ToResponseProto(configProto Protocol) proto.HostConfig_Protocol {
|
||||
}
|
||||
}
|
||||
|
||||
func toWiretrusteeConfig(config *Config, turnCredentials *Token, relayToken *Token) *proto.WiretrusteeConfig {
|
||||
func toNetbirdConfig(config *Config, turnCredentials *Token, relayToken *Token) *proto.NetbirdConfig {
|
||||
if config == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -595,7 +595,7 @@ func toWiretrusteeConfig(config *Config, turnCredentials *Token, relayToken *Tok
|
||||
}
|
||||
}
|
||||
|
||||
return &proto.WiretrusteeConfig{
|
||||
return &proto.NetbirdConfig{
|
||||
Stuns: stuns,
|
||||
Turns: turns,
|
||||
Signal: &proto.HostConfig{
|
||||
@@ -619,8 +619,8 @@ func toPeerConfig(peer *nbpeer.Peer, network *types.Network, dnsName string, dns
|
||||
|
||||
func toSyncResponse(ctx context.Context, config *Config, peer *nbpeer.Peer, turnCredentials *Token, relayCredentials *Token, networkMap *types.NetworkMap, dnsName string, checks []*posture.Checks, dnsCache *DNSConfigCache, dnsResolutionOnRoutingPeerEnbled bool) *proto.SyncResponse {
|
||||
response := &proto.SyncResponse{
|
||||
WiretrusteeConfig: toWiretrusteeConfig(config, turnCredentials, relayCredentials),
|
||||
PeerConfig: toPeerConfig(peer, networkMap.Network, dnsName, dnsResolutionOnRoutingPeerEnbled),
|
||||
NetbirdConfig: toNetbirdConfig(config, turnCredentials, relayCredentials),
|
||||
PeerConfig: toPeerConfig(peer, networkMap.Network, dnsName, dnsResolutionOnRoutingPeerEnbled),
|
||||
NetworkMap: &proto.NetworkMap{
|
||||
Serial: networkMap.Network.CurrentSerial(),
|
||||
Routes: toProtocolRoutes(networkMap.Routes),
|
||||
|
||||
@@ -7,15 +7,14 @@ import (
|
||||
"github.com/gorilla/mux"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/configs"
|
||||
nbpeer "github.com/netbirdio/netbird/management/server/peer"
|
||||
"github.com/netbirdio/netbird/management/server/types"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server"
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
"github.com/netbirdio/netbird/management/server/http/configs"
|
||||
"github.com/netbirdio/netbird/management/server/http/util"
|
||||
"github.com/netbirdio/netbird/management/server/jwtclaims"
|
||||
nbpeer "github.com/netbirdio/netbird/management/server/peer"
|
||||
"github.com/netbirdio/netbird/management/server/status"
|
||||
"github.com/netbirdio/netbird/management/server/types"
|
||||
)
|
||||
|
||||
// handler is a handler that returns groups of the account
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/magiconair/properties/assert"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/exp/maps"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server"
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
s "github.com/netbirdio/netbird/management/server"
|
||||
"github.com/netbirdio/netbird/management/server/groups"
|
||||
@@ -281,7 +282,12 @@ func (h *handler) collectIDsInNetwork(ctx context.Context, accountID, userID, ne
|
||||
}
|
||||
if len(router.PeerGroups) > 0 {
|
||||
for _, groupID := range router.PeerGroups {
|
||||
peerCounter += len(groups[groupID].Peers)
|
||||
group, ok := groups[groupID]
|
||||
if !ok {
|
||||
log.WithContext(ctx).Warnf("group %s not found", groupID)
|
||||
continue
|
||||
}
|
||||
peerCounter += len(group.Peers)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,17 +10,14 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
"github.com/netbirdio/netbird/management/server/jwtclaims"
|
||||
"github.com/netbirdio/netbird/management/server/mock_server"
|
||||
"github.com/netbirdio/netbird/management/server/status"
|
||||
"github.com/netbirdio/netbird/management/server/types"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/jwtclaims"
|
||||
|
||||
"github.com/magiconair/properties/assert"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/mock_server"
|
||||
)
|
||||
|
||||
func initPoliciesTestData(policies ...*types.Policy) *handler {
|
||||
|
||||
@@ -11,21 +11,19 @@ import (
|
||||
"net/netip"
|
||||
"testing"
|
||||
|
||||
"github.com/netbirdio/netbird/management/server/util"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/netbirdio/netbird/management/domain"
|
||||
"github.com/netbirdio/netbird/management/server/http/api"
|
||||
"github.com/netbirdio/netbird/management/server/jwtclaims"
|
||||
"github.com/netbirdio/netbird/management/server/mock_server"
|
||||
nbpeer "github.com/netbirdio/netbird/management/server/peer"
|
||||
"github.com/netbirdio/netbird/management/server/status"
|
||||
"github.com/netbirdio/netbird/management/server/types"
|
||||
"github.com/netbirdio/netbird/management/server/util"
|
||||
"github.com/netbirdio/netbird/route"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/magiconair/properties/assert"
|
||||
|
||||
"github.com/netbirdio/netbird/management/domain"
|
||||
"github.com/netbirdio/netbird/management/server/jwtclaims"
|
||||
"github.com/netbirdio/netbird/management/server/mock_server"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -94,7 +94,7 @@ func Test_SyncProtocol(t *testing.T) {
|
||||
mgmtServer, _, mgmtAddr, cleanup, err := startManagementForTest(t, "testdata/store_with_expired_peers.sql", &Config{
|
||||
Stuns: []*Host{{
|
||||
Proto: "udp",
|
||||
URI: "stun:stun.wiretrustee.com:3468",
|
||||
URI: "stun:stun.netbird.io:3468",
|
||||
}},
|
||||
TURNConfig: &TURNConfig{
|
||||
TimeBasedCredentials: false,
|
||||
@@ -102,12 +102,12 @@ func Test_SyncProtocol(t *testing.T) {
|
||||
Secret: "whatever",
|
||||
Turns: []*Host{{
|
||||
Proto: "udp",
|
||||
URI: "turn:stun.wiretrustee.com:3468",
|
||||
URI: "turn:stun.netbird.io:3468",
|
||||
}},
|
||||
},
|
||||
Signal: &Host{
|
||||
Proto: "http",
|
||||
URI: "signal.wiretrustee.com:10000",
|
||||
URI: "signal.netbird.io:10000",
|
||||
},
|
||||
Datadir: dir,
|
||||
HttpConfig: nil,
|
||||
@@ -173,64 +173,64 @@ func Test_SyncProtocol(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
wiretrusteeConfig := syncResp.GetWiretrusteeConfig()
|
||||
if wiretrusteeConfig == nil {
|
||||
t.Fatal("expecting SyncResponse to have non-nil WiretrusteeConfig")
|
||||
netbirdConfig := syncResp.GetNetbirdConfig()
|
||||
if netbirdConfig == nil {
|
||||
t.Fatal("expecting SyncResponse to have non-nil NetbirdConfig")
|
||||
}
|
||||
|
||||
if wiretrusteeConfig.GetSignal() == nil {
|
||||
t.Fatal("expecting SyncResponse to have WiretrusteeConfig with non-nil Signal config")
|
||||
if netbirdConfig.GetSignal() == nil {
|
||||
t.Fatal("expecting SyncResponse to have NetbirdConfig with non-nil Signal config")
|
||||
}
|
||||
|
||||
expectedSignalConfig := &mgmtProto.HostConfig{
|
||||
Uri: "signal.wiretrustee.com:10000",
|
||||
Uri: "signal.netbird.io:10000",
|
||||
Protocol: mgmtProto.HostConfig_HTTP,
|
||||
}
|
||||
|
||||
if wiretrusteeConfig.GetSignal().GetUri() != expectedSignalConfig.GetUri() {
|
||||
t.Fatalf("expecting SyncResponse to have WiretrusteeConfig with expected Signal URI: %v, actual: %v",
|
||||
if netbirdConfig.GetSignal().GetUri() != expectedSignalConfig.GetUri() {
|
||||
t.Fatalf("expecting SyncResponse to have NetbirdConfig with expected Signal URI: %v, actual: %v",
|
||||
expectedSignalConfig.GetUri(),
|
||||
wiretrusteeConfig.GetSignal().GetUri())
|
||||
netbirdConfig.GetSignal().GetUri())
|
||||
}
|
||||
|
||||
if wiretrusteeConfig.GetSignal().GetProtocol() != expectedSignalConfig.GetProtocol() {
|
||||
t.Fatalf("expecting SyncResponse to have WiretrusteeConfig with expected Signal Protocol: %v, actual: %v",
|
||||
if netbirdConfig.GetSignal().GetProtocol() != expectedSignalConfig.GetProtocol() {
|
||||
t.Fatalf("expecting SyncResponse to have NetbirdConfig with expected Signal Protocol: %v, actual: %v",
|
||||
expectedSignalConfig.GetProtocol().String(),
|
||||
wiretrusteeConfig.GetSignal().GetProtocol())
|
||||
netbirdConfig.GetSignal().GetProtocol())
|
||||
}
|
||||
|
||||
expectedStunsConfig := &mgmtProto.HostConfig{
|
||||
Uri: "stun:stun.wiretrustee.com:3468",
|
||||
Uri: "stun:stun.netbird.io:3468",
|
||||
Protocol: mgmtProto.HostConfig_UDP,
|
||||
}
|
||||
|
||||
if wiretrusteeConfig.GetStuns()[0].GetUri() != expectedStunsConfig.GetUri() {
|
||||
t.Fatalf("expecting SyncResponse to have WiretrusteeConfig with expected STUN URI: %v, actual: %v",
|
||||
if netbirdConfig.GetStuns()[0].GetUri() != expectedStunsConfig.GetUri() {
|
||||
t.Fatalf("expecting SyncResponse to have NetbirdConfig with expected STUN URI: %v, actual: %v",
|
||||
expectedStunsConfig.GetUri(),
|
||||
wiretrusteeConfig.GetStuns()[0].GetUri())
|
||||
netbirdConfig.GetStuns()[0].GetUri())
|
||||
}
|
||||
|
||||
if wiretrusteeConfig.GetStuns()[0].GetProtocol() != expectedStunsConfig.GetProtocol() {
|
||||
t.Fatalf("expecting SyncResponse to have WiretrusteeConfig with expected STUN Protocol: %v, actual: %v",
|
||||
if netbirdConfig.GetStuns()[0].GetProtocol() != expectedStunsConfig.GetProtocol() {
|
||||
t.Fatalf("expecting SyncResponse to have NetbirdConfig with expected STUN Protocol: %v, actual: %v",
|
||||
expectedStunsConfig.GetProtocol(),
|
||||
wiretrusteeConfig.GetStuns()[0].GetProtocol())
|
||||
netbirdConfig.GetStuns()[0].GetProtocol())
|
||||
}
|
||||
|
||||
expectedTRUNHost := &mgmtProto.HostConfig{
|
||||
Uri: "turn:stun.wiretrustee.com:3468",
|
||||
Uri: "turn:stun.netbird.io:3468",
|
||||
Protocol: mgmtProto.HostConfig_UDP,
|
||||
}
|
||||
|
||||
if wiretrusteeConfig.GetTurns()[0].GetHostConfig().GetUri() != expectedTRUNHost.GetUri() {
|
||||
t.Fatalf("expecting SyncResponse to have WiretrusteeConfig with expected TURN URI: %v, actual: %v",
|
||||
if netbirdConfig.GetTurns()[0].GetHostConfig().GetUri() != expectedTRUNHost.GetUri() {
|
||||
t.Fatalf("expecting SyncResponse to have NetbirdConfig with expected TURN URI: %v, actual: %v",
|
||||
expectedTRUNHost.GetUri(),
|
||||
wiretrusteeConfig.GetTurns()[0].GetHostConfig().GetUri())
|
||||
netbirdConfig.GetTurns()[0].GetHostConfig().GetUri())
|
||||
}
|
||||
|
||||
if wiretrusteeConfig.GetTurns()[0].GetHostConfig().GetProtocol() != expectedTRUNHost.GetProtocol() {
|
||||
t.Fatalf("expecting SyncResponse to have WiretrusteeConfig with expected TURN Protocol: %v, actual: %v",
|
||||
if netbirdConfig.GetTurns()[0].GetHostConfig().GetProtocol() != expectedTRUNHost.GetProtocol() {
|
||||
t.Fatalf("expecting SyncResponse to have NetbirdConfig with expected TURN Protocol: %v, actual: %v",
|
||||
expectedTRUNHost.GetProtocol().String(),
|
||||
wiretrusteeConfig.GetTurns()[0].GetHostConfig().GetProtocol())
|
||||
netbirdConfig.GetTurns()[0].GetHostConfig().GetProtocol())
|
||||
}
|
||||
|
||||
// ensure backward compatibility
|
||||
@@ -285,13 +285,13 @@ func loginPeerWithValidSetupKey(key wgtypes.Key, client mgmtProto.ManagementServ
|
||||
}
|
||||
|
||||
meta := &mgmtProto.PeerSystemMeta{
|
||||
Hostname: key.PublicKey().String(),
|
||||
GoOS: runtime.GOOS,
|
||||
OS: runtime.GOOS,
|
||||
Core: "core",
|
||||
Platform: "platform",
|
||||
Kernel: "kernel",
|
||||
WiretrusteeVersion: "",
|
||||
Hostname: key.PublicKey().String(),
|
||||
GoOS: runtime.GOOS,
|
||||
OS: runtime.GOOS,
|
||||
Core: "core",
|
||||
Platform: "platform",
|
||||
Kernel: "kernel",
|
||||
NetbirdVersion: "",
|
||||
}
|
||||
message, err := encryption.EncryptMessage(*serverKey, key, &mgmtProto.LoginRequest{SetupKey: TestValidSetupKey, Meta: meta})
|
||||
if err != nil {
|
||||
@@ -498,7 +498,7 @@ func testSyncStatusRace(t *testing.T) {
|
||||
mgmtServer, am, mgmtAddr, cleanup, err := startManagementForTest(t, "testdata/store_with_expired_peers.sql", &Config{
|
||||
Stuns: []*Host{{
|
||||
Proto: "udp",
|
||||
URI: "stun:stun.wiretrustee.com:3468",
|
||||
URI: "stun:stun.netbird.io:3468",
|
||||
}},
|
||||
TURNConfig: &TURNConfig{
|
||||
TimeBasedCredentials: false,
|
||||
@@ -506,12 +506,12 @@ func testSyncStatusRace(t *testing.T) {
|
||||
Secret: "whatever",
|
||||
Turns: []*Host{{
|
||||
Proto: "udp",
|
||||
URI: "turn:stun.wiretrustee.com:3468",
|
||||
URI: "turn:stun.netbird.io:3468",
|
||||
}},
|
||||
},
|
||||
Signal: &Host{
|
||||
Proto: "http",
|
||||
URI: "signal.wiretrustee.com:10000",
|
||||
URI: "signal.netbird.io:10000",
|
||||
},
|
||||
Datadir: dir,
|
||||
HttpConfig: nil,
|
||||
@@ -670,7 +670,7 @@ func Test_LoginPerformance(t *testing.T) {
|
||||
mgmtServer, am, _, cleanup, err := startManagementForTest(t, "testdata/store_with_expired_peers.sql", &Config{
|
||||
Stuns: []*Host{{
|
||||
Proto: "udp",
|
||||
URI: "stun:stun.wiretrustee.com:3468",
|
||||
URI: "stun:stun.netbird.io:3468",
|
||||
}},
|
||||
TURNConfig: &TURNConfig{
|
||||
TimeBasedCredentials: false,
|
||||
@@ -678,12 +678,12 @@ func Test_LoginPerformance(t *testing.T) {
|
||||
Secret: "whatever",
|
||||
Turns: []*Host{{
|
||||
Proto: "udp",
|
||||
URI: "turn:stun.wiretrustee.com:3468",
|
||||
URI: "turn:stun.netbird.io:3468",
|
||||
}},
|
||||
},
|
||||
Signal: &Host{
|
||||
Proto: "http",
|
||||
URI: "signal.wiretrustee.com:10000",
|
||||
URI: "signal.netbird.io:10000",
|
||||
},
|
||||
Datadir: dir,
|
||||
HttpConfig: nil,
|
||||
@@ -730,13 +730,13 @@ func Test_LoginPerformance(t *testing.T) {
|
||||
}
|
||||
|
||||
meta := &mgmtProto.PeerSystemMeta{
|
||||
Hostname: key.PublicKey().String(),
|
||||
GoOS: runtime.GOOS,
|
||||
OS: runtime.GOOS,
|
||||
Core: "core",
|
||||
Platform: "platform",
|
||||
Kernel: "kernel",
|
||||
WiretrusteeVersion: "",
|
||||
Hostname: key.PublicKey().String(),
|
||||
GoOS: runtime.GOOS,
|
||||
OS: runtime.GOOS,
|
||||
Core: "core",
|
||||
Platform: "platform",
|
||||
Kernel: "kernel",
|
||||
NetbirdVersion: "",
|
||||
}
|
||||
|
||||
peerLogin := PeerLogin{
|
||||
|
||||
@@ -47,7 +47,7 @@ var _ = Describe("Management service", func() {
|
||||
level, _ := log.ParseLevel("Debug")
|
||||
log.SetLevel(level)
|
||||
var err error
|
||||
dataDir, err = os.MkdirTemp("", "wiretrustee_mgmt_test_tmp_*")
|
||||
dataDir, err = os.MkdirTemp("", "netbird_mgmt_test_tmp_*")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
var listener net.Listener
|
||||
@@ -109,23 +109,23 @@ var _ = Describe("Management service", func() {
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
expectedSignalConfig := &mgmtProto.HostConfig{
|
||||
Uri: "signal.wiretrustee.com:10000",
|
||||
Uri: "signal.netbird.io:10000",
|
||||
Protocol: mgmtProto.HostConfig_HTTP,
|
||||
}
|
||||
expectedStunsConfig := &mgmtProto.HostConfig{
|
||||
Uri: "stun:stun.wiretrustee.com:3468",
|
||||
Uri: "stun:stun.netbird.io:3468",
|
||||
Protocol: mgmtProto.HostConfig_UDP,
|
||||
}
|
||||
expectedTRUNHost := &mgmtProto.HostConfig{
|
||||
Uri: "turn:stun.wiretrustee.com:3468",
|
||||
Uri: "turn:stun.netbird.io:3468",
|
||||
Protocol: mgmtProto.HostConfig_UDP,
|
||||
}
|
||||
|
||||
Expect(resp.WiretrusteeConfig.Signal).To(BeEquivalentTo(expectedSignalConfig))
|
||||
Expect(resp.WiretrusteeConfig.Stuns).To(ConsistOf(expectedStunsConfig))
|
||||
Expect(resp.NetbirdConfig.Signal).To(BeEquivalentTo(expectedSignalConfig))
|
||||
Expect(resp.NetbirdConfig.Stuns).To(ConsistOf(expectedStunsConfig))
|
||||
// TURN validation is special because credentials are dynamically generated
|
||||
Expect(resp.WiretrusteeConfig.Turns).To(HaveLen(1))
|
||||
actualTURN := resp.WiretrusteeConfig.Turns[0]
|
||||
Expect(resp.NetbirdConfig.Turns).To(HaveLen(1))
|
||||
actualTURN := resp.NetbirdConfig.Turns[0]
|
||||
Expect(len(actualTURN.User) > 0).To(BeTrue())
|
||||
Expect(actualTURN.HostConfig).To(BeEquivalentTo(expectedTRUNHost))
|
||||
Expect(len(resp.NetworkMap.OfflinePeers) == 0).To(BeTrue())
|
||||
@@ -286,25 +286,25 @@ var _ = Describe("Management service", func() {
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
expectedSignalConfig := &mgmtProto.HostConfig{
|
||||
Uri: "signal.wiretrustee.com:10000",
|
||||
Uri: "signal.netbird.io:10000",
|
||||
Protocol: mgmtProto.HostConfig_HTTP,
|
||||
}
|
||||
expectedStunsConfig := &mgmtProto.HostConfig{
|
||||
Uri: "stun:stun.wiretrustee.com:3468",
|
||||
Uri: "stun:stun.netbird.io:3468",
|
||||
Protocol: mgmtProto.HostConfig_UDP,
|
||||
}
|
||||
expectedTurnsConfig := &mgmtProto.ProtectedHostConfig{
|
||||
HostConfig: &mgmtProto.HostConfig{
|
||||
Uri: "turn:stun.wiretrustee.com:3468",
|
||||
Uri: "turn:stun.netbird.io:3468",
|
||||
Protocol: mgmtProto.HostConfig_UDP,
|
||||
},
|
||||
User: "some_user",
|
||||
Password: "some_password",
|
||||
}
|
||||
|
||||
Expect(decryptedResp.GetWiretrusteeConfig().Signal).To(BeEquivalentTo(expectedSignalConfig))
|
||||
Expect(decryptedResp.GetWiretrusteeConfig().Stuns).To(ConsistOf(expectedStunsConfig))
|
||||
Expect(decryptedResp.GetWiretrusteeConfig().Turns).To(ConsistOf(expectedTurnsConfig))
|
||||
Expect(decryptedResp.GetNetbirdConfig().Signal).To(BeEquivalentTo(expectedSignalConfig))
|
||||
Expect(decryptedResp.GetNetbirdConfig().Stuns).To(ConsistOf(expectedStunsConfig))
|
||||
Expect(decryptedResp.GetNetbirdConfig().Turns).To(ConsistOf(expectedTurnsConfig))
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -449,13 +449,13 @@ func loginPeerWithValidSetupKey(serverPubKey wgtypes.Key, key wgtypes.Key, clien
|
||||
defer GinkgoRecover()
|
||||
|
||||
meta := &mgmtProto.PeerSystemMeta{
|
||||
Hostname: key.PublicKey().String(),
|
||||
GoOS: runtime.GOOS,
|
||||
OS: runtime.GOOS,
|
||||
Core: "core",
|
||||
Platform: "platform",
|
||||
Kernel: "kernel",
|
||||
WiretrusteeVersion: "",
|
||||
Hostname: key.PublicKey().String(),
|
||||
GoOS: runtime.GOOS,
|
||||
OS: runtime.GOOS,
|
||||
Core: "core",
|
||||
Platform: "platform",
|
||||
Kernel: "kernel",
|
||||
NetbirdVersion: "",
|
||||
}
|
||||
message, err := encryption.EncryptMessage(serverPubKey, key, &mgmtProto.LoginRequest{SetupKey: ValidSetupKey, Meta: meta})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
@@ -1099,13 +1099,13 @@ func TestToSyncResponse(t *testing.T) {
|
||||
assert.Equal(t, "192.168.1.1/24", response.PeerConfig.Address)
|
||||
assert.Equal(t, "peer1.example.com", response.PeerConfig.Fqdn)
|
||||
assert.Equal(t, true, response.PeerConfig.SshConfig.SshEnabled)
|
||||
// assert wiretrustee config
|
||||
assert.Equal(t, "signal.uri", response.WiretrusteeConfig.Signal.Uri)
|
||||
assert.Equal(t, proto.HostConfig_HTTPS, response.WiretrusteeConfig.Signal.GetProtocol())
|
||||
assert.Equal(t, "stun.uri", response.WiretrusteeConfig.Stuns[0].Uri)
|
||||
assert.Equal(t, "turn.uri", response.WiretrusteeConfig.Turns[0].HostConfig.GetUri())
|
||||
assert.Equal(t, "turn-user", response.WiretrusteeConfig.Turns[0].User)
|
||||
assert.Equal(t, "turn-pass", response.WiretrusteeConfig.Turns[0].Password)
|
||||
// assert netbird config
|
||||
assert.Equal(t, "signal.uri", response.NetbirdConfig.Signal.Uri)
|
||||
assert.Equal(t, proto.HostConfig_HTTPS, response.NetbirdConfig.Signal.GetProtocol())
|
||||
assert.Equal(t, "stun.uri", response.NetbirdConfig.Stuns[0].Uri)
|
||||
assert.Equal(t, "turn.uri", response.NetbirdConfig.Turns[0].HostConfig.GetUri())
|
||||
assert.Equal(t, "turn-user", response.NetbirdConfig.Turns[0].User)
|
||||
assert.Equal(t, "turn-pass", response.NetbirdConfig.Turns[0].Password)
|
||||
// assert RemotePeers
|
||||
assert.Equal(t, 1, len(response.RemotePeers))
|
||||
assert.Equal(t, "192.168.1.2/32", response.RemotePeers[0].AllowedIps[0])
|
||||
|
||||
8
management/server/testdata/management.json
vendored
8
management/server/testdata/management.json
vendored
@@ -2,7 +2,7 @@
|
||||
"Stuns": [
|
||||
{
|
||||
"Proto": "udp",
|
||||
"URI": "stun:stun.wiretrustee.com:3468",
|
||||
"URI": "stun:stun.netbird.io:3468",
|
||||
"Username": "",
|
||||
"Password": null
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
"Turns": [
|
||||
{
|
||||
"Proto": "udp",
|
||||
"URI": "turn:stun.wiretrustee.com:3468",
|
||||
"URI": "turn:stun.netbird.io:3468",
|
||||
"Username": "some_user",
|
||||
"Password": "some_password"
|
||||
}
|
||||
@@ -22,7 +22,7 @@
|
||||
},
|
||||
"Signal": {
|
||||
"Proto": "http",
|
||||
"URI": "signal.wiretrustee.com:10000",
|
||||
"URI": "signal.netbird.io:10000",
|
||||
"Username": "",
|
||||
"Password": null
|
||||
},
|
||||
@@ -44,4 +44,4 @@
|
||||
"GrantType": "client_credentials"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
5
management/server/testdata/store.sql
vendored
5
management/server/testdata/store.sql
vendored
@@ -19,6 +19,7 @@ CREATE INDEX `idx_accounts_domain` ON `accounts`(`domain`);
|
||||
CREATE INDEX `idx_setup_keys_account_id` ON `setup_keys`(`account_id`);
|
||||
CREATE INDEX `idx_peers_key` ON `peers`(`key`);
|
||||
CREATE INDEX `idx_peers_account_id` ON `peers`(`account_id`);
|
||||
CREATE INDEX `idx_peers_account_id_ip` ON `peers`(`account_id`,`ip`);
|
||||
CREATE INDEX `idx_users_account_id` ON `users`(`account_id`);
|
||||
CREATE INDEX `idx_personal_access_tokens_user_id` ON `personal_access_tokens`(`user_id`);
|
||||
CREATE INDEX `idx_groups_account_id` ON `groups`(`account_id`);
|
||||
@@ -39,8 +40,11 @@ CREATE INDEX `idx_networks_account_id` ON `networks`(`account_id`);
|
||||
INSERT INTO accounts VALUES('bf1c8084-ba50-4ce7-9439-34653001fc3b','','2024-10-02 16:03:06.778746+02:00','test.com','private',1,'af1c8024-ha40-4ce2-9418-34653101fc3c','{"IP":"100.64.0.0","Mask":"//8AAA=="}','',0,'[]',0,86400000000000,0,0,0,'',NULL,NULL,NULL);
|
||||
INSERT INTO "groups" VALUES('cs1tnh0hhcjnqoiuebeg','bf1c8084-ba50-4ce7-9439-34653001fc3b','All','api','[]',0,'');
|
||||
INSERT INTO setup_keys VALUES('','bf1c8084-ba50-4ce7-9439-34653001fc3b','A2C8E62B-38F5-4553-B31E-DD66C696CEBB','Default key','reusable','2021-08-19 20:46:20.005936822+02:00','2321-09-18 20:46:20.005936822+02:00','2021-08-19 20:46:20.005936822+02:00',0,0,NULL,'["cs1tnh0hhcjnqoiuebeg"]',0,0);
|
||||
INSERT INTO users VALUES('a23efe53-63fb-11ec-90d6-0242ac120003','bf1c8084-ba50-4ce7-9439-34653001fc3b','owner',0,0,'','[]',0,NULL,'2024-10-02 16:03:06.779156+02:00','api',0,'');
|
||||
INSERT INTO users VALUES('edafee4e-63fb-11ec-90d6-0242ac120003','bf1c8084-ba50-4ce7-9439-34653001fc3b','admin',0,0,'','[]',0,NULL,'2024-10-02 16:03:06.779156+02:00','api',0,'');
|
||||
INSERT INTO users VALUES('f4f6d672-63fb-11ec-90d6-0242ac120003','bf1c8084-ba50-4ce7-9439-34653001fc3b','user',0,0,'','[]',0,NULL,'2024-10-02 16:03:06.779156+02:00','api',0,'');
|
||||
-- Unhashed PAT is "nbp_apTmlmUXHSC4PKmHwtIZNaGr8eqcVI2gMURp"
|
||||
INSERT INTO personal_access_tokens VALUES('9dj38s35-63fb-11ec-90d6-0242ac120004','a23efe53-63fb-11ec-90d6-0242ac120003','','smJvzexPcQ3NRezrVDUmF++0XqvFvXzx8Rsn2y9r1z0=','5023-02-27 00:00:00+00:00','user','2023-01-01 00:00:00+00:00','2023-02-01 00:00:00+00:00');
|
||||
INSERT INTO personal_access_tokens VALUES('9dj38s35-63fb-11ec-90d6-0242ac120003','f4f6d672-63fb-11ec-90d6-0242ac120003','','SoMeHaShEdToKeN','2023-02-27 00:00:00+00:00','user','2023-01-01 00:00:00+00:00','2023-02-01 00:00:00+00:00');
|
||||
INSERT INTO installations VALUES(1,'');
|
||||
INSERT INTO policies VALUES('cs1tnh0hhcjnqoiuebf0','bf1c8084-ba50-4ce7-9439-34653001fc3b','Default','This is a default rule that allows connections between all the resources',1,'[]');
|
||||
@@ -48,3 +52,4 @@ INSERT INTO policy_rules VALUES('cs387mkv2d4bgq41b6n0','cs1tnh0hhcjnqoiuebf0','D
|
||||
INSERT INTO network_routers VALUES('ctc20ji7qv9ck2sebc80','ct286bi7qv930dsrrug0','bf1c8084-ba50-4ce7-9439-34653001fc3b','cs1tnh0hhcjnqoiuebeg',NULL,0,0);
|
||||
INSERT INTO network_resources VALUES ('ctc4nci7qv9061u6ilfg','ct286bi7qv930dsrrug0','bf1c8084-ba50-4ce7-9439-34653001fc3b','Host','192.168.1.1');
|
||||
INSERT INTO networks VALUES('ct286bi7qv930dsrrug0','bf1c8084-ba50-4ce7-9439-34653001fc3b','Test Network','Test Network');
|
||||
INSERT INTO peers VALUES('ct286bi7qv930dsrrug0','bf1c8084-ba50-4ce7-9439-34653001fc3b','','','192.168.0.0','','','','','','','','','','','','','','','','','test','test','2023-01-01 00:00:00+00:00',0,0,0,'a23efe53-63fb-11ec-90d6-0242ac120003','',0,0,'2023-01-01 00:00:00+00:00','2023-01-01 00:00:00+00:00',0,'','','',0);
|
||||
|
||||
@@ -199,7 +199,7 @@ func (m *TimeBasedAuthSecretsManager) pushNewTURNAndRelayTokens(ctx context.Cont
|
||||
}
|
||||
|
||||
update := &proto.SyncResponse{
|
||||
WiretrusteeConfig: &proto.WiretrusteeConfig{
|
||||
NetbirdConfig: &proto.NetbirdConfig{
|
||||
Turns: turns,
|
||||
},
|
||||
}
|
||||
@@ -208,7 +208,7 @@ func (m *TimeBasedAuthSecretsManager) pushNewTURNAndRelayTokens(ctx context.Cont
|
||||
if m.relayCfg != nil {
|
||||
token, err := m.GenerateRelayToken()
|
||||
if err == nil {
|
||||
update.WiretrusteeConfig.Relay = &proto.RelayConfig{
|
||||
update.NetbirdConfig.Relay = &proto.RelayConfig{
|
||||
Urls: m.relayCfg.Addresses,
|
||||
TokenPayload: token.Payload,
|
||||
TokenSignature: token.Signature,
|
||||
@@ -228,7 +228,7 @@ func (m *TimeBasedAuthSecretsManager) pushNewRelayTokens(ctx context.Context, pe
|
||||
}
|
||||
|
||||
update := &proto.SyncResponse{
|
||||
WiretrusteeConfig: &proto.WiretrusteeConfig{
|
||||
NetbirdConfig: &proto.NetbirdConfig{
|
||||
Relay: &proto.RelayConfig{
|
||||
Urls: m.relayCfg.Addresses,
|
||||
TokenPayload: string(relayToken.Payload),
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
|
||||
var TurnTestHost = &Host{
|
||||
Proto: UDP,
|
||||
URI: "turn:turn.wiretrustee.com:77777",
|
||||
URI: "turn:turn.netbird.io:77777",
|
||||
Username: "username",
|
||||
Password: "",
|
||||
}
|
||||
@@ -124,7 +124,7 @@ loop:
|
||||
var firstRelayUpdate, secondRelayUpdate *proto.RelayConfig
|
||||
|
||||
for _, update := range updates {
|
||||
if turns := update.Update.GetWiretrusteeConfig().GetTurns(); len(turns) > 0 {
|
||||
if turns := update.Update.GetNetbirdConfig().GetTurns(); len(turns) > 0 {
|
||||
turnUpdates++
|
||||
if turnUpdates == 1 {
|
||||
firstTurnUpdate = turns[0]
|
||||
@@ -132,9 +132,9 @@ loop:
|
||||
secondTurnUpdate = turns[0]
|
||||
}
|
||||
}
|
||||
if relay := update.Update.GetWiretrusteeConfig().GetRelay(); relay != nil {
|
||||
if relay := update.Update.GetNetbirdConfig().GetRelay(); relay != nil {
|
||||
// avoid updating on turn updates since they also send relay credentials
|
||||
if update.Update.GetWiretrusteeConfig().GetTurns() == nil {
|
||||
if update.Update.GetNetbirdConfig().GetTurns() == nil {
|
||||
relayUpdates++
|
||||
if relayUpdates == 1 {
|
||||
firstRelayUpdate = relay
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"nhooyr.io/websocket"
|
||||
"github.com/coder/websocket"
|
||||
)
|
||||
|
||||
type Conn struct {
|
||||
|
||||
@@ -2,6 +2,8 @@ package ws
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
@@ -10,9 +12,10 @@ import (
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"nhooyr.io/websocket"
|
||||
"github.com/coder/websocket"
|
||||
|
||||
"github.com/netbirdio/netbird/relay/server/listener/ws"
|
||||
"github.com/netbirdio/netbird/util/embeddedroots"
|
||||
nbnet "github.com/netbirdio/netbird/util/net"
|
||||
)
|
||||
|
||||
@@ -66,10 +69,19 @@ func prepareURL(address string) (string, error) {
|
||||
func httpClientNbDialer() *http.Client {
|
||||
customDialer := nbnet.NewDialer()
|
||||
|
||||
certPool, err := x509.SystemCertPool()
|
||||
if err != nil || certPool == nil {
|
||||
log.Debugf("System cert pool not available; falling back to embedded cert, error: %v", err)
|
||||
certPool = embeddedroots.Get()
|
||||
}
|
||||
|
||||
customTransport := &http.Transport{
|
||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return customDialer.DialContext(ctx, network, addr)
|
||||
},
|
||||
TLSClientConfig: &tls.Config{
|
||||
RootCAs: certPool,
|
||||
},
|
||||
}
|
||||
|
||||
return &http.Client{
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"nhooyr.io/websocket"
|
||||
"github.com/coder/websocket"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"net/http"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"nhooyr.io/websocket"
|
||||
"github.com/coder/websocket"
|
||||
)
|
||||
|
||||
// URLPath is the path for the websocket connection.
|
||||
|
||||
@@ -2,11 +2,25 @@
|
||||
|
||||
package tls
|
||||
|
||||
import "crypto/tls"
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/netbirdio/netbird/util/embeddedroots"
|
||||
)
|
||||
|
||||
func ClientQUICTLSConfig() *tls.Config {
|
||||
certPool, err := x509.SystemCertPool()
|
||||
if err != nil || certPool == nil {
|
||||
log.Debugf("System cert pool not available; falling back to embedded cert, error: %v", err)
|
||||
certPool = embeddedroots.Get()
|
||||
}
|
||||
|
||||
return &tls.Config{
|
||||
InsecureSkipVerify: true, // Debug mode allows insecure connections
|
||||
NextProtos: []string{nbalpn}, // Ensure this matches the server's ALPN
|
||||
RootCAs: certPool,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,24 @@
|
||||
|
||||
package tls
|
||||
|
||||
import "crypto/tls"
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/netbirdio/netbird/util/embeddedroots"
|
||||
)
|
||||
|
||||
func ClientQUICTLSConfig() *tls.Config {
|
||||
certPool, err := x509.SystemCertPool()
|
||||
if err != nil || certPool == nil {
|
||||
log.Debugf("System cert pool not available; falling back to embedded cert, error: %v", err)
|
||||
certPool = embeddedroots.Get()
|
||||
}
|
||||
|
||||
return &tls.Config{
|
||||
NextProtos: []string{nbalpn},
|
||||
RootCAs: certPool,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
export PATH=$PATH:/usr/local/bin:/opt/homebrew/bin
|
||||
|
||||
# check if wiretrustee is installed
|
||||
WT_BIN=$(which wiretrustee)
|
||||
if [ -n "$WT_BIN" ]
|
||||
# check if netbird is installed
|
||||
NB_BIN=$(which netbird)
|
||||
if [ -n "$NB_BIN" ]
|
||||
then
|
||||
echo "Stopping and uninstalling Wiretrustee daemon"
|
||||
wiretrustee service stop || true
|
||||
wiretrustee service uninstall || true
|
||||
echo "Stopping and uninstalling Netbird daemon"
|
||||
netbird service stop || true
|
||||
netbird service uninstall || true
|
||||
fi
|
||||
|
||||
# check if netbird is installed
|
||||
|
||||
@@ -263,16 +263,16 @@ install_netbird() {
|
||||
add_aur_repo
|
||||
;;
|
||||
brew)
|
||||
# Remove Wiretrustee if it had been installed using Homebrew before
|
||||
if brew ls --versions wiretrustee >/dev/null 2>&1; then
|
||||
echo "Removing existing wiretrustee client"
|
||||
# Remove Netbird if it had been installed using Homebrew before
|
||||
if brew ls --versions netbird >/dev/null 2>&1; then
|
||||
echo "Removing existing netbird client"
|
||||
|
||||
# Stop and uninstall daemon service:
|
||||
wiretrustee service stop
|
||||
wiretrustee service uninstall
|
||||
netbird service stop
|
||||
netbird service uninstall
|
||||
|
||||
# Unlik the app
|
||||
brew unlink wiretrustee
|
||||
brew unlink netbird
|
||||
fi
|
||||
|
||||
brew install netbirdio/tap/netbird
|
||||
|
||||
@@ -60,7 +60,7 @@ subdomain sub.mydomain.com).
|
||||
|
||||
```bash
|
||||
# create a volume
|
||||
docker volume create wiretrustee-signal
|
||||
docker volume create netbird-signal
|
||||
# run the docker container
|
||||
docker run -d --name netbird-signal \
|
||||
-p 10000:10000 \
|
||||
|
||||
42
util/embeddedroots/embeddedroots.go
Normal file
42
util/embeddedroots/embeddedroots.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package embeddedroots
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
_ "embed"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func Get() *x509.CertPool {
|
||||
rootsVar.load()
|
||||
return rootsVar.p
|
||||
}
|
||||
|
||||
type roots struct {
|
||||
once sync.Once
|
||||
p *x509.CertPool
|
||||
}
|
||||
|
||||
var rootsVar roots
|
||||
|
||||
func (r *roots) load() {
|
||||
r.once.Do(func() {
|
||||
p := x509.NewCertPool()
|
||||
p.AppendCertsFromPEM([]byte(isrgRootX1RootPEM))
|
||||
p.AppendCertsFromPEM([]byte(isrgRootX2RootPEM))
|
||||
r.p = p
|
||||
})
|
||||
}
|
||||
|
||||
// Subject: O = Internet Security Research Group, CN = ISRG Root X1
|
||||
// Key type: RSA 4096
|
||||
// Validity: until 2030-06-04 (generated 2015-06-04)
|
||||
//
|
||||
//go:embed isrg-root-x1.pem
|
||||
var isrgRootX1RootPEM string
|
||||
|
||||
// Subject: O = Internet Security Research Group, CN = ISRG Root X2
|
||||
// Key type: ECDSA P-384
|
||||
// Validity: until 2035-09-04 (generated 2020-09-04)
|
||||
//
|
||||
//go:embed isrg-root-x2.pem
|
||||
var isrgRootX2RootPEM string
|
||||
31
util/embeddedroots/isrg-root-x1.pem
Normal file
31
util/embeddedroots/isrg-root-x1.pem
Normal file
@@ -0,0 +1,31 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
|
||||
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
|
||||
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
|
||||
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
|
||||
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
|
||||
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
|
||||
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
|
||||
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
|
||||
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
|
||||
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
|
||||
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
|
||||
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
|
||||
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
|
||||
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
|
||||
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
|
||||
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
|
||||
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
|
||||
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
|
||||
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
|
||||
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
|
||||
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
|
||||
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
|
||||
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
|
||||
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
|
||||
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
|
||||
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
|
||||
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
|
||||
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
|
||||
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
|
||||
-----END CERTIFICATE-----
|
||||
14
util/embeddedroots/isrg-root-x2.pem
Normal file
14
util/embeddedroots/isrg-root-x2.pem
Normal file
@@ -0,0 +1,14 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw
|
||||
CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg
|
||||
R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00
|
||||
MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT
|
||||
ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw
|
||||
EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW
|
||||
+1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9
|
||||
ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T
|
||||
AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI
|
||||
zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW
|
||||
tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1
|
||||
/q4AaOeMSQ+2b1tbFfLn
|
||||
-----END CERTIFICATE-----
|
||||
@@ -3,14 +3,16 @@ package grpc
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"net"
|
||||
"os/user"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc"
|
||||
@@ -18,6 +20,7 @@ import (
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/keepalive"
|
||||
|
||||
"github.com/netbirdio/netbird/util/embeddedroots"
|
||||
nbnet "github.com/netbirdio/netbird/util/net"
|
||||
)
|
||||
|
||||
@@ -57,9 +60,16 @@ func Backoff(ctx context.Context) backoff.BackOff {
|
||||
|
||||
func CreateConnection(addr string, tlsEnabled bool) (*grpc.ClientConn, error) {
|
||||
transportOption := grpc.WithTransportCredentials(insecure.NewCredentials())
|
||||
|
||||
if tlsEnabled {
|
||||
transportOption = grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{}))
|
||||
certPool, err := x509.SystemCertPool()
|
||||
if err != nil || certPool == nil {
|
||||
log.Debugf("System cert pool not available; falling back to embedded cert, error: %v", err)
|
||||
certPool = embeddedroots.Get()
|
||||
}
|
||||
|
||||
transportOption = grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
|
||||
RootCAs: certPool,
|
||||
}))
|
||||
}
|
||||
|
||||
connCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
|
||||
Reference in New Issue
Block a user