mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-12 17:59:06 +02:00
Prevent unvalidated registrations from reserving domain names indefinitely. Give pending registrations a 48-hour validation window and clean up expired entries at startup and every 60 minutes. Emit CustomDomainValidationExpired for each deletion and preserve registrations referenced by services. Reject validation after expiry and prevent concurrent validation from recreating deleted registrations. Normalize domain names with the shared parser before registration. Migrate existing pending registrations to receive a fresh 48-hour validation window.
110 lines
3.8 KiB
Go
110 lines
3.8 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/netbirdio/netbird/management/server/activity"
|
|
activitystore "github.com/netbirdio/netbird/management/server/activity/store"
|
|
"github.com/netbirdio/netbird/util/crypt"
|
|
)
|
|
|
|
func TestStoreEvent_CanceledContext(t *testing.T) {
|
|
t.Setenv("NB_EVENT_ACTIVITY_LOG_ENABLED", "true")
|
|
t.Setenv("NB_ACTIVITY_EVENT_STORE_ENGINE", "sqlite")
|
|
for _, code := range []activity.Activity{activity.CustomDomainValidationExpired, activity.DomainAdded} {
|
|
t.Run(code.StringCode(), func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
key, err := crypt.GenerateKey()
|
|
require.NoError(t, err)
|
|
eventStore, err := activitystore.NewSqlStore(context.Background(), dir, key)
|
|
require.NoError(t, err)
|
|
t.Cleanup(func() { assert.NoError(t, eventStore.Close(context.Background())) })
|
|
manager := &DefaultAccountManager{eventStore: eventStore}
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
cancel()
|
|
|
|
// The operation already succeeded when shutdown or the request cancels its context.
|
|
manager.StoreEvent(ctx, activity.SystemInitiator, "domain-id", "account-id",
|
|
code, map[string]any{"domain": "expired.example.com"})
|
|
if code != activity.CustomDomainValidationExpired {
|
|
require.Eventually(t, func() bool {
|
|
events, err := eventStore.Get(context.Background(), "account-id", 0, 10, true)
|
|
return err == nil && len(events) == 1
|
|
}, time.Second, time.Millisecond, "asynchronous events must survive request cancellation")
|
|
}
|
|
require.NoError(t, eventStore.Close(context.Background()))
|
|
|
|
reopened, err := activitystore.NewSqlStore(context.Background(), dir, key)
|
|
require.NoError(t, err)
|
|
t.Cleanup(func() { assert.NoError(t, reopened.Close(context.Background())) })
|
|
events, err := reopened.Get(context.Background(), "account-id", 0, 10, true)
|
|
require.NoError(t, err)
|
|
require.Len(t, events, 1, "the event must be persisted before shutdown closes the store")
|
|
assert.Equal(t, code, events[0].Activity, "persist the requested activity")
|
|
assert.Equal(t, "domain-id", events[0].TargetID, "retain the registration ID")
|
|
assert.Equal(t, "expired.example.com", events[0].Meta["domain"], "retain the domain name")
|
|
})
|
|
}
|
|
}
|
|
|
|
func generateAndStoreEvents(t *testing.T, manager *DefaultAccountManager, typ activity.Activity, initiatorID, targetID,
|
|
accountID string, count int) {
|
|
t.Helper()
|
|
for i := 0; i < count; i++ {
|
|
_, err := manager.eventStore.Save(context.Background(), &activity.Event{
|
|
Timestamp: time.Now().UTC(),
|
|
Activity: typ,
|
|
InitiatorID: initiatorID,
|
|
TargetID: targetID,
|
|
AccountID: accountID,
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDefaultAccountManager_GetEvents(t *testing.T) {
|
|
manager, _, err := createManager(t)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
accountID := "accountID"
|
|
|
|
t.Run("get empty events list", func(t *testing.T) {
|
|
events, err := manager.GetEvents(context.Background(), accountID, userID)
|
|
if err != nil {
|
|
return
|
|
}
|
|
assert.Len(t, events, 0)
|
|
_ = manager.eventStore.Close(context.Background()) //nolint
|
|
})
|
|
|
|
t.Run("get events", func(t *testing.T) {
|
|
generateAndStoreEvents(t, manager, activity.PeerAddedByUser, userID, "peer", accountID, 10)
|
|
events, err := manager.GetEvents(context.Background(), accountID, userID)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
assert.Len(t, events, 10)
|
|
_ = manager.eventStore.Close(context.Background()) //nolint
|
|
})
|
|
|
|
t.Run("get events without duplicates", func(t *testing.T) {
|
|
generateAndStoreEvents(t, manager, activity.UserJoined, userID, "", accountID, 10)
|
|
events, err := manager.GetEvents(context.Background(), accountID, userID)
|
|
if err != nil {
|
|
return
|
|
}
|
|
assert.Len(t, events, 1)
|
|
_ = manager.eventStore.Close(context.Background()) //nolint
|
|
})
|
|
}
|