mirror of
https://github.com/netbirdio/netbird.git
synced 2026-08-29 19:11:28 +02:00
Recording proxy usage is business logic, and it had ended up in the RPC handler: the throttle interval, the service-user skip, the exclusion rule for embedded and browser peers, and a store handle to write through. It moves to a reverseproxy module manager, matching how accesslogs, domain, service and proxy are already structured, and the RPC keeps only what is its own: calling the manager and deciding the request must not fail when the write does. The proxy service goes back to holding ProxyTokenChecker rather than a widened store interface. The policy tests move with the policy. The handler tests now assert only that a granted request reaches the manager, which is all the transport decides.
62 lines
2.2 KiB
Go
62 lines
2.2 KiB
Go
package manager
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/netbirdio/netbird/management/internals/modules/reverseproxy/activity"
|
|
"github.com/netbirdio/netbird/management/server/peer"
|
|
"github.com/netbirdio/netbird/management/server/store"
|
|
"github.com/netbirdio/netbird/management/server/types"
|
|
)
|
|
|
|
// peerSeenInterval is how stale a peer's LastSeen must be before reaching a
|
|
// private service refreshes it. Positive tunnel validations are cached on the
|
|
// proxy for five minutes, so without a floor a busy peer would rewrite its row
|
|
// behind every request; an hour still sits well inside the window activity
|
|
// accounting asks about.
|
|
const peerSeenInterval = time.Hour
|
|
|
|
type managerImpl struct {
|
|
store store.Store
|
|
}
|
|
|
|
// NewManager returns the activity manager backed by the management store.
|
|
func NewManager(store store.Store) activity.Manager {
|
|
return &managerImpl{store: store}
|
|
}
|
|
|
|
// RecordUserLogin stamps the login the same way the dashboard and device login
|
|
// paths do, so a person who only ever reaches proxied services still has a
|
|
// login on record.
|
|
func (m *managerImpl) RecordUserLogin(ctx context.Context, accountID string, user *types.User) error {
|
|
if user == nil || user.IsServiceUser {
|
|
return nil
|
|
}
|
|
|
|
return m.store.SaveUserLastLogin(ctx, accountID, user.Id, time.Now().UTC())
|
|
}
|
|
|
|
// RecordPeerSeen stamps LastSeen, the column a peer activates its owner
|
|
// through. The throttle reads the peer the caller already holds, so a peer seen
|
|
// inside the interval costs nothing to skip.
|
|
func (m *managerImpl) RecordPeerSeen(ctx context.Context, accountID string, peer *peer.Peer) error {
|
|
if peer == nil || !countsTowardActivity(peer) {
|
|
return nil
|
|
}
|
|
|
|
if peer.Status != nil && time.Since(peer.Status.LastSeen) < peerSeenInterval {
|
|
return nil
|
|
}
|
|
|
|
return m.store.RefreshPeerLastSeen(ctx, accountID, peer.ID)
|
|
}
|
|
|
|
// countsTowardActivity reports whether the peer represents a device a person
|
|
// actually runs. Embedded proxy peers are infrastructure and browser (WASM)
|
|
// clients are ephemeral sessions, so activity accounting ignores both and a
|
|
// write for them could never count.
|
|
func countsTowardActivity(peer *peer.Peer) bool {
|
|
return !peer.ProxyMeta.Embedded && peer.Meta.KernelVersion != "wasm"
|
|
}
|