Skip to content

Commit

Permalink
Merge branch 'main' into feat/pushd
Browse files Browse the repository at this point in the history
  • Loading branch information
IAmTomahawkx committed Nov 1, 2024
2 parents 323fb60 + 397b987 commit 6cccd0b
Show file tree
Hide file tree
Showing 27 changed files with 1,507 additions and 133 deletions.
607 changes: 595 additions & 12 deletions Cargo.lock

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions crates/bindings/node/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "revolt-nodejs-bindings"
version = "0.7.16"
version = "0.7.18"
description = "Node.js bindings for the Revolt software"
authors = ["Paul Makles <me@insrt.uk>"]
license = "MIT"
Expand All @@ -20,6 +20,6 @@ serde = { version = "1", features = ["derive"] }

async-std = "1.12.0"

revolt-config = { version = "0.7.16", path = "../../core/config" }
revolt-result = { version = "0.7.16", path = "../../core/result" }
revolt-database = { version = "0.7.16", path = "../../core/database" }
revolt-config = { version = "0.7.18", path = "../../core/config" }
revolt-result = { version = "0.7.18", path = "../../core/result" }
revolt-database = { version = "0.7.18", path = "../../core/database" }
4 changes: 2 additions & 2 deletions crates/bonfire/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "revolt-bonfire"
version = "0.7.16"
version = "0.7.18"
license = "AGPL-3.0-or-later"
edition = "2021"

Expand Down Expand Up @@ -41,7 +41,7 @@ revolt-result = { path = "../core/result" }
revolt-models = { path = "../core/models" }
revolt-config = { path = "../core/config" }
revolt-database = { path = "../core/database" }
revolt-permissions = { version = "0.7.16", path = "../core/permissions" }
revolt-permissions = { version = "0.7.18", path = "../core/permissions" }
revolt-presence = { path = "../core/presence", features = ["redis-is-patched"] }

# redis
Expand Down
4 changes: 2 additions & 2 deletions crates/core/config/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "revolt-config"
version = "0.7.16"
version = "0.7.18"
edition = "2021"
license = "MIT"
authors = ["Paul Makles <me@insrt.uk>"]
Expand Down Expand Up @@ -35,4 +35,4 @@ pretty_env_logger = "0.4.0"
sentry = "0.31.5"

# Core
revolt-result = { version = "0.7.16", path = "../result", optional = true }
revolt-result = { version = "0.7.18", path = "../result", optional = true }
12 changes: 6 additions & 6 deletions crates/core/database/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "revolt-database"
version = "0.7.16"
version = "0.7.18"
edition = "2021"
license = "AGPL-3.0-or-later"
authors = ["Paul Makles <me@insrt.uk>"]
Expand All @@ -24,15 +24,15 @@ default = ["mongodb", "async-std-runtime", "tasks"]

