mirror of
https://github.com/uowuo/abaddon.git
synced 2024-11-10 14:10:10 +00:00
basic permission handling + use for edit/delete
This commit is contained in:
parent
dbe9dc3c64
commit
8341781918
@ -173,6 +173,8 @@ add_executable(abaddon
|
||||
discord/message.cpp
|
||||
discord/invite.hpp
|
||||
discord/invite.cpp
|
||||
discord/permissions.hpp
|
||||
discord/permissions.cpp
|
||||
windows/mainwindow.hpp
|
||||
windows/mainwindow.cpp
|
||||
)
|
||||
|
@ -163,11 +163,12 @@ void ChatMessageItem::AttachMenuHandler(Gtk::Widget *widget) {
|
||||
// clang-format on
|
||||
|
||||
void ChatMessageItem::ShowMenu(const GdkEvent *event) {
|
||||
auto &client = Abaddon::Get().GetDiscordClient();
|
||||
auto *data = client.GetMessage(ID);
|
||||
bool can_manage = client.GetUserData().ID == data->Author.ID;
|
||||
m_menu_delete_message->set_sensitive(can_manage);
|
||||
m_menu_edit_message->set_sensitive(can_manage);
|
||||
const auto &client = Abaddon::Get().GetDiscordClient();
|
||||
const auto *data = client.GetMessage(ID);
|
||||
const bool can_edit = client.GetUserData().ID == data->Author.ID;
|
||||
const bool can_delete = can_edit || client.HasChannelPermission(client.GetUserData().ID, ChannelID, Permission::MANAGE_MESSAGES);
|
||||
m_menu_delete_message->set_sensitive(can_delete);
|
||||
m_menu_edit_message->set_sensitive(can_edit);
|
||||
m_menu.popup_at_pointer(event);
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ void from_json(const nlohmann::json &j, Channel &m) {
|
||||
JS_D("type", m.Type);
|
||||
JS_O("guild_id", m.GuildID);
|
||||
JS_O("position", m.Position);
|
||||
// JS_O("permission_overwrites", m.PermissionOverwrites);
|
||||
JS_O("permission_overwrites", m.PermissionOverwrites);
|
||||
JS_ON("name", m.Name);
|
||||
JS_ON("topic", m.Topic);
|
||||
JS_O("nsfw", m.IsNSFW);
|
||||
@ -20,3 +20,10 @@ void from_json(const nlohmann::json &j, Channel &m) {
|
||||
JS_ON("parent_id", m.ParentID);
|
||||
JS_ON("last_pin_timestamp", m.LastPinTimestamp);
|
||||
}
|
||||
|
||||
std::optional<PermissionOverwrite> Channel::GetOverwrite(Snowflake id) const {
|
||||
auto ret = std::find_if(PermissionOverwrites.begin(), PermissionOverwrites.end(), [id](const auto x) { return x.ID == id; });
|
||||
if (ret != PermissionOverwrites.end())
|
||||
return *ret;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
#include "snowflake.hpp"
|
||||
#include "json.hpp"
|
||||
#include "user.hpp"
|
||||
#include "permissions.hpp"
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -16,24 +18,26 @@ enum class ChannelType : int {
|
||||
};
|
||||
|
||||
struct Channel {
|
||||
Snowflake ID; //
|
||||
ChannelType Type; //
|
||||
Snowflake GuildID; // opt
|
||||
int Position = -1; // opt
|
||||
// std::vector<PermissionOverwriteData> PermissionOverwrites; // opt
|
||||
std::string Name; // opt, null (null for dm's)
|
||||
std::string Topic; // opt, null
|
||||
bool IsNSFW = false; // opt
|
||||
Snowflake LastMessageID; // opt, null
|
||||
int Bitrate = 0; // opt
|
||||
int UserLimit = 0; // opt
|
||||
int RateLimitPerUser = 0; // opt
|
||||
std::vector<User> Recipients; // opt
|
||||
std::string Icon; // opt, null
|
||||
Snowflake OwnerID; // opt
|
||||
Snowflake ApplicationID; // opt
|
||||
Snowflake ParentID; // opt, null
|
||||
std::string LastPinTimestamp; // opt, can be null even tho docs say otherwise
|
||||
Snowflake ID; //
|
||||
ChannelType Type; //
|
||||
Snowflake GuildID; // opt
|
||||
int Position = -1; // opt
|
||||
std::vector<PermissionOverwrite> PermissionOverwrites; // opt
|
||||
std::string Name; // opt, null (null for dm's)
|
||||
std::string Topic; // opt, null
|
||||
bool IsNSFW = false; // opt
|
||||
Snowflake LastMessageID; // opt, null
|
||||
int Bitrate = 0; // opt
|
||||
int UserLimit = 0; // opt
|
||||
int RateLimitPerUser = 0; // opt
|
||||
std::vector<User> Recipients; // opt
|
||||
std::string Icon; // opt, null
|
||||
Snowflake OwnerID; // opt
|
||||
Snowflake ApplicationID; // opt
|
||||
Snowflake ParentID; // opt, null
|
||||
std::string LastPinTimestamp; // opt, can be null even tho docs say otherwise
|
||||
|
||||
friend void from_json(const nlohmann::json &j, Channel &m);
|
||||
|
||||
std::optional<PermissionOverwrite> GetOverwrite(Snowflake id) const;
|
||||
};
|
||||
|
@ -194,6 +194,10 @@ const Guild *DiscordClient::GetGuild(Snowflake id) const {
|
||||
return m_store.GetGuild(id);
|
||||
}
|
||||
|
||||
const GuildMember *DiscordClient::GetMember(Snowflake user_id, Snowflake guild_id) const {
|
||||
return m_store.GetGuildMemberData(guild_id, user_id);
|
||||
}
|
||||
|
||||
Snowflake DiscordClient::GetMemberHoistedRole(Snowflake guild_id, Snowflake user_id, bool with_color) const {
|
||||
auto *data = m_store.GetGuildMemberData(guild_id, user_id);
|
||||
if (data == nullptr) return Snowflake::Invalid;
|
||||
@ -224,6 +228,91 @@ std::unordered_set<Snowflake> DiscordClient::GetUsersInGuild(Snowflake id) const
|
||||
return std::unordered_set<Snowflake>();
|
||||
}
|
||||
|
||||
std::unordered_set<Snowflake> DiscordClient::GetRolesInGuild(Snowflake id) const {
|
||||
std::unordered_set<Snowflake> ret;
|
||||
const auto &roles = m_store.GetRoles();
|
||||
for (const auto &[rid, rdata] : roles)
|
||||
ret.insert(rid);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool DiscordClient::HasGuildPermission(Snowflake user_id, Snowflake guild_id, Permission perm) const {
|
||||
const auto base = ComputePermissions(user_id, guild_id);
|
||||
return (base & perm) == perm;
|
||||
}
|
||||
|
||||
bool DiscordClient::HasChannelPermission(Snowflake user_id, Snowflake channel_id, Permission perm) const {
|
||||
const auto *channel = m_store.GetChannel(channel_id);
|
||||
if (channel == nullptr) return false;
|
||||
const auto base = ComputePermissions(user_id, channel->GuildID);
|
||||
const auto overwrites = ComputeOverwrites(base, user_id, channel_id);
|
||||
return (overwrites & perm) == perm;
|
||||
}
|
||||
|
||||
Permission DiscordClient::ComputePermissions(Snowflake member_id, Snowflake guild_id) const {
|
||||
const auto *member = GetMember(member_id, guild_id);
|
||||
const auto *guild = GetGuild(guild_id);
|
||||
if (member == nullptr || guild == nullptr)
|
||||
return Permission::NONE;
|
||||
|
||||
if (guild->OwnerID == member_id)
|
||||
return Permission::ALL;
|
||||
|
||||
const auto *everyone = GetRole(guild_id);
|
||||
if (everyone == nullptr)
|
||||
return Permission::NONE;
|
||||
|
||||
Permission perms = everyone->Permissions;
|
||||
for (const auto role_id : member->Roles) {
|
||||
const auto *role = GetRole(role_id);
|
||||
if (role != nullptr)
|
||||
perms |= role->Permissions;
|
||||
}
|
||||
|
||||
if ((perms & Permission::ADMINISTRATOR) == Permission::ADMINISTRATOR)
|
||||
return Permission::ALL;
|
||||
|
||||
return perms;
|
||||
}
|
||||
|
||||
Permission DiscordClient::ComputeOverwrites(Permission base, Snowflake member_id, Snowflake channel_id) const {
|
||||
if ((base & Permission::ADMINISTRATOR) == Permission::ADMINISTRATOR)
|
||||
return Permission::ALL;
|
||||
|
||||
const auto *channel = GetChannel(channel_id);
|
||||
const auto *member = GetMember(member_id, channel->GuildID);
|
||||
if (member == nullptr || channel == nullptr)
|
||||
return Permission::NONE;
|
||||
|
||||
Permission perms = base;
|
||||
auto overwrite_everyone = channel->GetOverwrite(channel->GuildID);
|
||||
if (overwrite_everyone.has_value()) {
|
||||
perms &= ~overwrite_everyone->Deny;
|
||||
perms |= overwrite_everyone->Allow;
|
||||
}
|
||||
|
||||
Permission allow = Permission::NONE;
|
||||
Permission deny = Permission::NONE;
|
||||
for (const auto role_id : member->Roles) {
|
||||
const auto overwrite = channel->GetOverwrite(role_id);
|
||||
if (overwrite.has_value()) {
|
||||
allow |= overwrite->Allow;
|
||||
deny |= overwrite->Deny;
|
||||
}
|
||||
}
|
||||
|
||||
perms &= ~deny;
|
||||
perms |= allow;
|
||||
|
||||
const auto member_overwrite = channel->GetOverwrite(member_id);
|
||||
if (member_overwrite.has_value()) {
|
||||
perms &= ~member_overwrite->Deny;
|
||||
perms |= member_overwrite->Allow;
|
||||
}
|
||||
|
||||
return perms;
|
||||
}
|
||||
|
||||
void DiscordClient::SendChatMessage(std::string content, Snowflake channel) {
|
||||
// @([^@#]{1,32})#(\\d{4})
|
||||
CreateMessageObject obj;
|
||||
|
@ -77,8 +77,15 @@ public:
|
||||
const User *GetUser(Snowflake id) const;
|
||||
const Role *GetRole(Snowflake id) const;
|
||||
const Guild *GetGuild(Snowflake id) const;
|
||||
const GuildMember *GetMember(Snowflake user_id, Snowflake guild_id) const;
|
||||
Snowflake GetMemberHoistedRole(Snowflake guild_id, Snowflake user_id, bool with_color = false) const;
|
||||
std::unordered_set<Snowflake> GetUsersInGuild(Snowflake id) const;
|
||||
std::unordered_set<Snowflake> GetRolesInGuild(Snowflake id) const;
|
||||
|
||||
bool HasGuildPermission(Snowflake user_id, Snowflake guild_id, Permission perm) const;
|
||||
bool HasChannelPermission(Snowflake user_id, Snowflake channel_id, Permission perm) const;
|
||||
Permission ComputePermissions(Snowflake member_id, Snowflake guild_id) const;
|
||||
Permission ComputeOverwrites(Permission base, Snowflake member_id, Snowflake channel_id) const;
|
||||
|
||||
void SendChatMessage(std::string content, Snowflake channel);
|
||||
void DeleteMessage(Snowflake channel_id, Snowflake id);
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "usersettings.hpp"
|
||||
#include "message.hpp"
|
||||
#include "invite.hpp"
|
||||
#include "permissions.hpp"
|
||||
|
||||
// most stuff below should just be objects that get processed and thrown away immediately
|
||||
|
||||
|
12
discord/permissions.cpp
Normal file
12
discord/permissions.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
#include "permissions.hpp"
|
||||
|
||||
void from_json(const nlohmann::json &j, PermissionOverwrite &m) {
|
||||
JS_D("id", m.ID);
|
||||
std::string tmp;
|
||||
JS_D("type", tmp);
|
||||
m.ID = tmp == "role" ? PermissionOverwrite::ROLE : PermissionOverwrite::MEMBER;
|
||||
JS_D("allow_new", tmp);
|
||||
m.Allow = static_cast<Permission>(std::stoull(tmp));
|
||||
JS_D("deny_new", tmp);
|
||||
m.Deny = static_cast<Permission>(std::stoull(tmp));
|
||||
}
|
60
discord/permissions.hpp
Normal file
60
discord/permissions.hpp
Normal file
@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include "snowflake.hpp"
|
||||
#include "json.hpp"
|
||||
#include "../util.hpp"
|
||||
|
||||
enum class Permission {
|
||||
NONE = 0,
|
||||
CREATE_INSTANT_INVITE = (1 << 0),
|
||||
KICK_MEMBERS = (1 << 1),
|
||||
BAN_MEMBERS = (1 << 2),
|
||||
ADMINISTRATOR = (1 << 3),
|
||||
MANAGE_CHANNELS = (1 << 4),
|
||||
MANAGE_GUILD = (1 << 5),
|
||||
ADD_REACTIONS = (1 << 6),
|
||||
VIEW_AUDIT_LOG = (1 << 7),
|
||||
PRIORITY_SPEAKER = (1 << 8),
|
||||
STREAM = (1 << 9),
|
||||
VIEW_CHANNEL = (1 << 10),
|
||||
SEND_MESSAGES = (1 << 11),
|
||||
SEND_TTS_MESSAGES = (1 << 12),
|
||||
MANAGE_MESSAGES = (1 << 13),
|
||||
EMBED_LINKS = (1 << 14),
|
||||
ATTACH_FILES = (1 << 15),
|
||||
READ_MESSAGE_HISTORY = (1 << 16),
|
||||
MENTION_EVERYONE = (1 << 17),
|
||||
USE_EXTERNAL_EMOJIS = (1 << 18),
|
||||
VIEW_GUILD_INSIGHTS = (1 << 19),
|
||||
CONNECT = (1 << 20),
|
||||
SPEAK = (1 << 21),
|
||||
MUTE_MEMBERS = (1 << 22),
|
||||
DEAFEN_MEMBERS = (1 << 23),
|
||||
MOVE_MEMBERS = (1 << 24),
|
||||
USE_VAD = (1 << 25), // voice activity detection
|
||||
CHANGE_NICKNAME = (1 << 26),
|
||||
MANAGE_NICKNAMES = (1 << 27),
|
||||
MANAGE_ROLES = (1 << 28),
|
||||
MANAGE_WEBHOOKS = (1 << 29),
|
||||
MANAGE_EMOJIS = (1 << 30),
|
||||
|
||||
ALL = 0x7FFFFFFF,
|
||||
};
|
||||
template<>
|
||||
struct Bitwise<Permission> {
|
||||
static const bool enable = true;
|
||||
};
|
||||
|
||||
struct PermissionOverwrite {
|
||||
enum OverwriteType {
|
||||
ROLE,
|
||||
MEMBER,
|
||||
};
|
||||
|
||||
Snowflake ID;
|
||||
OverwriteType Type;
|
||||
Permission Allow;
|
||||
Permission Deny;
|
||||
|
||||
friend void from_json(const nlohmann::json &j, PermissionOverwrite &m);
|
||||
};
|
@ -9,7 +9,7 @@ void from_json(const nlohmann::json &j, Role &m) {
|
||||
JS_D("permissions", m.PermissionsLegacy);
|
||||
std::string tmp;
|
||||
JS_D("permissions_new", tmp);
|
||||
m.Permissions = std::stoull(tmp);
|
||||
m.Permissions = static_cast<Permission>(std::stoull(tmp));
|
||||
JS_D("managed", m.IsManaged);
|
||||
JS_D("mentionable", m.IsMentionable);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include "snowflake.hpp"
|
||||
#include "json.hpp"
|
||||
#include "permissions.hpp"
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
@ -11,7 +12,7 @@ struct Role {
|
||||
bool IsHoisted;
|
||||
int Position;
|
||||
int PermissionsLegacy;
|
||||
uint64_t Permissions;
|
||||
Permission Permissions;
|
||||
bool IsManaged;
|
||||
bool IsMentionable;
|
||||
|
||||
|
@ -130,6 +130,10 @@ const Store::guilds_type &Store::GetGuilds() const {
|
||||
return m_guilds;
|
||||
}
|
||||
|
||||
const Store::roles_type &Store::GetRoles() const {
|
||||
return m_roles;
|
||||
}
|
||||
|
||||
void Store::ClearAll() {
|
||||
m_channels.clear();
|
||||
m_guilds.clear();
|
||||
|
@ -41,6 +41,7 @@ public:
|
||||
|
||||
const channels_type &GetChannels() const;
|
||||
const guilds_type &GetGuilds() const;
|
||||
const roles_type &GetRoles() const;
|
||||
|
||||
void ClearAll();
|
||||
|
||||
|
36
util.hpp
36
util.hpp
@ -9,6 +9,42 @@
|
||||
#include <string>
|
||||
#include <iomanip>
|
||||
|
||||
template<typename T>
|
||||
struct Bitwise {
|
||||
static const bool enable = false;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<Bitwise<T>::enable, T>::type operator|(T a, T b) {
|
||||
using x = typename std::underlying_type<T>::type;
|
||||
return static_cast<T>(static_cast<x>(a) | static_cast<x>(b));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<Bitwise<T>::enable, T>::type operator|=(T &a, T b) {
|
||||
using x = typename std::underlying_type<T>::type;
|
||||
a = static_cast<T>(static_cast<x>(a) | static_cast<x>(b));
|
||||
return a;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<Bitwise<T>::enable, T>::type operator&(T a, T b) {
|
||||
using x = typename std::underlying_type<T>::type;
|
||||
return static_cast<T>(static_cast<x>(a) & static_cast<x>(b));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<Bitwise<T>::enable, T>::type operator&=(T &a, T b) {
|
||||
using x = typename std::underlying_type<T>::type;
|
||||
a = static_cast<T>(static_cast<x>(a) & static_cast<x>(b));
|
||||
return a;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<Bitwise<T>::enable, T>::type operator~(T a) {
|
||||
return static_cast<T>(~static_cast<std::underlying_type<T>::type>(a));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void AlphabeticalSort(T start, T end, std::function<std::string(const typename std::iterator_traits<T>::value_type &)> get_string) {
|
||||
std::sort(start, end, [&](const auto &a, const auto &b) -> bool {
|
||||
|
Loading…
Reference in New Issue
Block a user