forked from jmug/stoatchat
Merge pull request #82 from revoltchat/rauth-v1
This commit is contained in:
@@ -9,14 +9,12 @@ use futures::StreamExt;
|
||||
use mongodb::options::UpdateOptions;
|
||||
use mongodb::{
|
||||
bson::{doc, to_bson, DateTime},
|
||||
options::FindOptions,
|
||||
};
|
||||
use rauth::entities::{Model, Session};
|
||||
use rocket::serde::json::Value;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ulid::Ulid;
|
||||
use web_push::{
|
||||
ContentEncoding, SubscriptionInfo, VapidSignatureBuilder, WebPushClient, WebPushMessageBuilder,
|
||||
};
|
||||
use web_push::{ContentEncoding, SubscriptionInfo, SubscriptionKeys, VapidSignatureBuilder, WebPushClient, WebPushMessageBuilder};
|
||||
use std::time::SystemTime;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
@@ -335,60 +333,47 @@ impl Message {
|
||||
}
|
||||
|
||||
// Fetch their corresponding sessions.
|
||||
if let Ok(mut cursor) = get_collection("accounts")
|
||||
.find(
|
||||
doc! {
|
||||
"_id": {
|
||||
"$in": target_ids
|
||||
},
|
||||
"sessions.subscription": {
|
||||
"$exists": true
|
||||
}
|
||||
},
|
||||
FindOptions::builder()
|
||||
.projection(doc! { "sessions": 1 })
|
||||
.build(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
let mut subscriptions = vec![];
|
||||
while let Some(result) = cursor.next().await {
|
||||
if let Ok(doc) = result {
|
||||
if let Ok(sessions) = doc.get_array("sessions") {
|
||||
for session in sessions {
|
||||
if let Some(doc) = session.as_document() {
|
||||
if let Ok(sub) = doc.get_document("subscription") {
|
||||
let endpoint = sub.get_str("endpoint").unwrap().to_string();
|
||||
let p256dh = sub.get_str("p256dh").unwrap().to_string();
|
||||
let auth = sub.get_str("auth").unwrap().to_string();
|
||||
|
||||
subscriptions
|
||||
.push(SubscriptionInfo::new(endpoint, p256dh, auth));
|
||||
}
|
||||
}
|
||||
if target_ids.len() > 0 {
|
||||
if let Ok(mut cursor) = Session::find(
|
||||
&get_db(),
|
||||
doc! {
|
||||
"_id": {
|
||||
"$in": target_ids
|
||||
},
|
||||
"subscription": {
|
||||
"$exists": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if subscriptions.len() > 0 {
|
||||
},
|
||||
None
|
||||
)
|
||||
.await {
|
||||
let enc = serde_json::to_string(&PushNotification::new(self, &c_clone).await).unwrap();
|
||||
let client = WebPushClient::new();
|
||||
let key =
|
||||
base64::decode_config(VAPID_PRIVATE_KEY.clone(), base64::URL_SAFE).unwrap();
|
||||
|
||||
for subscription in subscriptions {
|
||||
let mut builder = WebPushMessageBuilder::new(&subscription).unwrap();
|
||||
let sig_builder = VapidSignatureBuilder::from_pem(
|
||||
std::io::Cursor::new(&key),
|
||||
&subscription,
|
||||
)
|
||||
.unwrap();
|
||||
let signature = sig_builder.build().unwrap();
|
||||
builder.set_vapid_signature(signature);
|
||||
builder.set_payload(ContentEncoding::AesGcm, enc.as_bytes());
|
||||
let m = builder.build().unwrap();
|
||||
client.send(m).await.ok();
|
||||
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
|
||||
}
|
||||
};
|
||||
|
||||
let mut builder = WebPushMessageBuilder::new(&subscription).unwrap();
|
||||
let sig_builder = VapidSignatureBuilder::from_pem(
|
||||
std::io::Cursor::new(&key),
|
||||
&subscription,
|
||||
)
|
||||
.unwrap();
|
||||
let signature = sig_builder.build().unwrap();
|
||||
builder.set_vapid_signature(signature);
|
||||
builder.set_payload(ContentEncoding::AesGcm, enc.as_bytes());
|
||||
let m = builder.build().unwrap();
|
||||
client.send(m).await.ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -482,7 +467,7 @@ impl Message {
|
||||
let attachment_ids: Vec<String> =
|
||||
attachments.iter().map(|f| f.id.to_string()).collect();
|
||||
get_collection("attachments")
|
||||
.update_one(
|
||||
.update_many(
|
||||
doc! {
|
||||
"_id": {
|
||||
"$in": attachment_ids
|
||||
@@ -497,7 +482,7 @@ impl Message {
|
||||
)
|
||||
.await
|
||||
.map_err(|_| Error::DatabaseError {
|
||||
operation: "update_one",
|
||||
operation: "update_many",
|
||||
with: "attachment",
|
||||
})?;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::database::*;
|
||||
|
||||
use mongodb::bson::{doc, from_document};
|
||||
use rauth::auth::Session;
|
||||
use rauth::entities::Session;
|
||||
use rocket::http::Status;
|
||||
use rocket::request::{self, FromRequest, Outcome, Request};
|
||||
|
||||
@@ -15,7 +15,7 @@ impl<'r> FromRequest<'r> for User {
|
||||
.get("x-bot-token")
|
||||
.next()
|
||||
.map(|x| x.to_string());
|
||||
|
||||
|
||||
if let Some(bot_token) = header_bot_token {
|
||||
return if let Ok(result) = get_collection("bots")
|
||||
.find_one(
|
||||
@@ -40,7 +40,10 @@ impl<'r> FromRequest<'r> for User {
|
||||
if let Some(doc) = result {
|
||||
Outcome::Success(from_document(doc).unwrap())
|
||||
} else {
|
||||
Outcome::Failure((Status::Forbidden, rauth::util::Error::InvalidSession))
|
||||
Outcome::Failure((
|
||||
Status::Forbidden,
|
||||
rauth::util::Error::InvalidSession,
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Outcome::Failure((
|
||||
@@ -62,32 +65,34 @@ impl<'r> FromRequest<'r> for User {
|
||||
with: "bot",
|
||||
},
|
||||
))
|
||||
}
|
||||
};
|
||||
} else {
|
||||
let session: Session = request.guard::<Session>().await.unwrap();
|
||||
|
||||
if let Ok(result) = get_collection("users")
|
||||
.find_one(
|
||||
doc! {
|
||||
"_id": &session.user_id
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await
|
||||
{
|
||||
if let Some(doc) = result {
|
||||
Outcome::Success(from_document(doc).unwrap())
|
||||
if let Outcome::Success(session) = request.guard::<Session>().await {
|
||||
if let Ok(result) = get_collection("users")
|
||||
.find_one(
|
||||
doc! {
|
||||
"_id": &session.user_id
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await
|
||||
{
|
||||
if let Some(doc) = result {
|
||||
Outcome::Success(from_document(doc).unwrap())
|
||||
} else {
|
||||
Outcome::Failure((Status::Forbidden, rauth::util::Error::InvalidSession))
|
||||
}
|
||||
} else {
|
||||
Outcome::Failure((Status::Forbidden, rauth::util::Error::InvalidSession))
|
||||
Outcome::Failure((
|
||||
Status::InternalServerError,
|
||||
rauth::util::Error::DatabaseError {
|
||||
operation: "find_one",
|
||||
with: "user",
|
||||
},
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Outcome::Failure((
|
||||
Status::InternalServerError,
|
||||
rauth::util::Error::DatabaseError {
|
||||
operation: "find_one",
|
||||
with: "user",
|
||||
},
|
||||
))
|
||||
Outcome::Failure((Status::Forbidden, rauth::util::Error::InvalidSession))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,39 +71,6 @@ pub async fn create_database() {
|
||||
.await
|
||||
.expect("Failed to create pubsub collection.");
|
||||
|
||||
db.run_command(
|
||||
doc! {
|
||||
"createIndexes": "accounts",
|
||||
"indexes": [
|
||||
{
|
||||
"key": {
|
||||
"email": 1
|
||||
},
|
||||
"name": "email",
|
||||
"unique": true,
|
||||
"collation": {
|
||||
"locale": "en",
|
||||
"strength": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"key": {
|
||||
"email_normalised": 1
|
||||
},
|
||||
"name": "email_normalised",
|
||||
"unique": true,
|
||||
"collation": {
|
||||
"locale": "en",
|
||||
"strength": 2
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.expect("Failed to create account index.");
|
||||
|
||||
db.run_command(
|
||||
doc! {
|
||||
"createIndexes": "users",
|
||||
|
||||
@@ -10,10 +10,13 @@ pub async fn run_migrations() {
|
||||
.list_database_names(None, None)
|
||||
.await
|
||||
.expect("Failed to fetch database names.");
|
||||
|
||||
|
||||
if list.iter().position(|x| x == "revolt").is_none() {
|
||||
init::create_database().await;
|
||||
} else {
|
||||
scripts::migrate_database().await;
|
||||
}
|
||||
|
||||
// panic!("https://pbs.twimg.com/media/EDTpB5JWwAUvyxd.jpg");
|
||||
rauth::entities::sync_models(&super::get_db()).await;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use crate::database::{permissions, get_collection, get_db, PermissionTuple};
|
||||
|
||||
use futures::StreamExt;
|
||||
use log::info;
|
||||
use mongodb::{bson::{doc, from_document, to_document}, options::FindOptions};
|
||||
use mongodb::{bson::{Document, doc, from_bson, from_document, to_document}, options::FindOptions};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
@@ -11,7 +11,7 @@ struct MigrationInfo {
|
||||
revision: i32,
|
||||
}
|
||||
|
||||
pub const LATEST_REVISION: i32 = 8;
|
||||
pub const LATEST_REVISION: i32 = 9;
|
||||
|
||||
pub async fn migrate_database() {
|
||||
let migrations = get_collection("migrations");
|
||||
@@ -212,6 +212,80 @@ pub async fn run_migrations(revision: i32) -> i32 {
|
||||
.expect("Failed to create bots collection.");
|
||||
}
|
||||
|
||||
if revision <= 8 {
|
||||
info!("Running migration [revision 8 / 2021-09-10]: Update to rAuth version 1.");
|
||||
|
||||
get_db()
|
||||
.run_command(
|
||||
doc! {
|
||||
"dropIndexes": "accounts",
|
||||
"index": ["email", "email_normalised"]
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.expect("Failed to delete legacy account indexes.");
|
||||
|
||||
let col = get_collection("sessions");
|
||||
let mut cursor = get_collection("accounts")
|
||||
.find(doc! { }, None)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
while let Some(doc) = cursor.next().await {
|
||||
if let Ok(mut account) = doc {
|
||||
if let Some(sessions) = account.remove("sessions") {
|
||||
#[derive(Deserialize)]
|
||||
struct Session {
|
||||
id: String,
|
||||
token: String,
|
||||
friendly_name: String,
|
||||
subscription: Option<Document>,
|
||||
}
|
||||
|
||||
let sessions = from_bson::<Vec<Session>>(sessions).unwrap();
|
||||
for session in sessions {
|
||||
info!("Converting session {} to new format.", &session.id);
|
||||
|
||||
let mut doc = doc! {
|
||||
"_id": session.id,
|
||||
"token": session.token,
|
||||
"name": session.friendly_name,
|
||||
};
|
||||
|
||||
if let Some(sub) = session.subscription {
|
||||
doc.insert("subscription", sub);
|
||||
}
|
||||
|
||||
col.insert_one(doc, None).await.ok();
|
||||
}
|
||||
} else {
|
||||
info!("Account doesn't have any sessions!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get_collection("accounts")
|
||||
.update_many(
|
||||
doc! { },
|
||||
doc! {
|
||||
"$unset": {
|
||||
"sessions": 1,
|
||||
},
|
||||
"$set": {
|
||||
"mfa": {
|
||||
"recovery_codes": []
|
||||
}
|
||||
}
|
||||
},
|
||||
None
|
||||
)
|
||||
.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.
|
||||
LATEST_REVISION
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user