diff --git a/management/server/account.go b/management/server/account.go index efdfc6de6..97f054ff2 100644 --- a/management/server/account.go +++ b/management/server/account.go @@ -206,6 +206,7 @@ type Account struct { // User.Id it was created by CreatedBy string + CreatedAt time.Time Domain string `gorm:"index"` DomainCategory string IsDomainPrimaryAccount bool @@ -684,6 +685,7 @@ func (a *Account) Copy() *Account { return &Account{ Id: a.Id, CreatedBy: a.CreatedBy, + CreatedAt: a.CreatedAt, Domain: a.Domain, DomainCategory: a.DomainCategory, IsDomainPrimaryAccount: a.IsDomainPrimaryAccount, @@ -1875,6 +1877,7 @@ func newAccountWithId(accountID, userID, domain string) *Account { acc := &Account{ Id: accountID, + CreatedAt: time.Now().UTC(), SetupKeys: setupKeys, Network: network, Peers: peers, diff --git a/management/server/account_test.go b/management/server/account_test.go index 1890d3060..2b0c44196 100644 --- a/management/server/account_test.go +++ b/management/server/account_test.go @@ -94,6 +94,10 @@ func verifyNewAccountHasDefaultFields(t *testing.T, account *Account, createdBy t.Errorf("expecting newly created account to be created by user %s, got %s", createdBy, account.CreatedBy) } + if account.CreatedAt.IsZero() { + t.Errorf("expecting newly created account to have a non-zero creation time") + } + if account.Domain != domain { t.Errorf("expecting newly created account to have domain %s, got %s", domain, account.Domain) } @@ -1473,6 +1477,7 @@ func TestAccount_Copy(t *testing.T) { account := &Account{ Id: "account1", CreatedBy: "tester", + CreatedAt: time.Now().UTC(), Domain: "test.com", DomainCategory: "public", IsDomainPrimaryAccount: true, diff --git a/management/server/peer.go b/management/server/peer.go index 1a7b06a79..53b86e9b3 100644 --- a/management/server/peer.go +++ b/management/server/peer.go @@ -410,6 +410,8 @@ func (am *DefaultAccountManager) AddPeer(setupKey, userID string, peer *nbpeer.P return nil, nil, err } + registrationTime := time.Now().UTC() + newPeer := &nbpeer.Peer{ ID: xid.New().String(), Key: peer.Key, @@ -419,10 +421,11 @@ func (am *DefaultAccountManager) AddPeer(setupKey, userID string, peer *nbpeer.P Name: peer.Meta.Hostname, DNSLabel: newLabel, UserID: userID, - Status: &nbpeer.PeerStatus{Connected: false, LastSeen: time.Now().UTC()}, + Status: &nbpeer.PeerStatus{Connected: false, LastSeen: registrationTime}, SSHEnabled: false, SSHKey: peer.SSHKey, - LastLogin: time.Now().UTC(), + LastLogin: registrationTime, + CreatedAt: registrationTime, LoginExpirationEnabled: addedByUser, Ephemeral: ephemeral, } diff --git a/management/server/peer/peer.go b/management/server/peer/peer.go index 757f6b69a..e62843180 100644 --- a/management/server/peer/peer.go +++ b/management/server/peer/peer.go @@ -40,6 +40,8 @@ type Peer struct { LoginExpirationEnabled bool // LastLogin the time when peer performed last login operation LastLogin time.Time + // CreatedAt records the time the peer was created + CreatedAt time.Time // Indicate ephemeral peer attribute Ephemeral bool // Geo location based on connection IP @@ -157,6 +159,7 @@ func (p *Peer) Copy() *Peer { SSHEnabled: p.SSHEnabled, LoginExpirationEnabled: p.LoginExpirationEnabled, LastLogin: p.LastLogin, + CreatedAt: p.CreatedAt, Ephemeral: p.Ephemeral, Location: p.Location, } @@ -213,7 +216,7 @@ func (p *Peer) FQDN(dnsDomain string) string { // EventMeta returns activity event meta related to the peer func (p *Peer) EventMeta(dnsDomain string) map[string]any { - return map[string]any{"name": p.Name, "fqdn": p.FQDN(dnsDomain), "ip": p.IP} + return map[string]any{"name": p.Name, "fqdn": p.FQDN(dnsDomain), "ip": p.IP, "created_at": p.CreatedAt} } // Copy PeerStatus diff --git a/management/server/user.go b/management/server/user.go index 651488f2b..f1516139b 100644 --- a/management/server/user.go +++ b/management/server/user.go @@ -85,6 +85,8 @@ type User struct { Blocked bool // LastLogin is the last time the user logged in to IdP LastLogin time.Time + // CreatedAt records the time the user was created + CreatedAt time.Time // Issued of the user Issued string `gorm:"default:api"` @@ -173,6 +175,7 @@ func (u *User) Copy() *User { PATs: pats, Blocked: u.Blocked, LastLogin: u.LastLogin, + CreatedAt: u.CreatedAt, Issued: u.Issued, IntegrationReference: u.IntegrationReference, } @@ -188,6 +191,7 @@ func NewUser(id string, role UserRole, isServiceUser bool, nonDeletable bool, se ServiceUserName: serviceUserName, AutoGroups: autoGroups, Issued: issued, + CreatedAt: time.Now().UTC(), } } @@ -338,6 +342,7 @@ func (am *DefaultAccountManager) inviteNewUser(accountID, userID string, invite AutoGroups: invite.AutoGroups, Issued: invite.Issued, IntegrationReference: invite.IntegrationReference, + CreatedAt: time.Now().UTC(), } account.Users[idpUser.ID] = newUser @@ -414,7 +419,7 @@ func (am *DefaultAccountManager) ListUsers(accountID string) ([]*User, error) { } func (am *DefaultAccountManager) deleteServiceUser(account *Account, initiatorUserID string, targetUser *User) { - meta := map[string]any{"name": targetUser.ServiceUserName} + meta := map[string]any{"name": targetUser.ServiceUserName, "created_at": targetUser.CreatedAt} am.StoreEvent(initiatorUserID, targetUser.Id, account.Id, activity.ServiceUserDeleted, meta) delete(account.Users, targetUser.Id) } @@ -494,13 +499,23 @@ func (am *DefaultAccountManager) deleteRegularUser(account *Account, initiatorUs return err } + u, err := account.FindUser(targetUserID) + if err != nil { + log.Errorf("failed to find user %s for deletion, this should never happen: %s", targetUserID, err) + } + + var tuCreatedAt time.Time + if u != nil { + tuCreatedAt = u.CreatedAt + } + delete(account.Users, targetUserID) err = am.Store.SaveAccount(account) if err != nil { return err } - meta := map[string]any{"name": tuName, "email": tuEmail} + meta := map[string]any{"name": tuName, "email": tuEmail, "created_at": tuCreatedAt} am.StoreEvent(initiatorUserID, targetUserID, account.Id, activity.UserDeleted, meta) am.updateAccountPeers(account) diff --git a/management/server/user_test.go b/management/server/user_test.go index 8de2267b3..50cd726ef 100644 --- a/management/server/user_test.go +++ b/management/server/user_test.go @@ -273,7 +273,8 @@ func TestUser_Copy(t *testing.T) { }, }, Blocked: false, - LastLogin: time.Now(), + LastLogin: time.Now().UTC(), + CreatedAt: time.Now().UTC(), Issued: "test", IntegrationReference: IntegrationReference{ ID: 0,