[dependencies]
# Core
revolt-config = { version = "0.7.16", path = "../config", features = [
revolt-config = { version = "0.7.18", path = "../config", features = [
"report-macros",
] }
revolt-result = { version = "0.7.16", path = "../result" }
revolt-models = { version = "0.7.16", path = "../models", features = [
revolt-result = { version = "0.7.18", path = "../result" }
revolt-models = { version = "0.7.18", path = "../models", features = [
"validator",
] }
revolt-presence = { version = "0.7.16", path = "../presence" }
revolt-permissions = { version = "0.7.16", path = "../permissions", features = [
revolt-presence = { version = "0.7.18", path = "../presence" }
revolt-permissions = { version = "0.7.18", path = "../permissions", features = [
"serde",
"bson",
] }
Expand Down
29 changes: 28 additions & 1 deletion crates/core/database/src/models/messages/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,34 @@ impl Message {
}

if !mentions.is_empty() {
message.mentions.replace(mentions.into_iter().collect());
// FIXME: temp fix to stop spam attacks
match channel {
Channel::DirectMessage { ref recipients, .. }
| Channel::Group { ref recipients, .. } => {
let recipients_hash: HashSet<&String, RandomState> =
HashSet::from_iter(recipients.iter());

mentions.retain(|m| recipients_hash.contains(m));
}
Channel::TextChannel { ref server, .. }
| Channel::VoiceChannel { ref server, .. } => {
let mentions_vec = Vec::from_iter(mentions.iter().cloned());
let valid_members = db.fetch_members(server.as_str(), &mentions_vec[..]).await;
if let Ok(valid_members) = valid_members {
let valid_ids: HashSet<String, RandomState> = HashSet::from_iter(
valid_members.iter().map(|member| member.id.user.clone()),
);
mentions.retain(|m| valid_ids.contains(m));
} else {
revolt_config::capture_error(&valid_members.unwrap_err());
}
}
Channel::SavedMessages { .. } => mentions.clear(),
}

if !mentions.is_empty() {
message.mentions.replace(mentions.into_iter().collect());
}
}

if !replies.is_empty() {
Expand Down
24 changes: 21 additions & 3 deletions crates/core/files/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,20 +1,38 @@
[package]
name = "revolt-files"
version = "0.7.16"
version = "0.7.18"
edition = "2021"
license = "AGPL-3.0-or-later"
authors = ["Paul Makles <me@insrt.uk>"]
description = "Revolt Backend: S3 and encryption subroutines"

[dependencies]
tracing = "0.1"

ffprobe = "0.4.0"
imagesize = "0.13.0"
tempfile = "3.12.0"

base64 = "0.22.1"
aes-gcm = "0.10.3"
typenum = "1.17.0"

aws-config = "1.5.5"
aws-sdk-s3 = { version = "1.46.0", features = ["behavior-version-latest"] }

revolt-config = { version = "0.7.16", path = "../config", features = [
revolt-config = { version = "0.7.18", path = "../config", features = [
"report-macros",
] }
revolt-result = { version = "0.7.16", path = "../result" }
revolt-result = { version = "0.7.18", path = "../result" }

# image processing
jxl-oxide = "0.8.1"
image = { version = "0.25.2" }

# svg rendering
usvg = "0.44.0"
resvg = "0.44.0"
tiny-skia = "0.11.4"

# encoding
webp = "0.3.0"
164 changes: 163 additions & 1 deletion crates/core/files/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use std::io::Write;
use std::io::{BufRead, Read, Seek, Write};

use aes_gcm::{
aead::{AeadCore, AeadMutInPlace, OsRng},
Aes256Gcm, Key, KeyInit, Nonce,
};
use image::{DynamicImage, ImageBuffer};
use revolt_config::{config, report_internal_error, FilesS3};
use revolt_result::{create_error, Result};

Expand All @@ -13,6 +14,8 @@ use aws_sdk_s3::{
};

use base64::prelude::*;
use tempfile::NamedTempFile;
use tiny_skia::Pixmap;

/// Size of the authentication tag in the buffer
pub const AUTHENTICATION_TAG_SIZE_BYTES: usize = 16;
Expand Down Expand Up @@ -108,3 +111,162 @@ pub async fn upload_to_s3(bucket_id: &str, path: &str, buf: &[u8]) -> Result<Str

Ok(BASE64_STANDARD.encode(nonce))
}

/// Determine size of image at temp file
pub fn image_size(f: &NamedTempFile) -> Option<(usize, usize)> {
if let Ok(size) = imagesize::size(f.path())
.inspect_err(|err| tracing::error!("Failed to generate image size! {err:?}"))
{
Some((size.width, size.height))
} else {
None
}
}

/// Determine size of image with buffer
pub fn image_size_vec(v: &[u8], mime: &str) -> Option<(usize, usize)> {
match mime {
"image/svg+xml" => {
let tree =
report_internal_error!(usvg::Tree::from_data(v, &Default::default())).ok()?;

let size = tree.size();
Some((size.width() as usize, size.height() as usize))
}
_ => {
if let Ok(size) = imagesize::blob_size(v)
.inspect_err(|err| tracing::error!("Failed to generate image size! {err:?}"))
{
Some((size.width, size.height))
} else {
None
}
}
}
}

/// Determine size of video at temp file
pub fn video_size(f: &NamedTempFile) -> Option<(i64, i64)> {
if let Ok(data) = ffprobe::ffprobe(f.path())
.inspect_err(|err| tracing::error!("Failed to ffprobe file! {err:?}"))
{
// Use first valid stream
for stream in data.streams {
if let (Some(w), Some(h)) = (stream.width, stream.height) {
return Some((w, h));
}
}

None
} else {
None
}
}

/// Decode image from reader
pub fn decode_image<R: Read + BufRead + Seek>(reader: &mut R, mime: &str) -> Result<DynamicImage> {
match mime {
// Read image using jxl-oxide crate
"image/jxl" => {
let jxl_image = report_internal_error!(jxl_oxide::JxlImage::builder().read(reader))?;
if let Ok(frame) = jxl_image.render_frame(0) {
match frame.color_channels().len() {
3 => Ok(DynamicImage::ImageRgb8(
DynamicImage::ImageRgb32F(
ImageBuffer::from_vec(
jxl_image.width(),
jxl_image.height(),
frame.image().buf().to_vec(),
)
.ok_or_else(|| create_error!(ImageProcessingFailed))?,
)
.to_rgb8(),
)),
4 => Ok(DynamicImage::ImageRgba8(
DynamicImage::ImageRgba32F(
ImageBuffer::from_vec(
jxl_image.width(),
jxl_image.height(),
frame.image().buf().to_vec(),
)
.ok_or_else(|| create_error!(ImageProcessingFailed))?,
)
.to_rgba8(),
)),
_ => Err(create_error!(ImageProcessingFailed)),
}
} else {
Err(create_error!(ImageProcessingFailed))
}
}
// Read image using resvg
"image/svg+xml" => {
// usvg doesn't support Read trait so copy to buffer
let mut buf = Vec::new();
report_internal_error!(reader.read_to_end(&mut buf))?;

let tree = report_internal_error!(usvg::Tree::from_data(&buf, &Default::default()))?;
let size = tree.size();
let mut pixmap = Pixmap::new(size.width() as u32, size.height() as u32)
.ok_or_else(|| create_error!(ImageProcessingFailed))?;

let mut pixmap_mut = pixmap.as_mut();
resvg::render(&tree, Default::default(), &mut pixmap_mut);

Ok(DynamicImage::ImageRgba8(
ImageBuffer::from_vec(
size.width() as u32,
size.height() as u32,
pixmap.data().to_vec(),
)
.ok_or_else(|| create_error!(ImageProcessingFailed))?,
))
}
// Check if we can read using image-rs crate
_ => report_internal_error!(report_internal_error!(
image::ImageReader::new(reader).with_guessed_format()
)?
.decode()),
}
}

/// Check whether given reader has a valid image
pub fn is_valid_image<R: Read + BufRead + Seek>(reader: &mut R, mime: &str) -> bool {
match mime {
// Check if we can read using jxl-oxide crate
"image/jxl" => jxl_oxide::JxlImage::builder()
.read(reader)
.inspect_err(|err| tracing::error!("Failed to read JXL! {err:?}"))
.is_ok(),
// Check if we can read using image-rs crate
_ => !matches!(
image::ImageReader::new(reader)
.with_guessed_format()
.inspect_err(|err| tracing::error!("Failed to read image! {err:?}"))
.map(|f| f.decode()),
Err(_) | Ok(Err(_))
),
}
}

/// Create thumbnail from given image
pub async fn create_thumbnail(image: DynamicImage, tag: &str) -> Vec<u8> {
// Load configuration
let config = config().await;
let [w, h] = config.files.preview.get(tag).unwrap();

// Create thumbnail
//.resize(width as u32, height as u32, image::imageops::FilterType::Gaussian)
// resize is about 2.5x slower,
// thumbnail doesn't have terrible quality
// so we use thumbnail
let image = image.thumbnail(image.width().min(*w as u32), image.height().min(*h as u32));

// Encode it into WEBP
let encoder = webp::Encoder::from_image(&image).expect("Could not create encoder.");
if config.files.webp_quality != 100.0 {
encoder.encode(config.files.webp_quality).to_vec()
} else {
encoder.encode_lossless().to_vec()
}
}
6 changes: 3 additions & 3 deletions crates/core/models/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "revolt-models"
version = "0.7.16"
version = "0.7.18"
edition = "2021"
license = "MIT"
authors = ["Paul Makles <me@insrt.uk>"]
Expand All @@ -20,8 +20,8 @@ default = ["serde", "partials", "rocket"]

[dependencies]
# Core
revolt-config = { version = "0.7.16", path = "../config" }
revolt-permissions = { version = "0.7.16", path = "../permissions" }
revolt-config = { version = "0.7.18", path = "../config" }
revolt-permissions = { version = "0.7.18", path = "../permissions" }

# Utility
regex = "1"
Expand Down
Loading

0 comments on commit 6cccd0b

Please sign in to comment.