forked from jmug/stoatchat
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
815c3fe99e | ||
|
|
54878e8e8d | ||
|
|
6e4798f1d4 | ||
|
|
55bd6fb087 |
Generated
+8
-8
@@ -2843,7 +2843,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-bonfire"
|
||||
version = "0.6.3"
|
||||
version = "0.6.4"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"async-tungstenite",
|
||||
@@ -2860,7 +2860,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-database"
|
||||
version = "0.6.3"
|
||||
version = "0.6.4"
|
||||
dependencies = [
|
||||
"async-recursion",
|
||||
"async-std",
|
||||
@@ -2891,7 +2891,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-delta"
|
||||
version = "0.6.3"
|
||||
version = "0.6.4"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-std",
|
||||
@@ -2931,7 +2931,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-models"
|
||||
version = "0.6.3"
|
||||
version = "0.6.4"
|
||||
dependencies = [
|
||||
"revolt-permissions",
|
||||
"revolt_optional_struct",
|
||||
@@ -2942,7 +2942,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-permissions"
|
||||
version = "0.6.3"
|
||||
version = "0.6.4"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"async-trait",
|
||||
@@ -2956,7 +2956,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-presence"
|
||||
version = "0.6.3"
|
||||
version = "0.6.4"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"log",
|
||||
@@ -2967,7 +2967,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-quark"
|
||||
version = "0.6.3"
|
||||
version = "0.6.4"
|
||||
dependencies = [
|
||||
"async-lock",
|
||||
"async-recursion",
|
||||
@@ -3020,7 +3020,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "revolt-result"
|
||||
version = "0.6.3"
|
||||
version = "0.6.4"
|
||||
dependencies = [
|
||||
"revolt_okapi",
|
||||
"revolt_rocket_okapi",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-bonfire"
|
||||
version = "0.6.3"
|
||||
version = "0.6.4"
|
||||
license = "AGPL-3.0-or-later"
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-database"
|
||||
version = "0.6.3"
|
||||
version = "0.6.4"
|
||||
edition = "2021"
|
||||
license = "AGPL-3.0-or-later"
|
||||
authors = [ "Paul Makles <me@insrt.uk>" ]
|
||||
@@ -22,10 +22,10 @@ default = [ "mongodb", "async-std-runtime" ]
|
||||
|
||||
[dependencies]
|
||||
# Core
|
||||
revolt-result = { version = "0.6.3", path = "../result" }
|
||||
revolt-models = { version = "0.6.3", path = "../models" }
|
||||
revolt-presence = { version = "0.6.3", path = "../presence" }
|
||||
revolt-permissions = { version = "0.6.3", path = "../permissions", features = [ "serde", "bson" ] }
|
||||
revolt-result = { version = "0.6.4", path = "../result" }
|
||||
revolt-models = { version = "0.6.4", path = "../models" }
|
||||
revolt-presence = { version = "0.6.4", path = "../presence" }
|
||||
revolt-permissions = { version = "0.6.4", path = "../permissions", features = [ "serde", "bson" ] }
|
||||
|
||||
# Utility
|
||||
log = "0.4"
|
||||
|
||||
@@ -9,6 +9,7 @@ use crate::{
|
||||
};
|
||||
use futures::StreamExt;
|
||||
use rand::seq::SliceRandom;
|
||||
use revolt_permissions::DEFAULT_WEBHOOK_PERMISSIONS;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
@@ -945,6 +946,23 @@ pub async fn run_migrations(db: &MongoDb, revision: i32) -> i32 {
|
||||
)
|
||||
.await
|
||||
.expect("Failed to create username index.");
|
||||
};
|
||||
|
||||
if revision <= 25 {
|
||||
info!("Running migration [revision 25 / 11-06-2023]: Add permissions to webhooks.");
|
||||
|
||||
db.col::<Document>("webhooks")
|
||||
.update_many(
|
||||
doc! {},
|
||||
doc! {
|
||||
"$set": {
|
||||
"permissions": *DEFAULT_WEBHOOK_PERMISSIONS as i64
|
||||
}
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.expect("Failed to update webhooks.");
|
||||
}
|
||||
|
||||
if revision <= 25 {
|
||||
|
||||
@@ -20,6 +20,9 @@ auto_derived_partial!(
|
||||
/// The channel this webhook belongs to
|
||||
pub channel_id: String,
|
||||
|
||||
/// The permissions of the webhook
|
||||
pub permissions: u64,
|
||||
|
||||
/// The private token for the webhook
|
||||
pub token: Option<String>,
|
||||
},
|
||||
|
||||
@@ -52,6 +52,7 @@ impl From<crate::Webhook> for Webhook {
|
||||
avatar: value.avatar.map(|file| file.into()),
|
||||
channel_id: value.channel_id,
|
||||
token: value.token,
|
||||
permissions: value.permissions
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,6 +65,7 @@ impl From<crate::PartialWebhook> for PartialWebhook {
|
||||
avatar: value.avatar.map(|file| file.into()),
|
||||
channel_id: value.channel_id,
|
||||
token: value.token,
|
||||
permissions: value.permissions
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-models"
|
||||
version = "0.6.3"
|
||||
version = "0.6.4"
|
||||
edition = "2021"
|
||||
license = "AGPL-3.0-or-later"
|
||||
authors = [ "Paul Makles <me@insrt.uk>" ]
|
||||
@@ -18,7 +18,7 @@ default = [ "serde", "partials" ]
|
||||
|
||||
[dependencies]
|
||||
# Core
|
||||
revolt-permissions = { version = "0.6.3", path = "../permissions" }
|
||||
revolt-permissions = { version = "0.6.4", path = "../permissions" }
|
||||
|
||||
# Serialisation
|
||||
revolt_optional_struct = { version = "0.2.0", optional = true }
|
||||
|
||||
@@ -16,6 +16,9 @@ auto_derived_partial!(
|
||||
/// The channel this webhook belongs to
|
||||
pub channel_id: String,
|
||||
|
||||
/// The permissions for the webhook
|
||||
pub permissions: u64,
|
||||
|
||||
/// The private token for the webhook
|
||||
pub token: Option<String>,
|
||||
},
|
||||
@@ -43,6 +46,9 @@ auto_derived!(
|
||||
#[cfg_attr(feature = "validator", validate(length(min = 1, max = 128)))]
|
||||
pub avatar: Option<String>,
|
||||
|
||||
/// Webhook permissions
|
||||
pub permissions: Option<u64>,
|
||||
|
||||
/// Fields to remove from webhook
|
||||
#[cfg_attr(feature = "serde", serde(default))]
|
||||
pub remove: Vec<FieldsWebhook>,
|
||||
@@ -61,6 +67,9 @@ auto_derived!(
|
||||
|
||||
/// The channel this webhook belongs to
|
||||
pub channel_id: String,
|
||||
|
||||
/// The permissions for the webhook
|
||||
pub permissions: u64
|
||||
}
|
||||
|
||||
/// Optional fields on webhook object
|
||||
@@ -85,6 +94,7 @@ impl From<Webhook> for ResponseWebhook {
|
||||
name: value.name,
|
||||
avatar: value.avatar.map(|file| file.id),
|
||||
channel_id: value.channel_id,
|
||||
permissions: value.permissions
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-permissions"
|
||||
version = "0.6.3"
|
||||
version = "0.6.4"
|
||||
edition = "2021"
|
||||
license = "AGPL-3.0-or-later"
|
||||
authors = [ "Paul Makles <me@insrt.uk>" ]
|
||||
|
||||
@@ -135,3 +135,5 @@ pub static DEFAULT_PERMISSION_SERVER: Lazy<u64> = Lazy::new(|| {
|
||||
+ ChannelPermission::ChangeAvatar,
|
||||
)
|
||||
});
|
||||
|
||||
pub static DEFAULT_WEBHOOK_PERMISSIONS: Lazy<u64> = Lazy::new(|| ChannelPermission::SendMessage + ChannelPermission::SendEmbeds + ChannelPermission::Masquerade + ChannelPermission::React);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-presence"
|
||||
version = "0.6.3"
|
||||
version = "0.6.4"
|
||||
edition = "2021"
|
||||
license = "AGPL-3.0-or-later"
|
||||
authors = [ "Paul Makles <me@insrt.uk>" ]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-result"
|
||||
version = "0.6.3"
|
||||
version = "0.6.4"
|
||||
edition = "2021"
|
||||
license = "AGPL-3.0-or-later"
|
||||
authors = [ "Paul Makles <me@insrt.uk>" ]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-delta"
|
||||
version = "0.6.3"
|
||||
version = "0.6.4"
|
||||
license = "AGPL-3.0-or-later"
|
||||
authors = ["Paul Makles <paulmakles@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
@@ -2,6 +2,7 @@ use revolt_database::{Database, Webhook};
|
||||
use revolt_quark::{
|
||||
models::{Channel, User},
|
||||
perms, Db, Error, Permission, Ref, Result,
|
||||
DEFAULT_WEBHOOK_PERMISSIONS,
|
||||
};
|
||||
use rocket::{serde::json::Json, State};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -60,6 +61,7 @@ pub async fn req(
|
||||
name: data.name,
|
||||
avatar,
|
||||
channel_id: channel.id().to_string(),
|
||||
permissions: *DEFAULT_WEBHOOK_PERMISSIONS,
|
||||
token: Some(nanoid::nanoid!(64)),
|
||||
};
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ pub async fn req(db: &Db, user: User, target: Ref, role_id: String) -> Result<Em
|
||||
.throw_permission(db, Permission::ManageRole)
|
||||
.await?;
|
||||
|
||||
let member_rank = permissions.get_member_rank().unwrap_or(0);
|
||||
let member_rank = permissions.get_member_rank().unwrap_or(i64::MIN);
|
||||
|
||||
if let Some(role) = server.roles.remove(&role_id) {
|
||||
if role.rank <= member_rank {
|
||||
|
||||
@@ -35,11 +35,13 @@ pub async fn webhook_edit(
|
||||
let DataEditWebhook {
|
||||
name,
|
||||
avatar,
|
||||
permissions,
|
||||
remove,
|
||||
} = data;
|
||||
|
||||
let mut partial = PartialWebhook {
|
||||
name,
|
||||
permissions,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
|
||||
@@ -33,11 +33,13 @@ pub async fn webhook_edit_token(
|
||||
let DataEditWebhook {
|
||||
name,
|
||||
avatar,
|
||||
remove,
|
||||
permissions,
|
||||
remove
|
||||
} = data;
|
||||
|
||||
let mut partial = PartialWebhook {
|
||||
name,
|
||||
permissions,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
|
||||
@@ -29,8 +29,7 @@ pub async fn webhook_execute(
|
||||
let webhook = webhook_id.as_webhook(db).await.map_err(Error::from_core)?;
|
||||
webhook.assert_token(&token).map_err(Error::from_core)?;
|
||||
|
||||
// TODO: webhooks can currently always send masquerades, files, embeds, reactions (interactions)
|
||||
// TODO: they can also mention anyone
|
||||
data.validate_webhook_permissions(webhook.permissions)?;
|
||||
|
||||
let channel = legacy_db.fetch_channel(&webhook.channel_id).await?;
|
||||
let message = channel
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "revolt-quark"
|
||||
version = "0.6.3"
|
||||
version = "0.6.4"
|
||||
edition = "2021"
|
||||
license = "AGPL-3.0-or-later"
|
||||
|
||||
|
||||
@@ -23,8 +23,7 @@ impl Cache {
|
||||
pub async fn can_view_channel(&self, db: &Database, channel: &Channel) -> bool {
|
||||
match &channel {
|
||||
Channel::TextChannel { server, .. } | Channel::VoiceChannel { server, .. } => {
|
||||
let member = self.members.values().find(|x| &x.id.server == server);
|
||||
|
||||
let member = self.members.get(server);
|
||||
let server = self.servers.get(server);
|
||||
let mut perms = perms(self.users.get(&self.user_id).unwrap()).channel(channel);
|
||||
|
||||
@@ -107,9 +106,15 @@ impl State {
|
||||
|
||||
// Fetch all memberships with their corresponding servers.
|
||||
let members: Vec<Member> = db.fetch_all_memberships(&user.id).await?;
|
||||
self.cache.members = members
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|x| (x.id.server.clone(), x))
|
||||
.collect();
|
||||
|
||||
let server_ids: Vec<String> = members.iter().map(|x| x.id.server.clone()).collect();
|
||||
let servers = db.fetch_servers(&server_ids).await?;
|
||||
self.cache.servers = servers.iter().cloned().map(|x| (x.id.clone(), x)).collect();
|
||||
|
||||
// Collect channel ids from servers.
|
||||
let mut channel_ids = vec![];
|
||||
@@ -164,17 +169,11 @@ impl State {
|
||||
self.cache
|
||||
.users
|
||||
.insert(self.cache.user_id.clone(), user.clone());
|
||||
self.cache.servers = servers.iter().cloned().map(|x| (x.id.clone(), x)).collect();
|
||||
self.cache.channels = channels
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|x| (x.id().to_string(), x))
|
||||
.collect();
|
||||
self.cache.members = members
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|x| (x.id.server.clone(), x))
|
||||
.collect();
|
||||
|
||||
// Make all users appear from our perspective.
|
||||
let mut users: Vec<User> = users
|
||||
@@ -353,7 +352,7 @@ impl State {
|
||||
let could_view: bool = if let Some(channel) = self.cache.channels.get(id) {
|
||||
self.cache.can_view_channel(db, channel).await
|
||||
} else {
|
||||
true
|
||||
false
|
||||
};
|
||||
|
||||
if let Some(channel) = self.cache.channels.get_mut(id) {
|
||||
@@ -364,6 +363,12 @@ impl State {
|
||||
channel.apply_options(data.clone());
|
||||
}
|
||||
|
||||
if !self.cache.channels.contains_key(id) {
|
||||
if let Ok(channel) = db.fetch_channel(id).await {
|
||||
self.cache.channels.insert(id.clone(), channel);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(channel) = self.cache.channels.get(id) {
|
||||
let can_view = self.cache.can_view_channel(db, channel).await;
|
||||
if could_view != can_view {
|
||||
@@ -398,7 +403,9 @@ impl State {
|
||||
channels,
|
||||
} => {
|
||||
self.insert_subscription(id.clone());
|
||||
self.cache.servers.insert(id.to_string(), server.clone());
|
||||
self.cache.servers.insert(id.clone(), server.clone());
|
||||
let member = Member::new(id.clone(), self.cache.user_id.clone());
|
||||
self.cache.members.insert(id.clone(), member);
|
||||
|
||||
for channel in channels {
|
||||
self.cache
|
||||
@@ -436,6 +443,7 @@ impl State {
|
||||
self.cache.channels.remove(channel);
|
||||
}
|
||||
}
|
||||
self.cache.members.remove(id);
|
||||
}
|
||||
}
|
||||
EventV1::ServerDelete { id } => {
|
||||
@@ -447,6 +455,7 @@ impl State {
|
||||
self.cache.channels.remove(channel);
|
||||
}
|
||||
}
|
||||
self.cache.members.remove(id);
|
||||
}
|
||||
EventV1::ServerMemberUpdate { id, data, clear } => {
|
||||
if id.user == self.cache.user_id {
|
||||
|
||||
@@ -3,22 +3,10 @@ use crate::{AbstractServerMember, Result};
|
||||
|
||||
use super::super::DummyDb;
|
||||
|
||||
use iso8601_timestamp::Timestamp;
|
||||
|
||||
#[async_trait]
|
||||
impl AbstractServerMember for DummyDb {
|
||||
async fn fetch_member(&self, server: &str, user: &str) -> Result<Member> {
|
||||
Ok(Member {
|
||||
id: MemberCompositeKey {
|
||||
server: server.into(),
|
||||
user: user.into(),
|
||||
},
|
||||
joined_at: Timestamp::now_utc(),
|
||||
nickname: None,
|
||||
avatar: None,
|
||||
roles: vec![],
|
||||
timeout: None,
|
||||
})
|
||||
Ok(Member::new(server.into(), user.into()))
|
||||
}
|
||||
|
||||
async fn insert_member(&self, member: &Member) -> Result<()> {
|
||||
|
||||
@@ -10,7 +10,7 @@ use crate::{
|
||||
models::{
|
||||
message::{
|
||||
AppendMessage, BulkMessageResponse, Interactions, PartialMessage, SendableEmbed,
|
||||
SystemMessage,
|
||||
SystemMessage, DataMessageSend,
|
||||
},
|
||||
Channel, Emoji, Message, User,
|
||||
},
|
||||
@@ -451,3 +451,39 @@ impl Interactions {
|
||||
!self.restrict_reactions && self.reactions.is_none()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn throw_permission(permissions: u64, permission: Permission) -> Result<()> {
|
||||
if (permission as u64) & permissions == (permission as u64) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::MissingPermission { permission })
|
||||
}
|
||||
}
|
||||
|
||||
impl DataMessageSend {
|
||||
pub fn validate_webhook_permissions(
|
||||
&self,
|
||||
permissions: u64,
|
||||
) -> Result<()> {
|
||||
throw_permission(permissions, Permission::SendMessage)?;
|
||||
|
||||
if self.attachments.as_ref().map_or(false, |v| !v.is_empty()) {
|
||||
throw_permission(permissions, Permission::UploadFiles)?;
|
||||
};
|
||||
|
||||
if self.embeds.as_ref().map_or(false, |v| !v.is_empty()) {
|
||||
throw_permission(permissions, Permission::SendEmbeds)?;
|
||||
};
|
||||
|
||||
if self.masquerade.is_some() {
|
||||
throw_permission(permissions, Permission::Masquerade)?;
|
||||
};
|
||||
|
||||
if self.interactions.is_some() {
|
||||
throw_permission(permissions, Permission::React)?;
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use iso8601_timestamp::Timestamp;
|
||||
use ulid::Ulid;
|
||||
|
||||
use crate::{
|
||||
@@ -186,18 +185,7 @@ impl Server {
|
||||
return Err(Error::Banned);
|
||||
}
|
||||
|
||||
let member = Member {
|
||||
id: MemberCompositeKey {
|
||||
server: self.id.clone(),
|
||||
user: user.id.clone(),
|
||||
},
|
||||
joined_at: Timestamp::now_utc(),
|
||||
nickname: None,
|
||||
avatar: None,
|
||||
roles: vec![],
|
||||
timeout: None,
|
||||
};
|
||||
|
||||
let member = Member::new(self.id.clone(), user.id.clone());
|
||||
db.insert_member(&member).await?;
|
||||
|
||||
let should_fetch = channels.is_none();
|
||||
|
||||
@@ -3,13 +3,27 @@ use iso8601_timestamp::Timestamp;
|
||||
use crate::{
|
||||
events::client::EventV1,
|
||||
models::{
|
||||
server_member::{FieldsMember, PartialMember},
|
||||
server_member::{FieldsMember, MemberCompositeKey, PartialMember},
|
||||
Member, Server,
|
||||
},
|
||||
Database, Result,
|
||||
};
|
||||
|
||||
impl Member {
|
||||
pub fn new(server_id: String, user_id: String) -> Self {
|
||||
Self {
|
||||
id: MemberCompositeKey {
|
||||
server: server_id,
|
||||
user: user_id,
|
||||
},
|
||||
joined_at: Timestamp::now_utc(),
|
||||
nickname: None,
|
||||
avatar: None,
|
||||
roles: vec![],
|
||||
timeout: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Update member data
|
||||
pub async fn update<'a>(
|
||||
&mut self,
|
||||
|
||||
@@ -110,6 +110,7 @@ pub static DEFAULT_PERMISSION: Lazy<u64> = Lazy::new(|| DEFAULT_PERMISSION_VIEW_
|
||||
pub static DEFAULT_PERMISSION_SAVED_MESSAGES: u64 = Permission::GrantAllSafe as u64;
|
||||
pub static DEFAULT_PERMISSION_DIRECT_MESSAGE: Lazy<u64> = Lazy::new(|| DEFAULT_PERMISSION.add(Permission::ManageChannel + Permission::React));
|
||||
pub static DEFAULT_PERMISSION_SERVER: Lazy<u64> = Lazy::new(|| DEFAULT_PERMISSION.add(Permission::React + Permission::ChangeNickname + Permission::ChangeAvatar));
|
||||
pub static DEFAULT_WEBHOOK_PERMISSIONS: Lazy<u64> = Lazy::new(|| Permission::SendMessage + Permission::SendEmbeds + Permission::Masquerade + Permission::React);
|
||||
|
||||
bitfield! {
|
||||
#[derive(Default)]
|
||||
|
||||
Reference in New Issue
Block a user