mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-14 17:39:12 +02:00
[management] Record proxy logins and mesh activity for active-user accounting
Activity accounting counts a user as active from their last login or from a peer of theirs being seen. Neither timestamp moved when someone reached a service through the reverse proxy, so a person who only ever uses proxy-protected services and never opens the dashboard has no login on record at all and is skipped outright. The two proxy entry points mean different things, so they write different things. GenerateSessionToken is only reached after an ID token was verified, so a completed SSO sign-in records a login on the user. ValidateTunnelPeer authorises by tunnel IP with no IdP involved, so it records that the peer was seen instead; the owner counts through that. Both write on the granted path only, in UTC, and log and drop failures — no authorisation decision reads them back. The peer write is throttled to once an hour against the peer already in hand, so a busy peer does not rewrite its row behind every request. Both store methods update one column and leave the session-ownership fields to the sync stream that owns them. Peers that accounting excludes, embedded proxy peers and browser clients, are skipped rather than written for nothing.
This commit is contained in:
@@ -44,6 +44,8 @@ type Manager interface {
|
||||
// to. Used by the proxy's auth path to authorise a request by the calling
|
||||
// peer's group memberships.
|
||||
GetPeerWithGroups(ctx context.Context, accountID, peerID string) (*peer.Peer, []*types.Group, error)
|
||||
// RefreshLastSeen records that a peer was seen at seenAt.
|
||||
RefreshLastSeen(ctx context.Context, accountID, peerID string, seenAt time.Time) error
|
||||
}
|
||||
|
||||
type managerImpl struct {
|
||||
@@ -128,6 +130,10 @@ func (m *managerImpl) GetPeerWithGroups(ctx context.Context, accountID, peerID s
|
||||
return p, groups, nil
|
||||
}
|
||||
|
||||
func (m *managerImpl) RefreshLastSeen(ctx context.Context, accountID, peerID string, seenAt time.Time) error {
|
||||
return m.store.RefreshPeerLastSeen(ctx, accountID, peerID, seenAt)
|
||||
}
|
||||
|
||||
func (m *managerImpl) DeletePeers(ctx context.Context, accountID string, peerIDs []string, userID string, checkConnected bool) error {
|
||||
settings, err := m.store.GetAccountSettings(ctx, store.LockingStrengthNone, accountID)
|
||||
if err != nil {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
context "context"
|
||||
net "net"
|
||||
reflect "reflect"
|
||||
time "time"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
network_map "github.com/netbirdio/netbird/management/internals/controllers/network_map"
|
||||
@@ -174,6 +175,20 @@ func (mr *MockManagerMockRecorder) GetPeersByGroupIDs(ctx, accountID, groupsIDs
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPeersByGroupIDs", reflect.TypeOf((*MockManager)(nil).GetPeersByGroupIDs), ctx, accountID, groupsIDs)
|
||||
}
|
||||
|
||||
// RefreshLastSeen mocks base method.
|
||||
func (m *MockManager) RefreshLastSeen(ctx context.Context, accountID, peerID string, seenAt time.Time) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "RefreshLastSeen", ctx, accountID, peerID, seenAt)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// RefreshLastSeen indicates an expected call of RefreshLastSeen.
|
||||
func (mr *MockManagerMockRecorder) RefreshLastSeen(ctx, accountID, peerID, seenAt interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RefreshLastSeen", reflect.TypeOf((*MockManager)(nil).RefreshLastSeen), ctx, accountID, peerID, seenAt)
|
||||
}
|
||||
|
||||
// SetAccountManager mocks base method.
|
||||
func (m *MockManager) SetAccountManager(accountManager account.Manager) {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
Reference in New Issue
Block a user