Works out a hit's PhoenixKitWebAnalytics.TrafficFlags — whether it is
the site's own people or their networks — without a query on the way.
internal_network— the client address falls in one of the networks inconfig :phoenix_kit_web_analytics, internal_networks: [...](CIDR, IPv4 or IPv6; a bare address is one host). Parsed once and kept until the config changes.admin— the signed-in user holds a role listed inweb_analytics_internal_roles(Owner and Admin by default), byPhoenixKit.Users.Auth.Scope.held_roles/1: the roles they really hold, whichever one they are acting as. A hit that names only a user (no scope) is judged by a five-minute cache of that user's roles; on a miss the roles are looked up off the hit's path, so that hit goes unflagged and the next one — with the whole visit — gets the bit.admin_network— the client's network (an IPv4 address, an IPv6 /64, asPhoenixKit.Utils.IpAddress.network/1keys it) had a staff member signed in within the lastweb_analytics_admin_network_hours(24 by default;0turns it off). Learnt from two places: a staff sign-in (core's{:session_created, …}, which every node hears — the address is the session token's, so an admin who only ever works in the admin panel, which is never tracked, still counts) and a staff member's own request throughPhoenixKitWebAnalytics.Plug, shared with the other nodes. Private, loopback and unparseable addresses are never taken.
A network is remembered with the time a staff member was last seen on it, and judged against the hours set now: shortening them takes effect at once for every network already learnt.
A network learnt this way is held in memory only, under its plain key (hashing it would not protect anything: the key would sit on the same node), and forgotten when its time is up. Nothing about it is written to the database or the settings.
Behind carrier-grade NAT, a mobile network or an office gateway, one
address is many people: a staff sign-in from a phone flags everyone
behind the same public address for those hours. That's the trade-off of
the admin_network flag, and why it can be counted back in from
Settings or its hours set to 0.
Summary
Functions
Whether ip's network had a staff sign-in within the configured hours.
Returns a specification to start this module under a supervisor.
The flags of a hit: :ip (a tuple), :roles (the signed-in user's held
roles, when the hit came with a scope) and :user_uuid. Never raises;
0 when nothing can be told.
Forgets, now rather than at the next sweep, the networks past the hours
set now (all of them at 0) and the expired role entries. Called after
a settings save.
Whether ip is in one of the configured internal_networks. An invalid
entry is skipped, with one warning.
How many configured internal_networks are networks and how many aren't
(those are skipped) — for the settings page.
The flags an address alone gives — internal_network and
admin_network. What the recording endpoint can tell before it knows the
visit.
Notes that a staff member was seen at ip (a tuple or a string): its
network counts as a staff network for the configured hours. Told to the
other nodes only when the network is new here or past half its time, so a
staff member browsing doesn't cost a broadcast per request. Private,
loopback and unparseable addresses are ignored. Never raises.
"203.0.113.0/24" → [{32, base, 24}]; [] for anything that isn't a
network.
Whether any of roles is a staff role under config.
Whether a hit is a staff member's — by the roles it carries, or by its
user's cached roles (a miss starts the lookup and answers false).
Functions
@spec admin_network?( :inet.ip_address() | nil, PhoenixKitWebAnalytics.Config.collection_config() ) :: boolean()
Whether ip's network had a staff sign-in within the configured hours.
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec flags(map(), PhoenixKitWebAnalytics.Config.collection_config()) :: non_neg_integer()
The flags of a hit: :ip (a tuple), :roles (the signed-in user's held
roles, when the hit came with a scope) and :user_uuid. Never raises;
0 when nothing can be told.
@spec forget_expired() :: :ok
Forgets, now rather than at the next sweep, the networks past the hours
set now (all of them at 0) and the expired role entries. Called after
a settings save.
@spec internal_network?(:inet.ip_address() | nil) :: boolean()
Whether ip is in one of the configured internal_networks. An invalid
entry is skipped, with one warning.
@spec network_counts() :: %{valid: non_neg_integer(), invalid: non_neg_integer()}
How many configured internal_networks are networks and how many aren't
(those are skipped) — for the settings page.
@spec network_flags( :inet.ip_address() | nil, PhoenixKitWebAnalytics.Config.collection_config() ) :: non_neg_integer()
The flags an address alone gives — internal_network and
admin_network. What the recording endpoint can tell before it knows the
visit.
@spec note_admin_network( :inet.ip_address() | String.t() | nil, PhoenixKitWebAnalytics.Config.collection_config() ) :: :ok
Notes that a staff member was seen at ip (a tuple or a string): its
network counts as a staff network for the configured hours. Told to the
other nodes only when the network is new here or past half its time, so a
staff member browsing doesn't cost a broadcast per request. Private,
loopback and unparseable addresses are ignored. Never raises.
@spec parse_cidr(term()) :: [{32 | 128, non_neg_integer(), non_neg_integer()}]
"203.0.113.0/24" → [{32, base, 24}]; [] for anything that isn't a
network.
@spec staff?([String.t()] | nil, PhoenixKitWebAnalytics.Config.collection_config()) :: boolean()
Whether any of roles is a staff role under config.
@spec staff_hit?(map(), PhoenixKitWebAnalytics.Config.collection_config()) :: boolean()
Whether a hit is a staff member's — by the roles it carries, or by its
user's cached roles (a miss starts the lookup and answers false).