diff --git a/Cargo.lock b/Cargo.lock index 631d426..6a7da48 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1587,9 +1587,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.59" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" dependencies = [ "unicode-ident", ] @@ -2952,7 +2952,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] -name = "verder-helpen-comm-common" +name = "verder-helpen-comm-isolate" version = "0.1.0" dependencies = [ "accept-language", @@ -2976,19 +2976,6 @@ dependencies = [ "unic-langid", "verder-helpen-jwt", "verder-helpen-proto", -] - -[[package]] -name = "verder-helpen-comm-isolate" -version = "0.1.0" -dependencies = [ - "reqwest", - "rocket", - "serde", - "serde_json", - "verder-helpen-comm-common", - "verder-helpen-jwt", - "verder-helpen-proto", "verder-helpen-sentry", ] diff --git a/Cargo.toml b/Cargo.toml index 688f040..7102156 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,37 @@ -[workspace] +[package] +name = "verder-helpen-comm-isolate" +version = "0.1.0" +edition = "2021" -members = [ - "comm-common", - "comm-plugin", -] +[features] +default = ["auth_during_comm", "platform_token", "session_db"] +auth_during_comm = ["platform_token"] +platform_token = [] +sentry = ["dep:verder-helpen-sentry"] +session_db = ["platform_token"] + +[dependencies] +verder-helpen-jwt = { git = "https://github.com/verder-helpen/verder-helpen-jwt.git" } +verder-helpen-proto = { git = "https://github.com/verder-helpen/verder-helpen-proto.git" } +verder-helpen-sentry = { git = "https://github.com/verder-helpen/verder-helpen-sentry.git", optional = true } +accept-language = "2.0.0" +josekit = "0.8.2" +lazy_static = "1.4.0" +rand = "0.8.5" +reqwest = { version = "0.11.16", features = ["json"] } +rocket = { version = "0.5.0-rc.3", features = ["json"] } +rocket_oauth2 = { git = "https://github.com/arjentz/rocket_oauth2.git", rev = "214efa99b0bd95c0df4d3f3d4c6235ae25610e37" } +rocket_sync_db_pools = { version = "0.1.0-rc.3", features = ["postgres_pool"] } +serde = "1.0.159" +serde_json = "1.0.95" +serde_yaml = "0.9.19" +strum = "0.24.1" +strum_macros = "0.24.3" +tera = "1.18.1" +thiserror = "1.0.40" +unic-langid = "0.9.1" + +[dev-dependencies] +figment = { version = "0.10.8", features = ["env", "toml", "json"] } +serial_test = "2.0.0" +tokio-test = "0.4.2" diff --git a/comm-common/.gitignore b/comm-common/.gitignore deleted file mode 100644 index 96ef6c0..0000000 --- a/comm-common/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -Cargo.lock diff --git a/comm-common/Cargo.toml b/comm-common/Cargo.toml deleted file mode 100644 index b04af30..0000000 --- a/comm-common/Cargo.toml +++ /dev/null @@ -1,37 +0,0 @@ -[package] -name = "verder-helpen-comm-common" -version = "0.1.0" -edition = "2018" - -[features] -default = ["auth_during_comm", "platform_token", "session_db"] -auth_during_comm = ["platform_token"] -platform_token = [] -session_db = ["platform_token"] - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -verder-helpen-jwt = { git = "https://github.com/verder-helpen/verder-helpen-jwt.git" } -verder-helpen-proto = { git = "https://github.com/verder-helpen/verder-helpen-proto.git" } -josekit = "0.8.2" -rocket = { version = "0.5.0-rc.3", features = ["json"] } -rocket_oauth2 = { git = "https://github.com/arjentz/rocket_oauth2.git", rev = "214efa99b0bd95c0df4d3f3d4c6235ae25610e37" } -rocket_sync_db_pools = { version = "0.1.0-rc.3", features = ["postgres_pool"] } -serde = "1.0.159" -serde_json = "1.0.95" -serde_yaml = "0.9.19" -thiserror = "1.0.40" -reqwest = { version = "0.11.16", features = ["json"] } -strum = "0.24.1" -strum_macros = "0.24.3" -rand = "0.8.5" -tera = "1.18.1" -lazy_static = "1.4.0" -unic-langid = "0.9.1" -accept-language = "2.0.0" - -[dev-dependencies] -serial_test = "2.0.0" -tokio-test = "0.4.2" -figment = { version = "0.10.8", features = ["env", "toml", "json"] } diff --git a/comm-common/LICENSE b/comm-common/LICENSE deleted file mode 120000 index ea5b606..0000000 --- a/comm-common/LICENSE +++ /dev/null @@ -1 +0,0 @@ -../LICENSE \ No newline at end of file diff --git a/comm-common/README.md b/comm-common/README.md deleted file mode 100644 index f34a478..0000000 --- a/comm-common/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Verder Helpen Communication Common `verder-helpen-comm-common` - -This library contains Rust common utilities for setting up Verder Helpen communication plugins. diff --git a/comm-common/config.toml b/comm-common/config.toml deleted file mode 100644 index 8c3581b..0000000 --- a/comm-common/config.toml +++ /dev/null @@ -1,44 +0,0 @@ -[global] -default_locale = "en" - -[global.translations.en] -title = "Information" -unknown_error = "Unknown error" -loading = "Loading..." -purpose = "Subject" -attributes = "Verified information" -error = "An error occurred" -refresh = "Refresh" -report_move = "Report move" -request_permit = "Request a permit" -request_passport = "Request a passport" -email = "E-mail address" -login_necessary = "Please login to view user information" -login = "Login" -login_expired = "Your session expired or you do not have sufficient permissions to access this resource." -logout = "Logout" -login_successful = "Login successfull. You can close this window." -logout_successful = "Logout successfull. You can close this window." -insufficient_permission = "You do not have sufficient permissions to access this resource." -no_credentials_found = "There are no authenticated guests (yet)" - -[global.translations.nl] -title = "Verder Helpen gegevens" -unknown_error = "Onbekende fout" -loading = "Laden..." -purpose = "Onderwerp" -attributes = "Geverifieerde gegevens" -error = "Er is een fout opgetreden" -refresh = "Herladen" -report_move = "Verhuizing doorgeven" -request_permit = "Vergunning aanvragen" -request_passport = "Paspoort aanvragen" -email = "E-mailadres" -login_necessary = "Om gegevens van gebruikers te kunnen zien moet u eerst inloggen" -login = "Inloggen" -login_expired = "Uw sessie is verlopen of u heeft niet voldoende rechten" -logout = "Uitloggen" -login_successful = "U bent ingelogd. U kan dit venster nu sluiten" -logout_successful = "U bent uitgelogd. U kan dit venster nu sluiten" -insufficient_permission = "Uw account heeft niet voldoende rechten, probeer met een ander account in te loggen" -no_credentials_found = "Er zijn (nog) geen geïdentificeerde gasten" diff --git a/comm-common/schema.sql b/comm-common/schema.sql deleted file mode 120000 index 1450fbb..0000000 --- a/comm-common/schema.sql +++ /dev/null @@ -1 +0,0 @@ -../schema.sql \ No newline at end of file diff --git a/comm-common/src/templates/base.html b/comm-common/src/templates/base.html deleted file mode 100644 index a5063ac..0000000 --- a/comm-common/src/templates/base.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - {{ translations.title }} - - -
-
-
-

- {{ translations.attributes }} -

- {% include "credentials.html" %} -
-
-
- - diff --git a/comm-common/src/templates/credentials.html b/comm-common/src/templates/credentials.html deleted file mode 100644 index b246a3d..0000000 --- a/comm-common/src/templates/credentials.html +++ /dev/null @@ -1,16 +0,0 @@ -{%- for credential in credentials %} -
- {% if credential.name %} -

{{ credential.name }}

- {% endif %} - {% if credential.attributes %} -
- {%- for kv in credential.attributes %} -
{{ translations[kv.0]|default(value=kv.0) }}
-
{{ kv.1 }}
- {%- endfor %} -
- {% endif %} -
-{%- endfor %} -{% include "logout.html" %} diff --git a/comm-common/src/templates/expired.html b/comm-common/src/templates/expired.html deleted file mode 100644 index 44e6c58..0000000 --- a/comm-common/src/templates/expired.html +++ /dev/null @@ -1,4 +0,0 @@ -
-

{{ translations.login_expired }}

- {% include "logout.html" %} -
diff --git a/comm-common/src/templates/login.html b/comm-common/src/templates/login.html deleted file mode 100644 index cbe7bcb..0000000 --- a/comm-common/src/templates/login.html +++ /dev/null @@ -1,4 +0,0 @@ -
-

{{ translations.login_necessary }}

- {{ translations.login }} -
diff --git a/comm-common/src/templates/not_found.html b/comm-common/src/templates/not_found.html deleted file mode 100644 index e267c99..0000000 --- a/comm-common/src/templates/not_found.html +++ /dev/null @@ -1,4 +0,0 @@ -
-

{{ translations.no_credentials_found }}

- {% include "logout.html" %} -
diff --git a/comm-plugin/.gitignore b/comm-plugin/.gitignore deleted file mode 100644 index b31a466..0000000 --- a/comm-plugin/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -/target -/.cache -attribute-ui/node_modules/ -attribute-ui/public/ -attribute-ui/.parcel-cache -attribute-ui/.yarn-cache \ No newline at end of file diff --git a/comm-plugin/Cargo.toml b/comm-plugin/Cargo.toml deleted file mode 100644 index 76de2c6..0000000 --- a/comm-plugin/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "verder-helpen-comm-isolate" -version = "0.1.0" -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -verder-helpen-sentry = { git = "https://github.com/verder-helpen/verder-helpen-sentry.git", optional = true } -verder-helpen-jwt = { git = "https://github.com/verder-helpen/verder-helpen-jwt.git" } -verder-helpen-proto = { git = "https://github.com/verder-helpen/verder-helpen-proto.git" } -rocket = { version = "0.5.0-rc.3", features = ["json"] } -serde = "1.0.159" -serde_json = "1.0.95" -reqwest = { version = "0.11.16", features = ["json"] } - -[dependencies.verder-helpen-comm-common] -path = "../comm-common" -features = ["auth_during_comm", "session_db"] - -[features] -sentry = ["dep:verder-helpen-sentry"] diff --git a/comm-plugin/LICENSE b/comm-plugin/LICENSE deleted file mode 120000 index ea5b606..0000000 --- a/comm-plugin/LICENSE +++ /dev/null @@ -1 +0,0 @@ -../LICENSE \ No newline at end of file diff --git a/comm-plugin/attribute-ui/attribute.js b/comm-plugin/attribute-ui/attribute.js deleted file mode 100644 index eb8e881..0000000 --- a/comm-plugin/attribute-ui/attribute.js +++ /dev/null @@ -1,53 +0,0 @@ -document.addEventListener("DOMContentLoaded", function() { - const hostToken = window.location.pathname.split('/').pop(); - const rootElement = document.getElementById('root'); - - function fetchAndRender() { - return fetch(`session_info/${hostToken}`, { - credentials: 'include', - }) - .then((r) => { - if (r.status === 200 || r.status === 401 || r.status === 404) { - r.text().then((html) => { - rootElement.innerHTML = html; - }); - } - - return r.status; - }); - } - - function listenForEvents() { - const source = new EventSource(`live/session_info/${hostToken}`, { withCredentials: true }); - - source.onmessage = (event) => { - if (event.data) { - fetchAndRender(); - } - }; - - source.onerror = () => { - source.close(); - setTimeout(listenForEvents, 5 * 1000); - }; - } - - function poll() { - if (!document.hidden) { - fetchAndRender().then((status) => { - if (status === 401) { - // keep polling until user is logged in - setTimeout(poll, 5 * 1000); - } else { - // start listening for server updates - listenForEvents(); - } - }); - } else { - setTimeout(poll, 5 * 1000); - } - } - - // poll until user is logged in - poll(); -}); diff --git a/comm-plugin/attribute-ui/index.html b/comm-plugin/attribute-ui/index.html deleted file mode 100644 index bf2f855..0000000 --- a/comm-plugin/attribute-ui/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - Verder Helpen - - - - -
- - diff --git a/config.sample.toml b/config.sample.toml index c8df2b9..45002fa 100644 --- a/config.sample.toml +++ b/config.sample.toml @@ -1,5 +1,5 @@ [global] -## NOTE: Don't (!) use this key! Generate your own! +## NOTE: DON'T USE THIS KEY! GENERATE YOUR OWN! secret_key = "2P7d9MsOAZWyPu8HZn2AyMvOeN9MhkFEb4C9IzkLvno=" internal_url = "http://comm-isolate:8000/internal" @@ -149,7 +149,6 @@ Bs6neR/sZuHzNm8y/xtxj2ZAEw== session = { url = "postgres://tg@comm-isolate-psql:5432/tg" } [global.translations.en] -title = "Information" unknown_error = "Unknown error" loading = "Loading..." purpose = "Subject" @@ -168,9 +167,9 @@ login_successful = "Login successfull. You can close this window." logout_successful = "Logout successfull. You can close this window." insufficient_permission = "You do not have sufficient permissions to access this resource." no_credentials_found = "There are no authenticated guests (yet)" +secured_by = "secured by" [global.translations.nl] -title = "Verder Helpen gegevens" unknown_error = "Onbekende fout" loading = "Laden..." purpose = "Onderwerp" @@ -189,3 +188,4 @@ login_successful = "U bent ingelogd. U kan dit venster nu sluiten" logout_successful = "U bent uitgelogd. U kan dit venster nu sluiten" insufficient_permission = "Uw account heeft niet voldoende rechten, probeer met een ander account in te loggen" no_credentials_found = "Er zijn (nog) geen geïdentificeerde gasten" +secured_by = "beveiligd door" diff --git a/comm-common/src/auth.rs b/src/auth.rs similarity index 85% rename from comm-common/src/auth.rs rename to src/auth.rs index 74a4c70..f635297 100644 --- a/comm-common/src/auth.rs +++ b/src/auth.rs @@ -263,53 +263,3 @@ pub fn render_login( Err(Error::Unauthorized(login_url)) } - -pub fn render_unauthorized( - config: &Config, - render_type: RenderType, - translations: Translations, -) -> Result { - let logout_url = format!("{}/auth/logout", config.external_host_url()); - - if render_type == RenderType::Html { - let mut context = Context::new(); - - context.insert("translations", translations.all()); - if config.auth_provider().is_some() { - context.insert("logout_url", &logout_url); - } - - let content = TEMPLATES.render("expired.html", &context)?; - return Ok(RenderedContent { - content, - render_type, - }); - } - - Err(Error::Forbidden(logout_url)) -} - -pub fn render_not_found( - config: &Config, - render_type: RenderType, - translations: Translations, -) -> Result { - let logout_url = format!("{}/auth/logout", config.external_host_url()); - - if render_type == RenderType::Html { - let mut context = Context::new(); - - context.insert("translations", translations.all()); - if config.auth_provider().is_some() { - context.insert("logout_url", &logout_url); - } - - let content = TEMPLATES.render("not_found.html", &context)?; - return Ok(RenderedContent { - content, - render_type, - }); - } - - Err(Error::NotFound) -} diff --git a/comm-common/src/config.rs b/src/config.rs similarity index 98% rename from comm-common/src/config.rs rename to src/config.rs index bc29308..b08ae04 100644 --- a/comm-common/src/config.rs +++ b/src/config.rs @@ -19,6 +19,7 @@ pub struct RawConfig { external_guest_url: Option, external_host_url: Option, /// Sentry DSN + #[cfg(feature = "sentry")] sentry_dsn: Option, /// Default locale default_locale: String, @@ -36,6 +37,8 @@ pub struct RawConfig { #[serde(flatten)] /// Configuration specific for auth during comm auth_during_comm_config: RawAuthDuringCommConfig, + + custom_css: Option, } /// configuration container for a typical verder-helpen communication plugin @@ -45,6 +48,7 @@ pub struct Config { pub internal_url: String, pub external_guest_url: Option, pub external_host_url: Option, + #[cfg(feature = "sentry")] pub sentry_dsn: Option, pub default_locale: String, pub translations: LanguageTranslations, @@ -57,6 +61,8 @@ pub struct Config { #[cfg(feature = "auth_during_comm")] #[serde(flatten)] pub auth_during_comm_config: AuthDuringCommConfig, + + pub custom_css: Option, } // This tryfrom can be removed once try_from for fields lands in serde @@ -79,12 +85,14 @@ impl TryFrom for Config { internal_url: raw_config.internal_url, external_guest_url: raw_config.external_guest_url, external_host_url: raw_config.external_host_url, + #[cfg(feature = "sentry")] sentry_dsn: raw_config.sentry_dsn, default_locale: raw_config.default_locale, translations: raw_config.translations, auth_provider, decrypter: Box::::try_from(raw_config.decryption_privkey)?, verifier: Box::::try_from(raw_config.signature_pubkey)?, + custom_css: raw_config.custom_css, }) } } @@ -116,6 +124,7 @@ impl Config { } } + #[cfg(feature = "sentry")] pub fn sentry_dsn(&self) -> Option<&str> { self.sentry_dsn.as_deref() } diff --git a/comm-common/src/credentials.rs b/src/credentials.rs similarity index 70% rename from comm-common/src/credentials.rs rename to src/credentials.rs index 7e6cf23..592346b 100644 --- a/comm-common/src/credentials.rs +++ b/src/credentials.rs @@ -1,11 +1,10 @@ use serde::Serialize; -use serde_json; use tera::Context; #[cfg(feature = "session_db")] use crate::session::{Session, SessionDBConn}; #[cfg(feature = "session_db")] -use crate::types::platform_token::{FromPlatformJwt, HostToken}; +use crate::types::platform_token::HostToken; use crate::{ config::Config, error::Error, @@ -22,43 +21,45 @@ pub fn collect_credentials( let mut credentials: Vec = vec![]; for guest_auth_result in guest_auth_results.iter() { - if let Some(result) = &guest_auth_result.auth_result { - if let Some(attributes) = - verder_helpen_jwt::dangerous_decrypt_auth_result_without_verifying_expiration( - result, - config.verifier(), - config.decrypter(), - )? - .attributes - { - credentials.push(Credentials { - name: guest_auth_result.name.clone(), - purpose: guest_auth_result.purpose.clone(), - attributes, - }); - } + let attributes = if let Some(result) = &guest_auth_result.auth_result { + verder_helpen_jwt::dangerous_decrypt_auth_result_without_verifying_expiration( + result, + config.verifier(), + config.decrypter(), + )? + .attributes + } else { + None }; + + credentials.push(Credentials { + name: guest_auth_result.name.clone(), + purpose: guest_auth_result.purpose.clone(), + attributes, + }); } Ok(credentials) } -#[derive(Serialize)] +#[derive(Debug, Serialize)] pub struct SortedCredentials { pub purpose: Option, pub name: Option, - pub attributes: Vec<(String, String)>, + pub attributes: Option>, } /// sorted credentials are sorted by their name (key) impl From for SortedCredentials { fn from(credentials: Credentials) -> Self { - let mut attributes = credentials - .attributes - .into_iter() - .collect::>(); + let attributes = if let Some(attributes) = credentials.attributes { + let mut attributes = attributes.into_iter().collect::>(); - attributes.sort_by(|x, y| x.0.cmp(&y.0)); + attributes.sort_by(|x, y| x.0.cmp(&y.0)); + Some(attributes) + } else { + None + }; SortedCredentials { purpose: credentials.purpose, @@ -97,11 +98,11 @@ pub fn render_credentials( context.insert("logout_url", &logout_url); } - let content = if render_type == RenderType::HtmlPage { - TEMPLATES.render("base.html", &context)? - } else { - TEMPLATES.render("credentials.html", &context)? - }; + if let Some(custom_css) = &config.custom_css { + context.insert("custom_css", &custom_css); + } + + let content = TEMPLATES.render("credentials.html", &context)?; Ok(RenderedContent { content, @@ -109,31 +110,15 @@ pub fn render_credentials( }) } -/// retrieve sessions for all users in a room -/// the id of the room is provided by a host jwt -#[cfg(feature = "session_db")] -pub async fn get_sessions_for_host( - host_token: String, - config: &Config, - db: &SessionDBConn, -) -> Result, Error> { - let host_token = HostToken::from_platform_jwt( - &host_token, - config.auth_during_comm_config().host_verifier(), - )?; - - Session::find_by_room_id(host_token.room_id, db).await -} - /// retrieve authentication results for all users in a room /// the id of the room is provided by a host jwt #[cfg(feature = "session_db")] pub async fn get_credentials_for_host( - host_token: String, + host_token: HostToken, config: &Config, db: &SessionDBConn, ) -> Result, Error> { - let sessions = get_sessions_for_host(host_token, config, db).await?; + let sessions = Session::find_by_room_id(host_token.room_id, db).await?; for session in &sessions { session.mark_active(db).await?; } @@ -146,8 +131,10 @@ pub async fn get_credentials_for_host( auth_result: session.auth_result, }) .collect::>(); - - collect_credentials(&guest_auth_results, config) + println!("{:?}", &guest_auth_results); + let creds = collect_credentials(&guest_auth_results, config); + println!("{:?}", &creds); + creds } #[cfg(test)] @@ -247,6 +234,7 @@ mod tests { internal_url: "https://example.com".to_string(), external_host_url: None, external_guest_url: None, + #[cfg(feature = "sentry")] sentry_dsn: None, default_locale: String::from("nl"), translations: HashMap::new(), @@ -254,6 +242,7 @@ mod tests { auth_provider: None, verifier, auth_during_comm_config, + custom_css: None, }; let translations = Translations { @@ -262,43 +251,32 @@ mod tests { ("title".to_string(), "Gegevens".to_string()), ("age".to_string(), "Leeftijd".to_string()), ("email".to_string(), "E-mailadres".to_string()), + ("secured_by".to_string(), "Beveiligd door".to_string()), ]), language: "nl".to_string(), }; let credentials = collect_credentials(&guest_auth_results, &config).unwrap(); - let out_result = + let actual = render_credentials(&config, credentials, RenderType::Html, translations.clone()) .unwrap(); - let result: &str = "

HenkDieter
Leeftijd
42
E-mailadres
hd@example.com
"; - - assert_eq!( - remove_whitespace(result), - remove_whitespace(out_result.content()) - ); - - let credentials = collect_credentials(&guest_auth_results, &config).unwrap(); - let out_result = render_credentials( - &config, - credentials, - RenderType::HtmlPage, - translations.clone(), - ) - .unwrap(); - let result: &str = "Gegevens

Gegevens

HenkDieter
Leeftijd
42
E-mailadres
hd@example.com

"; + let expected: &str = + "Verder \ + Helpen

Henk \ + Dieter

Leeftijd
42
E-mailadres
hd@example.com
Beveiligd door
"; assert_eq!( - remove_whitespace(result), - remove_whitespace(out_result.content()) + remove_whitespace(expected), + remove_whitespace(actual.content()) ); let credentials = collect_credentials(&guest_auth_results, &config).unwrap(); @@ -308,10 +286,10 @@ mod tests { let result: serde_json::Value = serde_json::from_str(rendered.content()).unwrap(); let expected = serde_json::json! { [{ - "purpose":"test_purpose", - "name":"Henk Dieter", - "attributes":{"age":"42","email":"hd@example.com"}} - ] + "purpose": "test_purpose", + "name": "Henk Dieter", + "attributes": { "age":"42", "email": "hd@example.com" } + }] }; assert_eq!(result, expected); diff --git a/comm-common/src/error.rs b/src/error.rs similarity index 99% rename from comm-common/src/error.rs rename to src/error.rs index 0c4becb..b9a3389 100644 --- a/comm-common/src/error.rs +++ b/src/error.rs @@ -4,7 +4,6 @@ use rocket::{ }; use rocket_sync_db_pools::postgres; use serde_json::json; -use tera; use thiserror::Error; use crate::jwt::JwtError; diff --git a/comm-common/src/jwt.rs b/src/jwt.rs similarity index 68% rename from comm-common/src/jwt.rs rename to src/jwt.rs index 38de263..cb268d7 100644 --- a/comm-common/src/jwt.rs +++ b/src/jwt.rs @@ -83,37 +83,37 @@ mod tests { use verder_helpen_proto::StartRequestAuthOnly; use super::{sign_auth_select_params, sign_start_auth_request}; - use crate::prelude::AuthSelectParams; - - const RSA_PRIVKEY: &'static str = - "{\"type\":\"RSA\",\"key\":\"-----BEGIN PRIVATE \ - KEY-----\\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDn/BGtPZPgYa+5\\\ - nBhxaMuv+UV7nWxNXYUt3cYBoyIc3xD9VP9cSE/+RnrTjaXUGPZWlnbIzG/b3gkrA\\\ - nEIg1zfjxUth34N+QycnjJf0tkcrZaR7q0JYEH2ZiAaMzAI11dzNuX3rHX8d69pOi\\nu+T3WvMK/\ - PDq9XTyO2msDI3lpgxTgjT9xUnCLTduH+yStoAHXXSZBKqLVBT/bPoe\\nS5/v7/H9sALG+JYLI8J3/\ - CRc2kWFNxGV8V7IpzLSnAXHU4sIMnWpjuhT7PXBzKl4\\\ - n4d6JRLGuJIeVZpPbiR74nvwYZWacJl278xG66fmG+BqJbGeEgGYTEljq9G4yXCRt\\\ - nGo5+3lBNAgMBAAECggEARY9EsaCMLbS83wrhB37LWneFsHOTqhjHaypCaajvOp6C\\nqwo4b/\ - hFIqHm9WWSrGtc6ssNOtwAwphz14Fdhlybb6j6tX9dKeoHui+S6c4Ud/pY\\nReqDgPr1VR/\ - OkqVwxS8X4dmJVCz5AHrdK+eRMUY5KCtOBfXRuixsdCVTiu+uNH99\\\ - nQC3kID1mmOF3B0chOK4WPN4cCsQpfOvoJfPBcJOtyxUSLlQdJH+04s3gVA24nCJj\\\ - n66+AnVkjgkyQ3q0Jugh1vo0ikrUW8uSLmg40sT5eYDN9jP6r5Gc8yDqsmYNVbLhU\\\ - npY8XR4gtzbtAXK8R2ISKNhOSuTv4SWFXVZiDIBkuIQKBgQD3qnZYyhGzAiSM7T/R\\\ - nWS9KrQlzpRV5qSnEp2sPG/YF+SGAdgOaWOEUa3vbkCuLCTkoJhdTp67BZvv/657Q\\\ - n2eK2khsYRs02Oq+4rYvdcAv/wS2vkMbg6CUp1w2/pwBvwFTXegr00k6IabXNcXBy\\\ - nkAjMsZqVDSdQByrf80AlFyEsOQKBgQDvyoUDhLReeDNkbkPHL/EHD69Hgsc77Hm6\\\ - nMEiLdNljTJLRUl+DuD3yKX1xVBaCLp9fMJ/mCrxtkldhW+i6JBHRQ7vdf11zNsRf\\\ - n2Cud3Q97RMHTacCHhEQDGnYkOQNTRhk8L31N0XBKfUu0phSmVyTnu2lLWmYJ8hyO\\\ - nyOEB19JstQKBgQC3oVw+WRTmdSBEnWREBKxb4hCv/ib+Hb8qYDew7DpuE1oTtWzW\\ndC/\ - uxAMBuNOQMzZ93kBNdnbMT19pUXpfwC2o0IvmZBijrL+9Xm/lr7410zXchqvu\\n9jEX5Kv8/\ - gYE1cYSPhsBiy1PV5HE0edeCg18N/M1sJsFa0sO4X0eAxhFgQKBgQC7\\\ - niQDkUooaBBn1ZsM9agIwSpUD8YTOGdDNy+tAnf9SSNXePXUT+CkCVm6UDnaYE8xy\\nzv2PFUBu1W/\ - fZdkqkwEYT8gCoBS/AcstRkw+Z2AvQQPxyxhXJBto7e4NwEUYgI9F\\n4cI29SDEMR/\ - fRbCKs0basVjVJPr+tkqdZP+MyHT6rQKBgQCT1YjY4F45Qn0Vl+sZ\\nHqwVHvPMwVsexcRTdC0evaX/\ - 09s0xscSACvFJh5Dm9gnuMHElBcpZFATIvFcbV5Y\\nMbJ/\ - NNQiD63NEcL9VXwT96sMx2tnduOq4sYzu84kwPQ4ohxmPt/7xHU3L8SGqoec\\nBs6neR/sZuHzNm8y/\ - xtxj2ZAEw==\\n-----END PRIVATE KEY-----\"}"; - const RSA_PUBKEY: &'static str = + use crate::types::AuthSelectParams; + + const RSA_PRIVKEY: &str = "{\"type\":\"RSA\",\"key\":\"-----BEGIN PRIVATE \ + KEY-----\\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDn/\ + BGtPZPgYa+5\\nBhxaMuv+UV7nWxNXYUt3cYBoyIc3xD9VP9cSE/\ + +RnrTjaXUGPZWlnbIzG/b3gkrA\\\ + nEIg1zfjxUth34N+QycnjJf0tkcrZaR7q0JYEH2ZiAaMzAI11dzNuX3rHX8d69pOi\\\ + nu+T3WvMK/PDq9XTyO2msDI3lpgxTgjT9xUnCLTduH+yStoAHXXSZBKqLVBT/bPoe\\\ + nS5/v7/H9sALG+JYLI8J3/CRc2kWFNxGV8V7IpzLSnAXHU4sIMnWpjuhT7PXBzKl4\\\ + n4d6JRLGuJIeVZpPbiR74nvwYZWacJl278xG66fmG+BqJbGeEgGYTEljq9G4yXCRt\\\ + nGo5+3lBNAgMBAAECggEARY9EsaCMLbS83wrhB37LWneFsHOTqhjHaypCaajvOp6C\\\ + nqwo4b/hFIqHm9WWSrGtc6ssNOtwAwphz14Fdhlybb6j6tX9dKeoHui+S6c4Ud/pY\\\ + nReqDgPr1VR/OkqVwxS8X4dmJVCz5AHrdK+eRMUY5KCtOBfXRuixsdCVTiu+uNH99\\\ + nQC3kID1mmOF3B0chOK4WPN4cCsQpfOvoJfPBcJOtyxUSLlQdJH+04s3gVA24nCJj\\\ + n66+AnVkjgkyQ3q0Jugh1vo0ikrUW8uSLmg40sT5eYDN9jP6r5Gc8yDqsmYNVbLhU\\\ + npY8XR4gtzbtAXK8R2ISKNhOSuTv4SWFXVZiDIBkuIQKBgQD3qnZYyhGzAiSM7T/R\\\ + nWS9KrQlzpRV5qSnEp2sPG/YF+SGAdgOaWOEUa3vbkCuLCTkoJhdTp67BZvv/657Q\\\ + n2eK2khsYRs02Oq+4rYvdcAv/wS2vkMbg6CUp1w2/pwBvwFTXegr00k6IabXNcXBy\\\ + nkAjMsZqVDSdQByrf80AlFyEsOQKBgQDvyoUDhLReeDNkbkPHL/EHD69Hgsc77Hm6\\\ + nMEiLdNljTJLRUl+DuD3yKX1xVBaCLp9fMJ/mCrxtkldhW+i6JBHRQ7vdf11zNsRf\\\ + n2Cud3Q97RMHTacCHhEQDGnYkOQNTRhk8L31N0XBKfUu0phSmVyTnu2lLWmYJ8hyO\\\ + nyOEB19JstQKBgQC3oVw+WRTmdSBEnWREBKxb4hCv/ib+Hb8qYDew7DpuE1oTtWzW\\\ + ndC/uxAMBuNOQMzZ93kBNdnbMT19pUXpfwC2o0IvmZBijrL+9Xm/lr7410zXchqvu\\\ + n9jEX5Kv8/gYE1cYSPhsBiy1PV5HE0edeCg18N/M1sJsFa0sO4X0eAxhFgQKBgQC7\\\ + niQDkUooaBBn1ZsM9agIwSpUD8YTOGdDNy+tAnf9SSNXePXUT+CkCVm6UDnaYE8xy\\\ + nzv2PFUBu1W/fZdkqkwEYT8gCoBS/AcstRkw+Z2AvQQPxyxhXJBto7e4NwEUYgI9F\\\ + n4cI29SDEMR/fRbCKs0basVjVJPr+tkqdZP+MyHT6rQKBgQCT1YjY4F45Qn0Vl+sZ\\\ + nHqwVHvPMwVsexcRTdC0evaX/09s0xscSACvFJh5Dm9gnuMHElBcpZFATIvFcbV5Y\\\ + nMbJ/NNQiD63NEcL9VXwT96sMx2tnduOq4sYzu84kwPQ4ohxmPt/7xHU3L8SGqoec\\\ + nBs6neR/sZuHzNm8y/xtxj2ZAEw==\\n-----END PRIVATE KEY-----\"}"; + const RSA_PUBKEY: &str = "{\"type\":\"RSA\",\"key\":\"-----BEGIN PUBLIC \ KEY-----\\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5/wRrT2T4GGvuQYcWjLr\\n/\ lFe51sTV2FLd3GAaMiHN8Q/VT/XEhP/kZ6042l1Bj2VpZ2yMxv294JKwBCINc34\\\ diff --git a/comm-common/src/lib.rs b/src/lib.rs similarity index 93% rename from comm-common/src/lib.rs rename to src/lib.rs index 5eb0394..a2f98a1 100644 --- a/comm-common/src/lib.rs +++ b/src/lib.rs @@ -34,7 +34,7 @@ pub mod prelude { #[cfg(feature = "platform_token")] pub use crate::types::{FromPlatformJwt, GuestToken, HostToken}; pub use crate::{ - auth::{render_login, render_unauthorized, AuthProvider, Authorized, LoginUrl}, + auth::{render_login, AuthProvider, Authorized, LoginUrl}, config::Config, error::Error, jwt::sign_auth_select_params, diff --git a/comm-plugin/src/main.rs b/src/main.rs similarity index 73% rename from comm-plugin/src/main.rs rename to src/main.rs index cc9b67a..0d8c7cf 100644 --- a/comm-plugin/src/main.rs +++ b/src/main.rs @@ -1,12 +1,15 @@ +#[macro_use] +extern crate lazy_static; + use std::convert::Infallible; +use auth::Authorized; +use config::Config; +use error::Error; use rocket::{ - get, - http::Status, - post, + get, post, response::{ - content::{RawHtml, RawJavaScript}, - status, + content::{RawCss, RawJavaScript}, stream::{Event, EventStream}, Redirect, }, @@ -18,23 +21,26 @@ use rocket::{ }, Shutdown, State, }; -use verder_helpen_comm_common::{ - auth::{render_login, render_not_found, Authorized}, - config::Config, - credentials::{get_credentials_for_host, render_credentials}, - error::Error, - jwt::sign_auth_select_params, - session::{periodic_cleanup, Session, SessionDBConn}, - templates::{RenderType, RenderedContent}, - translations::Translations, - types::{AuthSelectParams, FromPlatformJwt, GuestToken, HostToken, StartRequest}, - util::random_string, -}; +use session::{Session, SessionDBConn}; +use templates::{RenderType, RenderedContent}; +use translations::Translations; +use types::{AuthSelectParams, FromPlatformJwt, GuestToken, HostToken, StartRequest}; use verder_helpen_proto::{ClientUrlResponse, StartRequestAuthOnly}; +mod auth; +mod config; +mod credentials; +mod error; +mod jwt; +mod session; +mod templates; +mod translations; +mod types; +mod util; + #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(crate = "rocket::serde")] -struct AttributesReceivedEvent { +struct AttributesUpdateEvent { pub attr_id: String, } @@ -56,7 +62,7 @@ async fn init(guest_token: String, config: &State) -> Result) -> Result, db: SessionDBConn, + queue: &State>, ) -> Result, Error> { let guest_token = GuestToken::from_platform_jwt( &guest_token, @@ -90,12 +98,12 @@ async fn start( )); } - let attr_id = random_string(64); + let attr_id = util::random_string(64); let comm_url = guest_token.redirect_url.clone(); let attr_url = format!("{}/auth_result/{}", config.internal_url(), attr_id); let purpose = guest_token.purpose.clone(); if !Session::restart_auth(guest_token.clone(), attr_id.clone(), &db).await? { - let session = Session::new(guest_token, attr_id); + let session = Session::new(guest_token, attr_id.clone()); session.persist(&db).await?; } @@ -107,7 +115,7 @@ async fn start( attr_url: Some(attr_url), }; - let start_request = verder_helpen_comm_common::jwt::sign_start_auth_request( + let start_request = jwt::sign_start_auth_request( start_request, config.auth_during_comm_config().start_auth_key_id(), config.auth_during_comm_config().start_auth_signer(), @@ -133,6 +141,13 @@ async fn start( .text() .await?; + // may fail when there are no subscribers + let res = queue.send(AttributesUpdateEvent { attr_id }); + match res { + Ok(_) => println!("Update sent"), + Err(_) => println!("Err, no update sent"), + } + let client_url_response = serde_json::from_str::(&client_url_response)?; Ok(Json(client_url_response)) } @@ -143,7 +158,7 @@ async fn auth_result( auth_result: String, config: &State, db: SessionDBConn, - queue: &State>, + queue: &State>, ) -> Result<(), Error> { verder_helpen_jwt::decrypt_and_verify_auth_result( &auth_result, @@ -153,7 +168,7 @@ async fn auth_result( let response = Session::register_auth_result(attr_id.clone(), auth_result, &db).await; // may fail when there are no subscribers - let _ = queue.send(AttributesReceivedEvent { attr_id }); + let _ = queue.send(AttributesUpdateEvent { attr_id }); response } @@ -171,25 +186,25 @@ impl<'r> rocket::request::FromRequest<'r> for MyRocket<'r> { } } -#[get("/live/session_info/")] -async fn live_session_info<'a>( - queue: &State>, +#[get("/live/")] +async fn session_info<'a>( + queue: &State>, mut end: Shutdown, - host_token: String, - config: &State, + token: String, + config: &'a State, authorized: Authorized, rocket: MyRocket<'a>, ) -> EventStream![Event + 'a] { let mut rx = queue.subscribe(); - let host_token = HostToken::from_platform_jwt( - &host_token, - config.auth_during_comm_config().host_verifier(), - ); - EventStream! { - if let Ok(host_token) = host_token { - if authorized.into() { + if authorized.into() { + let host_token = HostToken::from_platform_jwt( + &token, + config.auth_during_comm_config().host_verifier(), + ); + + if let Ok(host_token) = host_token { yield Event::data("start"); loop { @@ -200,6 +215,7 @@ async fn live_session_info<'a>( Some(db) => db, None => break, }; + // fetch all attribute ids related to the provided host token if let Ok(sessions) = Session::find_by_room_id( host_token.room_id.clone(), @@ -222,58 +238,58 @@ async fn live_session_info<'a>( }; } } + yield Event::data("badrequest"); } yield Event::data("forbidden"); } } -#[get("/session_info/")] -async fn session_info( - host_token: String, +#[get("/clean_db")] +async fn clean_db(db: SessionDBConn) -> Result<(), Error> { + session::clean_db(&db).await +} + +#[get("/")] +async fn attribute_ui( config: &State, db: SessionDBConn, authorized: Authorized, translations: Translations, -) -> Result, Error> { + token: String, +) -> Result { if authorized.into() { - let credentials = get_credentials_for_host(host_token, config, &db) - .await - .unwrap_or_else(|_| Vec::new()); - - // return 404 when no credentials are found - if credentials.is_empty() { - return Ok(status::Custom( - Status::NotFound, - render_not_found(config, RenderType::Html, translations)?, - )); + let host_token = + HostToken::from_platform_jwt(&token, config.auth_during_comm_config().host_verifier()); + + if let Ok(token) = host_token { + let credentials = credentials::get_credentials_for_host(token, config, &db) + .await + .unwrap_or_else(|_| Vec::new()); + + return Ok(credentials::render_credentials( + config, + credentials, + RenderType::Html, + translations, + ) + .unwrap()); } - return Ok(status::Custom( - Status::Ok, - render_credentials(config, credentials, RenderType::Html, translations)?, - )); + return Err(Error::BadRequest("invalid host token")); } - Ok(status::Custom( - Status::Unauthorized, - render_login(config, RenderType::Html, translations)?, - )) -} - -#[get("/clean_db")] -async fn clean_db(db: SessionDBConn) -> Result<(), Error> { - verder_helpen_comm_common::session::clean_db(&db).await + auth::render_login(config, RenderType::Html, translations) } -#[get("/<_token>")] -async fn attribute_ui(_token: String) -> RawHtml<&'static str> { - RawHtml(include_str!("../attribute-ui/index.html")) +#[get("/attribute.css")] +async fn attribute_css() -> RawCss<&'static str> { + RawCss(include_str!("templates/attribute.css")) } #[get("/attribute.js")] async fn attribute_js() -> RawJavaScript<&'static str> { - RawJavaScript(include_str!("../attribute-ui/attribute.js")) + RawJavaScript(include_str!("templates/attribute.js")) } #[rocket::main] @@ -281,12 +297,12 @@ async fn main() -> Result<(), rocket::Error> { #[cfg(feature = "sentry")] verder_helpen_sentry::SentryLogger::init(); let mut base = rocket::build() - .manage(channel::(1024).0) + .manage(channel::(1024).0) .mount("/internal", routes![auth_result, clean_db,]) .mount("/guest", routes![init, start,]) .mount( "/host", - routes![live_session_info, session_info, attribute_ui, attribute_js,], + routes![session_info, attribute_ui, attribute_css, attribute_js,], ) .attach(SessionDBConn::fairing()); @@ -318,12 +334,11 @@ async fn main() -> Result<(), rocket::Error> { .await .expect("Failed to fetch database connection for periodic cleanup"); rocket::tokio::spawn(async move { - periodic_cleanup(&connection, None) + session::periodic_cleanup(&connection, None) .await .expect("Failed cleanup"); }); - // manually ignoring `unused_must_use` for Rocket version 0.5.0-rc.2 - let _ = base.launch().await?; + base.launch().await?; Ok(()) } diff --git a/comm-common/src/session.rs b/src/session.rs similarity index 99% rename from comm-common/src/session.rs rename to src/session.rs index 8cd70a5..e5c40ad 100644 --- a/comm-common/src/session.rs +++ b/src/session.rs @@ -223,8 +223,9 @@ mod tests { use super::Session; use crate::{ - prelude::{random_string, GuestToken, SessionDBConn}, - session::clean_db, + session::{clean_db, SessionDBConn}, + types::GuestToken, + util::random_string, }; async fn init_db() -> Option { diff --git a/comm-common/src/templates.rs b/src/templates.rs similarity index 89% rename from comm-common/src/templates.rs rename to src/templates.rs index c3ea64a..27eee5e 100644 --- a/comm-common/src/templates.rs +++ b/src/templates.rs @@ -1,6 +1,5 @@ use std::path::Path; -use lazy_static; use rocket::{ response::{self, content, Responder}, Request, @@ -37,7 +36,6 @@ impl<'r> Responder<'r, 'static> for RenderedContent { pub enum RenderType { Json, Html, - HtmlPage, } // Includes template at runtime, if available, otherwise uses compile-time @@ -72,12 +70,14 @@ lazy_static! { pub static ref TEMPLATES: Tera = { let mut tera = Tera::default(); + include_template!(tera, "macros.html"); + include_template!(tera, "attribute.js"); include_template!(tera, "base.html"); include_template!(tera, "credentials.html"); - include_template!(tera, "expired.html"); include_template!(tera, "login.html"); - include_template!(tera, "logout.html"); - include_template!(tera, "not_found.html"); + include_template!(tera, "logout_form.html"); + include_template!(tera, "none_in_room.html"); + include_template!(tera, "footer.html"); tera }; diff --git a/src/templates/attribute.css b/src/templates/attribute.css new file mode 100644 index 0000000..757418b --- /dev/null +++ b/src/templates/attribute.css @@ -0,0 +1,144 @@ +:root { + --primary-color: 33, 0, 112; + --background-color: #fafbfb; + --container-max-width: 48rem; + --logo: url('/assets/verderhelpen.svg'); + --light-grey: #ebedef; + --grey: #dde0e4; + --dark-grey: #a9a9a9; + --dark: #696969; + --border-radius: 0.2rem; +} + +* { + box-sizing: border-box; +} + +html, body { + font-family: Arial, Helvetica, sans-serif; + font-size: 16; + line-height: 1.5; + margin: 0; + background-color: var(--background-color); + width: 100vw; + height: 100vh; +} + +main { + padding: 1.25rem 1rem; + max-width: var(--container-max-width); + margin: auto; + height: 100%; +} + +p { + color: var(--dark); + font-size: 17px; +} + +a { + color: var(--primary-color); +} + +.status { + display: flex; + flex-direction: column; + gap: 1rem; + height: 100%; +} + +.credential { + background-color: white; + border-radius: var(--border-radius); + border: 1px solid var(--grey); +} + +.credential > div { + padding: 1rem; +} + +.credential > div + div { + border-top: 1px solid var(--grey); +} + +.credential h4 { + margin: 0; +} + +.credential dl { + background-color: transparent; + padding: 0; + border: 0; + margin: 0; +} + +.credential dl dt { + color: rgb(var(--primary-color)); + font-size: 0.9rem; +} + +.credential dl dd { + display: inline-block; + margin: 0.5rem 0 1rem 0; +} + +.credential dl dd div { + display: flex; + padding: 0.4rem 0.6rem; + background: #d0f0c0; + border: 1px solid #a8e4a0; + border-radius: var(--border-radius); +} + +.credential dl dd div > .icon { + content: ' '; + display: inline-block; + width: 1.4rem; + height: 1.4rem; + margin-right: .4rem; + background-image: url('/assets/check-fill.svg'); + background-repeat: no-repeat; + background-position: center; + background-size: contain; +} + +.credential dl dd:last-child { + margin-bottom: 0.4rem; +} + +.footer { + display: flex; + flex-direction: column; + align-items: center; + margin-top: auto; +} + +.footer > .text { + color: var(--dark-grey); + font-size: 0.9rem; +} + +.footer > .logo { + height: 1.5rem; + width: 100%; + background-image: var(--logo); + background-repeat: no-repeat; + background-position: center; + background-size: contain; + filter: grayscale(100%); + opacity: 0.5; +} + +.notification { + display: inline-block; + background: #fef7ea; + border: 1px solid #fadeaf; + color: var(--dark-grey); + border-radius: var(--border-radius); + padding: 0 1rem; +} + +.notification.error { + background-color: #ffcbcb; + border: 1px solid #fc7676; +} diff --git a/src/templates/attribute.js b/src/templates/attribute.js new file mode 100644 index 0000000..9adf1a6 --- /dev/null +++ b/src/templates/attribute.js @@ -0,0 +1,23 @@ +document.addEventListener("DOMContentLoaded", function() { + const hostToken = window.location.pathname.split('/').pop(); + + function listenForEvents() { + const source = new EventSource(`live/${hostToken}`, { withCredentials: true }); + + source.onmessage = (event) => { + if (event.data && event.data === 'update') { + source.close(); + window.location.reload(); + } + }; + + source.onerror = (e) => { + source.close(); + console.error("EventSource failed:", e); + setTimeout(listenForEvents, 5 * 1000); + }; + } + + // poll until user is logged in + listenForEvents(); +}); diff --git a/src/templates/base.html b/src/templates/base.html new file mode 100644 index 0000000..2ea0ac8 --- /dev/null +++ b/src/templates/base.html @@ -0,0 +1,18 @@ + + + + + + Verder Helpen + + + {%- if custom_css -%} + + {%- endif -%} + + +
+ {% block content %}{% endblock %} +
+ + diff --git a/src/templates/credentials.html b/src/templates/credentials.html new file mode 100644 index 0000000..92a785e --- /dev/null +++ b/src/templates/credentials.html @@ -0,0 +1,18 @@ +{% extends "base.html" %} +{% import "macros.html" as macros %} + +{% block content %} +
+{%- for credential in credentials | reverse -%} + {%- if credential.attributes -%} + {{ macros::attributes(credential=credential) }} + {%- else -%} + {{ macros::guest_busy(credential=credential) }} + {%- endif -%} +{%- else -%} + {% include "none_in_room.html" %} +{%- endfor -%} +{% include "footer.html" %} +
+{% include "logout_form.html" %} +{% endblock content %} diff --git a/src/templates/footer.html b/src/templates/footer.html new file mode 100644 index 0000000..bd875cc --- /dev/null +++ b/src/templates/footer.html @@ -0,0 +1,4 @@ + diff --git a/src/templates/login.html b/src/templates/login.html new file mode 100644 index 0000000..efbad6c --- /dev/null +++ b/src/templates/login.html @@ -0,0 +1,10 @@ +{% extends "base.html" %} + +{% block content %} +
+

{{ translations.login_necessary }}

+

+ {{ translations.login }} +

+
+{% endblock content %} diff --git a/comm-common/src/templates/logout.html b/src/templates/logout_form.html similarity index 83% rename from comm-common/src/templates/logout.html rename to src/templates/logout_form.html index 5e79420..31a2e2f 100644 --- a/comm-common/src/templates/logout.html +++ b/src/templates/logout_form.html @@ -1,5 +1,5 @@ -{% if logout_url %} +{%- if logout_url -%}
-{% endif %} +{%- endif -%} diff --git a/src/templates/macros.html b/src/templates/macros.html new file mode 100644 index 0000000..e591185 --- /dev/null +++ b/src/templates/macros.html @@ -0,0 +1,46 @@ +{% macro attributes(credential) %} +
+ {%- if credential.name -%} +
+

{{ credential.name }}

+
+ {%- endif -%} + {%- if credential.attributes -%} +
+
+ {%- for kv in credential.attributes -%} +
+ {{ translations[kv.0]|default(value=kv.0) }} +
+
+
+ + {{ kv.1 }} +
+
+ {%- endfor -%} +
+
+ {%- endif -%} +
+{% endmacro attributes %} + +{% macro guest_busy(credential) %} +
+ {%- if credential.name -%} +

{{ credential.name }} {{ translations.guest_busy }}

+ {%- else -%} +

{{ translations.guest_busy_anonymous }}

+ {%- endif -%} +
+{% endmacro %} + +{% macro guest_cancelled(credential) %} +
+ {%- if credential.name -%} +

{{ credential.name }} {{ translations.guest_cancelled }}

+ {%- else -%} +

{{ translations.guest_cancelled_anonymous }}

+ {%- endif -%} +
+{% endmacro %} diff --git a/src/templates/none_in_room.html b/src/templates/none_in_room.html new file mode 100644 index 0000000..383b7a3 --- /dev/null +++ b/src/templates/none_in_room.html @@ -0,0 +1,4 @@ +
+

{{ translations.no_credentials_found }}

+ {% include "logout_form.html" %} +
diff --git a/comm-common/src/translations.rs b/src/translations.rs similarity index 96% rename from comm-common/src/translations.rs rename to src/translations.rs index 4dc016e..00ef782 100644 --- a/comm-common/src/translations.rs +++ b/src/translations.rs @@ -36,14 +36,14 @@ impl<'r> Translations { let raw_accept_language: Option<&str> = req.headers().get("accept-language").next(); // parse into normalized language identifiers - let accept_languages = raw_accept_language + let accept_languages: Vec<_> = raw_accept_language .map(|raw_accept_language| { accept_language::parse(raw_accept_language) .iter() .filter_map(|al| parse_language_identifier(al.as_bytes()).ok()) .collect() }) - .unwrap_or_else(Vec::new); + .unwrap_or_default(); // retrieve translations keys and parse into normalized langiage identifiers let keys: Vec = config diff --git a/comm-common/src/types.rs b/src/types.rs similarity index 99% rename from comm-common/src/types.rs rename to src/types.rs index ceaa795..8c0b881 100644 --- a/comm-common/src/types.rs +++ b/src/types.rs @@ -33,7 +33,7 @@ pub struct GuestAuthResult { pub struct Credentials { pub purpose: Option, pub name: Option, - pub attributes: HashMap, + pub attributes: Option>, } #[cfg(feature = "platform_token")] diff --git a/comm-common/src/util.rs b/src/util.rs similarity index 100% rename from comm-common/src/util.rs rename to src/util.rs