Messages permissions // G -> General global permissions // L -> Changelog permissions // N -> News permissions // F -> Global Forum perms // C -> Global Comments perms // X -> unallocated public const G_IS_JANITOR = 0b00000_00000000_00000000_00000000_00000000_00000000_00000001; public const G_LOGS_VIEW = 0b00000_00000000_00000000_00000000_00000000_00000000_00000010; public const G_EMOTES_MANAGE = 0b00000_00000000_00000000_00000000_00000000_00000000_00000100; public const G_CONFIG_MANAGE = 0b00000_00000000_00000000_00000000_00000000_00000000_00001000; //public const G_IS_TESTER = 0b00000_00000000_00000000_00000000_00000000_00000000_00010000; // deprecated: tester status went unused public const G_BLACKLIST_MANAGE = 0b00000_00000000_00000000_00000000_00000000_00000000_00100000; // unused: blacklist is currently removed to reduce overhead and it seemed like it was broken //public const G_TWITTER_MANAGE = 0b00000_00000000_00000000_00000000_00000000_00000000_01000000; // deprecated: twitter integration has been removed public const G_TIMINGS_VIEW = 0b00000_00000000_00000000_00000000_00000000_00000000_10000000; public const G_CL_CHANGES_MANAGE = 0b00000_00000000_00000000_00000000_00000000_00000001_00000000; public const G_CL_TAGS_MANAGE = 0b00000_00000000_00000000_00000000_00000000_00000010_00000000; //public const G_CL_ACTIONS_MANAGE = 0b00000_00000000_00000000_00000000_00000000_00000100_00000000; // deprecated: actions are hardcoded now public const G_NEWS_POSTS_MANAGE = 0b00000_00000000_00000000_00000000_00000001_00000000_00000000; public const G_NEWS_CATEGORIES_MANAGE = 0b00000_00000000_00000000_00000000_00000010_00000000_00000000; public const G_FORUM_CATEGORIES_MANAGE = 0b00000_00000000_00000000_00000001_00000000_00000000_00000000; public const G_FORUM_LEADERBOARD_VIEW = 0b00000_00000000_00000000_00000010_00000000_00000000_00000000; public const G_FORUM_TOPIC_REDIRS_MANAGE = 0b00000_00000000_00000000_00000100_00000000_00000000_00000000; public const G_MESSAGES_VIEW = 0b00000_00000000_00000000_00010000_00000000_00000000_00000000; public const G_MESSAGES_SEND = 0b00000_00000000_00000000_00100000_00000000_00000000_00000000; public const G_COMMENTS_CREATE = 0b00000_00000000_00000001_00000000_00000000_00000000_00000000; public const G_COMMENTS_EDIT_OWN = 0b00000_00000000_00000010_00000000_00000000_00000000_00000000; // unused: editing not implemented public const G_COMMENTS_EDIT_ANY = 0b00000_00000000_00000100_00000000_00000000_00000000_00000000; // unused: editing not implemented public const G_COMMENTS_DELETE_OWN = 0b00000_00000000_00001000_00000000_00000000_00000000_00000000; public const G_COMMENTS_DELETE_ANY = 0b00000_00000000_00010000_00000000_00000000_00000000_00000000; public const G_COMMENTS_PIN = 0b00000_00000000_00100000_00000000_00000000_00000000_00000000; public const G_COMMENTS_LOCK = 0b00000_00000000_01000000_00000000_00000000_00000000_00000000; public const G_COMMENTS_VOTE = 0b00000_00000000_10000000_00000000_00000000_00000000_00000000; // USER ALLOCATION: // There's no rules here, manage perms started abouts halfway through the 31-bit integer // Maybe formally define the octets regardless later? public const U_PROFILE_EDIT = 0b00000_00000000_00000000_00000000_00000000_00000000_00000001; public const U_AVATAR_CHANGE = 0b00000_00000000_00000000_00000000_00000000_00000000_00000010; public const U_PROFILE_BACKGROUND_CHANGE = 0b00000_00000000_00000000_00000000_00000000_00000000_00000100; public const U_PROFILE_ABOUT_EDIT = 0b00000_00000000_00000000_00000000_00000000_00000000_00001000; public const U_PROFILE_BIRTHDATE_EDIT = 0b00000_00000000_00000000_00000000_00000000_00000000_00010000; public const U_FORUM_SIGNATURE_EDIT = 0b00000_00000000_00000000_00000000_00000000_00000000_00100000; public const U_USERS_MANAGE = 0b00000_00000000_00000000_00000000_00010000_00000000_00000000; public const U_ROLES_MANAGE = 0b00000_00000000_00000000_00000000_00100000_00000000_00000000; public const U_PERMS_MANAGE = 0b00000_00000000_00000000_00000000_01000000_00000000_00000000; public const U_REPORTS_MANAGE = 0b00000_00000000_00000000_00000000_10000000_00000000_00000000; // unused: reports are not implemented public const U_WARNINGS_MANAGE = 0b00000_00000000_00000000_00000001_00000000_00000000_00000000; //public const U_BLACKLISTS_MANAGE = 0b00000_00000000_00000000_00000010_00000000_00000000_00000000; // deprecated: replaced with GLOBAL_BLACKLIST_MANAGE public const U_NOTES_MANAGE = 0b00000_00000000_00000000_00000100_00000000_00000000_00000000; public const U_BANS_MANAGE = 0b00000_00000000_00000000_00001000_00000000_00000000_00000000; public const U_CAN_IMPERSONATE = 0b00000_00000000_00000000_00010000_00000000_00000000_00000000; // FORUM ALLOCATION: // 0bXXXXX_XXXXXXXX_XXXXXXXX_PPPPPPPP_PPPPTTTT_TTTTTTTT_CCCCCCCC // C -> Category related // T -> Topic related // N -> Post related // X -> unallocated public const F_CATEGORY_LIST = 0b00000_00000000_00000000_00000000_00000000_00000000_00000001; public const F_CATEGORY_VIEW = 0b00000_00000000_00000000_00000000_00000000_00000000_00000010; public const F_TOPIC_CREATE = 0b00000_00000000_00000000_00000000_00000000_00000100_00000000; //public const F_TOPIC_DELETE = 0b00000_00000000_00000000_00000000_00000000_00001000_00000000; // deprecated: use F_POST_DELETE_ANY instead public const F_TOPIC_MOVE = 0b00000_00000000_00000000_00000000_00000000_00010000_00000000; // unused: topic moving not implemented public const F_TOPIC_LOCK = 0b00000_00000000_00000000_00000000_00000000_00100000_00000000; public const F_TOPIC_STICKY = 0b00000_00000000_00000000_00000000_00000000_01000000_00000000; public const F_TOPIC_ANNOUNCE_LOCAL = 0b00000_00000000_00000000_00000000_00000000_10000000_00000000; public const F_TOPIC_ANNOUNCE_GLOBAL = 0b00000_00000000_00000000_00000000_00000001_00000000_00000000; public const F_TOPIC_BUMP = 0b00000_00000000_00000000_00000000_00000010_00000000_00000000; public const F_TOPIC_PRIORITY_VOTE = 0b00000_00000000_00000000_00000000_00000100_00000000_00000000; // unused: feature postponed, reuse if it makes sense otherwise deprecate public const F_POST_CREATE = 0b00000_00000000_00000000_00000000_00010000_00000000_00000000; public const F_POST_EDIT_OWN = 0b00000_00000000_00000000_00000000_00100000_00000000_00000000; public const F_POST_EDIT_ANY = 0b00000_00000000_00000000_00000000_01000000_00000000_00000000; public const F_POST_DELETE_OWN = 0b00000_00000000_00000000_00000000_10000000_00000000_00000000; public const F_POST_DELETE_ANY = 0b00000_00000000_00000000_00000001_00000000_00000000_00000000; // CHAT ALLOCATION: // 0bXXXXX_XXXXXXXX_XXXXXXXX_XXXXXXXX_XXXXXXMA_MMUMUUMT_ATATAMMM // U -> Normal user permissions // T -> Tenshi permissions // M -> Moderator permissions // A -> Administrator permissions // no staircase here because it's a mess public const C_USER_KICK = 0b00000_00000000_00000000_00000000_00000000_00000000_00000001; public const C_USER_BAN = 0b00000_00000000_00000000_00000000_00000000_00000000_00000010; //public const C_USER_SILENCE = 0b00000_00000000_00000000_00000000_00000000_00000000_00000100; // deprecated: silencing is no longer a thing public const C_MESSAGE_BROADCAST = 0b00000_00000000_00000000_00000000_00000000_00000000_00001000; public const C_NICK_SET_OWN = 0b00000_00000000_00000000_00000000_00000000_00000000_00010000; public const C_NICK_SET_ANY = 0b00000_00000000_00000000_00000000_00000000_00000000_00100000; public const C_CHANNEL_CREATE = 0b00000_00000000_00000000_00000000_00000000_00000000_01000000; public const C_CHANNEL_SET_PERSIST = 0b00000_00000000_00000000_00000000_00000000_00000000_10000000; public const C_CHANNEL_SET_PASSWORD = 0b00000_00000000_00000000_00000000_00000000_00000001_00000000; public const C_CHANNEL_SET_MIN_RANK = 0b00000_00000000_00000000_00000000_00000000_00000010_00000000; public const C_MESSAGE_SEND = 0b00000_00000000_00000000_00000000_00000000_00000100_00000000; public const C_MESSAGE_DELETE_OWN = 0b00000_00000000_00000000_00000000_00000000_00001000_00000000; public const C_MESSAGE_DELETE_ANY = 0b00000_00000000_00000000_00000000_00000000_00010000_00000000; public const C_MESSAGE_EDIT_OWN = 0b00000_00000000_00000000_00000000_00000000_00100000_00000000; public const C_MESSAGE_EDIT_ANY = 0b00000_00000000_00000000_00000000_00000000_01000000_00000000; public const C_USER_VIEW_ADDR = 0b00000_00000000_00000000_00000000_00000000_10000000_00000000; public const C_CHANNEL_DELETE = 0b00000_00000000_00000000_00000000_00000001_00000000_00000000; public const C_CHANNEL_JOIN_ANY = 0b00000_00000000_00000000_00000000_00000010_00000000_00000000; public const INFO_FOR_USER = ['global', 'user', 'chat']; public const INFO_FOR_ROLE = self::INFO_FOR_USER; // just alias for now, no clue if this will ever desync public const INFO_FOR_FORUM_CATEGORY = ['forum']; public const LISTS_FOR_USER = ['global:general', 'global:changelog', 'global:news', 'global:forum', 'global:messages', 'global:comments', 'user:personal', 'user:manage', 'chat:general']; public const LISTS_FOR_ROLE = self::LISTS_FOR_USER; // idem public const LISTS_FOR_FORUM_CATEGORY = ['forum:category', 'forum:topic', 'forum:post']; public const LISTS = [ 'global:general' => [ 'title' => 'Global Permissions', 'perms' => [ 'global', self::G_IS_JANITOR, self::G_LOGS_VIEW, self::G_EMOTES_MANAGE, self::G_CONFIG_MANAGE, self::G_BLACKLIST_MANAGE, self::G_TIMINGS_VIEW, ], ], 'global:changelog' => [ 'title' => 'Changelog Permissions', 'perms' => [ 'global', self::G_CL_CHANGES_MANAGE, self::G_CL_TAGS_MANAGE, ], ], 'global:news' => [ 'title' => 'News Permissions', 'perms' => [ 'global', self::G_NEWS_POSTS_MANAGE, self::G_NEWS_CATEGORIES_MANAGE, ], ], 'global:forum' => [ 'title' => 'Global Forum Permissions', 'perms' => [ 'global', self::G_FORUM_CATEGORIES_MANAGE, self::G_FORUM_LEADERBOARD_VIEW, self::G_FORUM_TOPIC_REDIRS_MANAGE, ], ], 'global:messages' => [ 'title' => 'Private Messages Permissions', 'perms' => [ 'global', self::G_MESSAGES_VIEW, self::G_MESSAGES_SEND, ], ], 'global:comments' => [ 'title' => 'Comments Permissions', 'perms' => [ 'global', self::G_COMMENTS_CREATE, self::G_COMMENTS_EDIT_OWN, self::G_COMMENTS_EDIT_ANY, self::G_COMMENTS_DELETE_OWN, self::G_COMMENTS_DELETE_ANY, self::G_COMMENTS_PIN, self::G_COMMENTS_LOCK, self::G_COMMENTS_VOTE, ], ], 'user:personal' => [ 'title' => 'User Permissions', 'perms' => [ 'user', self::U_PROFILE_EDIT, self::U_AVATAR_CHANGE, self::U_PROFILE_BACKGROUND_CHANGE, self::U_PROFILE_ABOUT_EDIT, self::U_FORUM_SIGNATURE_EDIT, self::U_PROFILE_BIRTHDATE_EDIT, ], ], 'user:manage' => [ 'title' => 'User Management Permissions', 'perms' => [ 'user', self::U_REPORTS_MANAGE, self::U_NOTES_MANAGE, self::U_WARNINGS_MANAGE, self::U_BANS_MANAGE, self::U_USERS_MANAGE, self::U_ROLES_MANAGE, self::U_PERMS_MANAGE, self::U_CAN_IMPERSONATE, ], ], 'forum:category' => [ 'title' => 'Forum Category Permissions', 'perms' => [ 'forum', self::F_CATEGORY_LIST, self::F_CATEGORY_VIEW, ], ], 'forum:topic' => [ 'title' => 'Forum Topic Permissions', 'perms' => [ 'forum', self::F_TOPIC_CREATE, self::F_TOPIC_MOVE, self::F_TOPIC_LOCK, self::F_TOPIC_STICKY, self::F_TOPIC_ANNOUNCE_LOCAL, self::F_TOPIC_ANNOUNCE_GLOBAL, self::F_TOPIC_BUMP, self::F_TOPIC_PRIORITY_VOTE, ], ], 'forum:post' => [ 'title' => 'Forum Topic Permissions', 'perms' => [ 'forum', self::F_POST_CREATE, self::F_POST_EDIT_OWN, self::F_POST_EDIT_ANY, self::F_POST_DELETE_OWN, self::F_POST_DELETE_ANY, ], ], 'chat:general' => [ 'title' => 'Chat Permissions', 'perms' => [ 'chat', self::C_MESSAGE_SEND, self::C_MESSAGE_BROADCAST, self::C_MESSAGE_EDIT_OWN, self::C_MESSAGE_EDIT_ANY, self::C_MESSAGE_DELETE_OWN, self::C_MESSAGE_DELETE_ANY, self::C_NICK_SET_OWN, self::C_NICK_SET_ANY, self::C_USER_KICK, self::C_USER_BAN, self::C_USER_VIEW_ADDR, self::C_CHANNEL_CREATE, self::C_CHANNEL_SET_PERSIST, self::C_CHANNEL_SET_PASSWORD, self::C_CHANNEL_SET_MIN_RANK, self::C_CHANNEL_JOIN_ANY, self::C_CHANNEL_DELETE, ], ], ]; public const LABELS = [ 'global' => [ self::G_IS_JANITOR => 'Can access the Broom closet.', self::G_LOGS_VIEW => 'Can view global audit logs.', self::G_EMOTES_MANAGE => 'Can manage emoticons.', self::G_CONFIG_MANAGE => 'Can manage global configuration.', //self::G_IS_TESTER => 'Can test experimental features.', self::G_BLACKLIST_MANAGE => 'Can manage registration IP address blacklist.', //self::G_TWITTER_MANAGE => 'Can manage Twitter integration settings.', self::G_TIMINGS_VIEW => 'Can view page load timings.', self::G_CL_CHANGES_MANAGE => 'Can manage changelog entries.', self::G_CL_TAGS_MANAGE => 'Can manage changelog tags.', //self::G_CL_ACTIONS_MANAGE => 'Can manage changelog action types.', self::G_NEWS_POSTS_MANAGE => 'Can manage news posts.', self::G_NEWS_CATEGORIES_MANAGE => 'Can manage news categories.', self::G_FORUM_CATEGORIES_MANAGE => 'Can manage forum categories.', self::G_FORUM_LEADERBOARD_VIEW => 'Can view forum leaderboard.', self::G_FORUM_TOPIC_REDIRS_MANAGE => 'Can create redirects for deleted forum topics.', self::G_MESSAGES_VIEW => 'Can view private messages.', self::G_MESSAGES_SEND => 'Can send private messages.', self::G_COMMENTS_CREATE => 'Can post comments.', self::G_COMMENTS_EDIT_OWN => 'Can edit own comments.', self::G_COMMENTS_EDIT_ANY => 'Can edit ANY comment.', self::G_COMMENTS_DELETE_OWN => 'Can delete own comments.', self::G_COMMENTS_DELETE_ANY => 'Can delete ANY comment.', self::G_COMMENTS_PIN => 'Can pin commments.', self::G_COMMENTS_LOCK => 'Can lock comment categories.', self::G_COMMENTS_VOTE => 'Can vote (like or dislike) on comments.', ], 'user' => [ self::U_PROFILE_EDIT => 'Can edit own profile.', self::U_AVATAR_CHANGE => 'Can change own avatar.', self::U_PROFILE_BACKGROUND_CHANGE => 'Can change own profile background.', self::U_PROFILE_ABOUT_EDIT => 'Can edit own profile about section.', self::U_PROFILE_BIRTHDATE_EDIT => 'Can edit own profile birthdate.', self::U_FORUM_SIGNATURE_EDIT => 'Can edit own forum signature.', self::U_USERS_MANAGE => 'Can manage other users.', self::U_ROLES_MANAGE => 'Can manage user roles.', self::U_PERMS_MANAGE => 'Can manage permissions.', self::U_REPORTS_MANAGE => 'Can handle reports.', self::U_WARNINGS_MANAGE => 'Can manage user warnings.', //self::U_BLACKLISTS_MANAGE => 'Can manage registration IP address blacklist.', self::U_NOTES_MANAGE => 'Can manage user notes.', self::U_BANS_MANAGE => 'Can manage user bans.', self::U_CAN_IMPERSONATE => 'Can impersonate select other users. Requires whitelisting in the configuration or super user status.', ], 'forum' => [ self::F_CATEGORY_LIST => 'Can see the forum category listed but cannot access it.', self::F_CATEGORY_VIEW => 'Can access the forum category.', self::F_TOPIC_CREATE => 'Can create forum topics.', //self::F_TOPIC_DELETE => 'Can delete forum topics.', self::F_TOPIC_MOVE => 'Can move forum topics to other categories.', self::F_TOPIC_LOCK => 'Can lock forum topics.', self::F_TOPIC_STICKY => 'Can make sticky topics.', self::F_TOPIC_ANNOUNCE_LOCAL => 'Can make local announcement topics.', self::F_TOPIC_ANNOUNCE_GLOBAL => 'Can make global announcement topics.', self::F_TOPIC_BUMP => 'Can bump topics without posting a reply.', self::F_TOPIC_PRIORITY_VOTE => 'Can use the priority voting system.', self::F_POST_CREATE => 'Can create forum posts (replies only, if not allowed to create topics).', self::F_POST_EDIT_OWN => 'Can edit own forum posts.', self::F_POST_EDIT_ANY => 'Can edit ANY forum post.', self::F_POST_DELETE_OWN => 'Can delete own forum posts.', self::F_POST_DELETE_ANY => 'Can delete ANY forum post.', ], 'chat' => [ self::C_USER_KICK => 'Can kick other users.', self::C_USER_BAN => 'Can ban other users.', //self::C_USER_SILENCE => 'Can silence other users.', self::C_MESSAGE_BROADCAST => 'Can broadcast messages across all channels.', self::C_NICK_SET_OWN => 'Can change own nickname.', self::C_NICK_SET_ANY => 'Can change ANYONE\'s nickname.', self::C_CHANNEL_CREATE => 'Can create channels.', self::C_CHANNEL_SET_PERSIST => 'Can set channels to persist after all users leave it.', self::C_CHANNEL_SET_PASSWORD => 'Can set passwords for own channel.', self::C_CHANNEL_SET_MIN_RANK => 'Can set minimum requires rank to join channel.', self::C_MESSAGE_SEND => 'Can send messages.', self::C_MESSAGE_DELETE_OWN => 'Can delete own messages.', self::C_MESSAGE_DELETE_ANY => 'Can delete ANY message.', self::C_MESSAGE_EDIT_OWN => 'Can edit own messages.', self::C_MESSAGE_EDIT_ANY => 'Can edit ANY message.', self::C_USER_VIEW_ADDR => 'Can view IP addresses of other users.', self::C_CHANNEL_DELETE => 'Can delete own channels.', self::C_CHANNEL_JOIN_ANY => 'Can join any channel regardless of join requirements.', ], ]; public static function label(string $category, int $permission): string { return array_key_exists($category, self::LABELS) && array_key_exists($permission, self::LABELS[$category]) ? self::LABELS[$category][$permission] : ''; } public static function createList(array $sections): array { $list = []; foreach($sections as $sectionName) { if(!array_key_exists($sectionName, self::LISTS)) continue; $currentCategoryName = ''; $sectionInfo = self::LISTS[$sectionName]; $list[] = $item = new stdClass; $item->name = $sectionName; $item->title = $sectionInfo['title']; $item->perms = []; foreach($sectionInfo['perms'] as $permInfo) { if(is_string($permInfo)) { $currentCategoryName = $permInfo; continue; } $categoryName = $currentCategoryName; $perm = 0; // if(is_array($permInfo)) // [$categoryName, $perm] = $permInfo; // else if(is_int($permInfo)) $perm = $permInfo; $item->perms[] = $permItem = new stdClass; $permItem->category = $categoryName; $permItem->name = sprintf('perms[%s:%d]', $categoryName, $perm); $permItem->title = self::label($categoryName, $perm); $permItem->value = $perm; } } return $list; } public static function convertSubmission(array $raw, array $categories): array { $apply = []; foreach($raw as $name => $mode) { $nameParts = explode(':', $name, 2); if(count($nameParts) !== 2 || !ctype_alpha($nameParts[0]) || !ctype_digit($nameParts[1])) continue; [$category, $value] = $nameParts; if(!in_array($category, $categories)) continue; if($mode === 'yes' || $mode === 'never') { if(!array_key_exists($category, $apply)) $apply[$category] = ['allow' => 0, 'deny' => 0]; $apply[$category][$mode === 'yes' ? 'allow' : 'deny'] |= (int)$value; } } return $apply; } }