diff options
| -rw-r--r-- | sqlx-data.json | 461 | ||||
| -rw-r--r-- | src/api/mod.rs | 9 | ||||
| -rw-r--r-- | src/api/oauth.rs | 60 | ||||
| -rw-r--r-- | src/api/ops.rs | 13 | ||||
| -rw-r--r-- | src/main.rs | 2 | ||||
| -rw-r--r-- | src/resources/templates.rs | 19 | ||||
| -rw-r--r-- | src/services/db/client.rs | 19 |
7 files changed, 452 insertions, 131 deletions
diff --git a/sqlx-data.json b/sqlx-data.json index 4cab0aa..9dafd7c 100644 --- a/sqlx-data.json +++ b/sqlx-data.json @@ -1,10 +1,10 @@ { "db": "MySQL", - "2e6664bc143576c82ced1c6e58fdcd39606d0fa5c2d74f7eb4680f72cb3bede2": { + "07221a593704fa3cb5d17f15f3fc18dff0359631db8393b5a1cebfdef748b495": { "describe": { "columns": [ { - "name": "id", + "name": "id: Uuid", "ordinal": 0, "type_info": { "char_set": 63, @@ -75,90 +75,158 @@ "Right": 1 } }, - "query": "SELECT id, username, password_hash, password_salt, password_version\n\t\t FROM users WHERE id = ?" + "query": "SELECT id as `id: Uuid`, username, password_hash, password_salt, password_version\n\t\t FROM users\n\t\t WHERE LOCATE(?, username) != 0" }, - "3803dd22a747fc5f3d9b56248c2372be8050a77771a898a531fb8cb6cb1aaf1f": { + "0d28efa4c9c7bdc32bc51152dab7cf4b2ecdd2955c930e59abfeed6e4b25e726": { "describe": { "columns": [ { - "name": "id", + "name": "e: bool", "ordinal": 0, "type_info": { "char_set": 63, "flags": { - "bits": 4231 + "bits": 129 }, - "max_size": 16, - "type": "String" + "max_size": 1, + "type": "LongLong" } - }, + } + ], + "nullable": [ + false + ], + "parameters": { + "Right": 1 + } + }, + "query": "SELECT EXISTS(SELECT id FROM clients WHERE id = ?) as `e: bool`" + }, + "0fb414b2015617ebdbe1303d71439302920d31275c97995d3d50513b07382ac1": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Right": 2 + } + }, + "query": "UPDATE clients SET type = ? WHERE id = ?" + }, + "19270d592676012569585d7796cb407d2c331dfbc7ac4481e5e38bcee5b6fcde": { + "describe": { + "columns": [ { - "name": "username", - "ordinal": 1, + "name": "type: ClientType", + "ordinal": 0, "type_info": { "char_set": 224, "flags": { - "bits": 4101 + "bits": 4097 }, - "max_size": 1020, + "max_size": 180, "type": "VarString" } - }, + } + ], + "nullable": [ + false + ], + "parameters": { + "Right": 1 + } + }, + "query": "SELECT type as `type: ClientType` FROM clients WHERE id = ?" + }, + "1ef0455513dcdc1b7e468d826139613502a8209aca0db3372cd4acc46c226ba5": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Right": 1 + } + }, + "query": "DELETE FROM client_redirect_uris WHERE client_id = ?" + }, + "2558b6cad04d6c8af7efabc0e95e669e1de0ce9e04f7de2be321db4cbfae9eb5": { + "describe": { + "columns": [ { - "name": "password_hash", - "ordinal": 2, + "name": "e: bool", + "ordinal": 0, "type_info": { "char_set": 63, "flags": { - "bits": 4241 + "bits": 129 }, - "max_size": 255, - "type": "Blob" + "max_size": 1, + "type": "LongLong" } - }, + } + ], + "nullable": [ + false + ], + "parameters": { + "Right": 2 + } + }, + "query": "SELECT EXISTS(\n\t\t\t SELECT redirect_uri\n\t\t\t FROM client_redirect_uris\n\t\t\t WHERE client_id = ? AND redirect_uri = ?\n\t\t ) as `e: bool`" + }, + "32e1e172efd2dfe26c97ec9bf82b5d773a7373ebf949bbe73677c863cc67b45d": { + "describe": { + "columns": [ { - "name": "password_salt", - "ordinal": 3, + "name": "e: bool", + "ordinal": 0, "type_info": { "char_set": 63, "flags": { - "bits": 4241 + "bits": 129 }, - "max_size": 255, - "type": "Blob" + "max_size": 1, + "type": "LongLong" } - }, + } + ], + "nullable": [ + false + ], + "parameters": { + "Right": 1 + } + }, + "query": "SELECT EXISTS(SELECT alias FROM clients WHERE alias = ?) as `e: bool`" + }, + "3eef97b5a7d77ef845923d890f929321c9a8a125893fe5f6c847364797d20c9c": { + "describe": { + "columns": [ { - "name": "password_version", - "ordinal": 4, + "name": "redirect_uri", + "ordinal": 0, "type_info": { - "char_set": 63, + "char_set": 224, "flags": { - "bits": 33 + "bits": 4099 }, - "max_size": 10, - "type": "Long" + "max_size": 1020, + "type": "VarString" } } ], "nullable": [ - false, - false, - false, - false, false ], "parameters": { - "Right": 3 + "Right": 1 } }, - "query": "SELECT id, username, password_hash, password_salt, password_version\n\t\t FROM users\n\t\t WHERE LOCATE(?, username) != 0\n\t\t LIMIT ?\n\t\t OFFSET ?" + "query": "SELECT redirect_uri FROM client_redirect_uris WHERE client_id = ?" }, - "41ce01000e31fd3df199a16cc5d9835fd21319103f8615ef71960f78d8c1ae3c": { + "4e98a6a157a30d9da7621af79845d653ab29eabed1346cd2be60258d8841929d": { "describe": { "columns": [ { - "name": "id", + "name": "id: Uuid", "ordinal": 0, "type_info": { "char_set": 63, @@ -170,7 +238,7 @@ } }, { - "name": "username", + "name": "alias", "ordinal": 1, "type_info": { "char_set": 224, @@ -182,64 +250,28 @@ } }, { - "name": "password_hash", + "name": "client_type: ClientType", "ordinal": 2, "type_info": { - "char_set": 63, - "flags": { - "bits": 4241 - }, - "max_size": 255, - "type": "Blob" - } - }, - { - "name": "password_salt", - "ordinal": 3, - "type_info": { - "char_set": 63, - "flags": { - "bits": 4241 - }, - "max_size": 255, - "type": "Blob" - } - }, - { - "name": "password_version", - "ordinal": 4, - "type_info": { - "char_set": 63, + "char_set": 224, "flags": { - "bits": 33 + "bits": 4097 }, - "max_size": 10, - "type": "Long" + "max_size": 180, + "type": "VarString" } } ], "nullable": [ false, false, - false, - false, false ], "parameters": { "Right": 1 } }, - "query": "SELECT id, username, password_hash, password_salt, password_version\n\t\t FROM users\n\t\t WHERE LOCATE(?, username) != 0" - }, - "6c084e6931262b2e4a735a056022ed1aa4fddd65fca68f5193fc899f24c1220b": { - "describe": { - "columns": [], - "nullable": [], - "parameters": { - "Right": 5 - } - }, - "query": "INSERT INTO users (id, username, password_hash, password_salt, password_version)\n\t\t\t\t\t VALUES (?, ?, ?, ?, ?)" + "query": "SELECT id as `id: Uuid`,\n\t\t alias,\n\t\t\t\t type as `client_type: ClientType`\n\t\t FROM clients WHERE id = ?" }, "76a5f21dacb2b48fb797bcc0e5054b519192ae0bb6dcf8c29fbf9c2913b4746b": { "describe": { @@ -266,11 +298,61 @@ }, "query": "SELECT username FROM users where id = ?" }, - "7b8de80e805fff9ea8a461cc7708cafb062539ca4b75b2f66bfaf44987c736c9": { + "866d1d42c698528f0195a0c2fc7c971ca1a140802dd205bd9918bdcc08fe377b": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Right": 2 + } + }, + "query": "UPDATE clients SET alias = ? WHERE id = ?" + }, + "8f4656ed3a928dd4b33cf037b9aa60092a17219b9a46366a5fdb0c28ea3e79a7": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Right": 1 + } + }, + "query": "UPDATE clients\n\t\t\t SET secret_hash = NULL, secret_salt = NULL, secret_version = NULL\n\t\t\t WHERE id = ?" + }, + "91688c5521ab1272e4937451a2bd9c467915f8e4d8cef6eac95013a5a94cc08a": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Right": 5 + } + }, + "query": "INSERT INTO users (id, username, password_hash, password_salt, password_version)\n\t\t\t\t\t VALUES ( ?, ?, ?, ?, ?)" + }, + "970643c05b6189e1277cfd695492dd3706e0c30615e64812cbd29246ada36bb7": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Right": 6 + } + }, + "query": "INSERT INTO clients (id, alias, type, secret_hash, secret_salt, secret_version)\n\t\t\t\t\t VALUES ( ?, ?, ?, ?, ?, ?)" + }, + "9710cd5915616165c6d27031b21cc7b3cfbd5aae574eb07797dca57064880ef9": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Right": 2 + } + }, + "query": "UPDATE users SET username = ? WHERE id = ?" + }, + "a5d7e7e4a36cb1bb0675ccde12dadd013ae2c847648b3274494e206b14cc1370": { "describe": { "columns": [ { - "name": "id", + "name": "id: Uuid", "ordinal": 0, "type_info": { "char_set": 63, @@ -341,9 +423,9 @@ "Right": 1 } }, - "query": "SELECT id, username, password_hash, password_salt, password_version\n\t\t FROM users WHERE username = ?" + "query": "SELECT id as `id: Uuid`, username, password_hash, password_salt, password_version\n\t\t FROM users WHERE id = ?" }, - "9710cd5915616165c6d27031b21cc7b3cfbd5aae574eb07797dca57064880ef9": { + "ac93da5d341986aef384f8f11c24861fc290aa9974c44400fb46ee09e383dcae": { "describe": { "columns": [], "nullable": [], @@ -351,7 +433,7 @@ "Right": 2 } }, - "query": "UPDATE users SET username = ? WHERE id = ?" + "query": "INSERT INTO client_redirect_uris (client_id, redirect_uri)\n\t\t\t\t\t\t\t\t\t VALUES ( ?, ?)" }, "b1d60244a68b9c132e5b3125505606d156913acf062802e4e1783f9e859f4c49": { "describe": { @@ -378,7 +460,7 @@ }, "query": "SELECT EXISTS(SELECT id FROM users WHERE username = ?) as \"e: bool\"" }, - "b6c6433f0080471d1db6875bdbbe633cd56d781e80f7cbe854f80a5a11aa4a8f": { + "c61516c0c3d51f322a8207581802c2c9723a65beeaeae558d997590dc9e88ef2": { "describe": { "columns": [ { @@ -401,7 +483,32 @@ "Right": 1 } }, - "query": "SELECT EXISTS(SELECT id FROM users WHERE id = ?) as \"e: bool\"" + "query": "SELECT EXISTS(SELECT id FROM users WHERE id = ?) as `e: bool`" + }, + "dda087e364dd82216ea8e5d7266d63ab671382744eb350d446fe1025e2df12bb": { + "describe": { + "columns": [ + { + "name": "alias", + "ordinal": 0, + "type_info": { + "char_set": 224, + "flags": { + "bits": 4101 + }, + "max_size": 1020, + "type": "VarString" + } + } + ], + "nullable": [ + false + ], + "parameters": { + "Right": 1 + } + }, + "query": "SELECT alias FROM clients WHERE id = ?" }, "df0033aa7c0e5066fed30d944387293d26d1de93b1a24a202214d6ee06fc6a1c": { "describe": { @@ -413,6 +520,103 @@ }, "query": "UPDATE users SET\n\t\tpassword_hash = ?,\n\t\tpassword_salt = ?,\n\t\tpassword_version = ?\n\t\tWHERE id = ?" }, + "f488b319d6f387db08fb49920ddb381b2b1496605914275cd1ccd81c9420b23c": { + "describe": { + "columns": [ + { + "name": "id: Uuid", + "ordinal": 0, + "type_info": { + "char_set": 63, + "flags": { + "bits": 4231 + }, + "max_size": 16, + "type": "String" + } + }, + { + "name": "username", + "ordinal": 1, + "type_info": { + "char_set": 224, + "flags": { + "bits": 4101 + }, + "max_size": 1020, + "type": "VarString" + } + }, + { + "name": "password_hash", + "ordinal": 2, + "type_info": { + "char_set": 63, + "flags": { + "bits": 4241 + }, + "max_size": 255, + "type": "Blob" + } + }, + { + "name": "password_salt", + "ordinal": 3, + "type_info": { + "char_set": 63, + "flags": { + "bits": 4241 + }, + "max_size": 255, + "type": "Blob" + } + }, + { + "name": "password_version", + "ordinal": 4, + "type_info": { + "char_set": 63, + "flags": { + "bits": 33 + }, + "max_size": 10, + "type": "Long" + } + } + ], + "nullable": [ + false, + false, + false, + false, + false + ], + "parameters": { + "Right": 3 + } + }, + "query": "SELECT id as `id: Uuid`, username, password_hash, password_salt, password_version\n\t\t FROM users\n\t\t WHERE LOCATE(?, username) != 0\n\t\t LIMIT ?\n\t\t OFFSET ?" + }, + "f4e088a309a5fa63652fd1aeb95805d64d255a12d5313dbf2f7f2f99c7918e62": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Right": 4 + } + }, + "query": "UPDATE clients SET secret_hash = ?, secret_salt = ?, secret_version = ? WHERE id = ?" + }, + "f88f4fead2c0aeba318dd45546d5321271cdc1cb4f3b39576087b73a1024b78a": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Right": 6 + } + }, + "query": "UPDATE clients SET\n\t\talias = ?,\n\t\ttype = ?,\n\t\tsecret_hash = ?,\n\t\tsecret_salt = ?,\n\t\tsecret_version = ?\n\t\tWHERE id = ?" + }, "f9d2c85bdcc3b7d0d1fca4e2f0bb37df6dee23bc50af97d8e4112baacd6eb7c9": { "describe": { "columns": [], @@ -422,5 +626,82 @@ } }, "query": "UPDATE users SET\n\t\t username = ?,\n\t\t password_hash = ?,\n\t\t password_salt = ?,\n\t\t password_version = ?\n\t\t WHERE id = ?" + }, + "fc393b1464413bb7045d33a8ca5aa0100ab217434570e6be732f97db1d9b04aa": { + "describe": { + "columns": [ + { + "name": "id: Uuid", + "ordinal": 0, + "type_info": { + "char_set": 63, + "flags": { + "bits": 4231 + }, + "max_size": 16, + "type": "String" + } + }, + { + "name": "username", + "ordinal": 1, + "type_info": { + "char_set": 224, + "flags": { + "bits": 4101 + }, + "max_size": 1020, + "type": "VarString" + } + }, + { + "name": "password_hash", + "ordinal": 2, + "type_info": { + "char_set": 63, + "flags": { + "bits": 4241 + }, + "max_size": 255, + "type": "Blob" + } + }, + { + "name": "password_salt", + "ordinal": 3, + "type_info": { + "char_set": 63, + "flags": { + "bits": 4241 + }, + "max_size": 255, + "type": "Blob" + } + }, + { + "name": "password_version", + "ordinal": 4, + "type_info": { + "char_set": 63, + "flags": { + "bits": 33 + }, + "max_size": 10, + "type": "Long" + } + } + ], + "nullable": [ + false, + false, + false, + false, + false + ], + "parameters": { + "Right": 1 + } + }, + "query": "SELECT id as `id: Uuid`, username, password_hash, password_salt, password_version\n\t\t FROM users WHERE username = ?" } }
\ No newline at end of file diff --git a/src/api/mod.rs b/src/api/mod.rs index 3d74be8..0ab4037 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,10 +1,13 @@ +mod clients; mod liveops; +mod oauth; mod ops; mod users; -mod oauth; -mod clients; +pub use clients::service as clients; pub use liveops::service as liveops; +pub use oauth::service as oauth; pub use ops::service as ops; pub use users::service as users; -pub use clients::service as clients; + +pub use oauth::AuthorizationParameters; diff --git a/src/api/oauth.rs b/src/api/oauth.rs index 9e0e5c6..9916053 100644 --- a/src/api/oauth.rs +++ b/src/api/oauth.rs @@ -1,24 +1,60 @@ -use std::collections::HashMap; +use std::str::FromStr; -use actix_web::{web, HttpResponse}; -use serde::Deserialize; +use actix_web::{get, post, web, HttpResponse, Scope}; +use serde::{Deserialize, Serialize}; +use sqlx::MySqlPool; +use tera::Tera; +use unic_langid::subtags::Language; use url::Url; -use uuid::Uuid; -#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)] +use crate::resources::{languages, templates}; +use crate::services::db; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] enum ResponseType { Code, Token, } -#[derive(Debug, Clone, Deserialize)] -struct AuthorizationParameters { +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct AuthorizationParameters { response_type: ResponseType, - client_id: Uuid, - redirect_uri: Url, - state: Box<str>, + redirect_uri: Option<Url>, +} + +#[derive(Debug, Clone, Deserialize)] +struct AuthorizeCredentials { + username: Box<str>, + password: Box<str>, +} + +#[post("/authorize")] +async fn authorize( + query: web::Query<AuthorizationParameters>, + credentials: web::Form<AuthorizeCredentials>, +) -> HttpResponse { + // TODO check that the URI is valid + todo!() +} + +#[get("/authorize")] +async fn authorize_page( + db: web::Data<MySqlPool>, + tera: web::Data<Tera>, + translations: web::Data<languages::Translations>, + query: web::Query<AuthorizationParameters>, +) -> HttpResponse { + // TODO find a better way of doing languages + // TODO check that the URI is valid + let language = Language::from_str("en").unwrap(); + let page = + templates::login_page(&tera, &query, language, translations.get_ref().clone()).unwrap(); + HttpResponse::Ok().content_type("text/html").body(page) +} - #[serde(flatten)] - additional_parameters: HashMap<Box<str>, Box<str>>, +pub fn service() -> Scope { + web::scope("/oauth") + .service(authorize_page) + .service(authorize) } diff --git a/src/api/ops.rs b/src/api/ops.rs index d947e64..555bb1b 100644 --- a/src/api/ops.rs +++ b/src/api/ops.rs @@ -65,17 +65,6 @@ async fn login( Ok(response) } -#[get("/login")] -async fn login_page( - tera: web::Data<Tera>, - translations: web::Data<languages::Translations>, -) -> HttpResponse { - // TODO find a better way of doing this - let language = Language::from_str("en").unwrap(); - let page = templates::login_page(&tera, language, translations.get_ref().clone()).unwrap(); - HttpResponse::Ok().content_type("text/html").body(page) -} - pub fn service() -> Scope { - web::scope("").service(login).service(login_page) + web::scope("").service(login) } diff --git a/src/main.rs b/src/main.rs index aca5977..c288c7a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -49,7 +49,6 @@ async fn main() -> Result<(), RawUnexpected> { .app_data(Data::new(tera.clone())) .app_data(Data::new(translations.clone())) // frontend services - // has to be first so they don't get overwritten by the "" scope .service(style::get_css) .service(scripts::get_js) .service(languages::languages()) @@ -57,6 +56,7 @@ async fn main() -> Result<(), RawUnexpected> { .service(api::liveops()) .service(api::users()) .service(api::clients()) + .service(api::oauth()) .service(api::ops()) }) .shutdown_timeout(1) diff --git a/src/resources/templates.rs b/src/resources/templates.rs index 43d6b67..7578256 100644 --- a/src/resources/templates.rs +++ b/src/resources/templates.rs @@ -5,13 +5,9 @@ use raise::yeet; use tera::{Function, Tera, Value}; use unic_langid::subtags::Language; -use super::languages; +use crate::api::AuthorizationParameters; -fn make_lang(language: Language) -> impl Function { - Box::new(move |_: &HashMap<String, Value>| -> tera::Result<Value> { - Ok(Value::String(language.to_string())) - }) -} +use super::languages; fn make_msg(language: Language, translations: languages::Translations) -> impl Function { Box::new( @@ -24,10 +20,6 @@ fn make_msg(language: Language, translations: languages::Translations) -> impl F ) } -fn make_base_url() -> impl Function { - Box::new(|_: &HashMap<String, Value>| Ok(Value::String("foo".to_string()))) -} - fn extend_tera( tera: &Tera, language: Language, @@ -35,9 +27,7 @@ fn extend_tera( ) -> Result<Tera, RawUnexpected> { let mut new_tera = initialize()?; new_tera.extend(tera)?; - new_tera.register_function("lang", make_lang(language)); new_tera.register_function("msg", make_msg(language, translations)); - new_tera.register_function("baseUrl", make_base_url()); Ok(new_tera) } @@ -48,12 +38,15 @@ pub fn initialize() -> tera::Result<Tera> { pub fn login_page( tera: &Tera, + params: &AuthorizationParameters, language: Language, mut translations: languages::Translations, ) -> Result<String, RawUnexpected> { translations.refresh()?; let mut tera = extend_tera(tera, language, translations)?; tera.full_reload()?; - let context = tera::Context::new(); + let mut context = tera::Context::new(); + context.insert("lang", language.as_str()); + context.insert("params", &serde_urlencoded::to_string(params)?); tera.render("login.html", &context).unexpect() } diff --git a/src/services/db/client.rs b/src/services/db/client.rs index d1531be..4643f49 100644 --- a/src/services/db/client.rs +++ b/src/services/db/client.rs @@ -98,6 +98,25 @@ pub async fn get_client_redirect_uris<'c>( .collect() } +pub async fn client_has_redirect_uri<'c>( + executor: impl Executor<'c, Database = MySql>, + id: Uuid, + url: Url, +) -> Result<bool, RawUnexpected> { + query_scalar!( + r"SELECT EXISTS( + SELECT redirect_uri + FROM client_redirect_uris + WHERE client_id = ? AND redirect_uri = ? + ) as `e: bool`", + id, + url.to_string() + ) + .fetch_one(executor) + .await + .unexpect() +} + async fn delete_client_redirect_uris<'c>( executor: impl Executor<'c, Database = MySql>, id: Uuid, |
