move towards using #[rocket::async_trait]

this also upgrades some dependencies
some of that fixes stuff, others breaks stuff.
This commit is contained in:
Igor Galić 2020-05-15 22:38:21 +02:00
parent 097d0ea9ce
commit 3c830ab0ce
No known key found for this signature in database
GPG Key ID: ACFEFF7F6A123A86
21 changed files with 314 additions and 291 deletions

1
.gitignore vendored
View File

@ -18,3 +18,4 @@ tags.*
search_index
.buildconfig
__pycache__
.vscode/

79
Cargo.lock generated
View File

@ -6,7 +6,7 @@ version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bfd311e7b4102971757a2a6f143a93b1a8e6b5afc2c46936af827fd9eab403f"
dependencies = [
"activitystreams-derive",
"activitystreams-derive 0.1.1",
"activitystreams-traits",
"activitystreams-types",
"serde",
@ -25,6 +25,17 @@ dependencies = [
"syn 0.13.11",
]
[[package]]
name = "activitystreams-derive"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65608fdeae5eb05485d5b71a3d2242d76b2b7413608c196d47eb4dff3eed7b85"
dependencies = [
"proc-macro2 1.0.12",
"quote 1.0.4",
"syn 1.0.19",
]
[[package]]
name = "activitystreams-traits"
version = "0.1.0"
@ -42,7 +53,7 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff74c5765278614a009f97b9ec12f9a7c732bbcc5e0337fcfcab619b784860ec"
dependencies = [
"activitystreams-derive",
"activitystreams-derive 0.1.1",
"activitystreams-traits",
"chrono",
"mime 0.3.16",
@ -142,7 +153,7 @@ checksum = "da71fef07bc806586090247e971229289f64c210a278ee5ae419314eb386b31d"
dependencies = [
"proc-macro2 1.0.12",
"quote 1.0.4",
"syn 1.0.18",
"syn 1.0.19",
]
[[package]]
@ -746,7 +757,7 @@ dependencies = [
"bitflags 1.2.1",
"proc-macro2 1.0.12",
"quote 1.0.4",
"syn 1.0.18",
"syn 1.0.19",
]
[[package]]
@ -784,7 +795,7 @@ checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3"
dependencies = [
"proc-macro2 1.0.12",
"quote 1.0.4",
"syn 1.0.18",
"syn 1.0.19",
]
[[package]]
@ -978,7 +989,7 @@ checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
dependencies = [
"proc-macro2 1.0.12",
"quote 1.0.4",
"syn 1.0.18",
"syn 1.0.19",
"synstructure",
]
@ -993,9 +1004,9 @@ dependencies = [
[[package]]
name = "filetime"
version = "0.2.9"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f59efc38004c988e4201d11d263b8171f49a2e7ec0bdbb71773433f271504a5e"
checksum = "affc17579b132fc2461adf7c575cc6e8b134ebca52c51f5411388965227dc695"
dependencies = [
"cfg-if",
"libc",
@ -1179,7 +1190,7 @@ dependencies = [
"proc-macro-hack 0.5.15",
"proc-macro2 1.0.12",
"quote 1.0.4",
"syn 1.0.18",
"syn 1.0.19",
]
[[package]]
@ -1829,7 +1840,7 @@ dependencies = [
"migrations_internals",
"proc-macro2 1.0.12",
"quote 1.0.4",
"syn 1.0.18",
"syn 1.0.19",
]
[[package]]
@ -2171,9 +2182,9 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
[[package]]
name = "openssl-sys"
version = "0.9.55"
version = "0.9.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7717097d810a0f2e2323f9e5d11e71608355e24828410b55b9d4f18aa5f9a5d8"
checksum = "f02309a7f127000ed50594f0b50ecc69e7c654e16d41b4e8156d1b3df8e0b52e"
dependencies = [
"autocfg 1.0.0",
"cc",
@ -2354,29 +2365,29 @@ dependencies = [
[[package]]
name = "pin-project"
version = "0.4.10"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36e3dcd42688c05a66f841d22c5d8390d9a5d4c9aaf57b9285eae4900a080063"
checksum = "82c3bfbfb5bb42f99498c7234bbd768c220eb0cea6818259d0d18a1aa3d2595d"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "0.4.10"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4d7346ac577ff1296e06a418e7618e22655bae834d4970cb6e39d6da8119969"
checksum = "ccbf6449dcfb18562c015526b085b8df1aa3cdab180af8ec2ebd300a3bd28f63"
dependencies = [
"proc-macro2 1.0.12",
"quote 1.0.4",
"syn 1.0.18",
"syn 1.0.19",
]
[[package]]
name = "pin-project-lite"
version = "0.1.4"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "237844750cfbb86f67afe27eee600dfbbcb6188d734139b534cbfbf4f96792ae"
checksum = "f7505eeebd78492e0f6108f7171c4948dbb120ee8119d9d77d0afa5469bef67f"
[[package]]
name = "pin-utils"
@ -2435,7 +2446,6 @@ dependencies = [
"rpassword",
"rsass",
"ructe",
"runtime-fmt",
"scheduled-thread-pool",
"serde",
"serde_json",
@ -2472,7 +2482,7 @@ name = "plume-common"
version = "0.4.0"
dependencies = [
"activitypub",
"activitystreams-derive",
"activitystreams-derive 0.2.0",
"activitystreams-traits",
"array_tool",
"base64 0.10.1",
@ -3066,7 +3076,7 @@ dependencies = [
[[package]]
name = "rocket_i18n"
version = "0.5.0"
source = "git+https://github.com/Plume-org/rocket_i18n?branch=go-async#a6c8cfb3c516d857493d938ec0c89e7bd0c29cad"
source = "git+https://github.com/Plume-org/rocket_i18n?branch=go-async#6ff7e2a7dd6dfc730478433f881300f36930ff52"
dependencies = [
"gettext 0.4.0",
"rocket",
@ -3108,15 +3118,6 @@ dependencies = [
"nom 5.1.1",
]
[[package]]
name = "runtime-fmt"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "703425f78450961e590726ac24d823e6dc2340dc18282cf0cb6a417b26ca2ce8"
dependencies = [
"unicode-xid 0.2.0",
]
[[package]]
name = "rust-stemmers"
version = "1.2.0"
@ -3266,7 +3267,7 @@ checksum = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c"
dependencies = [
"proc-macro2 1.0.12",
"quote 1.0.4",
"syn 1.0.18",
"syn 1.0.19",
]
[[package]]
@ -3326,7 +3327,7 @@ dependencies = [
"itertools",
"proc-macro2 1.0.12",
"quote 1.0.4",
"syn 1.0.18",
"syn 1.0.19",
]
[[package]]
@ -3339,7 +3340,7 @@ dependencies = [
"itertools",
"proc-macro2 1.0.12",
"quote 1.0.4",
"syn 1.0.18",
"syn 1.0.19",
]
[[package]]
@ -3561,9 +3562,9 @@ dependencies = [
[[package]]
name = "syn"
version = "1.0.18"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "410a7488c0a728c7ceb4ad59b9567eb4053d02e8cc7f5c0e0eeeb39518369213"
checksum = "e8e5aa70697bb26ee62214ae3288465ecec0000f05182f039b477001f08f5ae7"
dependencies = [
"proc-macro2 1.0.12",
"quote 1.0.4",
@ -3587,7 +3588,7 @@ checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
dependencies = [
"proc-macro2 1.0.12",
"quote 1.0.4",
"syn 1.0.18",
"syn 1.0.19",
"unicode-xid 0.2.0",
]
@ -4069,7 +4070,7 @@ dependencies = [
"log 0.4.8",
"proc-macro2 1.0.12",
"quote 1.0.4",
"syn 1.0.18",
"syn 1.0.19",
"wasm-bindgen-shared",
]
@ -4103,7 +4104,7 @@ checksum = "8eb197bd3a47553334907ffd2f16507b4f4f01bbec3ac921a7719e0decdfe72a"
dependencies = [
"proc-macro2 1.0.12",
"quote 1.0.4",
"syn 1.0.18",
"syn 1.0.19",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]

View File

@ -23,7 +23,6 @@ num_cpus = "1.10"
rocket = { git = "https://github.com/SergioBenitez/Rocket", rev = "async" }
rocket_contrib = { git = "https://github.com/SergioBenitez/Rocket", rev = "async" , features = ["json"] }
rpassword = "4.0"
runtime-fmt = "0.4.0"
scheduled-thread-pool = "0.2.2"
serde = "1.0"
serde_json = "1.0"

View File

@ -6,7 +6,7 @@ edition = "2018"
[dependencies]
activitypub = "0.1.1"
activitystreams-derive = "0.1.1"
activitystreams-derive = "0.2"
activitystreams-traits = "0.1.0"
array_tool = "1.0"
base64 = "0.10"

View File

@ -3,8 +3,8 @@ use array_tool::vec::Uniq;
use reqwest::ClientBuilder;
use rocket::{
http::Status,
request::{FromRequestAsync, FromRequestFuture, Request},
response::{Responder, Response, ResultFuture},
request::{FromRequest, Request},
response::{Responder, Response, Result},
Outcome,
};
use serde_json;
@ -61,42 +61,36 @@ impl<T> ActivityStream<T> {
ActivityStream(t)
}
}
#[rocket::async_trait]
impl<'r, O: Object + Send + 'r> Responder<'r> for ActivityStream<O> {
fn respond_to(self, request: &'r Request<'_>) -> ResultFuture<'r> {
Box::pin(async move {
let mut json =
serde_json::to_value(&self.0).map_err(|_| Status::InternalServerError)?;
json["@context"] = context();
let result = serde_json::to_string(&json).map_err(rocket::response::Debug);
match result.respond_to(request).await {
Ok(r) => {
Response::build_from(r)
.raw_header("Content-Type", "application/activity+json")
.ok()
.await
}
Err(e) => Err(e),
}
})
async fn respond_to(self, request: &'r Request<'_>) -> Result<'r> {
let mut json = serde_json::to_value(&self.0).map_err(|_| Status::InternalServerError)?;
json["@context"] = context();
let result = serde_json::to_string(&json).map_err(rocket::response::Debug);
match result.respond_to(request).await {
Ok(r) => Response::build_from(r)
.raw_header("Content-Type", "application/activity+json")
.ok(),
Err(e) => Err(e),
}
}
}
#[derive(Clone)]
pub struct ApRequest;
impl<'a, 'r> FromRequestAsync<'a, 'r> for ApRequest {
#[rocket::async_trait]
impl<'a, 'r> FromRequest<'a, 'r> for ApRequest {
type Error = ();
fn from_request(request: &'a Request<'r>) -> FromRequestFuture<'a, Self, Self::Error> {
Box::pin(async move {
request
.headers()
.get_one("Accept")
.map(|header| {
header
.split(',')
.map(|ct| {
match ct.trim() {
async fn from_request(request: &'a Request<'r>) -> Outcome<Self, (Status, Self::Error), ()> {
request
.headers()
.get_one("Accept")
.map(|header| {
header
.split(',')
.map(|ct| {
match ct.trim() {
// bool for Forward: true if found a valid Content-Type for Plume first (HTML),
// false otherwise
"application/ld+json; profile=\"https://w3.org/ns/activitystreams\""
@ -106,18 +100,17 @@ impl<'a, 'r> FromRequestAsync<'a, 'r> for ApRequest {
"text/html" => Outcome::Forward(true),
_ => Outcome::Forward(false),
}
})
.fold(Outcome::Forward(false), |out, ct| {
if out.clone().forwarded().unwrap_or_else(|| out.is_success()) {
out
} else {
ct
}
})
.map_forward(|_| ())
})
.unwrap_or(Outcome::Forward(()))
})
})
.fold(Outcome::Forward(false), |out, ct| {
if out.clone().forwarded().unwrap_or_else(|| out.is_success()) {
out
} else {
ct
}
})
.map_forward(|_| ())
})
.unwrap_or(Outcome::Forward(()))
}
}
pub fn broadcast<S, A, T, C>(sender: &S, act: A, to: Vec<T>)
@ -217,8 +210,7 @@ pub struct PublicKey {
pub public_key_pem: Option<serde_json::Value>,
}
#[derive(Clone, Debug, Default, UnitString)]
#[activitystreams(Hashtag)]
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct HashtagType;
#[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)]

View File

@ -1,42 +1,40 @@
use crate::users::User;
use rocket::{
http::Status,
request::{self, FromRequestAsync, Request},
request::{self, FromRequest, Request},
Outcome,
};
/// Wrapper around User to use as a request guard on pages reserved to admins.
pub struct Admin(pub User);
impl<'a, 'r> FromRequestAsync<'a, 'r> for Admin {
#[rocket::async_trait]
impl<'a, 'r> FromRequest<'a, 'r> for Admin {
type Error = ();
fn from_request(request: &'a Request<'r>) -> request::FromRequestFuture<'a, Self, Self::Error> {
Box::pin(async move {
let user = try_outcome!(User::from_request(request).await);
if user.is_admin() {
Outcome::Success(Admin(user))
} else {
Outcome::Failure((Status::Unauthorized, ()))
}
})
async fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
let user = try_outcome!(User::from_request(request).await);
if user.is_admin() {
Outcome::Success(Admin(user))
} else {
Outcome::Failure((Status::Unauthorized, ()))
}
}
}
/// Same as `Admin` but for moderators.
pub struct Moderator(pub User);
impl<'a, 'r> FromRequestAsync<'a, 'r> for Moderator {
#[rocket::async_trait]
impl<'a, 'r> FromRequest<'a, 'r> for Moderator {
type Error = ();
fn from_request(request: &'a Request<'r>) -> request::FromRequestFuture<'a, Self, Self::Error> {
Box::pin(async move {
let user = try_outcome!(User::from_request(request).await);
if user.is_moderator() {
Outcome::Success(Moderator(user))
} else {
Outcome::Failure((Status::Unauthorized, ()))
}
})
async fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
let user = try_outcome!(User::from_request(request).await);
if user.is_moderator() {
Outcome::Success(Moderator(user))
} else {
Outcome::Failure((Status::Unauthorized, ()))
}
}
}

View File

@ -3,7 +3,7 @@ use chrono::NaiveDateTime;
use diesel::{self, ExpressionMethods, QueryDsl, RunQueryDsl};
use rocket::{
http::Status,
request::{self, FromRequestAsync, Request},
request::{self, FromRequest, Request},
Outcome,
};
@ -76,39 +76,38 @@ pub enum TokenError {
DbError,
}
impl<'a, 'r> FromRequestAsync<'a, 'r> for ApiToken {
#[rocket::async_trait]
impl<'a, 'r> FromRequest<'a, 'r> for ApiToken {
type Error = TokenError;
fn from_request(request: &'a Request<'r>) -> request::FromRequestFuture<'a, Self, Self::Error> {
Box::pin(async move {
let headers: Vec<_> = request.headers().get("Authorization").collect();
if headers.len() != 1 {
return Outcome::Failure((Status::BadRequest, TokenError::NoHeader));
}
async fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
let headers: Vec<_> = request.headers().get("Authorization").collect();
if headers.len() != 1 {
return Outcome::Failure((Status::BadRequest, TokenError::NoHeader));
}
let mut parsed_header = headers[0].split(' ');
if let Some(auth_type) = parsed_header.next() {
if let Some(val) = parsed_header.next() {
if auth_type == "Bearer" {
if let Outcome::Success(conn) = DbConn::from_request(request).await {
if let Ok(token) = ApiToken::find_by_value(&*conn, val) {
return Outcome::Success(token);
}
} else {
return Outcome::Failure((
Status::InternalServerError,
TokenError::DbError,
));
let mut parsed_header = headers[0].split(' ');
if let Some(auth_type) = parsed_header.next() {
if let Some(val) = parsed_header.next() {
if auth_type == "Bearer" {
if let Outcome::Success(conn) = DbConn::from_request(request).await {
if let Ok(token) = ApiToken::find_by_value(&*conn, val) {
return Outcome::Success(token);
}
} else {
return Outcome::Failure((
Status::InternalServerError,
TokenError::DbError,
));
}
} else {
return Outcome::Failure((Status::BadRequest, TokenError::NoValue));
}
} else {
return Outcome::Failure((Status::BadRequest, TokenError::NoType));
return Outcome::Failure((Status::BadRequest, TokenError::NoValue));
}
} else {
return Outcome::Failure((Status::BadRequest, TokenError::NoType));
}
Outcome::Forward(())
})
Outcome::Forward(())
}
}

View File

@ -6,7 +6,7 @@ use diesel::r2d2::{
use diesel::{dsl::sql_query, ConnectionError, RunQueryDsl};
use rocket::{
http::Status,
request::{self, FromRequestAsync},
request::{self, FromRequest},
Outcome, Request,
};
use std::ops::Deref;
@ -21,16 +21,15 @@ pub struct DbConn(pub PooledConnection<ConnectionManager<Connection>>);
/// Attempts to retrieve a single connection from the managed database pool. If
/// no pool is currently managed, fails with an `InternalServerError` status. If
/// no connections are available, fails with a `ServiceUnavailable` status.
impl<'a, 'r> FromRequestAsync<'a, 'r> for DbConn {
#[rocket::async_trait]
impl<'a, 'r> FromRequest<'a, 'r> for DbConn {
type Error = ();
fn from_request(request: &'a Request<'r>) -> request::FromRequestFuture<'a, Self, Self::Error> {
Box::pin(async move {
match DbConn::from_request(request).await {
Outcome::Success(a) => return Outcome::Success(a),
_ => return Outcome::Failure((Status::ServiceUnavailable, ())),
};
})
async fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
match DbConn::from_request(request).await {
Outcome::Success(a) => return Outcome::Success(a),
_ => return Outcome::Failure((Status::ServiceUnavailable, ())),
};
}
}

View File

@ -6,10 +6,11 @@ use rocket::{
pub struct Headers<'r>(pub HeaderMap<'r>);
#[rocket::async_trait]
impl<'a, 'r> FromRequest<'a, 'r> for Headers<'r> {
type Error = ();
fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, ()> {
async fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, ()> {
let mut headers = HeaderMap::new();
for header in request.headers().clone().into_iter() {
headers.add(header);

View File

@ -4,7 +4,7 @@ pub use self::module::PlumeRocket;
mod module {
use crate::{db_conn::DbConn, search, users};
use rocket::{
request::{self, FlashMessage, FromRequestAsync, Request},
request::{self, FlashMessage, FromRequest, Request},
Outcome, State,
};
use scheduled_thread_pool::ScheduledThreadPool;
@ -20,29 +20,38 @@ mod module {
pub flash_msg: Option<(String, String)>,
}
impl<'a, 'r> FromRequestAsync<'a, 'r> for PlumeRocket {
#[rocket::async_trait]
impl<'a, 'r> FromRequest<'a, 'r> for PlumeRocket {
type Error = ();
fn from_request(
request: &'a Request<'r>,
) -> request::FromRequestFuture<'a, Self, Self::Error> {
Box::pin(async move {
let conn = try_outcome!(DbConn::from_request(request).await);
let intl = try_outcome!(rocket_i18n::I18n::from_request(request).await);
let user = try_outcome!(users::User::from_request(request).await);
let worker =
try_outcome!(request.guard::<'_, State<'_, Arc<ScheduledThreadPool>>>());
let searcher =
try_outcome!(request.guard::<'_, State<'_, Arc<search::Searcher>>>());
let flash_msg = request.guard::<FlashMessage<'_, '_>>().succeeded();
Outcome::Success(PlumeRocket {
conn,
intl,
user: Some(user),
flash_msg: flash_msg.map(|f| (f.name().into(), f.msg().into())),
worker: worker.clone(),
searcher: searcher.clone(),
})
async fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
let conn = DbConn::from_request(request).await.succeeded().unwrap();
let intl = rocket_i18n::I18n::from_request(request)
.await
.succeeded()
.unwrap();
let user = users::User::from_request(request)
.await
.succeeded()
.unwrap();
let worker = request
.guard::<State<'_, Arc<ScheduledThreadPool>>>()
.await
.succeeded()
.unwrap();
let searcher = request
.guard::<State<'_, Arc<search::Searcher>>>()
.await
.succeeded()
.unwrap();
let flash_msg = request.guard::<FlashMessage<'_, '_>>().await.succeeded();
Outcome::Success(PlumeRocket {
conn,
intl,
user: Some(user),
flash_msg: flash_msg.map(|f| (f.name().into(), f.msg().into())),
worker: worker.clone(),
searcher: searcher.clone(),
})
}
}
@ -52,7 +61,7 @@ mod module {
mod module {
use crate::{db_conn::DbConn, search, users};
use rocket::{
request::{self, FromRequestAsync, Request},
request::{self, FromRequest, Request},
Outcome, State,
};
use scheduled_thread_pool::ScheduledThreadPool;
@ -66,25 +75,20 @@ mod module {
pub worker: Arc<ScheduledThreadPool>,
}
impl<'a, 'r> FromRequestAsync<'a, 'r> for PlumeRocket {
#[rocket::async_trait]
impl<'a, 'r> FromRequest<'a, 'r> for PlumeRocket {
type Error = ();
fn from_request(
request: &'a Request<'r>,
) -> request::FromRequestFuture<'a, Self, Self::Error> {
Box::pin(async move {
let conn = try_outcome!(DbConn::from_request(request).await);
let user = try_outcome!(users::User::from_request(request).await);
let worker =
try_outcome!(request.guard::<'_, State<'_, Arc<ScheduledThreadPool>>>());
let searcher =
try_outcome!(request.guard::<'_, State<'_, Arc<search::Searcher>>>());
Outcome::Success(PlumeRocket {
conn,
user: Some(user),
worker: worker.clone(),
searcher: searcher.clone(),
})
async fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
let conn = try_outcome!(DbConn::from_request(request).await);
let user = try_outcome!(users::User::from_request(request).await);
let worker = try_outcome!(request.guard::<'_, State<'_, Arc<ScheduledThreadPool>>>());
let searcher = try_outcome!(request.guard::<'_, State<'_, Arc<search::Searcher>>>());
Outcome::Success(PlumeRocket {
conn,
user: Some(user),
worker: worker.clone(),
searcher: searcher.clone(),
})
}
}

View File

@ -35,7 +35,7 @@ use reqwest::{
};
use rocket::{
outcome::IntoOutcome,
request::{self, FromRequestAsync, Request},
request::{self, FromRequest, Request},
};
use serde_json;
use std::{
@ -796,19 +796,18 @@ impl User {
}
}
impl<'a, 'r> FromRequestAsync<'a, 'r> for User {
#[rocket::async_trait]
impl<'a, 'r> FromRequest<'a, 'r> for User {
type Error = ();
fn from_request(request: &'a Request<'r>) -> request::FromRequestFuture<'a, Self, Self::Error> {
Box::pin(async move {
let conn = try_outcome!(DbConn::from_request(request).await);
request
.cookies()
.get_private(AUTH_COOKIE)
.and_then(|cookie| cookie.value().parse().ok())
.and_then(|id| User::get(&*conn, id).ok())
.or_forward(())
})
async fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
let conn = try_outcome!(DbConn::from_request(request).await);
request
.cookies()
.get_private(AUTH_COOKIE)
.and_then(|cookie| cookie.value().parse().ok())
.and_then(|id| User::get(&*conn, id).ok())
.or_forward(())
}
}

View File

@ -1 +1 @@
nightly-2020-01-15
nightly-2020-05-05

View File

@ -35,6 +35,7 @@ impl Scope for plume_models::posts::Post {
pub struct Authorization<A, S>(pub ApiToken, PhantomData<(A, S)>);
#[rocket::async_trait]
impl<'a, 'r, A, S> FromRequest<'a, 'r> for Authorization<A, S>
where
A: Action,
@ -42,9 +43,10 @@ where
{
type Error = ();
fn from_request(request: &'a Request<'r>) -> request::Outcome<Authorization<A, S>, ()> {
async fn from_request(request: &'a Request<'r>) -> request::Outcome<Authorization<A, S>, ()> {
request
.guard::<ApiToken>()
.await
.map_failure(|_| (Status::Unauthorized, ()))
.and_then(|token| {
if token.can(A::to_str(), S::to_str()) {

View File

@ -2,6 +2,7 @@
use rocket::{
request::{Form, Request},
response::{self, Responder},
Outcome,
};
use rocket_contrib::json::Json;
use serde_json;
@ -26,21 +27,31 @@ impl From<std::option::NoneError> for ApiError {
}
}
#[rocket::async_trait]
impl<'r> Responder<'r> for ApiError {
fn respond_to(self, req: &'r Request) -> response::ResultFuture<'r> {
async fn respond_to(self, req: &'r Request<'_>) -> response::Result<'r> {
match self.0 {
Error::NotFound => Json(json!({
"error": "Not found"
}))
.respond_to(req),
Error::Unauthorized => Json(json!({
"error": "You are not authorized to access this resource"
}))
.respond_to(req),
_ => Json(json!({
"error": "Server error"
}))
.respond_to(req),
Error::NotFound => {
Json(json!({
"error": "Not found"
}))
.respond_to(req)
.await
}
Error::Unauthorized => {
Json(json!({
"error": "You are not authorized to access this resource"
}))
.respond_to(req)
.await
}
_ => {
Json(json!({
"error": "Server error"
}))
.respond_to(req)
.await
}
}
}
}
@ -62,7 +73,7 @@ pub fn oauth(
let conn = &*rockets.conn;
let app = App::find_by_client_id(conn, &query.client_id)?;
if app.client_secret == query.client_secret {
if let Ok(user) = User::find_by_fqn(&rockets, &query.username) {
if let Outcome::Success(user) = User::find_by_fqn(&rockets, &query.username) {
if user.auth(&query.password) {
let token = ApiToken::insert(
conn,

View File

@ -6,8 +6,6 @@ extern crate gettext_macros;
#[macro_use]
extern crate rocket;
#[macro_use]
extern crate runtime_fmt;
#[macro_use]
extern crate serde_json;
#[macro_use]
extern crate validator_derive;

View File

@ -1,7 +1,7 @@
use crate::template_utils::{IntoContext, Ructe};
use plume_models::{Error, PlumeRocket};
use rocket::{
request::FromRequestAsync,
request::FromRequest,
response::{self, Responder},
Request,
};
@ -15,29 +15,28 @@ impl From<Error> for ErrorPage {
}
}
#[rocket::async_trait]
impl<'r> Responder<'r> for ErrorPage {
fn respond_to(self, req: &'r Request<'_>) -> response::ResultFuture<'r> {
Box::pin(async move {
let rockets = PlumeRocket::from_request(req).await.unwrap();
async fn respond_to(self, req: &'r Request<'_>) -> response::Result<'r> {
let rockets = PlumeRocket::from_request(req).await.unwrap();
match self.0 {
Error::NotFound => {
render!(errors::not_found(&rockets.to_context()))
.respond_to(req)
.await
}
Error::Unauthorized => {
render!(errors::not_found(&rockets.to_context()))
.respond_to(req)
.await
}
_ => {
render!(errors::not_found(&rockets.to_context()))
.respond_to(req)
.await
}
match self.0 {
Error::NotFound => {
render!(errors::not_found(&rockets.to_context()))
.respond_to(req)
.await
}
})
Error::Unauthorized => {
render!(errors::not_found(&rockets.to_context()))
.respond_to(req)
.await
}
_ => {
render!(errors::not_found(&rockets.to_context()))
.respond_to(req)
.await
}
}
}
}

View File

@ -94,10 +94,11 @@ impl Page {
#[derive(Shrinkwrap)]
pub struct ContentLen(pub u64);
#[rocket::async_trait]
impl<'a, 'r> FromRequest<'a, 'r> for ContentLen {
type Error = ();
fn from_request(r: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
async fn from_request(r: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
match r.limits().get("forms") {
Some(l) => Outcome::Success(ContentLen(l)),
None => Outcome::Failure((Status::InternalServerError, ())),
@ -213,32 +214,29 @@ pub struct CachedFile {
#[derive(Debug)]
pub struct ThemeFile(NamedFile);
#[rocket::async_trait]
impl<'r> Responder<'r> for ThemeFile {
fn respond_to(self, r: &'r Request<'_>) -> response::ResultFuture<'r> {
Box::pin(async move {
let contents = std::fs::read(self.0.path()).map_err(|_| Status::InternalServerError)?;
async fn respond_to(self, r: &'r Request<'_>) -> response::Result<'r> {
let contents = std::fs::read(self.0.path()).map_err(|_| Status::InternalServerError)?;
let mut hasher = DefaultHasher::new();
hasher.write(&contents);
let etag = format!("{:x}", hasher.finish());
let mut hasher = DefaultHasher::new();
hasher.write(&contents);
let etag = format!("{:x}", hasher.finish());
if r.headers()
.get("If-None-Match")
.any(|s| s[1..s.len() - 1] == etag)
{
Response::build()
.status(Status::NotModified)
.header(Header::new("ETag", etag))
.ok()
.await
} else {
Response::build()
.merge(self.0.respond_to(r).await.ok().unwrap())
.header(Header::new("ETag", etag))
.ok()
.await
}
})
if r.headers()
.get("If-None-Match")
.any(|s| s[1..s.len() - 1] == etag)
{
Response::build()
.status(Status::NotModified)
.header(Header::new("ETag", etag))
.ok()
} else {
Response::build()
.merge(self.0.respond_to(r).await.ok().unwrap())
.header(Header::new("ETag", etag))
.ok()
}
}
}

View File

@ -643,7 +643,7 @@ pub fn remote_interact_post(
.and_then(|blog| Post::find_by_slug(&rockets.conn, &slug, blog.id))?;
if let Some(uri) = User::fetch_remote_interact_uri(&remote.remote)
.ok()
.and_then(|uri| rt_format!(uri, uri = target.ap_url).ok())
.and_then(|uri| uri.replace("{uri}", format!("{}", target.ap_url)).ok())
{
Ok(Redirect::to(uri).into())
} else {

View File

@ -201,15 +201,14 @@ pub fn follow_not_connected(
if let Some(uri) = User::fetch_remote_interact_uri(&remote_form)
.ok()
.and_then(|uri| {
rt_format!(
uri,
uri = format!(
uri.replace(
"{uri}",
format!(
"{}@{}",
target.fqn,
target.get_instance(&rockets.conn).ok()?.public_domain
)
),
)
.ok()
})
{
Ok(Redirect::to(uri).into())

View File

@ -44,21 +44,47 @@ pub fn host_meta() -> String {
struct WebfingerResolver;
impl Resolver<PlumeRocket> for WebfingerResolver {
fn instance_domain<'a>() -> &'a str {
fn instance_domain<'a>(&self) -> &'a str {
CONFIG.base_url.as_str()
}
fn find(prefix: Prefix, acct: String, ctx: PlumeRocket) -> Result<Webfinger, ResolverError> {
fn find(
&self,
prefix: Prefix,
acct: String,
ctx: PlumeRocket,
) -> Result<Webfinger, ResolverError> {
match prefix {
Prefix::Acct => User::find_by_fqn(&ctx, &acct)
.await
.and_then(|usr| usr.webfinger(&*ctx.conn))
.or(Err(ResolverError::NotFound)),
Prefix::Group => Blog::find_by_fqn(&ctx, &acct)
.await
.and_then(|blog| blog.webfinger(&*ctx.conn))
.or(Err(ResolverError::NotFound)),
Prefix::Custom(_) => Err(ResolverError::NotFound),
}
}
fn endpoint(
&self,
resource: impl Into<String>,
resource_repo: PlumeRocket,
) -> Result<Webfinger, ResolverError> {
let resource = resource.into();
let mut parsed_query = resource.splitn(2, ':');
let res_prefix = Prefix::from(parsed_query.next().ok_or(ResolverError::InvalidResource)?);
let res = parsed_query.next().ok_or(ResolverError::InvalidResource)?;
let mut parsed_res = res.splitn(2, '@');
let user = parsed_res.next().ok_or(ResolverError::InvalidResource)?;
let domain = parsed_res.next().ok_or(ResolverError::InvalidResource)?;
if domain == webfinger.instance_domain() {
webfinger.find(res_prefix, user.to_string(), resource_repo)
} else {
Err(ResolverError::WrongDomain)
}
}
}
#[get("/.well-known/webfinger?<resource>")]

View File

@ -51,33 +51,30 @@ impl IntoContext for PlumeRocket {
#[derive(Debug)]
pub struct Ructe(pub Vec<u8>);
#[rocket::async_trait]
impl<'r> Responder<'r> for Ructe {
fn respond_to(self, r: &'r Request) -> response::ResultFuture<'r> {
Box::pin(async move {
//if method is not Get or page contain a form, no caching
if r.method() != Method::Get || self.0.windows(6).any(|w| w == b"<form ") {
return HtmlCt(self.0).respond_to(r).await;
}
let mut hasher = DefaultHasher::new();
hasher.write(&self.0);
let etag = format!("{:x}", hasher.finish());
if r.headers()
.get("If-None-Match")
.any(|s| s[1..s.len() - 1] == etag)
{
Response::build()
.status(Status::NotModified)
.header(Header::new("ETag", etag))
.ok()
.await
} else {
Response::build()
.merge(HtmlCt(self.0).respond_to(r).await.ok().unwrap())
.header(Header::new("ETag", etag))
.ok()
.await
}
})
async fn respond_to(self, r: &'r Request<'_>) -> response::Result<'r> {
//if method is not Get or page contain a form, no caching
if r.method() != Method::Get || self.0.windows(6).any(|w| w == b"<form ") {
return HtmlCt(self.0).respond_to(r).await;
}
let mut hasher = DefaultHasher::new();
hasher.write(&self.0);
let etag = format!("{:x}", hasher.finish());
if r.headers()
.get("If-None-Match")
.any(|s| s[1..s.len() - 1] == etag)
{
Response::build()
.status(Status::NotModified)
.header(Header::new("ETag", etag))
.ok()
} else {
Response::build()
.merge(HtmlCt(self.0).respond_to(r).await.ok().unwrap())
.header(Header::new("ETag", etag))
.ok()
}
}
}