Course:CPSC312-2019-Discord-Permissions

From UBC Wiki

Discord Permissions

Authors: Rebecca Li, JeongSoo Doo

What is the problem?

Discord is an instant messaging client with complex permissions. Permissions can be applied at a guild-wide level for @everyone, individual members, and roles (which members may belong to). These permissions may be overwritten on a per-channel basis. The following hierarchy is observed:

(Taken from Discord documentation, found here.)

  1. Base permissions given to @everyone are applied at a guild level
  2. Permissions allowed to a user by their roles are applied at a guild level
  3. Overwrites that deny permissions for @everyone are applied at a channel level
  4. Overwrites that allow permissions for @everyone are applied at a channel level
  5. Overwrites that deny permissions for specific roles are applied at a channel level
  6. Overwrites that allow permissions for specific roles are applied at a channel level
  7. Member-specific overwrites that deny permissions are applied at a channel level
  8. Member-specific overwrites that allow permissions are applied at a channel level

Permissions are represented by a permissions integer whose bits correspond to various flags. Individual permissions may be extracted through bitwise operations/masking (e.g. CREATE_INSTANT_INVITE is 0x00000001).

Our project implements per-channel permissions overwriting in Prolog, allowing the permissions integer for a particular user to be computed given a guild or a channel (and their IDs).

What is the something extra?

Using the Discord API to fetch real data including guild permissions, users, roles, and channels. This is done through HTTP requests by a bot user that has access to the guild whose data is requested using http/http_open.

Data is received in JSON format and parsed into Prolog dicts via http/json.

What did we learn from doing this?

Logic programming is suitable for the task, though it has some downsides.

  • Understanding the Prolog documentation was difficult, but the code itself for retrieving the data is relatively simple. The docs indicate argument modes, which we did not discuss (directly) in class.
  • Prolog supports use of hexadecimal values (lead with 0x) and bitwise operations (/\, \/), which was convenient.
  • When writing multiple definitions of a predicate, it can be easy to make mistakes that cause multiple answers to be returned when only one answer is desired (e.g. guild_permissions and channel_permissions should only produce one permissions integer for the given user). Care must be taken to separate distinct cases.
    • This was especially messy with the many helpers in permissions.pl.
  • Constant values are saved using predicates (see flags.pl and token.pl). This can be useful if the relations are complex, but in our case we only used permission names to get the one corresponding integer.

Links to code etc

Project repository.