Register creation time for peer, user and account (#1654)

This change register creation time for new peers, users and accounts
This commit is contained in:
Maycon Santos 2024-03-02 13:49:40 +01:00 committed by GitHub
parent 452419c4c3
commit aa935bdae3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 36 additions and 6 deletions

View File

@ -206,6 +206,7 @@ type Account struct {
// User.Id it was created by // User.Id it was created by
CreatedBy string CreatedBy string
CreatedAt time.Time
Domain string `gorm:"index"` Domain string `gorm:"index"`
DomainCategory string DomainCategory string
IsDomainPrimaryAccount bool IsDomainPrimaryAccount bool
@ -684,6 +685,7 @@ func (a *Account) Copy() *Account {
return &Account{ return &Account{
Id: a.Id, Id: a.Id,
CreatedBy: a.CreatedBy, CreatedBy: a.CreatedBy,
CreatedAt: a.CreatedAt,
Domain: a.Domain, Domain: a.Domain,
DomainCategory: a.DomainCategory, DomainCategory: a.DomainCategory,
IsDomainPrimaryAccount: a.IsDomainPrimaryAccount, IsDomainPrimaryAccount: a.IsDomainPrimaryAccount,
@ -1875,6 +1877,7 @@ func newAccountWithId(accountID, userID, domain string) *Account {
acc := &Account{ acc := &Account{
Id: accountID, Id: accountID,
CreatedAt: time.Now().UTC(),
SetupKeys: setupKeys, SetupKeys: setupKeys,
Network: network, Network: network,
Peers: peers, Peers: peers,

View File

@ -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) 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 { if account.Domain != domain {
t.Errorf("expecting newly created account to have domain %s, got %s", domain, account.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{ account := &Account{
Id: "account1", Id: "account1",
CreatedBy: "tester", CreatedBy: "tester",
CreatedAt: time.Now().UTC(),
Domain: "test.com", Domain: "test.com",
DomainCategory: "public", DomainCategory: "public",
IsDomainPrimaryAccount: true, IsDomainPrimaryAccount: true,

View File

@ -410,6 +410,8 @@ func (am *DefaultAccountManager) AddPeer(setupKey, userID string, peer *nbpeer.P
return nil, nil, err return nil, nil, err
} }
registrationTime := time.Now().UTC()
newPeer := &nbpeer.Peer{ newPeer := &nbpeer.Peer{
ID: xid.New().String(), ID: xid.New().String(),
Key: peer.Key, Key: peer.Key,
@ -419,10 +421,11 @@ func (am *DefaultAccountManager) AddPeer(setupKey, userID string, peer *nbpeer.P
Name: peer.Meta.Hostname, Name: peer.Meta.Hostname,
DNSLabel: newLabel, DNSLabel: newLabel,
UserID: userID, UserID: userID,
Status: &nbpeer.PeerStatus{Connected: false, LastSeen: time.Now().UTC()}, Status: &nbpeer.PeerStatus{Connected: false, LastSeen: registrationTime},
SSHEnabled: false, SSHEnabled: false,
SSHKey: peer.SSHKey, SSHKey: peer.SSHKey,
LastLogin: time.Now().UTC(), LastLogin: registrationTime,
CreatedAt: registrationTime,
LoginExpirationEnabled: addedByUser, LoginExpirationEnabled: addedByUser,
Ephemeral: ephemeral, Ephemeral: ephemeral,
} }

View File

@ -40,6 +40,8 @@ type Peer struct {
LoginExpirationEnabled bool LoginExpirationEnabled bool
// LastLogin the time when peer performed last login operation // LastLogin the time when peer performed last login operation
LastLogin time.Time LastLogin time.Time
// CreatedAt records the time the peer was created
CreatedAt time.Time
// Indicate ephemeral peer attribute // Indicate ephemeral peer attribute
Ephemeral bool Ephemeral bool
// Geo location based on connection IP // Geo location based on connection IP
@ -157,6 +159,7 @@ func (p *Peer) Copy() *Peer {
SSHEnabled: p.SSHEnabled, SSHEnabled: p.SSHEnabled,
LoginExpirationEnabled: p.LoginExpirationEnabled, LoginExpirationEnabled: p.LoginExpirationEnabled,
LastLogin: p.LastLogin, LastLogin: p.LastLogin,
CreatedAt: p.CreatedAt,
Ephemeral: p.Ephemeral, Ephemeral: p.Ephemeral,
Location: p.Location, Location: p.Location,
} }
@ -213,7 +216,7 @@ func (p *Peer) FQDN(dnsDomain string) string {
// EventMeta returns activity event meta related to the peer // EventMeta returns activity event meta related to the peer
func (p *Peer) EventMeta(dnsDomain string) map[string]any { 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 // Copy PeerStatus

View File

@ -85,6 +85,8 @@ type User struct {
Blocked bool Blocked bool
// LastLogin is the last time the user logged in to IdP // LastLogin is the last time the user logged in to IdP
LastLogin time.Time LastLogin time.Time
// CreatedAt records the time the user was created
CreatedAt time.Time
// Issued of the user // Issued of the user
Issued string `gorm:"default:api"` Issued string `gorm:"default:api"`
@ -173,6 +175,7 @@ func (u *User) Copy() *User {
PATs: pats, PATs: pats,
Blocked: u.Blocked, Blocked: u.Blocked,
LastLogin: u.LastLogin, LastLogin: u.LastLogin,
CreatedAt: u.CreatedAt,
Issued: u.Issued, Issued: u.Issued,
IntegrationReference: u.IntegrationReference, IntegrationReference: u.IntegrationReference,
} }
@ -188,6 +191,7 @@ func NewUser(id string, role UserRole, isServiceUser bool, nonDeletable bool, se
ServiceUserName: serviceUserName, ServiceUserName: serviceUserName,
AutoGroups: autoGroups, AutoGroups: autoGroups,
Issued: issued, Issued: issued,
CreatedAt: time.Now().UTC(),
} }
} }
@ -338,6 +342,7 @@ func (am *DefaultAccountManager) inviteNewUser(accountID, userID string, invite
AutoGroups: invite.AutoGroups, AutoGroups: invite.AutoGroups,
Issued: invite.Issued, Issued: invite.Issued,
IntegrationReference: invite.IntegrationReference, IntegrationReference: invite.IntegrationReference,
CreatedAt: time.Now().UTC(),
} }
account.Users[idpUser.ID] = newUser 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) { 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) am.StoreEvent(initiatorUserID, targetUser.Id, account.Id, activity.ServiceUserDeleted, meta)
delete(account.Users, targetUser.Id) delete(account.Users, targetUser.Id)
} }
@ -494,13 +499,23 @@ func (am *DefaultAccountManager) deleteRegularUser(account *Account, initiatorUs
return err 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) delete(account.Users, targetUserID)
err = am.Store.SaveAccount(account) err = am.Store.SaveAccount(account)
if err != nil { if err != nil {
return err 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.StoreEvent(initiatorUserID, targetUserID, account.Id, activity.UserDeleted, meta)
am.updateAccountPeers(account) am.updateAccountPeers(account)

View File

@ -273,7 +273,8 @@ func TestUser_Copy(t *testing.T) {
}, },
}, },
Blocked: false, Blocked: false,
LastLogin: time.Now(), LastLogin: time.Now().UTC(),
CreatedAt: time.Now().UTC(),
Issued: "test", Issued: "test",
IntegrationReference: IntegrationReference{ IntegrationReference: IntegrationReference{
ID: 0, ID: 0,