forked from jmug/stoatchat
Compare commits
16
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4c00a7dfb7 | ||
|
|
b9ae333b02 | ||
|
|
bf0fc504a9 | ||
|
|
705e517871 | ||
|
|
6f99ac2160 | ||
|
|
2fcc714546 | ||
|
|
1e72f7bc77 | ||
|
|
af0d24c7c6 | ||
|
|
ab58177dfa | ||
|
|
df07426019 | ||
|
|
c30d9a2620 | ||
|
|
7b44317705 | ||
|
|
876068a37e | ||
|
|
397b9878e1 | ||
|
|
d9deadc65a | ||
|
|
58d3c5cc2e |
No files matched your search
Vendored
+2
-1
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"editor.formatOnSave": true,
|
"editor.formatOnSave": true,
|
||||||
"rust-analyzer.checkOnSave.command": "clippy",
|
"rust-analyzer.checkOnSave.command": "clippy",
|
||||||
"nixEnvSelector.suggestion": false
|
"nixEnvSelector.suggestion": false,
|
||||||
|
"nixEnvSelector.nixFile": "${workspaceFolder}/default.nix"
|
||||||
}
|
}
|
||||||
Generated
+12
-20
@@ -2004,12 +2004,6 @@ version = "0.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257"
|
checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dotenv"
|
|
||||||
version = "0.15.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dtoa"
|
name = "dtoa"
|
||||||
version = "1.0.9"
|
version = "1.0.9"
|
||||||
@@ -5580,7 +5574,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-autumn"
|
name = "revolt-autumn"
|
||||||
version = "0.7.18"
|
version = "0.7.19"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
"axum-macros",
|
"axum-macros",
|
||||||
@@ -5617,7 +5611,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-bonfire"
|
name = "revolt-bonfire"
|
||||||
version = "0.7.18"
|
version = "0.7.19"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-channel 2.3.1",
|
"async-channel 2.3.1",
|
||||||
"async-std",
|
"async-std",
|
||||||
@@ -5647,12 +5641,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-config"
|
name = "revolt-config"
|
||||||
version = "0.7.18"
|
version = "0.7.19"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-std",
|
"async-std",
|
||||||
"cached",
|
"cached",
|
||||||
"config",
|
"config",
|
||||||
"dotenv",
|
|
||||||
"futures-locks",
|
"futures-locks",
|
||||||
"log",
|
"log",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@@ -5664,7 +5657,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-database"
|
name = "revolt-database"
|
||||||
version = "0.7.18"
|
version = "0.7.19"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-lock 2.8.0",
|
"async-lock 2.8.0",
|
||||||
"async-recursion",
|
"async-recursion",
|
||||||
@@ -5712,7 +5705,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-delta"
|
name = "revolt-delta"
|
||||||
version = "0.7.18"
|
version = "0.7.19"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-channel 1.6.1",
|
"async-channel 1.6.1",
|
||||||
"async-std",
|
"async-std",
|
||||||
@@ -5720,7 +5713,6 @@ dependencies = [
|
|||||||
"bitfield",
|
"bitfield",
|
||||||
"chrono",
|
"chrono",
|
||||||
"dashmap",
|
"dashmap",
|
||||||
"dotenv",
|
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"futures",
|
"futures",
|
||||||
"impl_ops",
|
"impl_ops",
|
||||||
@@ -5759,7 +5751,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-files"
|
name = "revolt-files"
|
||||||
version = "0.7.18"
|
version = "0.7.19"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes-gcm 0.10.3",
|
"aes-gcm 0.10.3",
|
||||||
"aws-config",
|
"aws-config",
|
||||||
@@ -5782,7 +5774,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-january"
|
name = "revolt-january"
|
||||||
version = "0.7.18"
|
version = "0.7.19"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-recursion",
|
"async-recursion",
|
||||||
"axum",
|
"axum",
|
||||||
@@ -5810,7 +5802,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-models"
|
name = "revolt-models"
|
||||||
version = "0.7.18"
|
version = "0.7.19"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 1.9.3",
|
"indexmap 1.9.3",
|
||||||
"iso8601-timestamp 0.2.11",
|
"iso8601-timestamp 0.2.11",
|
||||||
@@ -5828,7 +5820,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-nodejs-bindings"
|
name = "revolt-nodejs-bindings"
|
||||||
version = "0.7.18"
|
version = "0.7.19"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-std",
|
"async-std",
|
||||||
"neon",
|
"neon",
|
||||||
@@ -5841,7 +5833,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-permissions"
|
name = "revolt-permissions"
|
||||||
version = "0.7.18"
|
version = "0.7.19"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-std",
|
"async-std",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@@ -5856,7 +5848,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-presence"
|
name = "revolt-presence"
|
||||||
version = "0.7.18"
|
version = "0.7.19"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-std",
|
"async-std",
|
||||||
"log",
|
"log",
|
||||||
@@ -5867,7 +5859,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "revolt-result"
|
name = "revolt-result"
|
||||||
version = "0.7.18"
|
version = "0.7.19"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
"revolt_okapi",
|
"revolt_okapi",
|
||||||
|
|||||||
@@ -95,17 +95,21 @@ Then continue:
|
|||||||
# start other necessary services
|
# start other necessary services
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
|
|
||||||
|
# run everything together
|
||||||
|
./scripts/start.sh
|
||||||
|
# .. or individually
|
||||||
# run the API server
|
# run the API server
|
||||||
cargo run --bin revolt-delta
|
cargo run --bin revolt-delta
|
||||||
# run the events server
|
# run the events server
|
||||||
cargo run --bin revolt-bonfire
|
cargo run --bin revolt-bonfire
|
||||||
# run the file server
|
# run the file server
|
||||||
cargo run --bin revolt-autumn
|
cargo run --bin revolt-autumn
|
||||||
# run th proxy server
|
# run the proxy server
|
||||||
cargo run --bin revolt-january
|
cargo run --bin revolt-january
|
||||||
|
|
||||||
# hint:
|
# hint:
|
||||||
# mold -run <cargo build, cargo run, etc...>
|
# mold -run <cargo build, cargo run, etc...>
|
||||||
|
# mold -run ./scripts/start.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
You can start a web client by doing the following:
|
You can start a web client by doing the following:
|
||||||
|
|||||||
+4
-5
@@ -32,13 +32,12 @@ services:
|
|||||||
image: minio/mc
|
image: minio/mc
|
||||||
depends_on:
|
depends_on:
|
||||||
- minio
|
- minio
|
||||||
environment:
|
|
||||||
MINIO_ROOT_USER: minioautumn
|
|
||||||
MINIO_ROOT_PASSWORD: minioautumn
|
|
||||||
entrypoint: >
|
entrypoint: >
|
||||||
/bin/sh -c "
|
/bin/sh -c "
|
||||||
/usr/bin/mc config host add minio http://minio:9000 $MINIO_ROOT_USER $MINIO_ROOT_PASSWORD;
|
while ! /usr/bin/mc ready minio; do
|
||||||
while ! /usr/bin/mc ready minio; do echo 'Waiting minio...' && sleep 1; done;
|
/usr/bin/mc config host add minio http://minio:9000 minioautumn minioautumn;
|
||||||
|
echo 'Waiting minio...' && sleep 1;
|
||||||
|
done;
|
||||||
/usr/bin/mc mb minio/revolt-uploads;
|
/usr/bin/mc mb minio/revolt-uploads;
|
||||||
exit 0;
|
exit 0;
|
||||||
"
|
"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-nodejs-bindings"
|
name = "revolt-nodejs-bindings"
|
||||||
version = "0.7.18"
|
version = "0.7.19"
|
||||||
description = "Node.js bindings for the Revolt software"
|
description = "Node.js bindings for the Revolt software"
|
||||||
authors = ["Paul Makles <me@insrt.uk>"]
|
authors = ["Paul Makles <me@insrt.uk>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
@@ -20,6 +20,6 @@ serde = { version = "1", features = ["derive"] }
|
|||||||
|
|
||||||
async-std = "1.12.0"
|
async-std = "1.12.0"
|
||||||
|
|
||||||
revolt-config = { version = "0.7.18", path = "../../core/config" }
|
revolt-config = { version = "0.7.19", path = "../../core/config" }
|
||||||
revolt-result = { version = "0.7.18", path = "../../core/result" }
|
revolt-result = { version = "0.7.19", path = "../../core/result" }
|
||||||
revolt-database = { version = "0.7.18", path = "../../core/database" }
|
revolt-database = { version = "0.7.19", path = "../../core/database" }
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-bonfire"
|
name = "revolt-bonfire"
|
||||||
version = "0.7.18"
|
version = "0.7.19"
|
||||||
license = "AGPL-3.0-or-later"
|
license = "AGPL-3.0-or-later"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ revolt-result = { path = "../core/result" }
|
|||||||
revolt-models = { path = "../core/models" }
|
revolt-models = { path = "../core/models" }
|
||||||
revolt-config = { path = "../core/config" }
|
revolt-config = { path = "../core/config" }
|
||||||
revolt-database = { path = "../core/database" }
|
revolt-database = { path = "../core/database" }
|
||||||
revolt-permissions = { version = "0.7.18", path = "../core/permissions" }
|
revolt-permissions = { version = "0.7.19", path = "../core/permissions" }
|
||||||
revolt-presence = { path = "../core/presence", features = ["redis-is-patched"] }
|
revolt-presence = { path = "../core/presence", features = ["redis-is-patched"] }
|
||||||
|
|
||||||
# redis
|
# redis
|
||||||
|
|||||||
@@ -79,7 +79,9 @@ pub async fn client(db: &'static Database, stream: TcpStream, addr: SocketAddr)
|
|||||||
// Try to authenticate the user.
|
// Try to authenticate the user.
|
||||||
let Some(token) = config.get_session_token().as_ref() else {
|
let Some(token) = config.get_session_token().as_ref() else {
|
||||||
write
|
write
|
||||||
.send(config.encode(&create_error!(InvalidSession)))
|
.send(config.encode(&EventV1::Error {
|
||||||
|
data: create_error!(InvalidSession),
|
||||||
|
}))
|
||||||
.await
|
.await
|
||||||
.ok();
|
.ok();
|
||||||
return;
|
return;
|
||||||
@@ -88,7 +90,10 @@ pub async fn client(db: &'static Database, stream: TcpStream, addr: SocketAddr)
|
|||||||
let (user, session_id) = match User::from_token(db, token, UserHint::Any).await {
|
let (user, session_id) = match User::from_token(db, token, UserHint::Any).await {
|
||||||
Ok(user) => user,
|
Ok(user) => user,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
write.send(config.encode(&err)).await.ok();
|
write
|
||||||
|
.send(config.encode(&EventV1::Error { data: err }))
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -301,25 +306,23 @@ async fn listener(
|
|||||||
PayloadType::Json => message
|
PayloadType::Json => message
|
||||||
.value
|
.value
|
||||||
.as_str()
|
.as_str()
|
||||||
.and_then(|s| serde_json::from_str::<EventV1>(s.as_ref()).ok()),
|
.and_then(|s| report_internal_error!(serde_json::from_str::<EventV1>(s.as_ref())).ok()),
|
||||||
PayloadType::Msgpack => message
|
PayloadType::Msgpack => message
|
||||||
.value
|
.value
|
||||||
.as_bytes()
|
.as_bytes()
|
||||||
.and_then(|b| rmp_serde::from_slice::<EventV1>(b).ok()),
|
.and_then(|b| report_internal_error!(rmp_serde::from_slice::<EventV1>(b)).ok()),
|
||||||
PayloadType::Bincode => message
|
PayloadType::Bincode => message
|
||||||
.value
|
.value
|
||||||
.as_bytes()
|
.as_bytes()
|
||||||
.and_then(|b| bincode::deserialize::<EventV1>(b).ok()),
|
.and_then(|b| report_internal_error!(bincode::deserialize::<EventV1>(b)).ok()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(mut event) = event else {
|
let Some(mut event) = event else {
|
||||||
let err = format!(
|
let err = format!(
|
||||||
"Failed to deserialise an event for {}! Introspection: `{:?}`",
|
"Failed to deserialise event for {}: `{:?}`",
|
||||||
message.channel,
|
message.channel,
|
||||||
message
|
message
|
||||||
.value
|
.value
|
||||||
.as_string()
|
|
||||||
.map(|x| x.chars().take(32).collect::<String>())
|
|
||||||
);
|
);
|
||||||
|
|
||||||
error!("{}", err);
|
error!("{}", err);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-config"
|
name = "revolt-config"
|
||||||
version = "0.7.18"
|
version = "0.7.19"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["Paul Makles <me@insrt.uk>"]
|
authors = ["Paul Makles <me@insrt.uk>"]
|
||||||
@@ -15,7 +15,6 @@ default = ["test"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Utility
|
# Utility
|
||||||
dotenv = "0.15.0"
|
|
||||||
config = "0.13.3"
|
config = "0.13.3"
|
||||||
cached = "0.44.0"
|
cached = "0.44.0"
|
||||||
once_cell = "1.18.0"
|
once_cell = "1.18.0"
|
||||||
@@ -35,4 +34,4 @@ pretty_env_logger = "0.4.0"
|
|||||||
sentry = "0.31.5"
|
sentry = "0.31.5"
|
||||||
|
|
||||||
# Core
|
# Core
|
||||||
revolt-result = { version = "0.7.18", path = "../result", optional = true }
|
revolt-result = { version = "0.7.19", path = "../result", optional = true }
|
||||||
@@ -132,6 +132,7 @@ emojis = [128, 128]
|
|||||||
#
|
#
|
||||||
# Backblaze B2:
|
# Backblaze B2:
|
||||||
# - endpoint is listed on the "Buckets" page
|
# - endpoint is listed on the "Buckets" page
|
||||||
|
# - path_style_buckets is set to true
|
||||||
# - region is `eu-central-003` string from endpoint URL
|
# - region is `eu-central-003` string from endpoint URL
|
||||||
# - access_key_id is keyID generated on the "Application Keys" page
|
# - access_key_id is keyID generated on the "Application Keys" page
|
||||||
# - secret_access_key is token generated on the "Application Keys" page
|
# - secret_access_key is token generated on the "Application Keys" page
|
||||||
@@ -139,6 +140,9 @@ emojis = [128, 128]
|
|||||||
|
|
||||||
# S3 protocol endpoint
|
# S3 protocol endpoint
|
||||||
endpoint = "http://minio:9000"
|
endpoint = "http://minio:9000"
|
||||||
|
# Whether to use path-style buckets
|
||||||
|
# Generally true, except for MinIO
|
||||||
|
path_style_buckets = false
|
||||||
# S3 region name
|
# S3 region name
|
||||||
region = "minio"
|
region = "minio"
|
||||||
# S3 protocol key ID
|
# S3 protocol key ID
|
||||||
|
|||||||
@@ -175,6 +175,7 @@ pub struct FilesLimit {
|
|||||||
#[derive(Deserialize, Debug, Clone)]
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
pub struct FilesS3 {
|
pub struct FilesS3 {
|
||||||
pub endpoint: String,
|
pub endpoint: String,
|
||||||
|
pub path_style_buckets: bool,
|
||||||
pub region: String,
|
pub region: String,
|
||||||
pub access_key_id: String,
|
pub access_key_id: String,
|
||||||
pub secret_access_key: String,
|
pub secret_access_key: String,
|
||||||
@@ -286,8 +287,6 @@ pub async fn config() -> Settings {
|
|||||||
|
|
||||||
/// Configure logging and common Rust variables
|
/// Configure logging and common Rust variables
|
||||||
pub async fn setup_logging(release: &'static str, dsn: String) -> Option<sentry::ClientInitGuard> {
|
pub async fn setup_logging(release: &'static str, dsn: String) -> Option<sentry::ClientInitGuard> {
|
||||||
dotenv::dotenv().ok();
|
|
||||||
|
|
||||||
if std::env::var("RUST_LOG").is_err() {
|
if std::env::var("RUST_LOG").is_err() {
|
||||||
std::env::set_var("RUST_LOG", "info");
|
std::env::set_var("RUST_LOG", "info");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-database"
|
name = "revolt-database"
|
||||||
version = "0.7.18"
|
version = "0.7.19"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "AGPL-3.0-or-later"
|
license = "AGPL-3.0-or-later"
|
||||||
authors = ["Paul Makles <me@insrt.uk>"]
|
authors = ["Paul Makles <me@insrt.uk>"]
|
||||||
@@ -24,15 +24,15 @@ default = ["mongodb", "async-std-runtime", "tasks"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Core
|
# Core
|
||||||
revolt-config = { version = "0.7.18", path = "../config", features = [
|
revolt-config = { version = "0.7.19", path = "../config", features = [
|
||||||
"report-macros",
|
"report-macros",
|
||||||
] }
|
] }
|
||||||
revolt-result = { version = "0.7.18", path = "../result" }
|
revolt-result = { version = "0.7.19", path = "../result" }
|
||||||
revolt-models = { version = "0.7.18", path = "../models", features = [
|
revolt-models = { version = "0.7.19", path = "../models", features = [
|
||||||
"validator",
|
"validator",
|
||||||
] }
|
] }
|
||||||
revolt-presence = { version = "0.7.18", path = "../presence" }
|
revolt-presence = { version = "0.7.19", path = "../presence" }
|
||||||
revolt-permissions = { version = "0.7.18", path = "../permissions", features = [
|
revolt-permissions = { version = "0.7.19", path = "../permissions", features = [
|
||||||
"serde",
|
"serde",
|
||||||
"bson",
|
"bson",
|
||||||
] }
|
] }
|
||||||
|
|||||||
@@ -1,25 +1,16 @@
|
|||||||
use authifier::AuthifierEvent;
|
use authifier::AuthifierEvent;
|
||||||
|
use revolt_result::Error;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use revolt_models::v0::{
|
use revolt_models::v0::{
|
||||||
AppendMessage, Channel, ChannelUnread, Emoji, FieldsChannel, FieldsMember, FieldsMessage, FieldsRole, FieldsServer, FieldsUser, FieldsWebhook, Member, MemberCompositeKey, Message, PartialChannel, PartialMember, PartialMessage, PartialRole, PartialServer, PartialUser, PartialWebhook, RemovalIntention, Report, Server, User, UserSettings, Webhook
|
AppendMessage, Channel, ChannelUnread, Emoji, FieldsChannel, FieldsMember, FieldsMessage,
|
||||||
|
FieldsRole, FieldsServer, FieldsUser, FieldsWebhook, Member, MemberCompositeKey, Message,
|
||||||
|
PartialChannel, PartialMember, PartialMessage, PartialRole, PartialServer, PartialUser,
|
||||||
|
PartialWebhook, RemovalIntention, Report, Server, User, UserSettings, Webhook,
|
||||||
};
|
};
|
||||||
use revolt_result::Error;
|
|
||||||
|
|
||||||
use crate::Database;
|
use crate::Database;
|
||||||
|
|
||||||
/// WebSocket Client Errors
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
||||||
#[serde(tag = "error")]
|
|
||||||
pub enum WebSocketError {
|
|
||||||
LabelMe,
|
|
||||||
InternalError { at: String },
|
|
||||||
InvalidSession,
|
|
||||||
OnboardingNotFinished,
|
|
||||||
AlreadyAuthenticated,
|
|
||||||
MalformedData { msg: String },
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Ping Packet
|
/// Ping Packet
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
@@ -28,14 +19,6 @@ pub enum Ping {
|
|||||||
Number(usize),
|
Number(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Untagged Error
|
|
||||||
#[derive(Serialize)]
|
|
||||||
#[serde(untagged)]
|
|
||||||
pub enum ErrorEvent {
|
|
||||||
Error(WebSocketError),
|
|
||||||
APIError(Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Fields provided in Ready payload
|
/// Fields provided in Ready payload
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
pub enum ReadyPayloadFields {
|
pub enum ReadyPayloadFields {
|
||||||
@@ -55,6 +38,8 @@ pub enum ReadyPayloadFields {
|
|||||||
pub enum EventV1 {
|
pub enum EventV1 {
|
||||||
/// Multiple events
|
/// Multiple events
|
||||||
Bulk { v: Vec<EventV1> },
|
Bulk { v: Vec<EventV1> },
|
||||||
|
/// Error event
|
||||||
|
Error { data: Error },
|
||||||
|
|
||||||
/// Successfully authenticated
|
/// Successfully authenticated
|
||||||
Authenticated,
|
Authenticated,
|
||||||
@@ -89,6 +74,7 @@ pub enum EventV1 {
|
|||||||
id: String,
|
id: String,
|
||||||
channel: String,
|
channel: String,
|
||||||
data: PartialMessage,
|
data: PartialMessage,
|
||||||
|
#[serde(default)]
|
||||||
clear: Vec<FieldsMessage>,
|
clear: Vec<FieldsMessage>,
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -140,6 +126,7 @@ pub enum EventV1 {
|
|||||||
ServerUpdate {
|
ServerUpdate {
|
||||||
id: String,
|
id: String,
|
||||||
data: PartialServer,
|
data: PartialServer,
|
||||||
|
#[serde(default)]
|
||||||
clear: Vec<FieldsServer>,
|
clear: Vec<FieldsServer>,
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -150,6 +137,7 @@ pub enum EventV1 {
|
|||||||
ServerMemberUpdate {
|
ServerMemberUpdate {
|
||||||
id: MemberCompositeKey,
|
id: MemberCompositeKey,
|
||||||
data: PartialMember,
|
data: PartialMember,
|
||||||
|
#[serde(default)]
|
||||||
clear: Vec<FieldsMember>,
|
clear: Vec<FieldsMember>,
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -168,6 +156,7 @@ pub enum EventV1 {
|
|||||||
id: String,
|
id: String,
|
||||||
role_id: String,
|
role_id: String,
|
||||||
data: PartialRole,
|
data: PartialRole,
|
||||||
|
#[serde(default)]
|
||||||
clear: Vec<FieldsRole>,
|
clear: Vec<FieldsRole>,
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -178,6 +167,7 @@ pub enum EventV1 {
|
|||||||
UserUpdate {
|
UserUpdate {
|
||||||
id: String,
|
id: String,
|
||||||
data: PartialUser,
|
data: PartialUser,
|
||||||
|
#[serde(default)]
|
||||||
clear: Vec<FieldsUser>,
|
clear: Vec<FieldsUser>,
|
||||||
event_id: Option<String>,
|
event_id: Option<String>,
|
||||||
},
|
},
|
||||||
@@ -212,6 +202,7 @@ pub enum EventV1 {
|
|||||||
ChannelUpdate {
|
ChannelUpdate {
|
||||||
id: String,
|
id: String,
|
||||||
data: PartialChannel,
|
data: PartialChannel,
|
||||||
|
#[serde(default)]
|
||||||
clear: Vec<FieldsChannel>,
|
clear: Vec<FieldsChannel>,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use bson::oid::ObjectId;
|
|||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
use revolt_permissions::DEFAULT_WEBHOOK_PERMISSIONS;
|
use revolt_permissions::DEFAULT_WEBHOOK_PERMISSIONS;
|
||||||
|
use revolt_result::{Error, ErrorType};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use unicode_segmentation::UnicodeSegmentation;
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ struct MigrationInfo {
|
|||||||
revision: i32,
|
revision: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const LATEST_REVISION: i32 = 30;
|
pub const LATEST_REVISION: i32 = 31;
|
||||||
|
|
||||||
pub async fn migrate_database(db: &MongoDb) {
|
pub async fn migrate_database(db: &MongoDb) {
|
||||||
let migrations = db.col::<Document>("migrations");
|
let migrations = db.col::<Document>("migrations");
|
||||||
@@ -1139,53 +1140,7 @@ pub async fn run_migrations(db: &MongoDb, revision: i32) -> i32 {
|
|||||||
.expect("Failed to create attachment_hashes index.");
|
.expect("Failed to create attachment_hashes index.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if revision <= 29 {
|
// Revision 29 omitted due to bug.
|
||||||
info!("Running migration [revision 29 / 29-09-2024]: Add creator_id to webhooks.");
|
|
||||||
|
|
||||||
#[derive(serde::Serialize, serde::Deserialize)]
|
|
||||||
struct WebhookShell {
|
|
||||||
_id: String,
|
|
||||||
channel_id: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
let invites = db
|
|
||||||
.db()
|
|
||||||
.collection::<WebhookShell>("channel_webhooks")
|
|
||||||
.find(doc! {}, None)
|
|
||||||
.await
|
|
||||||
.expect("webhooks")
|
|
||||||
.filter_map(|s| async { s.ok() })
|
|
||||||
.collect::<Vec<WebhookShell>>()
|
|
||||||
.await;
|
|
||||||
|
|
||||||
for invite in invites {
|
|
||||||
let channel = db.fetch_channel(&invite.channel_id).await.expect("channel");
|
|
||||||
let creator_id = match channel {
|
|
||||||
Channel::Group { owner, .. } => owner,
|
|
||||||
Channel::TextChannel { server, .. } | Channel::VoiceChannel { server, .. } => {
|
|
||||||
let server = db.fetch_server(&server).await.expect("server");
|
|
||||||
server.owner
|
|
||||||
}
|
|
||||||
_ => unreachable!("not server or group channel!"),
|
|
||||||
};
|
|
||||||
|
|
||||||
db.db()
|
|
||||||
.collection::<Document>("channel_webhooks")
|
|
||||||
.update_one(
|
|
||||||
doc! {
|
|
||||||
"_id": invite._id,
|
|
||||||
},
|
|
||||||
doc! {
|
|
||||||
"$set" : {
|
|
||||||
"creator_id": creator_id
|
|
||||||
}
|
|
||||||
},
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.expect("update webhook");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if revision <= 30 {
|
if revision <= 30 {
|
||||||
info!("Running migration [revision 30 / 29-09-2024]: Add index for used_for.id to attachments.");
|
info!("Running migration [revision 30 / 29-09-2024]: Add index for used_for.id to attachments.");
|
||||||
@@ -1209,7 +1164,68 @@ pub async fn run_migrations(db: &MongoDb, revision: i32) -> i32 {
|
|||||||
.expect("Failed to create attachments index.");
|
.expect("Failed to create attachments index.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to migrate fields on attachments, change `user_id`, `object_id`, etc to `parent`.
|
if revision <= 31 {
|
||||||
|
info!("Running migration [revision 31 / 31-10-2024]: Add creator_id to webhooks and delete those whose channels don't exist.");
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
|
struct WebhookShell {
|
||||||
|
_id: String,
|
||||||
|
channel_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
let webhooks = db
|
||||||
|
.db()
|
||||||
|
.collection::<WebhookShell>("channel_webhooks")
|
||||||
|
.find(doc! {}, None)
|
||||||
|
.await
|
||||||
|
.expect("webhooks")
|
||||||
|
.filter_map(|s| async { s.ok() })
|
||||||
|
.collect::<Vec<WebhookShell>>()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
for webhook in webhooks {
|
||||||
|
match db.fetch_channel(&webhook.channel_id).await {
|
||||||
|
Ok(channel) => {
|
||||||
|
let creator_id = match channel {
|
||||||
|
Channel::Group { owner, .. } => owner,
|
||||||
|
Channel::TextChannel { server, .. }
|
||||||
|
| Channel::VoiceChannel { server, .. } => {
|
||||||
|
let server = db.fetch_server(&server).await.expect("server");
|
||||||
|
server.owner
|
||||||
|
}
|
||||||
|
_ => unreachable!("not server or group channel!"),
|
||||||
|
};
|
||||||
|
|
||||||
|
db.db()
|
||||||
|
.collection::<Document>("channel_webhooks")
|
||||||
|
.update_one(
|
||||||
|
doc! {
|
||||||
|
"_id": webhook._id,
|
||||||
|
},
|
||||||
|
doc! {
|
||||||
|
"$set" : {
|
||||||
|
"creator_id": creator_id
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.expect("update webhook");
|
||||||
|
}
|
||||||
|
Err(Error {
|
||||||
|
error_type: ErrorType::NotFound,
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
db.db()
|
||||||
|
.collection::<WebhookShell>("channel_webhooks")
|
||||||
|
.delete_one(doc! { "_id": webhook._id }, None)
|
||||||
|
.await
|
||||||
|
.expect("failed to delete invalid webhook");
|
||||||
|
}
|
||||||
|
Err(err) => panic!("{err:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Reminder to update LATEST_REVISION when adding new migrations.
|
// Reminder to update LATEST_REVISION when adding new migrations.
|
||||||
LATEST_REVISION.max(revision)
|
LATEST_REVISION.max(revision)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use std::collections::HashSet;
|
use std::{collections::HashSet, hash::RandomState};
|
||||||
|
|
||||||
use indexmap::{IndexMap, IndexSet};
|
use indexmap::{IndexMap, IndexSet};
|
||||||
use iso8601_timestamp::Timestamp;
|
use iso8601_timestamp::Timestamp;
|
||||||
@@ -338,7 +338,34 @@ impl Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !mentions.is_empty() {
|
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() {
|
if !replies.is_empty() {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-files"
|
name = "revolt-files"
|
||||||
version = "0.7.18"
|
version = "0.7.19"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "AGPL-3.0-or-later"
|
license = "AGPL-3.0-or-later"
|
||||||
authors = ["Paul Makles <me@insrt.uk>"]
|
authors = ["Paul Makles <me@insrt.uk>"]
|
||||||
@@ -20,10 +20,10 @@ typenum = "1.17.0"
|
|||||||
aws-config = "1.5.5"
|
aws-config = "1.5.5"
|
||||||
aws-sdk-s3 = { version = "1.46.0", features = ["behavior-version-latest"] }
|
aws-sdk-s3 = { version = "1.46.0", features = ["behavior-version-latest"] }
|
||||||
|
|
||||||
revolt-config = { version = "0.7.18", path = "../config", features = [
|
revolt-config = { version = "0.7.19", path = "../config", features = [
|
||||||
"report-macros",
|
"report-macros",
|
||||||
] }
|
] }
|
||||||
revolt-result = { version = "0.7.18", path = "../result" }
|
revolt-result = { version = "0.7.19", path = "../result" }
|
||||||
|
|
||||||
# image processing
|
# image processing
|
||||||
jxl-oxide = "0.8.1"
|
jxl-oxide = "0.8.1"
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ pub fn create_client(s3_config: FilesS3) -> Client {
|
|||||||
let config = Config::builder()
|
let config = Config::builder()
|
||||||
.region(Region::new(s3_config.region))
|
.region(Region::new(s3_config.region))
|
||||||
.endpoint_url(s3_config.endpoint)
|
.endpoint_url(s3_config.endpoint)
|
||||||
|
.force_path_style(s3_config.path_style_buckets)
|
||||||
.credentials_provider(creds)
|
.credentials_provider(creds)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-models"
|
name = "revolt-models"
|
||||||
version = "0.7.18"
|
version = "0.7.19"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["Paul Makles <me@insrt.uk>"]
|
authors = ["Paul Makles <me@insrt.uk>"]
|
||||||
@@ -20,8 +20,8 @@ default = ["serde", "partials", "rocket"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Core
|
# Core
|
||||||
revolt-config = { version = "0.7.18", path = "../config" }
|
revolt-config = { version = "0.7.19", path = "../config" }
|
||||||
revolt-permissions = { version = "0.7.18", path = "../permissions" }
|
revolt-permissions = { version = "0.7.19", path = "../permissions" }
|
||||||
|
|
||||||
# Utility
|
# Utility
|
||||||
regex = "1"
|
regex = "1"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-permissions"
|
name = "revolt-permissions"
|
||||||
version = "0.7.18"
|
version = "0.7.19"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["Paul Makles <me@insrt.uk>"]
|
authors = ["Paul Makles <me@insrt.uk>"]
|
||||||
@@ -21,7 +21,7 @@ async-std = { version = "1.8.0", features = ["attributes"] }
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Core
|
# Core
|
||||||
revolt-result = { version = "0.7.18", path = "../result" }
|
revolt-result = { version = "0.7.19", path = "../result" }
|
||||||
|
|
||||||
# Utility
|
# Utility
|
||||||
auto_ops = "0.3.0"
|
auto_ops = "0.3.0"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-presence"
|
name = "revolt-presence"
|
||||||
version = "0.7.18"
|
version = "0.7.19"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "AGPL-3.0-or-later"
|
license = "AGPL-3.0-or-later"
|
||||||
authors = ["Paul Makles <me@insrt.uk>"]
|
authors = ["Paul Makles <me@insrt.uk>"]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-result"
|
name = "revolt-result"
|
||||||
version = "0.7.18"
|
version = "0.7.19"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["Paul Makles <me@insrt.uk>"]
|
authors = ["Paul Makles <me@insrt.uk>"]
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ impl IntoResponse for Error {
|
|||||||
ErrorType::FileTooLarge { .. } => StatusCode::UNPROCESSABLE_ENTITY,
|
ErrorType::FileTooLarge { .. } => StatusCode::UNPROCESSABLE_ENTITY,
|
||||||
ErrorType::FileTypeNotAllowed => StatusCode::BAD_REQUEST,
|
ErrorType::FileTypeNotAllowed => StatusCode::BAD_REQUEST,
|
||||||
ErrorType::ImageProcessingFailed => StatusCode::INTERNAL_SERVER_ERROR,
|
ErrorType::ImageProcessingFailed => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
ErrorType::NoEmbedData => StatusCode::BAD_REQUEST,
|
||||||
};
|
};
|
||||||
|
|
||||||
(status, Json(&self)).into_response()
|
(status, Json(&self)).into_response()
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ pub enum ErrorType {
|
|||||||
},
|
},
|
||||||
FileTypeNotAllowed,
|
FileTypeNotAllowed,
|
||||||
ImageProcessingFailed,
|
ImageProcessingFailed,
|
||||||
|
NoEmbedData,
|
||||||
|
|
||||||
// ? Legacy errors
|
// ? Legacy errors
|
||||||
VosoUnavailable,
|
VosoUnavailable,
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ impl<'r> Responder<'r, 'static> for Error {
|
|||||||
ErrorType::FileTooLarge { .. } => Status::UnprocessableEntity,
|
ErrorType::FileTooLarge { .. } => Status::UnprocessableEntity,
|
||||||
ErrorType::FileTypeNotAllowed => Status::BadRequest,
|
ErrorType::FileTypeNotAllowed => Status::BadRequest,
|
||||||
ErrorType::ImageProcessingFailed => Status::InternalServerError,
|
ErrorType::ImageProcessingFailed => Status::InternalServerError,
|
||||||
|
ErrorType::NoEmbedData => Status::BadRequest,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Serialize the error data structure into JSON.
|
// Serialize the error data structure into JSON.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-delta"
|
name = "revolt-delta"
|
||||||
version = "0.7.18"
|
version = "0.7.19"
|
||||||
license = "AGPL-3.0-or-later"
|
license = "AGPL-3.0-or-later"
|
||||||
authors = ["Paul Makles <paulmakles@gmail.com>"]
|
authors = ["Paul Makles <paulmakles@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
@@ -16,7 +16,6 @@ redis-kiss = "0.1.4"
|
|||||||
lru = "0.7.0"
|
lru = "0.7.0"
|
||||||
url = "2.2.2"
|
url = "2.2.2"
|
||||||
log = "0.4.11"
|
log = "0.4.11"
|
||||||
dotenv = "0.15.0"
|
|
||||||
dashmap = "5.2.0"
|
dashmap = "5.2.0"
|
||||||
linkify = "0.6.0"
|
linkify = "0.6.0"
|
||||||
once_cell = "1.17.1"
|
once_cell = "1.17.1"
|
||||||
|
|||||||
@@ -19,8 +19,6 @@ pub struct TestHarness {
|
|||||||
|
|
||||||
impl TestHarness {
|
impl TestHarness {
|
||||||
pub async fn new() -> TestHarness {
|
pub async fn new() -> TestHarness {
|
||||||
dotenv::dotenv().ok();
|
|
||||||
|
|
||||||
let client = Client::tracked(crate::web().await)
|
let client = Client::tracked(crate::web().await)
|
||||||
.await
|
.await
|
||||||
.expect("valid rocket instance");
|
.expect("valid rocket instance");
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-autumn"
|
name = "revolt-autumn"
|
||||||
version = "0.7.18"
|
version = "0.7.19"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
@@ -13,7 +13,7 @@ webp = "0.3.0"
|
|||||||
sha2 = "0.10.8"
|
sha2 = "0.10.8"
|
||||||
jxl-oxide = "0.8.1"
|
jxl-oxide = "0.8.1"
|
||||||
kamadak-exif = "0.5.4"
|
kamadak-exif = "0.5.4"
|
||||||
# revolt_little_exif = "0.4.0"
|
# revolt_little_exif = "0.5.1"
|
||||||
image = { version = "0.25.2" } # avif encode requires dav1d system library: features = ["avif-native"]
|
image = { version = "0.25.2" } # avif encode requires dav1d system library: features = ["avif-native"]
|
||||||
|
|
||||||
# File processing
|
# File processing
|
||||||
@@ -42,12 +42,12 @@ tracing = "0.1"
|
|||||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
|
|
||||||
# Core crates
|
# Core crates
|
||||||
revolt-files = { version = "0.7.18", path = "../../core/files" }
|
revolt-files = { version = "0.7.19", path = "../../core/files" }
|
||||||
revolt-config = { version = "0.7.18", path = "../../core/config" }
|
revolt-config = { version = "0.7.19", path = "../../core/config" }
|
||||||
revolt-database = { version = "0.7.18", path = "../../core/database", features = [
|
revolt-database = { version = "0.7.19", path = "../../core/database", features = [
|
||||||
"axum-impl",
|
"axum-impl",
|
||||||
] }
|
] }
|
||||||
revolt-result = { version = "0.7.18", path = "../../core/result", features = [
|
revolt-result = { version = "0.7.19", path = "../../core/result", features = [
|
||||||
"utoipa",
|
"utoipa",
|
||||||
"axum",
|
"axum",
|
||||||
] }
|
] }
|
||||||
|
|||||||
@@ -207,16 +207,27 @@ async fn upload_file(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Find an existing hash and use that if possible
|
// Find an existing hash and use that if possible
|
||||||
if let Ok(file_hash) = db
|
let file_hash_exists = if let Ok(file_hash) = db
|
||||||
.fetch_attachment_hash(&format!("{original_hash:02x}"))
|
.fetch_attachment_hash(&format!("{original_hash:02x}"))
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
let tag: &'static str = tag.into();
|
if !file_hash.iv.is_empty() {
|
||||||
db.insert_attachment(&file_hash.into_file(id.clone(), tag.to_owned(), filename, user.id))
|
let tag: &'static str = tag.into();
|
||||||
|
db.insert_attachment(&file_hash.into_file(
|
||||||
|
id.clone(),
|
||||||
|
tag.to_owned(),
|
||||||
|
filename,
|
||||||
|
user.id,
|
||||||
|
))
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
return Ok(Json(UploadResponse { id }));
|
return Ok(Json(UploadResponse { id }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
// Determine the mime type for the file
|
// Determine the mime type for the file
|
||||||
let mime_type = determine_mime_type(&mut file.contents, &buf, &filename);
|
let mime_type = determine_mime_type(&mut file.contents, &buf, &filename);
|
||||||
@@ -274,7 +285,10 @@ async fn upload_file(
|
|||||||
size: new_file_size as isize,
|
size: new_file_size as isize,
|
||||||
};
|
};
|
||||||
|
|
||||||
db.insert_attachment_hash(&file_hash).await?;
|
// Add attachment hash if it doesn't exist
|
||||||
|
if !file_hash_exists {
|
||||||
|
db.insert_attachment_hash(&file_hash).await?;
|
||||||
|
}
|
||||||
|
|
||||||
// Upload the file to S3 and commit nonce to database
|
// Upload the file to S3 and commit nonce to database
|
||||||
let upload_start = Instant::now();
|
let upload_start = Instant::now();
|
||||||
|
|||||||
@@ -17,23 +17,24 @@ pub async fn strip_metadata(
|
|||||||
) -> Result<(Vec<u8>, Metadata)> {
|
) -> Result<(Vec<u8>, Metadata)> {
|
||||||
match &metadata {
|
match &metadata {
|
||||||
Metadata::Image { width, height } => match mime {
|
Metadata::Image { width, height } => match mime {
|
||||||
// little_exif does not appear to parse JPEGs correctly? had 2/2 files fail
|
// // little_exif does not appear to parse JPEGs correctly? had 2/2 files fail
|
||||||
/* "image/jpeg" | "image/png" => {
|
// "image/jpeg" | "image/png" => {
|
||||||
// use little_exif to strip metadata except for orientation and colour profile
|
// // use little_exif to strip metadata except for orientation and colour profile
|
||||||
// PNGs must also be re-encoded to mitigate CVE-2023-21036
|
// // PNGs must also be re-encoded to mitigate CVE-2023-21036
|
||||||
let metadata = revolt_little_exif::metadata::Metadata::new_from_path_with_filetype(
|
// let metadata = revolt_little_exif::metadata::Metadata::new_from_path_with_filetype(
|
||||||
file.path(),
|
// file.path(),
|
||||||
match mime {
|
// match mime {
|
||||||
"image/jpeg" => revolt_little_exif::filetype::FileExtension::JPEG,
|
// "image/jpeg" => revolt_little_exif::filetype::FileExtension::JPEG,
|
||||||
"image/png" => revolt_little_exif::filetype::FileExtension::PNG {
|
// "image/png" => revolt_little_exif::filetype::FileExtension::PNG {
|
||||||
as_zTXt_chunk: true,
|
// as_zTXt_chunk: true,
|
||||||
},
|
// },
|
||||||
_ => unreachable!(),
|
// _ => unreachable!(),
|
||||||
},
|
// },
|
||||||
)
|
// )
|
||||||
.unwrap();
|
// .unwrap();
|
||||||
dbg!(metadata.data());
|
// dbg!(metadata.data());
|
||||||
} */
|
// todo!()
|
||||||
|
// }
|
||||||
// Apply orientation manually & strip all other EXIF data
|
// Apply orientation manually & strip all other EXIF data
|
||||||
"image/jpeg" | "image/png" | "image/avif" | "image/tiff" => {
|
"image/jpeg" | "image/png" | "image/avif" | "image/tiff" => {
|
||||||
// Create a reader
|
// Create a reader
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "revolt-january"
|
name = "revolt-january"
|
||||||
version = "0.7.18"
|
version = "0.7.19"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
@@ -31,13 +31,13 @@ tracing = "0.1"
|
|||||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
|
|
||||||
# Core crates
|
# Core crates
|
||||||
revolt-config = { version = "0.7.18", path = "../../core/config" }
|
revolt-config = { version = "0.7.19", path = "../../core/config" }
|
||||||
revolt-models = { version = "0.7.18", path = "../../core/models" }
|
revolt-models = { version = "0.7.19", path = "../../core/models" }
|
||||||
revolt-result = { version = "0.7.18", path = "../../core/result", features = [
|
revolt-result = { version = "0.7.19", path = "../../core/result", features = [
|
||||||
"utoipa",
|
"utoipa",
|
||||||
"axum",
|
"axum",
|
||||||
] }
|
] }
|
||||||
revolt-files = { version = "0.7.18", path = "../../core/files" }
|
revolt-files = { version = "0.7.19", path = "../../core/files" }
|
||||||
|
|
||||||
# Axum / web server
|
# Axum / web server
|
||||||
axum = { version = "0.7.5" }
|
axum = { version = "0.7.5" }
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use axum::{extract::Query, response::IntoResponse, routing::get, Json, Router};
|
use axum::{extract::Query, response::IntoResponse, routing::get, Json, Router};
|
||||||
use reqwest::header;
|
use reqwest::header;
|
||||||
use revolt_result::Result;
|
use revolt_models::v0::Embed;
|
||||||
|
use revolt_result::{create_error, Result};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use utoipa::ToSchema;
|
use utoipa::ToSchema;
|
||||||
|
|
||||||
@@ -87,5 +88,9 @@ async fn embed(
|
|||||||
Query(UrlQuery { url }): Query<UrlQuery>,
|
Query(UrlQuery { url }): Query<UrlQuery>,
|
||||||
// TypedHeader(Authorization(_bearer)): TypedHeader<Authorization<Bearer>>,
|
// TypedHeader(Authorization(_bearer)): TypedHeader<Authorization<Bearer>>,
|
||||||
) -> Result<impl IntoResponse> {
|
) -> Result<impl IntoResponse> {
|
||||||
Request::generate_embed(url).await.map(Json)
|
match Request::generate_embed(url).await {
|
||||||
|
Ok(Embed::None) => Err(create_error!(NoEmbedData)),
|
||||||
|
result => result,
|
||||||
|
}
|
||||||
|
.map(Json)
|
||||||
}
|
}
|
||||||
@@ -156,8 +156,13 @@ pub async fn create_website_embed(original_url: &str, document: &str) -> Option<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove image if video exists
|
||||||
|
if metadata.video.is_some() {
|
||||||
|
metadata.image.take();
|
||||||
|
}
|
||||||
|
|
||||||
// fetch image size if missing
|
// fetch image size if missing
|
||||||
if metadata.special.is_none() && metadata.image.is_none() {
|
if metadata.special.is_none() {
|
||||||
if let Some(Image {
|
if let Some(Image {
|
||||||
width, height, url, ..
|
width, height, url, ..
|
||||||
}) = &metadata.image
|
}) = &metadata.image
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
- [Introduction](./hello.md)
|
- [Introduction](./hello.md)
|
||||||
- [Project Structure]()
|
- [Project Structure]()
|
||||||
|
- [Creating new API features](./new_features.md)
|
||||||
- [Testing]()
|
- [Testing]()
|
||||||
- [Writing a new database test]()
|
- [Writing a new database test]()
|
||||||
- [Writing a new API test]()
|
- [Writing a new API test]()
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# New API features
|
||||||
|
|
||||||
|
New API features must be documented where appropriate, this document aims to cover everywhere you need to update for new features.
|
||||||
|
|
||||||
|
Before writing new API features, generally a good idea to:
|
||||||
|
|
||||||
|
- Consult with other developers in the [Revolt Developers space](https://rvlt.gg/API)
|
||||||
|
- If it's a relatively big feature, also [write an RFC](https://github.com/revoltchat/rfcs)
|
||||||
|
|
||||||
|
When your feature is ready to release, ensure to:
|
||||||
|
|
||||||
|
- Update backend documentation (what you're reading now!) if applicable
|
||||||
|
- Update the [developers documentation](https://github.com/revoltchat/wiki) if applicable
|
||||||
|
- Update the Feature Matrix (or ask someone that can to do so)
|
||||||
|
- Ensure it is properly listed in the backend release changelog
|
||||||
Executable
+13
@@ -0,0 +1,13 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
cargo build \
|
||||||
|
--bin revolt-delta \
|
||||||
|
--bin revolt-bonfire \
|
||||||
|
--bin revolt-autumn \
|
||||||
|
--bin revolt-january
|
||||||
|
|
||||||
|
trap 'pkill -f revolt-' SIGINT
|
||||||
|
cargo run --bin revolt-delta &
|
||||||
|
cargo run --bin revolt-bonfire &
|
||||||
|
cargo run --bin revolt-autumn &
|
||||||
|
cargo run --bin revolt-january
|
||||||
Reference in new issue
Block a user