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 0 when the user has no stored privileges and is not an admin.

Return type:

int

Parameters:
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 bit for user_id: for each alias in user_aliases (defaulting to just user_id) it strips any platform: prefix, loads that identity’s bitmask via get_user_privileges(), and returns True on the first alias whose mask has bit set. 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 a PRIVILEGES[...] constant as bit.

Parameters:
  • redis (Any) – Async Redis client used to read each identity’s privilege mask.

  • user_id (str) – The primary user id to check (used when user_aliases is empty).

  • bit (int) – Zero-based bit index of the privilege to test (1 << bit).

  • config (Any) – Optional config forwarded to get_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:

True if any checked identity has bit enabled, else False.

Return type:

bool

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:

bool

Parameters:
  • bit (int)

  • global_mask (int)

  • guild_mask (int | None)

  • channel_mask (int | None)

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 — by message_processor/processor.py and generate_and_send.py, feature_toggles.py, platforms/discord.py, game_ui/action_handler.py, and tools such as set_user_timezone and context_window_tools — typically for the STARGAZER_USE access gate and admin checks.

Parameters:
  • redis (Any) – Async Redis client used to read the scoped masks.

  • user_id (str) – Platform user ID (used when user_aliases is 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:

bool

Returns:

True if any alias holds the bit under its resolution mode, else False.