Plume/src/api/mod.rs
Igor Galić 25c5da1a7c
add tokio (0.2) as dependency to further async-ify our FromData code
i'm using this opportunity to also update reqwest (0.10), but it's
turning out to be a little trickier, as it requires more modern async
setup, and that appears to need a lot of thinking…
2020-05-06 22:23:35 +02:00

102 lines
2.8 KiB
Rust

#![warn(clippy::too_many_arguments)]
use rocket::{
request::{Form, Request},
response::{self, Responder},
};
use rocket_contrib::json::Json;
use serde_json;
use plume_common::utils::random_hex;
use plume_models::{api_tokens::*, apps::App, users::User, Error, PlumeRocket};
type Api<T> = Result<Json<T>, ApiError>;
#[derive(Debug)]
pub struct ApiError(Error);
impl From<Error> for ApiError {
fn from(err: Error) -> ApiError {
ApiError(err)
}
}
impl From<std::option::NoneError> for ApiError {
fn from(err: std::option::NoneError) -> ApiError {
ApiError(err.into())
}
}
impl<'r> Responder<'r> for ApiError {
fn respond_to(self, req: &'r Request) -> response::ResultFuture<'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),
}
}
}
#[derive(FromForm)]
pub struct OAuthRequest {
client_id: String,
client_secret: String,
password: String,
username: String,
scopes: String,
}
#[get("/oauth2?<query..>")]
pub fn oauth(
query: Form<OAuthRequest>,
rockets: PlumeRocket,
) -> Result<Json<serde_json::Value>, ApiError> {
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 user.auth(&query.password) {
let token = ApiToken::insert(
conn,
NewApiToken {
app_id: app.id,
user_id: user.id,
value: random_hex(),
scopes: query.scopes.clone(),
},
)?;
Ok(Json(json!({
"token": token.value
})))
} else {
Ok(Json(json!({
"error": "Invalid credentials"
})))
}
} else {
// Making fake password verification to avoid different
// response times that would make it possible to know
// if a username is registered or not.
User::get(conn, 1)?.auth(&query.password);
Ok(Json(json!({
"error": "Invalid credentials"
})))
}
} else {
Ok(Json(json!({
"error": "Invalid client_secret"
})))
}
}
pub mod apps;
pub mod authorization;
pub mod posts;