mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-28 15:29:09 +01:00
The debug-bundle paths that upload without a human picking a destination compiled the vendor endpoint in: the mobile clients and the desktop UI hold `https://upload.debug.netbird.io/upload-url` as a constant, the CLI defaults its flag to it, and the remote job falls back to it when nothing else is set. A self-hosted deployment therefore shipped peer logs, routes, DNS and firewall state to NetBird-run infrastructure without its operator ever configuring that, and had no way to point those paths anywhere else. #7147 and #7153 gave the remote job a per-job URL and an MDM override, but neither reaches the mobile, UI or CLI paths, and both fail open when unset. Publish the destination from the management server instead, on the channel that already carries stun/turn/signal/relay/flow/metrics: - `NetbirdConfig.debug.upload_url`, sourced from the new account setting `debug_bundle_upload_url` (REST + dashboard) and falling back to the new `DebugUpload.URL` in the management server config, which a self-hosted install can set once so a fresh account is not left on the vendor default. Both are validated as https-with-host where they are written; a change fans out to connected peers rather than waiting for the next login. - One resolver on the client, `debug.ResolveUploadURL`, used by every path: MDM override > explicitly named URL > destination published by management > the NetBird service, but only for a peer enrolled with NetBird's cloud. Anything else fails closed with ErrNoUploadDestination and the bundle stays local, which is the behaviour change: a self-hosted deployment that names no upload service no longer uploads at all. - The engine keeps the published value (`Engine.DebugUploadURL`) so the bundle paths, which run off the engine loop, do not have to read it back out of the opt-in sync-response store. - The daemon request grows `upload`, so "upload to wherever this deployment says" is expressible; an empty `uploadURL` no longer has to mean "no upload". The privilege gate is unchanged and still applies only to a URL the local caller named — a destination published by management is the operator naming their own service. - The desktop UI stops carrying a vendor URL of its own and sends the intent. Reported privately as GHSA-hf99-43rj-h577.
540 lines
22 KiB
Go
540 lines
22 KiB
Go
package accounts
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"io"
|
|
"math"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/netip"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gorilla/mux"
|
|
"github.com/stretchr/testify/assert"
|
|
"go.uber.org/mock/gomock"
|
|
|
|
nbcontext "github.com/netbirdio/netbird/management/server/context"
|
|
"github.com/netbirdio/netbird/management/server/mock_server"
|
|
"github.com/netbirdio/netbird/management/server/settings"
|
|
"github.com/netbirdio/netbird/management/server/types"
|
|
"github.com/netbirdio/netbird/shared/auth"
|
|
"github.com/netbirdio/netbird/shared/management/http/api"
|
|
"github.com/netbirdio/netbird/shared/management/status"
|
|
)
|
|
|
|
func initAccountsTestData(t *testing.T, account *types.Account) *handler {
|
|
ctrl := gomock.NewController(t)
|
|
t.Cleanup(ctrl.Finish)
|
|
settingsMockManager := settings.NewMockManager(ctrl)
|
|
settingsMockManager.EXPECT().
|
|
GetSettings(gomock.Any(), account.Id, "test_user").
|
|
Return(account.Settings, nil).
|
|
AnyTimes()
|
|
settingsMockManager.EXPECT().
|
|
GetEffectiveNetworkRanges(gomock.Any(), account.Id).
|
|
Return(netip.Prefix{}, netip.Prefix{}, nil).
|
|
AnyTimes()
|
|
|
|
return &handler{
|
|
accountManager: &mock_server.MockAccountManager{
|
|
GetAccountSettingsFunc: func(ctx context.Context, accountID string, userID string) (*types.Settings, error) {
|
|
return account.Settings, nil
|
|
},
|
|
UpdateAccountSettingsFunc: func(ctx context.Context, accountID, userID string, newSettings *types.Settings) (*types.Settings, error) {
|
|
halfYearLimit := 180 * 24 * time.Hour
|
|
if newSettings.PeerLoginExpiration > halfYearLimit {
|
|
return nil, status.Errorf(status.InvalidArgument, "peer login expiration can't be larger than 180 days")
|
|
}
|
|
|
|
if newSettings.PeerLoginExpiration < time.Hour {
|
|
return nil, status.Errorf(status.InvalidArgument, "peer login expiration can't be smaller than one hour")
|
|
}
|
|
|
|
return newSettings, nil
|
|
},
|
|
GetAccountByIDFunc: func(ctx context.Context, accountID string, userID string) (*types.Account, error) {
|
|
return account.Copy(), nil
|
|
},
|
|
GetAccountMetaFunc: func(ctx context.Context, accountID string, userID string) (*types.AccountMeta, error) {
|
|
return account.GetMeta(), nil
|
|
},
|
|
GetAccountOnboardingFunc: func(ctx context.Context, accountID string, userID string) (*types.AccountOnboarding, error) {
|
|
return &types.AccountOnboarding{
|
|
OnboardingFlowPending: true,
|
|
SignupFormPending: true,
|
|
}, nil
|
|
},
|
|
UpdateAccountOnboardingFunc: func(ctx context.Context, accountID, userID string, onboarding *types.AccountOnboarding) (*types.AccountOnboarding, error) {
|
|
return &types.AccountOnboarding{
|
|
OnboardingFlowPending: true,
|
|
SignupFormPending: true,
|
|
}, nil
|
|
},
|
|
},
|
|
settingsManager: settingsMockManager,
|
|
}
|
|
}
|
|
|
|
func TestAccounts_AccountsHandler(t *testing.T) {
|
|
accountID := "test_account"
|
|
adminUser := types.NewAdminUser("test_user")
|
|
|
|
sr := func(v string) *string { return &v }
|
|
br := func(v bool) *bool { return &v }
|
|
|
|
handler := initAccountsTestData(t, &types.Account{
|
|
Id: accountID,
|
|
Domain: "hotmail.com",
|
|
Network: types.NewNetwork(),
|
|
Users: map[string]*types.User{
|
|
adminUser.Id: adminUser,
|
|
},
|
|
Settings: &types.Settings{
|
|
PeerLoginExpirationEnabled: false,
|
|
PeerLoginExpiration: time.Hour,
|
|
RegularUsersViewBlocked: true,
|
|
},
|
|
})
|
|
|
|
tt := []struct {
|
|
name string
|
|
expectedStatus int
|
|
expectedBody bool
|
|
expectedID string
|
|
expectedArray bool
|
|
expectedSettings api.AccountSettings
|
|
requestType string
|
|
requestPath string
|
|
requestBody io.Reader
|
|
}{
|
|
{
|
|
name: "getAllAccounts OK",
|
|
expectedBody: true,
|
|
requestType: http.MethodGet,
|
|
requestPath: "/api/accounts",
|
|
expectedStatus: http.StatusOK,
|
|
expectedSettings: api.AccountSettings{
|
|
PeerLoginExpiration: int(time.Hour.Seconds()),
|
|
PeerLoginExpirationEnabled: false,
|
|
GroupsPropagationEnabled: br(false),
|
|
JwtGroupsClaimName: sr(""),
|
|
JwtGroupsEnabled: br(false),
|
|
JwtAllowGroups: &[]string{},
|
|
RegularUsersViewBlocked: true,
|
|
RoutingPeerDnsResolutionEnabled: br(false),
|
|
LazyConnectionEnabled: br(false),
|
|
DnsDomain: sr(""),
|
|
DebugBundleUploadUrl: sr(""),
|
|
AutoUpdateAlways: br(false),
|
|
AutoUpdateVersion: sr(""),
|
|
MetricsPushEnabled: br(false),
|
|
AgentNetworkOnly: br(false),
|
|
EmbeddedIdpEnabled: br(false),
|
|
LocalAuthDisabled: br(false),
|
|
LocalMfaEnabled: br(false),
|
|
},
|
|
expectedArray: true,
|
|
expectedID: accountID,
|
|
},
|
|
{
|
|
name: "PutAccount OK",
|
|
expectedBody: true,
|
|
requestType: http.MethodPut,
|
|
requestPath: "/api/accounts/" + accountID,
|
|
requestBody: bytes.NewBufferString("{\"settings\": {\"peer_login_expiration\": 15552000,\"peer_login_expiration_enabled\": true},\"onboarding\": {\"onboarding_flow_pending\": true,\"signup_form_pending\": true}}"),
|
|
expectedStatus: http.StatusOK,
|
|
expectedSettings: api.AccountSettings{
|
|
PeerLoginExpiration: 15552000,
|
|
PeerLoginExpirationEnabled: true,
|
|
GroupsPropagationEnabled: br(false),
|
|
JwtGroupsClaimName: sr(""),
|
|
JwtGroupsEnabled: br(false),
|
|
JwtAllowGroups: &[]string{},
|
|
RegularUsersViewBlocked: false,
|
|
RoutingPeerDnsResolutionEnabled: br(false),
|
|
LazyConnectionEnabled: br(false),
|
|
DnsDomain: sr(""),
|
|
DebugBundleUploadUrl: sr(""),
|
|
AutoUpdateAlways: br(false),
|
|
AutoUpdateVersion: sr(""),
|
|
MetricsPushEnabled: br(false),
|
|
AgentNetworkOnly: br(false),
|
|
EmbeddedIdpEnabled: br(false),
|
|
LocalAuthDisabled: br(false),
|
|
LocalMfaEnabled: br(false),
|
|
},
|
|
expectedArray: false,
|
|
expectedID: accountID,
|
|
},
|
|
{
|
|
name: "PutAccount OK with autoUpdateVersion",
|
|
expectedBody: true,
|
|
requestType: http.MethodPut,
|
|
requestPath: "/api/accounts/" + accountID,
|
|
requestBody: bytes.NewBufferString("{\"settings\": {\"auto_update_version\": \"latest\", \"peer_login_expiration\": 15552000,\"peer_login_expiration_enabled\": true},\"onboarding\": {\"onboarding_flow_pending\": true,\"signup_form_pending\": true}}"),
|
|
expectedStatus: http.StatusOK,
|
|
expectedSettings: api.AccountSettings{
|
|
PeerLoginExpiration: 15552000,
|
|
PeerLoginExpirationEnabled: true,
|
|
GroupsPropagationEnabled: br(false),
|
|
JwtGroupsClaimName: sr(""),
|
|
JwtGroupsEnabled: br(false),
|
|
JwtAllowGroups: &[]string{},
|
|
RegularUsersViewBlocked: false,
|
|
RoutingPeerDnsResolutionEnabled: br(false),
|
|
LazyConnectionEnabled: br(false),
|
|
DnsDomain: sr(""),
|
|
DebugBundleUploadUrl: sr(""),
|
|
AutoUpdateAlways: br(false),
|
|
AutoUpdateVersion: sr("latest"),
|
|
MetricsPushEnabled: br(false),
|
|
AgentNetworkOnly: br(false),
|
|
EmbeddedIdpEnabled: br(false),
|
|
LocalAuthDisabled: br(false),
|
|
LocalMfaEnabled: br(false),
|
|
},
|
|
expectedArray: false,
|
|
expectedID: accountID,
|
|
},
|
|
{
|
|
name: "PutAccount OK with JWT",
|
|
expectedBody: true,
|
|
requestType: http.MethodPut,
|
|
requestPath: "/api/accounts/" + accountID,
|
|
requestBody: bytes.NewBufferString("{\"settings\": {\"peer_login_expiration\": 15552000,\"peer_login_expiration_enabled\": false,\"jwt_groups_enabled\":true,\"jwt_groups_claim_name\":\"roles\",\"jwt_allow_groups\":[\"test\"],\"regular_users_view_blocked\":true},\"onboarding\": {\"onboarding_flow_pending\": true,\"signup_form_pending\": true}}"),
|
|
expectedStatus: http.StatusOK,
|
|
expectedSettings: api.AccountSettings{
|
|
PeerLoginExpiration: 15552000,
|
|
PeerLoginExpirationEnabled: false,
|
|
GroupsPropagationEnabled: br(false),
|
|
JwtGroupsClaimName: sr("roles"),
|
|
JwtGroupsEnabled: br(true),
|
|
JwtAllowGroups: &[]string{"test"},
|
|
RegularUsersViewBlocked: true,
|
|
RoutingPeerDnsResolutionEnabled: br(false),
|
|
LazyConnectionEnabled: br(false),
|
|
DnsDomain: sr(""),
|
|
DebugBundleUploadUrl: sr(""),
|
|
AutoUpdateAlways: br(false),
|
|
AutoUpdateVersion: sr(""),
|
|
MetricsPushEnabled: br(false),
|
|
AgentNetworkOnly: br(false),
|
|
EmbeddedIdpEnabled: br(false),
|
|
LocalAuthDisabled: br(false),
|
|
LocalMfaEnabled: br(false),
|
|
},
|
|
expectedArray: false,
|
|
expectedID: accountID,
|
|
},
|
|
{
|
|
name: "PutAccount OK with JWT Propagation",
|
|
expectedBody: true,
|
|
requestType: http.MethodPut,
|
|
requestPath: "/api/accounts/" + accountID,
|
|
requestBody: bytes.NewBufferString("{\"settings\": {\"peer_login_expiration\": 554400,\"peer_login_expiration_enabled\": true,\"jwt_groups_enabled\":true,\"jwt_groups_claim_name\":\"groups\",\"groups_propagation_enabled\":true,\"regular_users_view_blocked\":true},\"onboarding\": {\"onboarding_flow_pending\": true,\"signup_form_pending\": true}}"),
|
|
expectedStatus: http.StatusOK,
|
|
expectedSettings: api.AccountSettings{
|
|
PeerLoginExpiration: 554400,
|
|
PeerLoginExpirationEnabled: true,
|
|
GroupsPropagationEnabled: br(true),
|
|
JwtGroupsClaimName: sr("groups"),
|
|
JwtGroupsEnabled: br(true),
|
|
JwtAllowGroups: &[]string{},
|
|
RegularUsersViewBlocked: true,
|
|
RoutingPeerDnsResolutionEnabled: br(false),
|
|
LazyConnectionEnabled: br(false),
|
|
DnsDomain: sr(""),
|
|
DebugBundleUploadUrl: sr(""),
|
|
AutoUpdateAlways: br(false),
|
|
AutoUpdateVersion: sr(""),
|
|
MetricsPushEnabled: br(false),
|
|
AgentNetworkOnly: br(false),
|
|
EmbeddedIdpEnabled: br(false),
|
|
LocalAuthDisabled: br(false),
|
|
LocalMfaEnabled: br(false),
|
|
},
|
|
expectedArray: false,
|
|
expectedID: accountID,
|
|
},
|
|
{
|
|
name: "PutAccount OK without onboarding",
|
|
expectedBody: true,
|
|
requestType: http.MethodPut,
|
|
requestPath: "/api/accounts/" + accountID,
|
|
requestBody: bytes.NewBufferString("{\"settings\": {\"peer_login_expiration\": 15552000,\"peer_login_expiration_enabled\": false,\"jwt_groups_enabled\":true,\"jwt_groups_claim_name\":\"roles\",\"jwt_allow_groups\":[\"test\"],\"regular_users_view_blocked\":true}}"),
|
|
expectedStatus: http.StatusOK,
|
|
expectedSettings: api.AccountSettings{
|
|
PeerLoginExpiration: 15552000,
|
|
PeerLoginExpirationEnabled: false,
|
|
GroupsPropagationEnabled: br(false),
|
|
JwtGroupsClaimName: sr("roles"),
|
|
JwtGroupsEnabled: br(true),
|
|
JwtAllowGroups: &[]string{"test"},
|
|
RegularUsersViewBlocked: true,
|
|
RoutingPeerDnsResolutionEnabled: br(false),
|
|
LazyConnectionEnabled: br(false),
|
|
DnsDomain: sr(""),
|
|
DebugBundleUploadUrl: sr(""),
|
|
AutoUpdateAlways: br(false),
|
|
AutoUpdateVersion: sr(""),
|
|
MetricsPushEnabled: br(false),
|
|
AgentNetworkOnly: br(false),
|
|
EmbeddedIdpEnabled: br(false),
|
|
LocalAuthDisabled: br(false),
|
|
LocalMfaEnabled: br(false),
|
|
},
|
|
expectedArray: false,
|
|
expectedID: accountID,
|
|
},
|
|
{
|
|
name: "PutAccount OK enabling agent_network_only",
|
|
expectedBody: true,
|
|
requestType: http.MethodPut,
|
|
requestPath: "/api/accounts/" + accountID,
|
|
requestBody: bytes.NewBufferString("{\"settings\": {\"peer_login_expiration\": 15552000,\"peer_login_expiration_enabled\": true,\"agent_network_only\": true,\"dashboard_features\": {\"agent_network\": true}},\"onboarding\": {\"onboarding_flow_pending\": true,\"signup_form_pending\": true}}"),
|
|
expectedStatus: http.StatusOK,
|
|
expectedSettings: api.AccountSettings{
|
|
PeerLoginExpiration: 15552000,
|
|
PeerLoginExpirationEnabled: true,
|
|
GroupsPropagationEnabled: br(false),
|
|
JwtGroupsClaimName: sr(""),
|
|
JwtGroupsEnabled: br(false),
|
|
JwtAllowGroups: &[]string{},
|
|
RegularUsersViewBlocked: false,
|
|
RoutingPeerDnsResolutionEnabled: br(false),
|
|
LazyConnectionEnabled: br(false),
|
|
DnsDomain: sr(""),
|
|
DebugBundleUploadUrl: sr(""),
|
|
AutoUpdateAlways: br(false),
|
|
AutoUpdateVersion: sr(""),
|
|
MetricsPushEnabled: br(false),
|
|
AgentNetworkOnly: br(true),
|
|
DashboardFeatures: &api.AccountDashboardFeatures{
|
|
AgentNetwork: br(true),
|
|
},
|
|
EmbeddedIdpEnabled: br(false),
|
|
LocalAuthDisabled: br(false),
|
|
LocalMfaEnabled: br(false),
|
|
},
|
|
expectedArray: false,
|
|
expectedID: accountID,
|
|
},
|
|
{
|
|
name: "PutAccount OK setting debug_bundle_upload_url",
|
|
expectedBody: true,
|
|
requestType: http.MethodPut,
|
|
requestPath: "/api/accounts/" + accountID,
|
|
requestBody: bytes.NewBufferString("{\"settings\": {\"peer_login_expiration\": 15552000,\"peer_login_expiration_enabled\": true,\"debug_bundle_upload_url\": \"https://upload.example.com/upload-url\"},\"onboarding\": {\"onboarding_flow_pending\": true,\"signup_form_pending\": true}}"),
|
|
expectedStatus: http.StatusOK,
|
|
expectedSettings: api.AccountSettings{
|
|
PeerLoginExpiration: 15552000,
|
|
PeerLoginExpirationEnabled: true,
|
|
GroupsPropagationEnabled: br(false),
|
|
JwtGroupsClaimName: sr(""),
|
|
JwtGroupsEnabled: br(false),
|
|
JwtAllowGroups: &[]string{},
|
|
RegularUsersViewBlocked: false,
|
|
RoutingPeerDnsResolutionEnabled: br(false),
|
|
LazyConnectionEnabled: br(false),
|
|
DnsDomain: sr(""),
|
|
DebugBundleUploadUrl: sr("https://upload.example.com/upload-url"),
|
|
AutoUpdateAlways: br(false),
|
|
AutoUpdateVersion: sr(""),
|
|
MetricsPushEnabled: br(false),
|
|
AgentNetworkOnly: br(false),
|
|
EmbeddedIdpEnabled: br(false),
|
|
LocalAuthDisabled: br(false),
|
|
LocalMfaEnabled: br(false),
|
|
},
|
|
expectedArray: false,
|
|
expectedID: accountID,
|
|
},
|
|
{
|
|
// The peers fetch an upload URL from this endpoint and then PUT the
|
|
// bundle to whatever comes back, so a plaintext destination must not
|
|
// be storable at all.
|
|
name: "PutAccount fails on a plaintext debug_bundle_upload_url",
|
|
expectedBody: true,
|
|
requestType: http.MethodPut,
|
|
requestPath: "/api/accounts/" + accountID,
|
|
requestBody: bytes.NewBufferString("{\"settings\": {\"peer_login_expiration\": 15552000,\"peer_login_expiration_enabled\": true,\"debug_bundle_upload_url\": \"http://upload.example.com/upload-url\"},\"onboarding\": {\"onboarding_flow_pending\": true,\"signup_form_pending\": true}}"),
|
|
expectedStatus: http.StatusUnprocessableEntity,
|
|
expectedArray: false,
|
|
},
|
|
{
|
|
name: "PutAccount fails enabling agent_network_only without dashboard_features",
|
|
expectedBody: true,
|
|
requestType: http.MethodPut,
|
|
requestPath: "/api/accounts/" + accountID,
|
|
requestBody: bytes.NewBufferString("{\"settings\": {\"peer_login_expiration\": 15552000,\"peer_login_expiration_enabled\": true,\"agent_network_only\": true},\"onboarding\": {\"onboarding_flow_pending\": true,\"signup_form_pending\": true}}"),
|
|
expectedStatus: http.StatusUnprocessableEntity,
|
|
expectedArray: false,
|
|
},
|
|
{
|
|
name: "PutAccount OK setting dashboard_features agent_network",
|
|
expectedBody: true,
|
|
requestType: http.MethodPut,
|
|
requestPath: "/api/accounts/" + accountID,
|
|
requestBody: bytes.NewBufferString("{\"settings\": {\"peer_login_expiration\": 15552000,\"peer_login_expiration_enabled\": true,\"dashboard_features\": {\"agent_network\": true}},\"onboarding\": {\"onboarding_flow_pending\": true,\"signup_form_pending\": true}}"),
|
|
expectedStatus: http.StatusOK,
|
|
expectedSettings: api.AccountSettings{
|
|
PeerLoginExpiration: 15552000,
|
|
PeerLoginExpirationEnabled: true,
|
|
GroupsPropagationEnabled: br(false),
|
|
JwtGroupsClaimName: sr(""),
|
|
JwtGroupsEnabled: br(false),
|
|
JwtAllowGroups: &[]string{},
|
|
RegularUsersViewBlocked: false,
|
|
RoutingPeerDnsResolutionEnabled: br(false),
|
|
LazyConnectionEnabled: br(false),
|
|
DnsDomain: sr(""),
|
|
DebugBundleUploadUrl: sr(""),
|
|
AutoUpdateAlways: br(false),
|
|
AutoUpdateVersion: sr(""),
|
|
MetricsPushEnabled: br(false),
|
|
AgentNetworkOnly: br(false),
|
|
DashboardFeatures: &api.AccountDashboardFeatures{
|
|
AgentNetwork: br(true),
|
|
},
|
|
EmbeddedIdpEnabled: br(false),
|
|
LocalAuthDisabled: br(false),
|
|
LocalMfaEnabled: br(false),
|
|
},
|
|
expectedArray: false,
|
|
expectedID: accountID,
|
|
},
|
|
{
|
|
name: "PutAccount OK disabling agent_network_only again",
|
|
expectedBody: true,
|
|
requestType: http.MethodPut,
|
|
requestPath: "/api/accounts/" + accountID,
|
|
requestBody: bytes.NewBufferString("{\"settings\": {\"peer_login_expiration\": 15552000,\"peer_login_expiration_enabled\": true,\"agent_network_only\": false},\"onboarding\": {\"onboarding_flow_pending\": true,\"signup_form_pending\": true}}"),
|
|
expectedStatus: http.StatusOK,
|
|
expectedSettings: api.AccountSettings{
|
|
PeerLoginExpiration: 15552000,
|
|
PeerLoginExpirationEnabled: true,
|
|
GroupsPropagationEnabled: br(false),
|
|
JwtGroupsClaimName: sr(""),
|
|
JwtGroupsEnabled: br(false),
|
|
JwtAllowGroups: &[]string{},
|
|
RegularUsersViewBlocked: false,
|
|
RoutingPeerDnsResolutionEnabled: br(false),
|
|
LazyConnectionEnabled: br(false),
|
|
DnsDomain: sr(""),
|
|
DebugBundleUploadUrl: sr(""),
|
|
AutoUpdateAlways: br(false),
|
|
AutoUpdateVersion: sr(""),
|
|
MetricsPushEnabled: br(false),
|
|
AgentNetworkOnly: br(false),
|
|
EmbeddedIdpEnabled: br(false),
|
|
LocalAuthDisabled: br(false),
|
|
LocalMfaEnabled: br(false),
|
|
},
|
|
expectedArray: false,
|
|
expectedID: accountID,
|
|
},
|
|
{
|
|
name: "Update account failure with high peer_login_expiration more than 180 days",
|
|
expectedBody: true,
|
|
requestType: http.MethodPut,
|
|
requestPath: "/api/accounts/" + accountID,
|
|
requestBody: bytes.NewBufferString("{\"settings\": {\"peer_login_expiration\": 15552001,\"peer_login_expiration_enabled\": true},\"onboarding\": {\"onboarding_flow_pending\": true,\"signup_form_pending\": true}}"),
|
|
expectedStatus: http.StatusUnprocessableEntity,
|
|
expectedArray: false,
|
|
},
|
|
{
|
|
name: "Update account failure with peer_login_expiration less than an hour",
|
|
expectedBody: true,
|
|
requestType: http.MethodPut,
|
|
requestPath: "/api/accounts/" + accountID,
|
|
requestBody: bytes.NewBufferString("{\"settings\": {\"peer_login_expiration\": 3599,\"peer_login_expiration_enabled\": true},\"onboarding\": {\"onboarding_flow_pending\": true,\"signup_form_pending\": true}}"),
|
|
expectedStatus: http.StatusUnprocessableEntity,
|
|
expectedArray: false,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tt {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
recorder := httptest.NewRecorder()
|
|
req := httptest.NewRequest(tc.requestType, tc.requestPath, tc.requestBody)
|
|
req = nbcontext.SetUserAuthInRequest(req, auth.UserAuth{
|
|
UserId: adminUser.Id,
|
|
AccountId: accountID,
|
|
Domain: "hotmail.com",
|
|
})
|
|
|
|
router := mux.NewRouter()
|
|
router.HandleFunc("/api/accounts", handler.getAllAccounts).Methods("GET")
|
|
router.HandleFunc("/api/accounts/{accountId}", handler.updateAccount).Methods("PUT")
|
|
router.ServeHTTP(recorder, req)
|
|
|
|
res := recorder.Result()
|
|
defer res.Body.Close()
|
|
|
|
if status := recorder.Code; status != tc.expectedStatus {
|
|
t.Errorf("handler returned wrong status code: got %v want %v",
|
|
status, tc.expectedStatus)
|
|
return
|
|
}
|
|
|
|
if tc.expectedStatus != http.StatusOK {
|
|
return
|
|
}
|
|
|
|
if !tc.expectedBody {
|
|
return
|
|
}
|
|
|
|
content, err := io.ReadAll(res.Body)
|
|
if err != nil {
|
|
t.Fatalf("I don't know what I expected; %v", err)
|
|
}
|
|
|
|
var actual *api.Account
|
|
if tc.expectedArray {
|
|
var got []*api.Account
|
|
if err = json.Unmarshal(content, &got); err != nil {
|
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
|
}
|
|
|
|
assert.Len(t, got, 1)
|
|
actual = got[0]
|
|
} else {
|
|
if err = json.Unmarshal(content, &actual); err != nil {
|
|
t.Fatalf("Sent content is not in correct json format; %v", err)
|
|
}
|
|
}
|
|
|
|
assert.Equal(t, tc.expectedID, actual.Id)
|
|
assert.Equal(t, tc.expectedSettings, actual.Settings)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCalculateMaxHosts(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
prefix string
|
|
min int64
|
|
}{
|
|
{"v4 /24", "100.64.0.0/24", 254},
|
|
{"v4 /16", "100.64.0.0/16", 65534},
|
|
{"v4 /28", "100.64.0.0/28", 14},
|
|
{"v6 /64", "fd00::/64", math.MaxInt64},
|
|
{"v6 /120", "fd00::/120", 256},
|
|
{"v6 /112", "fd00::/112", 65536},
|
|
{"v6 /48", "fd00::/48", math.MaxInt64},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
prefix := netip.MustParsePrefix(tt.prefix)
|
|
got := calculateMaxHosts(prefix)
|
|
assert.Equal(t, tt.min, got)
|
|
})
|
|
}
|
|
}
|