feat: update to rAuth v1

This commit is contained in:
Paul Makles
2022-06-04 18:20:38 +01:00
parent 020f2a1b1a
commit 7390b3c087
27 changed files with 596 additions and 1022 deletions

79
.env Normal file
View File

@@ -0,0 +1,79 @@
# MongoDB URI
MONGODB=mongodb://localhost
# URL to where the Revolt app is publicly accessible
REVOLT_APP_URL=http://local.revolt.chat:5000
# URL to where the API is publicly accessible
REVOLT_PUBLIC_URL=http://local.revolt.chat:8000
VITE_API_URL=http://local.revolt.chat:8000
# URL to where the WebSocket server is publicly accessible
REVOLT_EXTERNAL_WS_URL=ws://local.revolt.chat:9000
# URL to where Autumn is publicly available
AUTUMN_PUBLIC_URL=http://local.revolt.chat:3000
# URL to where January is publicly available
JANUARY_PUBLIC_URL=http://local.revolt.chat:7000
# URL to where Vortex is publicly available
# VOSO_PUBLIC_URL=https://voso.revolt.chat
##
## hCaptcha Settings
##
# If you are sure that you don't want to use hCaptcha, set to 1.
REVOLT_UNSAFE_NO_CAPTCHA=1
# hCaptcha API key
# REVOLT_HCAPTCHA_KEY=0x0000000000000000000000000000000000000000
# hCaptcha site key
# REVOLT_HCAPTCHA_SITEKEY=10000000-ffff-ffff-ffff-000000000001
##
## Email Settings
##
# If you are sure that you don't want to use email verification, set to 1.
REVOLT_UNSAFE_NO_EMAIL=1
# SMTP host
# REVOLT_SMTP_HOST=smtp.example.com
# SMTP username
# REVOLT_SMTP_USERNAME=noreply@example.com
# SMTP password
# REVOLT_SMTP_PASSWORD=CHANGEME
# SMTP From header
# REVOLT_SMTP_FROM=Revolt <noreply@example.com>
##
## Application Settings
##
# Whether to only allow users to sign up if they have an invite code
REVOLT_INVITE_ONLY=0
# Maximum number of people that can be in a group chat
REVOLT_MAX_GROUP_SIZE=150
# VAPID keys for push notifications
# Generate using this guide: https://gitlab.insrt.uk/revolt/delta/-/wikis/vapid
# --> Please replace these keys before going into production! <--
REVOLT_VAPID_PRIVATE_KEY=LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSUJSUWpyTWxLRnBiVWhsUHpUbERvcEliYk1yeVNrNXpKYzVYVzIxSjJDS3hvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFWnkrQkg2TGJQZ2hEa3pEempXOG0rUXVPM3pCajRXT1phdkR6ZU00c0pqbmFwd1psTFE0WAp1ZDh2TzVodU94QWhMQlU3WWRldVovWHlBdFpWZmNyQi9BPT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=
REVOLT_VAPID_PUBLIC_KEY=BGcvgR-i2z4IQ5Mw841vJvkLjt8wY-FjmWrw83jOLCY52qcGZS0OF7nfLzuYbjsQISwVO2HXrmf18gLWVX3Kwfw=
##
## Vortex configuration
##
# VOSO_MANAGE_TOKEN=CHANGEME

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
Rocket.toml
target
.data

