├── Example.gif ├── LICENSE ├── README.md ├── index.js └── manifest.json /Example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/powercord-community/permission-viewer/b96e87d4138cc6ffdb1cfbbf53135ab36d6deec2/Example.gif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Joakim 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Permission Viewer Plugin 2 | This is a permission viewer plugin made for [Powercord](https://github.com/powercord-org/powercord) 3 | 4 | ## Installation 5 | **git clone https://github.com/powercord-community/permission-viewer.git** 6 | 7 | ## Example 8 | ![](Example.gif) 9 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const { Plugin } = require('powercord/entities'); 2 | 3 | const { 4 | getModule, 5 | React, 6 | constants 7 | } = require('powercord/webpack'); 8 | 9 | const { Menu: { MenuItem } } = require('powercord/components'); 10 | 11 | const Permissions = Object.assign({}, constants.Permissions); // eslint-disable-line no-shadow 12 | 13 | if (Permissions.MANAGE_GUILD) { 14 | Permissions.MANAGE_SERVER = Permissions.MANAGE_GUILD; 15 | 16 | delete Permissions.MANAGE_GUILD; 17 | } 18 | 19 | const { injectContextMenu, findInReactTree } = require("powercord/util"); 20 | 21 | const { uninject } = require('powercord/injector'); 22 | 23 | module.exports = class PermissionViewer extends Plugin { 24 | async import (filter, functionName = filter) { 25 | if (typeof filter === 'string') { 26 | filter = [ filter ]; 27 | } 28 | 29 | this[functionName] = (await getModule(filter))[functionName]; 30 | } 31 | 32 | async doImport () { 33 | await this.import('Messages'); 34 | await this.import('getMember'); 35 | await this.import('getGuild'); 36 | } 37 | 38 | /* Whether or not permissions that are implied (by administrator) should be shown as well */ 39 | impliedPermissions = true; 40 | 41 | getAllPermissionsRaw() { 42 | return Object.values(Permissions).reduce((a, b) => a | b, 0n); 43 | } 44 | 45 | getPermissionsRaw (guildId, userId) { 46 | let permissions = 0n; 47 | 48 | const guild = this.getGuild(guildId); 49 | const member = this.getMember(guildId, userId); 50 | 51 | if (guild && member) { 52 | if (guild.ownerId === userId) { 53 | /* If they are the owner they have all the permissions */ 54 | return this.getAllPermissionsRaw(); 55 | } 56 | 57 | /* @everyone is not inlcuded in the member's roles */ 58 | permissions |= guild.roles[guild.id].permissions; 59 | 60 | for (const roleId of member.roles) { 61 | permissions |= guild.roles[roleId].permissions; 62 | } 63 | 64 | if (this.impliedPermissions) { 65 | if ((permissions & Permissions.ADMINISTRATOR) === Permissions.ADMINISTRATOR) { 66 | return this.getAllPermissionsRaw(); 67 | } 68 | } 69 | } 70 | 71 | return permissions; 72 | } 73 | 74 | toTitleCase (str) { 75 | return str.replace( 76 | /\w\S*/g, 77 | (txt) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase() 78 | ); 79 | } 80 | 81 | getPermissions (guildId, userId) { 82 | const raw = this.getPermissionsRaw(guildId, userId); 83 | 84 | const permissions = { 85 | raw, 86 | entries: [] 87 | }; 88 | 89 | Object.keys(Permissions).forEach(key => { 90 | if ((raw & Permissions[key]) === Permissions[key]) { 91 | permissions.entries.push({ 92 | key, 93 | readable: this.Messages[key] || this.toTitleCase(key.replace(/_/g, ' ')), 94 | raw: Permissions[key] 95 | }); 96 | } 97 | }); 98 | 99 | return permissions; 100 | } 101 | 102 | getRolesWithPermission (guildId, permissions, roles = null) { 103 | const withPermissions = []; 104 | const guild = this.getGuild(guildId); 105 | 106 | if (!roles) { 107 | roles = guild.roles; // eslint-disable-line prefer-destructuring 108 | } 109 | 110 | for (let role of roles) { 111 | if (typeof role === 'string') { 112 | role = guild.roles[role]; 113 | } 114 | 115 | if (role) { 116 | const rolePermissions = role.permissions; 117 | if ((rolePermissions & permissions) === permissions) { 118 | withPermissions.push(role); 119 | } else if (this.impliedPermissions) { 120 | if ((rolePermissions & Permissions.ADMINISTRATOR) === Permissions.ADMINISTRATOR) { 121 | withPermissions.push(role); 122 | } 123 | } 124 | } 125 | } 126 | 127 | return withPermissions; 128 | } 129 | 130 | _injectContextMenu () { 131 | injectContextMenu('permission-viewer-user', 'GuildChannelUserContextMenu', (args, res) => { 132 | if (!res) return res; 133 | // Attempt to find the context menu area containing the "Roles" item. 134 | // If no such area is found (i.e. the user has no roles), then fall back 135 | // to using the next menu area after the one containing "Block" or "Unblock" 136 | // (the ID is the same regardless of whether a user is blocked). 137 | const idsArray = ['roles', 'block', 'change-nickname']; 138 | const menuItems = findInReactTree(res.props.children, e => { 139 | return Array.isArray(e) && e.some(f => { 140 | return Array.isArray(f?.props?.children) && f.props.children.some(g => { 141 | return idsArray.includes(g?.props?.id); 142 | }); 143 | }); 144 | }); 145 | let childIndex = 0; 146 | let blockAreaIndex = 0; 147 | const rolesMenuArea = menuItems.find(item => { 148 | ++childIndex; 149 | // If the item is empty, we know it's not it 150 | // The one we're looking for has an array of children 151 | if (!(item && Array.isArray(item.props.children))) { 152 | return false; 153 | } 154 | return item.props.children.some(c => { 155 | if (c && c.props) { 156 | if (c.props.id === 'roles') { 157 | return true; 158 | } else if (c.props.id === 'block' || c.props.id === 'change-nickname') { 159 | blockAreaIndex = childIndex; 160 | } 161 | } 162 | return false; 163 | }); 164 | }) ?? menuItems[blockAreaIndex + 1]; 165 | 166 | const { guildId } = args[0]; 167 | const userId = args[0].user.id; 168 | 169 | const member = this.getMember(guildId, userId); 170 | if (member) { 171 | const permissions = this.getPermissions(guildId, userId); 172 | 173 | const items = []; 174 | 175 | if (permissions.raw === 0n) { 176 | items.push(React.createElement(MenuItem, { 177 | id: 'none', 178 | label: 'None' 179 | })); 180 | } 181 | 182 | for (const permission of permissions.entries) { 183 | const roles = this.getRolesWithPermission(guildId, permission.raw, member.roles.concat([ guildId ])); 184 | 185 | if (roles.length > 0) { 186 | items.push(React.createElement(MenuItem, { 187 | id: permission.key.toLowerCase(), 188 | label: permission.readable, 189 | children: roles.map(role => React.createElement(MenuItem, { 190 | id: role.id, 191 | label: React.createElement("span", { 192 | style: { 193 | color: role.colorString 194 | } 195 | }, role.name) 196 | })) 197 | })); 198 | } else { 199 | items.push(React.createElement(MenuItem, { 200 | id: permission.readable.toLowerCase(), 201 | label: permission.readable 202 | })); 203 | } 204 | } 205 | 206 | if (!Array.isArray(rolesMenuArea.props.children)) { 207 | rolesMenuArea.props.children = [rolesMenuArea.props.children]; 208 | } 209 | rolesMenuArea.props.children.push(React.createElement(MenuItem, { 210 | id: 'permissions', 211 | label: 'Permissions', 212 | children: items 213 | })); 214 | } 215 | 216 | return res; 217 | }); 218 | } 219 | 220 | async startPlugin () { 221 | await this.doImport(); 222 | 223 | this._injectContextMenu(); 224 | } 225 | 226 | pluginWillUnload () { 227 | uninject('permission-viewer-user'); 228 | } 229 | }; 230 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Permission Viewer", 3 | "version": "0.0.4", 4 | "description": "Simple permission viewer which can be used to see what permissions a user has as well as what role it originated from", 5 | "author": "Joakim#9814", 6 | "license": "MIT", 7 | "repo": "https://github.com/powercord-community/permission-viewer", 8 | "dependencies": [] 9 | } --------------------------------------------------------------------------------