tools.alter_privileges module
User privilege management with a 64-bit bitmask stored in Redis.
Each bit is a named privilege. The canonical registry is PRIVILEGES
(name → bit index, 0–63). Admins (config.admin_user_ids) implicitly have
all bits set. Unknown set bits are reported as bit_N.
Other modules check privileges with:
from tools.alter_privileges import has_privilege, PRIVILEGES
Tool-facing descriptions below are built from PRIVILEGES so they stay
in sync when bits are added or renamed.
- async tools.alter_privileges.get_user_privileges(redis, user_id, config=None)[source]
Return the privilege bitmask for user_id.
Admins get all 64 bits. Returns
0when the user has no stored privileges and is not an admin.
- async tools.alter_privileges.has_privilege(redis, user_id, bit, config=None, user_aliases=None)[source]
Report whether a user (or any alias) has one privilege bit set.
Checks the single privilege flag
bitforuser_id: for each alias inuser_aliases(defaulting to justuser_id) it strips anyplatform:prefix, loads that identity’s bitmask viaget_user_privileges(), and returnsTrueon the first alias whose mask hasbitset. Read-only against Redis.This is the shared gate the tool layer uses to authorize privileged actions – e.g.
tools.prowlarr_search._check_web_search_access()and the other per-tool access checks pass aPRIVILEGES[...]constant asbit.- Parameters:
redis (
Any) – Async Redis client used to read each identity’s privilege mask.user_id (
str) – The primary user id to check (used whenuser_aliasesis empty).bit (
int) – Zero-based bit index of the privilege to test (1 << bit).config (
Any) – Optional config forwarded toget_user_privileges()(e.g. for owner/superuser short-circuits).user_aliases (
list[str] |None) – Optional list of equivalent identities (cross-platform links); any one of them holding the bit grants access.
- Returns:
Trueif any checked identity hasbitenabled, elseFalse.- Return type:
- tools.alter_privileges.resolve_privilege_bit(bit, global_mask, guild_mask, channel_mask)[source]
Resolve a single privilege bit across all three scope masks.
- Return type:
- Parameters:
- Resolution modes:
0 (NORMAL): channel > guild > global — most specific scope wins. 1 (INVERTED): global > guild > channel — most general scope wins. 2 (DANGEROUS): global only — scoped masks ignored. 3 (ANY): granted if set at any scope (global OR guild OR channel).
- async tools.alter_privileges.has_scoped_privilege(redis, user_id, bit, config=None, guild_id=None, channel_id=None, user_aliases=None)[source]
Check a scoped privilege bit across all of a user’s linked aliases.
The primary public scope-aware access check: a user may appear under several platform identities (cross-platform alias links), so this strips any
platform:prefix from each alias and grants access if any alias passes_has_scoped_privilege_single(), which applies the bit’s per-scope resolution mode against the global, guild, and channel masks read from Redis. Short-circuits on the first alias that succeeds. Used pervasively as the gatekeeper for feature and tool access — bymessage_processor/processor.pyandgenerate_and_send.py,feature_toggles.py,platforms/discord.py,game_ui/action_handler.py, and tools such asset_user_timezoneandcontext_window_tools— typically for theSTARGAZER_USEaccess gate and admin checks.- Parameters:
redis (
Any) – Async Redis client used to read the scoped masks.user_id (
str) – Platform user ID (used whenuser_aliasesis not given).bit (
int) – Privilege bit index (0-63) to check.config (
Any) – Bot config for the admin short-circuit; optional.guild_id (
str|None) – Guild/server ID for scoped resolution; optional.channel_id (
str|None) – Channel ID for the most-specific scope; optional.user_aliases (
list[str] |None) – Full alias list to test; defaults to[user_id].
- Return type:
- Returns:
True if any alias holds the bit under its resolution mode, else False.