1026
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -44,7 +44,6 @@ async-std = { version = "1.8.0", features = ["tokio1", "tokio02", "attributes"]
# internal util
lettre = "0.10.0-alpha.4"
rauth = { git = "https://github.com/insertish/rauth", rev = "001a9698c56cea79e69e4ae71d7bc2cb48aec1a6" }
# redis
redis = { version = "0.21.2", features = ["async-std-comp"] }
@@ -52,15 +51,15 @@ mobc = { version = "0.7.3" }
mobc-redis = { version = "0.7.0", default-features = false, features = ["async-std-comp"] }
# web
rocket_empty = { git = "https://github.com/insertish/rocket_empty", branch = "rc1" }
rocket = { version = "0.5.0-rc.1", default-features = false, features = ["json"] }
mongodb = { version = "1.2.2", features = ["async-std-runtime"], default-features = false }
rocket = { version = "0.5.0-rc.2", default-features = false, features = ["json"] }
rocket_empty = { git = "https://github.com/insertish/rocket_empty", branch = "master" }
rocket_rauth = { git = "https://github.com/insertish/rauth", rev = "a82cb5d23da4787e75d6f3c795189ce31e1590c4" }
rocket_cors = { git = "https://github.com/lawliet89/rocket_cors", rev = "5843861a88958c16bfaa0b40f0d8910772bcd2f6" }
# spec generation
schemars = "0.8.8"
# rocket_okapi = "0.8.0-rc.1"
rocket_okapi = { git = "https://github.com/insertish/okapi", rev = "dcf0df115596ee07a587a7a543cddf3d7944645b", features = [ "swagger" ] }
rocket_okapi = { git = "https://github.com/insertish/okapi", rev = "a1048d0c8cd771e424ec97d33d825c32e06aa120", features = [ "swagger" ] }
# quark
revolt-quark = { path = "../quark" }

View File

@@ -13,10 +13,10 @@ pub mod util;
pub mod version;
use log::info;
use rauth::{
config::{Captcha, Config, EmailVerification, SMTPSettings, Template, Templates},
logic::Auth,
use revolt_quark::rauth::config::{
Captcha, Config, EmailVerificationConfig, SMTPSettings, Template, Templates,
};
use revolt_quark::rauth::RAuth;
use revolt_quark::variables::delta::{
APP_URL, HCAPTCHA_KEY, INVITE_ONLY, SMTP_FROM, SMTP_HOST, SMTP_PASSWORD, SMTP_USERNAME,
USE_EMAIL, USE_HCAPTCHA,
@@ -25,8 +25,8 @@ use revolt_quark::DatabaseInfo;
use rocket_cors::AllowedOrigins;
use std::str::FromStr;
#[async_std::main]
async fn main() {
#[launch]
async fn rocket() -> _ {
let _guard = revolt_quark::setup_logging();
info!(
@@ -58,7 +58,7 @@ async fn main() {
let mut config = Config {
email_verification: if *USE_EMAIL {
EmailVerification::Enabled {
EmailVerificationConfig::Enabled {
smtp: SMTPSettings {
from: (*SMTP_FROM).to_string(),
host: (*SMTP_HOST).to_string(),
@@ -86,7 +86,7 @@ async fn main() {
},
}
} else {
EmailVerification::Disabled
EmailVerificationConfig::Disabled
},
..Default::default()
};
@@ -101,23 +101,20 @@ async fn main() {
};
}
// Setup database
let db = DatabaseInfo::Auto.connect().await.unwrap();
db.migrate_database().await.unwrap();
// This is entirely temporary code until rauth is migrated to quark.
// (and / or otherwise gets updated to MongoDB v2 driver)
let mongo_db = mongodb::Client::with_uri_str(
&std::env::var("MONGODB").unwrap_or_else(|_| "mongodb://localhost".to_string()),
)
.await
.expect("Failed to init db connection.");
rauth::entities::sync_models(&mongo_db.database("revolt")).await;
// Setup rAuth
let rauth = RAuth {
database: db.clone().into(),
config,
};
// Launch background task workers.
async_std::task::spawn(revolt_quark::tasks::start_workers(db.clone()));
let auth = Auth::new(mongo_db.database("revolt"), config);
// Configure Rocket
let rocket = rocket::build();
routes::mount(rocket)
.mount("/", rocket_cors::catch_all_options_routes())
@@ -129,14 +126,11 @@ async fn main() {
..Default::default()
}),
)
.manage(auth)
.manage(rauth)
.manage(db)
.manage(cors.clone())
.attach(util::ratelimiter::RatelimitFairing)
.attach(cors)
.launch()
.await
.unwrap();
}
/// Resolve asset

View File

@@ -25,8 +25,9 @@ pub fn mount(mut rocket: Rocket<Build>) -> Rocket<Build> {
"/channels" => channels::routes(),
"/servers" => servers::routes(),
"/invites" => invites::routes(),
"/auth/account" => rauth::web::account::routes(),
"/auth/session" => rauth::web::session::routes(),
"/auth/account" => rocket_rauth::routes::account::routes(),
"/auth/session" => rocket_rauth::routes::session::routes(),
"/auth/mfa" => rocket_rauth::routes::mfa::routes(),
"/onboard" => onboard::routes(),
"/push" => push::routes(),
"/sync" => sync::routes(),

View File

@@ -1,7 +1,6 @@
use crate::util::regex::RE_USERNAME;
use revolt_quark::{models::User, Database, EmptyResponse, Error, Result};
use revolt_quark::{models::User, rauth::models::Session, Database, EmptyResponse, Error, Result};
use rauth::entities::Session;
use rocket::{serde::json::Json, State};
use serde::{Deserialize, Serialize};
use validator::Validate;

View File

@@ -1,5 +1,4 @@
use rauth::entities::Session;
use revolt_quark::models::User;
use revolt_quark::{models::User, rauth::models::Session};
use rocket::serde::json::Json;
use serde::Serialize;

View File

@@ -1,9 +1,11 @@
use revolt_quark::{EmptyResponse, Error, Result};
use rauth::{
entities::{Model, Session, WebPushSubscription},
logic::Auth,
use revolt_quark::{
rauth::{
models::{Session, WebPushSubscription},
RAuth,
},
EmptyResponse, Error, Result,
};
use rocket::{serde::json::Json, State};
/// # Push Subscribe
@@ -14,13 +16,13 @@ use rocket::{serde::json::Json, State};
#[openapi(tag = "Web Push")]
#[post("/subscribe", data = "<data>")]
pub async fn req(
auth: &State<Auth>,
rauth: &State<RAuth>,
mut session: Session,
data: Json<WebPushSubscription>,
) -> Result<EmptyResponse> {
session.subscription = Some(data.into_inner());
session
.save(&auth.db, None)
.save(&rauth)
.await
.map(|_| EmptyResponse)
.map_err(|_| Error::DatabaseError {

View File

@@ -1,9 +1,8 @@
use revolt_quark::{EmptyResponse, Error, Result};
use rauth::{
entities::{Model, Session},
logic::Auth,
use revolt_quark::{
rauth::{models::Session, RAuth},
EmptyResponse, Error, Result,
};
use rocket::State;
/// # Unsubscribe
@@ -11,10 +10,10 @@ use rocket::State;
/// Remove the Web Push subscription associated with the current session.
#[openapi(tag = "Web Push")]
#[post("/unsubscribe")]
pub async fn req(auth: &State<Auth>, mut session: Session) -> Result<EmptyResponse> {
pub async fn req(rauth: &State<RAuth>, mut session: Session) -> Result<EmptyResponse> {
session.subscription = None;
session
.save(&auth.db, None)
.save(&rauth)
.await
.map(|_| EmptyResponse)
.map_err(|_| Error::DatabaseError {

View File

@@ -1,5 +1,5 @@
use revolt_quark::models::User;
use revolt_quark::r#impl::generic::users::user_settings::UserSettingsImpl;
use revolt_quark::r#impl::UserSettingsImpl;
use revolt_quark::{Db, EmptyResponse, Result};
use chrono::prelude::*;

View File

@@ -1,6 +1,5 @@
use crate::util::regex::RE_USERNAME;
use rauth::entities::Account;
use revolt_quark::{models::User, Database, Error, Result};
use revolt_quark::{models::User, rauth::models::Account, Database, Error, Result};
use rocket::{serde::json::Json, State};
use serde::{Deserialize, Serialize};
use validator::Validate;

View File

@@ -1,5 +1,4 @@
use async_std::sync::Mutex;
use mongodb::bson::doc;
use revolt_quark::{Error, Result};
use rocket::http::Status;
use rocket::request::{FromRequest, Outcome};

View File

@@ -8,6 +8,7 @@ use std::hash::Hasher;
use std::ops::Add;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use revolt_quark::rauth::models::Session;
use rocket::fairing::{Fairing, Info, Kind};
use rocket::http::uri::Origin;
use rocket::http::{Method, Status};
@@ -207,10 +208,9 @@ impl<'r> FromRequest<'r> for Ratelimiter {
let ratelimiter = request
.local_cache_async(async {
use rocket::outcome::Outcome;
let identifier = if let Outcome::Success(session) =
request.guard::<rauth::entities::Session>().await
let identifier = if let Outcome::Success(session) = request.guard::<Session>().await
{
session.id.expect("`id` on User")
session.id
} else {
to_real_ip(request)
};

View File

@@ -8,8 +8,9 @@ edition = "2021"
[features]
mongo = [ "mongodb" ]
rocket_impl = [ "rocket", "rocket_empty" ]
test = [ "async-std", "mongo", "mongodb/async-std-runtime", "rocket_impl", "rauth" ]
rocket_impl = [ "rocket", "rocket_empty", "rauth/database-mongodb", "rauth/rocket_impl", "rauth/okapi_impl" ]
test = [ "async-std", "mongo", "mongodb/async-std-runtime", "rocket_impl" ]
default = [ "test" ]
[dependencies]
@@ -26,8 +27,8 @@ bson = { version = "2.1.0", features = ["chrono-0_4"] }
# Spec Generation
schemars = "0.8.8"
okapi = { git = "https://github.com/insertish/okapi", rev = "dcf0df115596ee07a587a7a543cddf3d7944645b" }
rocket_okapi = { git = "https://github.com/insertish/okapi", rev = "dcf0df115596ee07a587a7a543cddf3d7944645b" }
okapi = { git = "https://github.com/insertish/okapi", rev = "a1048d0c8cd771e424ec97d33d825c32e06aa120" }
rocket_okapi = { git = "https://github.com/insertish/okapi", rev = "a1048d0c8cd771e424ec97d33d825c32e06aa120" }
# okapi = "0.7.0-rc.1"
# rocket_okapi = "0.8.0-rc.1"
@@ -63,10 +64,12 @@ base64 = "0.13.0"
web-push = "0.7.2"
# Implementations
rauth = { optional = true, git = "https://github.com/insertish/rauth", rev = "001a9698c56cea79e69e4ae71d7bc2cb48aec1a6" }
rocket = { optional = true, version = "=0.5.0-rc.1", default-features = false, features = ["json"] }
rocket_http = { optional = true, version = "=0.5.0-rc.1" }
rocket_empty = { optional = true, git = "https://github.com/insertish/rocket_empty", branch = "rc1" }
rocket_http = { optional = true, version = "0.5.0-rc.2" }
rocket = { optional = true, version = "0.5.0-rc.2", default-features = false, features = ["json"] }
rocket_empty = { optional = true, git = "https://github.com/insertish/rocket_empty", branch = "master" }
# rAuth
rauth = { git = "https://github.com/insertish/rauth", rev = "a82cb5d23da4787e75d6f3c795189ce31e1590c4", features = [ "async-std-runtime" ] }
# Sentry
sentry = "0.25.0"

View File

@@ -1,8 +1,7 @@
use std::env;
use std::ops::Deref;
use crate::r#impl::dummy::DummyDb;
use crate::r#impl::mongo::MongoDb;
use crate::r#impl::{DummyDb, MongoDb};
use crate::AbstractDatabase;
/// Database information to use to create a client
@@ -61,3 +60,14 @@ impl Deref for Database {
}
}
}
impl From<Database> for rauth::Database {
fn from(val: Database) -> Self {
match val {
Database::Dummy(_) => rauth::Database::default(),
Database::MongoDb(MongoDb(client)) => {
rauth::Database::MongoDb(rauth::database::MongoDb(client.database("revolt")))
}
}
}
}

View File

@@ -8,9 +8,6 @@ use crate::{perms, Database, Error, Result};
use futures::try_join;
use impl_ops::impl_op_ex_commutative;
use okapi::openapi3::{SecurityScheme, SecuritySchemeData};
use rocket_okapi::gen::OpenApiGenerator;
use rocket_okapi::request::{OpenApiFromRequest, RequestHeaderInput};
use std::ops;
impl_op_ex_commutative!(+ |a: &i32, b: &Badges| -> i32 { *a | *b as i32 });
@@ -359,72 +356,3 @@ impl User {
}
}
}
use rauth::entities::Session;
use rocket::http::Status;
use rocket::request::{self, FromRequest, Outcome, Request};
#[rocket::async_trait]
impl<'r> FromRequest<'r> for User {
type Error = rauth::util::Error;
async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
let user: &Option<User> = request
.local_cache_async(async {
let db = request
.rocket()
.state::<Database>()
.expect("Database state not reachable!");
let header_bot_token = request
.headers()
.get("x-bot-token")
.next()
.map(|x| x.to_string());
if let Some(bot_token) = header_bot_token {
if let Ok(user) = User::from_token(db, &bot_token, UserHint::Bot).await {
return Some(user);
}
} else if let Outcome::Success(session) = request.guard::<Session>().await {
// This uses a guard so can't really easily be refactored into from_token at this stage.
if let Ok(user) = db.fetch_user(&session.user_id).await {
return Some(user);
}
}
None
})
.await;
if let Some(user) = user {
Outcome::Success(user.clone())
} else {
Outcome::Failure((Status::Unauthorized, rauth::util::Error::InvalidSession))
}
}
}
impl<'r> OpenApiFromRequest<'r> for User {
fn from_request_input(
_gen: &mut OpenApiGenerator,
_name: String,
_required: bool,
) -> rocket_okapi::Result<RequestHeaderInput> {
let mut requirements = schemars::Map::new();
requirements.insert("Api Key".to_owned(), vec![]);
Ok(RequestHeaderInput::Security(
"Api Key".to_owned(),
SecurityScheme {
data: SecuritySchemeData::ApiKey {
name: "x-session-token".to_owned(),
location: "header".to_owned(),
},
description: Some("Session Token".to_owned()),
extensions: schemars::Map::new(),
},
requirements,
))
}
}

View File

@@ -1,3 +1,10 @@
pub mod dummy;
pub mod generic;
pub mod mongo;
mod dummy;
mod generic;
mod mongo;
#[cfg(feature = "rocket_impl")]
mod rocket;
pub use self::generic::users::user_settings::UserSettingsImpl;
pub use dummy::DummyDb;
pub use mongo::MongoDb;

View File

@@ -17,7 +17,7 @@ struct MigrationInfo {
revision: i32,
}
pub const LATEST_REVISION: i32 = 15;
pub const LATEST_REVISION: i32 = 16;
pub async fn migrate_database(db: &MongoDb) {
let migrations = db.col::<Document>("migrations");
@@ -603,6 +603,15 @@ pub async fn run_migrations(db: &MongoDb, revision: i32) -> i32 {
.unwrap();
}
if revision <= 15 {
info!("Running migration [revision 15 / 04-06-2022]: Migrate rAuth to latest version.");
let db = rauth::Database::MongoDb(rauth::database::MongoDb(db.db()));
db.run_migration(rauth::Migration::M2022_06_03EnsureUpToSpec)
.await
.unwrap();
}
// Need to migrate fields on attachments, change `user_id`, `object_id`, etc to `parent`.
// Reminder to update LATEST_REVISION when adding new migrations.

View File

@@ -0,0 +1,73 @@
use okapi::openapi3::{SecurityScheme, SecuritySchemeData};
use rauth::models::Session;
use rocket_okapi::gen::OpenApiGenerator;
use rocket_okapi::request::{OpenApiFromRequest, RequestHeaderInput};
use rocket::http::Status;
use rocket::request::{self, FromRequest, Outcome, Request};
use crate::models::user::UserHint;
use crate::models::User;
use crate::Database;
#[rocket::async_trait]
impl<'r> FromRequest<'r> for User {
type Error = rauth::Error;
async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
let user: &Option<User> = request
.local_cache_async(async {
let db = request.rocket().state::<Database>().expect("`Database`");
let header_bot_token = request
.headers()
.get("x-bot-token")
.next()
.map(|x| x.to_string());
if let Some(bot_token) = header_bot_token {
if let Ok(user) = User::from_token(db, &bot_token, UserHint::Bot).await {
return Some(user);
}
} else if let Outcome::Success(session) = request.guard::<Session>().await {
// This uses a guard so can't really easily be refactored into from_token at this stage.
if let Ok(user) = db.fetch_user(&session.user_id).await {
return Some(user);
}
}
None
})
.await;
if let Some(user) = user {
Outcome::Success(user.clone())
} else {
Outcome::Failure((Status::Unauthorized, rauth::Error::InvalidSession))
}
}
}
impl<'r> OpenApiFromRequest<'r> for User {
fn from_request_input(
_gen: &mut OpenApiGenerator,
_name: String,
_required: bool,
) -> rocket_okapi::Result<RequestHeaderInput> {
let mut requirements = schemars::Map::new();
requirements.insert("Api Key".to_owned(), vec![]);
Ok(RequestHeaderInput::Security(
"Api Key".to_owned(),
SecurityScheme {
data: SecuritySchemeData::ApiKey {
name: "x-session-token".to_owned(),
location: "header".to_owned(),
},
description: Some("Session Token".to_owned()),
extensions: schemars::Map::new(),
},
requirements,
))
}
}

View File

@@ -18,6 +18,7 @@ extern crate bitfield;
pub extern crate bson;
pub use iso8601_timestamp::Timestamp;
pub use rauth;
pub use redis_kiss;
pub mod events;
@@ -27,6 +28,9 @@ pub mod presence;
pub mod tasks;
pub mod types;
#[cfg(feature = "rocket_impl")]
pub mod web;
mod database;
mod permissions;
mod traits;
@@ -38,38 +42,11 @@ pub use traits::*;
pub use permissions::defn::*;
pub use permissions::{get_relationship, perms};
pub use util::r#ref::Ref;
pub use util::result::{Error, Result};
pub use util::variables;
pub use util::{
log::setup_logging,
r#ref::Ref,
result::{Error, Result},
variables,
};
#[cfg(feature = "rocket_impl")]
pub use rocket_empty::EmptyResponse;
#[cfg(feature = "rocket_impl")]
use rocket::State;
#[cfg(feature = "rocket_impl")]
pub type Db = State<Database>;
/// Configure logging and common Rust variables
pub fn setup_logging() -> sentry::ClientInitGuard {
dotenv::dotenv().ok();
if std::env::var("RUST_LOG").is_err() {
std::env::set_var("RUST_LOG", "info");
}
if std::env::var("ROCKET_ADDRESS").is_err() {
std::env::set_var("ROCKET_ADDRESS", "0.0.0.0");
}
pretty_env_logger::init();
sentry::init((
"https://62fd0e02c5354905b4e286757f4beb16@sentry.insert.moe/4",
sentry::ClientOptions {
release: sentry::release_name!(),
..Default::default()
},
))
}
pub use web::{Db, EmptyResponse};

View File

@@ -18,7 +18,7 @@ pub async fn start_workers(db: Database) {
task::spawn(ack::worker(db.clone()));
task::spawn(last_message_id::worker(db.clone()));
task::spawn(process_embeds::worker(db.clone()));
task::spawn(web_push::worker(db.clone()));
task::spawn(web_push::worker(db.clone().into()));
}
}

View File

@@ -1,9 +1,8 @@
use crate::bson::doc;
use crate::util::variables::delta::VAPID_PRIVATE_KEY;
use crate::{bson::doc, r#impl::mongo::MongoDb, Database};
use deadqueue::limited::Queue;
use futures::StreamExt;
use rauth::entities::Session;
use rauth::Database;
use web_push::{
ContentEncoding, SubscriptionInfo, SubscriptionKeys, VapidSignatureBuilder, WebPushClient,
WebPushMessageBuilder,
@@ -43,90 +42,69 @@ pub async fn worker(db: Database) {
let key = base64::decode_config(VAPID_PRIVATE_KEY.clone(), base64::URL_SAFE)
.expect("valid `VAPID_PRIVATE_KEY`");
if let Database::MongoDb(MongoDb(db)) = db {
loop {
let task = Q.pop().await;
loop {
let task = Q.pop().await;
// ! FIXME: this is hard-coded until rauth is merged into quark
if let Ok(mut cursor) = db
.database("revolt")
.collection::<Session>("sessions")
.find(
doc! {
"user_id": {
"$in": task.recipients
if let Ok(sessions) = db.find_sessions_with_subscription(&task.recipients).await {
for session in sessions {
if let Some(sub) = session.subscription {
let subscription = SubscriptionInfo {
endpoint: sub.endpoint,
keys: SubscriptionKeys {
auth: sub.auth,
p256dh: sub.p256dh,
},
"subscription": {
"$exists": true
}
},
None,
)
.await
{
while let Some(Ok(session)) = cursor.next().await {
if let Some(sub) = session.subscription {
let subscription = SubscriptionInfo {
endpoint: sub.endpoint,
keys: SubscriptionKeys {
auth: sub.auth,
p256dh: sub.p256dh,
},
};
};
match WebPushMessageBuilder::new(&subscription) {
Ok(mut builder) => {
match VapidSignatureBuilder::from_pem(
std::io::Cursor::new(&key),
&subscription,
) {
Ok(sig_builder) => match sig_builder.build() {
Ok(signature) => {
builder.set_vapid_signature(signature);
builder.set_payload(
ContentEncoding::AesGcm,
task.payload.as_bytes(),
);
match WebPushMessageBuilder::new(&subscription) {
Ok(mut builder) => {
match VapidSignatureBuilder::from_pem(
std::io::Cursor::new(&key),
&subscription,
) {
Ok(sig_builder) => match sig_builder.build() {
Ok(signature) => {
builder.set_vapid_signature(signature);
builder.set_payload(
ContentEncoding::AesGcm,
task.payload.as_bytes(),
);
match builder.build() {
Ok(msg) => match client.send(msg).await {
Ok(_) => {
info!(
"Sent Web Push notification to {:?}.",
session.id
)
}
Err(err) => {
error!(
"Hit error sending Web Push! {:?}",
err
)
}
},
Err(err) => {
error!(
"Failed to build message for {}! {:?}",
session.user_id, err
match builder.build() {
Ok(msg) => match client.send(msg).await {
Ok(_) => {
info!(
"Sent Web Push notification to {:?}.",
session.id
)
}
Err(err) => {
error!("Hit error sending Web Push! {:?}", err)
}
},
Err(err) => {
error!(
"Failed to build message for {}! {:?}",
session.user_id, err
)
}
}
Err(err) => error!(
"Failed to build signature for {}! {:?}",
session.user_id, err
),
},
}
Err(err) => error!(
"Failed to create signature builder for {}! {:?}",
"Failed to build signature for {}! {:?}",
session.user_id, err
),
}
},
Err(err) => error!(
"Failed to create signature builder for {}! {:?}",
session.user_id, err
),
}
Err(err) => error!(
"Invalid subscription information for {}! {:?}",
session.user_id, err
),
}
Err(err) => error!(
"Invalid subscription information for {}! {:?}",
session.user_id, err
),
}
}
}

View File

@@ -0,0 +1,22 @@
/// Configure logging and common Rust variables
pub fn setup_logging() -> sentry::ClientInitGuard {
dotenv::dotenv().ok();
if std::env::var("RUST_LOG").is_err() {
std::env::set_var("RUST_LOG", "info");
}
if std::env::var("ROCKET_ADDRESS").is_err() {
std::env::set_var("ROCKET_ADDRESS", "0.0.0.0");
}
pretty_env_logger::init();
sentry::init((
"https://62fd0e02c5354905b4e286757f4beb16@sentry.insert.moe/4",
sentry::ClientOptions {
release: sentry::release_name!(),
..Default::default()
},
))
}

View File

@@ -1,3 +1,4 @@
pub mod log;
pub mod manipulation;
pub mod r#ref;
pub mod result;

View File

@@ -0,0 +1,5 @@
use crate::Database;
use rocket::State;
pub use rocket_empty::EmptyResponse;
pub type Db = State<Database>;

12
docker-compose.yml Normal file
View File

@@ -0,0 +1,12 @@
version: "3.3"
services:
redis:
image: eqalpha/keydb
ports:
- "6379:6379"
database:
image: mongo
ports:
- "27017:27017"
volumes:
- ./.data/db:/data/db