ferri/ferri-server/src/endpoints/oauth.rs

127 lines
3 KiB
Rust
Raw Normal View History

2025-04-24 20:19:54 +01:00
use crate::Db;
2025-04-12 15:16:40 +01:00
use rocket::{
2025-04-24 20:19:54 +01:00
FromForm,
form::Form,
2025-04-12 15:16:40 +01:00
get, post,
response::Redirect,
serde::{Deserialize, Serialize, json::Json},
};
2025-04-24 20:19:54 +01:00
use rocket_db_pools::Connection;
2025-04-11 12:29:29 +01:00
#[get("/oauth/authorize?<client_id>&<scope>&<redirect_uri>&<_response_type>")]
2025-04-11 12:29:29 +01:00
pub async fn authorize(
client_id: &str,
scope: &str,
redirect_uri: &str,
_response_type: &str,
2025-04-24 20:19:54 +01:00
mut db: Connection<Db>,
2025-04-11 12:29:29 +01:00
) -> Redirect {
2025-04-24 20:19:54 +01:00
// For now, we will always authorize the request and assign it to an admin user
let user_id = "9b9d497b-2731-435f-a929-e609ca69dac9";
let code = main::gen_token(15);
// This will act as a token for the user, but we will in future say that it expires very shortly
// and can only be used for obtaining an access token etc
sqlx::query!(
2025-04-25 16:46:47 +01:00
r#"
INSERT INTO auth (token, user_id)
VALUES (?1, ?2)
"#,
2025-04-24 20:19:54 +01:00
code,
user_id
)
.execute(&mut **db)
.await
.unwrap();
let id_token = main::gen_token(10);
2025-04-25 16:46:47 +01:00
2025-04-24 20:19:54 +01:00
// Add an oauth entry for the `code` which /oauth/token will rewrite
sqlx::query!(
r#"
INSERT INTO oauth (id_token, client_id, expires_in, scope, access_token)
VALUES (?1, ?2, ?3, ?4, ?5)
"#,
id_token,
client_id,
3600,
scope,
code
)
.execute(&mut **db)
.await
.unwrap();
Redirect::temporary(format!("{}?code={}", redirect_uri, code))
2025-04-11 12:29:29 +01:00
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(crate = "rocket::serde")]
pub struct Token {
pub access_token: String,
pub token_type: String,
pub expires_in: i64,
pub scope: String,
pub id_token: String,
}
2025-04-24 20:19:54 +01:00
#[derive(Deserialize, Debug, FromForm)]
#[serde(crate = "rocket::serde")]
2025-04-25 16:46:47 +01:00
pub struct NewTokenRequest {
// pub client_id: String,
// pub redirect_uri: String,
// pub grant_type: String,
pub code: String,
// pub client_secret: String,
2025-04-24 20:19:54 +01:00
}
#[post("/oauth/token", data = "<req>")]
pub async fn new_token(req: Form<NewTokenRequest>, mut db: Connection<Db>) -> Json<Token> {
2025-04-25 16:46:47 +01:00
let oauth = sqlx::query!("
2025-04-24 20:19:54 +01:00
SELECT o.*, a.*
FROM oauth o
INNER JOIN auth a ON a.token = ?2
WHERE o.access_token = ?1
2025-04-25 16:46:47 +01:00
", req.code, req.code)
.fetch_one(&mut **db)
.await
.unwrap();
2025-04-24 20:19:54 +01:00
let access_token = main::gen_token(15);
// Important: setup 'auth' first
sqlx::query!(
r#"
INSERT INTO auth (token, user_id)
VALUES (?1, ?2)
"#,
access_token,
oauth.user_id
)
.execute(&mut **db)
.await
.unwrap();
sqlx::query!(
"UPDATE oauth SET access_token = ?1 WHERE access_token = ?2",
access_token,
req.code
)
.execute(&mut **db)
.await
.unwrap();
sqlx::query!("DELETE FROM auth WHERE token = ?1", req.code)
.execute(&mut **db)
.await
.unwrap();
2025-04-11 12:29:29 +01:00
Json(Token {
2025-04-24 20:19:54 +01:00
access_token: access_token.to_string(),
2025-04-11 12:29:29 +01:00
token_type: "Bearer".to_string(),
2025-04-24 20:19:54 +01:00
expires_in: oauth.expires_in,
scope: oauth.scope.to_string(),
id_token: oauth.id_token,
2025-04-11 12:29:29 +01:00
})
}