summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock10
-rw-r--r--Cargo.toml1
-rw-r--r--src/api/oauth.rs79
-rw-r--r--src/resources/templates.rs32
-rw-r--r--static/languages/en.ini10
-rw-r--r--static/templates/base.html2
-rw-r--r--static/templates/error.html7
7 files changed, 129 insertions, 12 deletions
diff --git a/Cargo.lock b/Cargo.lock
index bbb5065..1fa4db3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1688,6 +1688,7 @@ dependencies = [
"serde",
"serde_json",
"serde_urlencoded",
+ "serde_variant",
"sha2",
"sqlx",
"tera",
@@ -1808,6 +1809,15 @@ dependencies = [
]
[[package]]
+name = "serde_variant"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47a8ec0b2fd0506290348d9699c0e3eb2e3e8c0498b5a9a6158b3bd4d6970076"
+dependencies = [
+ "serde",
+]
+
+[[package]]
name = "sha1"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 28841be..eae42e1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -33,3 +33,4 @@ sqlx = { version = "0.6", features = [ "runtime-actix-rustls", "mysql", "uuid",
log = "0.4"
chrono = { version = "0.4", features = ["serde"] }
hex = "0.4"
+serde_variant = "0.1"
diff --git a/src/api/oauth.rs b/src/api/oauth.rs
index de98e80..353f287 100644
--- a/src/api/oauth.rs
+++ b/src/api/oauth.rs
@@ -131,12 +131,18 @@ async fn authorize(
db: web::Data<MySqlPool>,
req: web::Query<AuthorizationParameters>,
credentials: web::Json<AuthorizeCredentials>,
+ tera: web::Data<Tera>,
+ translations: web::Data<languages::Translations>,
) -> HttpResponse {
// TODO use sessions to verify that the request was previously validated
// TODO handle internal server error
let db = db.get_ref();
let Some(client_id) = db::get_client_id_by_alias(db, &req.client_id).await.unwrap() else {
- todo!("client not found")
+ // TODO find a better way of doing languages
+ let language = Language::from_str("en").unwrap();
+ let translations = translations.get_ref().clone();
+ let page = templates::error_page(&tera, language, translations, templates::ErrorPage::ClientNotFound).unwrap();
+ return HttpResponse::NotFound().content_type("text/html").body(page);
};
let self_id = Url::parse("www.google.com").unwrap(); // TODO find the actual value
let state = req.state.clone();
@@ -147,7 +153,18 @@ async fn authorize(
} else {
let redirect_uris = db::get_client_redirect_uris(db, client_id).await.unwrap();
if redirect_uris.len() != 1 {
- todo!("no redirect uri");
+ let language = Language::from_str("en").unwrap();
+ let translations = translations.get_ref().clone();
+ let page = templates::error_page(
+ &tera,
+ language,
+ translations,
+ templates::ErrorPage::MissingRedirectUri,
+ )
+ .unwrap();
+ return HttpResponse::NotFound()
+ .content_type("text/html")
+ .body(page);
}
redirect_uris[0].clone()
@@ -230,21 +247,44 @@ async fn authorize_page(
translations: web::Data<languages::Translations>,
request: HttpRequest,
) -> HttpResponse {
+ // TODO handle internal server error
+ let language = Language::from_str("en").unwrap();
+ let translations = translations.get_ref().clone();
+
let params = request.query_string();
let params = serde_urlencoded::from_str::<AuthorizationParameters>(params);
let Ok(params) = params else {
- todo!("invalid request")
+ let page = templates::error_page(
+ &tera,
+ language,
+ translations,
+ templates::ErrorPage::InvalidRequest,
+ )
+ .unwrap();
+ return HttpResponse::BadRequest()
+ .content_type("text/html")
+ .body(page);
};
let db = db.get_ref();
let Some(client_id) = db::get_client_id_by_alias(db, &params.client_id).await.unwrap() else {
- todo!("client not found")
+ let page = templates::error_page(
+ &tera,
+ language,
+ translations,
+ templates::ErrorPage::ClientNotFound,
+ )
+ .unwrap();
+ return HttpResponse::NotFound()
+ .content_type("text/html")
+ .body(page);
};
// verify scope
- let Some(allowed_scopes) = db::get_client_allowed_scopes(db, client_id).await.unwrap() else {
- todo!("client not found")
- };
+ let allowed_scopes = db::get_client_allowed_scopes(db, client_id)
+ .await
+ .unwrap()
+ .unwrap();
// verify redirect uri
let redirect_uri: Url;
@@ -254,12 +294,30 @@ async fn authorize_page(
.await
.unwrap()
{
- todo!("access denied")
+ let page = templates::error_page(
+ &tera,
+ language,
+ translations,
+ templates::ErrorPage::InvalidRedirectUri,
+ )
+ .unwrap();
+ return HttpResponse::BadRequest()
+ .content_type("text/html")
+ .body(page);
}
} else {
let redirect_uris = db::get_client_redirect_uris(db, client_id).await.unwrap();
if redirect_uris.len() != 1 {
- todo!("must have redirect uri")
+ let page = templates::error_page(
+ &tera,
+ language,
+ translations,
+ templates::ErrorPage::MissingRedirectUri,
+ )
+ .unwrap();
+ return HttpResponse::NotFound()
+ .content_type("text/html")
+ .body(page);
}
redirect_uri = redirect_uris.get(0).unwrap().clone();
@@ -290,8 +348,7 @@ async fn authorize_page(
// TODO find a better way of doing languages
let language = Language::from_str("en").unwrap();
- let page =
- templates::login_page(&tera, &params, language, translations.get_ref().clone()).unwrap();
+ let page = templates::login_page(&tera, &params, language, translations).unwrap();
HttpResponse::Ok().content_type("text/html").body(page)
}
diff --git a/src/resources/templates.rs b/src/resources/templates.rs
index 7578256..88c1fad 100644
--- a/src/resources/templates.rs
+++ b/src/resources/templates.rs
@@ -2,6 +2,7 @@ use std::collections::HashMap;
use exun::{RawUnexpected, ResultErrorExt};
use raise::yeet;
+use serde::Serialize;
use tera::{Function, Tera, Value};
use unic_langid::subtags::Language;
@@ -36,6 +37,37 @@ pub fn initialize() -> tera::Result<Tera> {
Ok(tera)
}
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub enum ErrorPage {
+ InvalidRequest,
+ ClientNotFound,
+ MissingRedirectUri,
+ InvalidRedirectUri,
+}
+
+pub fn error_page(
+ tera: &Tera,
+ language: Language,
+ mut translations: languages::Translations,
+ error: ErrorPage,
+) -> Result<String, RawUnexpected> {
+ translations.refresh()?;
+ let mut tera = extend_tera(tera, language, translations)?;
+ tera.full_reload()?;
+
+ let error = serde_variant::to_variant_name(&error)?;
+ let header = format!("errorHeader_{error}");
+ let message = format!("errorMessage_{error}");
+
+ let mut context = tera::Context::new();
+ context.insert("lang", language.as_str());
+ context.insert("errorHeader", &header);
+ context.insert("errormessage", &message);
+
+ tera.render("error.html", &context).unexpect()
+}
+
pub fn login_page(
tera: &Tera,
params: &AuthorizationParameters,
diff --git a/static/languages/en.ini b/static/languages/en.ini
index 1848a7d..e926ec0 100644
--- a/static/languages/en.ini
+++ b/static/languages/en.ini
@@ -4,3 +4,13 @@ usernamePlaceholder = Enter your username
passwordLabel = Password
passwordPlaceholder = Enter your password
loginSubmitButton = Log In
+
+errorTitle = Error
+errorHeader_invalidRequest = Invalid Request
+errorMessage_invalidRequest = The client sent a bad request.
+errorHeader_clientNotFound = Client Not Found
+errorMessage_clientNotFound = The client gave an incorrect ID, so we cannot redirect to it.
+errorHeader_missingRedirectUri = Missing Redirect URI
+errorMessage_missingRedirectUri = There are many redirect URIs for the client, but the client did not specify which one to use.
+errorHeader_invalidRedirectUri = Invalid Redirect URI
+errorMessage_invalidRedirectUri = The client provided a redirect URI that it is not allowed to redirect to.
diff --git a/static/templates/base.html b/static/templates/base.html
index fe4875e..021f95e 100644
--- a/static/templates/base.html
+++ b/static/templates/base.html
@@ -10,7 +10,7 @@
<body>
{% block content %}{% endblock content %}
<footer>
- <div id="copyright">&copy; 2023 Amplify Education Inc.</div>
+ <div id="copyright">&copy; 2023</div>
</footer>
</body>
</html>
diff --git a/static/templates/error.html b/static/templates/error.html
new file mode 100644
index 0000000..4fbe87f
--- /dev/null
+++ b/static/templates/error.html
@@ -0,0 +1,7 @@
+{% extends "base.html" %}
+{% block title %}{{ msg(key="errorTitle") }}{% endblock title %}
+
+{% block content %}
+<p>{{ msg(key=errorHeader) }}</p>
+<p>{{ msg(key=errorMessage) }}</p>
+{% endblock content %}