From 8f5480ee163cf723794b1dbffaf184cc787086f8 Mon Sep 17 00:00:00 2001 From: Jippe Holwerda Date: Tue, 22 Oct 2024 08:55:56 +0200 Subject: [PATCH 1/7] Enter BSN twice for extra verification; show how many data has been preloaded; allow clearing all data --- .../src/bin/gba_fetch_frontend.rs | 100 +++++++++++------- .../gba_hc_converter/src/gba/encryption.rs | 36 ++++++- .../gba_hc_converter/src/haal_centraal.rs | 2 +- .../gba_hc_converter/templates/index.askama | 75 +++++++------ .../gba_hc_converter/templates/result.askama | 17 +++ 5 files changed, 158 insertions(+), 72 deletions(-) create mode 100644 wallet_core/gba_hc_converter/templates/result.askama diff --git a/wallet_core/gba_hc_converter/src/bin/gba_fetch_frontend.rs b/wallet_core/gba_hc_converter/src/bin/gba_fetch_frontend.rs index 3581e894f..fe12c0869 100644 --- a/wallet_core/gba_hc_converter/src/bin/gba_fetch_frontend.rs +++ b/wallet_core/gba_hc_converter/src/bin/gba_fetch_frontend.rs @@ -1,4 +1,4 @@ -use std::{env, path::PathBuf, result::Result as StdResult, sync::Arc}; +use std::{default::Default, env, path::PathBuf, result::Result as StdResult, sync::Arc}; use aes_gcm::Aes256Gcm; use anyhow::anyhow; @@ -8,7 +8,7 @@ use axum::{ middleware, middleware::Next, response::{IntoResponse, Response}, - routing::get, + routing::{get, post}, Form, Router, }; use axum_csrf::{CsrfConfig, CsrfLayer, CsrfToken}; @@ -23,7 +23,7 @@ use gba_hc_converter::{ fetch::askama_axum, gba::{ client::{GbavClient, HttpGbavClient}, - encryption::{encrypt_bytes_to_dir, HmacSha256}, + encryption::{clear_files_in_dir, count_files_in_dir, encrypt_bytes_to_dir, HmacSha256}, }, haal_centraal::Bsn, settings::{PreloadedSettings, RunMode, Settings}, @@ -68,7 +68,9 @@ impl From for Error { impl IntoResponse for Error { fn into_response(self) -> Response { warn!("error result: {:?}", self); - let result = IndexTemplate::from_error(self.0.to_string()); + let result = ResultTemplate { + msg: self.0.to_string(), + }; let mut response = askama_axum::into_response(&result); *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; response @@ -111,6 +113,7 @@ async fn serve(settings: Settings) -> anyhow::Result<()> { "/", Router::new() .route("/", get(index).post(fetch)) + .route("/clear", post(clear)) .with_state(app_state) .layer(CsrfLayer::new(csrf_config)) .layer(middleware::from_fn(check_auth)) @@ -130,59 +133,57 @@ async fn check_auth(headers: HeaderMap, request: Request, next: Next) -> StdResu Ok(response) } -#[derive(Deserialize, Debug)] -struct Payload { +#[derive(Deserialize)] +struct PreloadPayload { bsn: String, + repeat_bsn: String, authenticity_token: String, } -#[derive(Template)] +#[derive(Deserialize, Debug)] +struct ClearPayload { + confirmation_text: String, + authenticity_token: String, +} + +#[derive(Template, Default)] #[template(path = "index.askama", escape = "html", ext = "html")] struct IndexTemplate { - authenticity_token: Option, - msg: Option, - error: Option, + authenticity_token: String, + preloaded_count: u64, } -impl IndexTemplate { - fn new(authenticity_token: String) -> Self { - IndexTemplate { - authenticity_token: Some(authenticity_token), - error: None, - msg: None, - } - } +#[derive(Template, Default)] +#[template(path = "result.askama", escape = "html", ext = "html")] +struct ResultTemplate { + msg: String, +} - fn from_error(err: String) -> Self { - IndexTemplate { - authenticity_token: None, - error: Some(err), - msg: None, - } - } +async fn index(State(state): State>, token: CsrfToken) -> Result { + let path = &state.base_path.join(&state.preloaded_settings.xml_path); + let preloaded_count = count_files_in_dir(path).await.map_err(|err| anyhow!(err))?; - fn from_msg(msg: String) -> Self { - IndexTemplate { - authenticity_token: None, - msg: Some(msg), - error: None, - } - } -} + let result = IndexTemplate { + authenticity_token: token.authenticity_token().map_err(|err| anyhow!(err))?, + preloaded_count, + }; -async fn index(token: CsrfToken) -> Result { - let result = IndexTemplate::new(token.authenticity_token().map_err(|err| anyhow!(err))?); Ok(askama_axum::into_response_with_csrf(token, &result)) } async fn fetch( State(state): State>, token: CsrfToken, - Form(payload): Form, + Form(payload): Form, ) -> Result { token.verify(&payload.authenticity_token).map_err(|err| anyhow!(err))?; + if payload.bsn != payload.repeat_bsn { + return Err(anyhow!("BSN's do not match"))?; + } + let bsn = Bsn::try_new(payload.bsn).map_err(|err| anyhow!(err))?; + let path = &state.base_path.join(&state.preloaded_settings.xml_path); let xml = state .http_client @@ -195,13 +196,36 @@ async fn fetch( state.preloaded_settings.encryption_key.key::(), state.preloaded_settings.hmac_key.key::(), xml.as_bytes(), - &state.base_path.join(&state.preloaded_settings.xml_path), + path, bsn.as_ref(), ) .await .map_err(|err| anyhow!(err))?; - let result = IndexTemplate::from_msg(String::from("Ok")); + let result = ResultTemplate { + msg: String::from("Successfully preloaded"), + }; + + Ok(askama_axum::into_response(&result)) +} + +async fn clear( + State(state): State>, + token: CsrfToken, + Form(payload): Form, +) -> Result { + token.verify(&payload.authenticity_token).map_err(|err| anyhow!(err))?; + + if payload.confirmation_text != "clear all data" { + return Err(anyhow!("Confirmation text is not correct"))?; + } + + let path = &state.base_path.join(&state.preloaded_settings.xml_path); + let count = clear_files_in_dir(path).await.map_err(|err| anyhow!(err))?; + + let result = ResultTemplate { + msg: format!("Successfully cleared {count} items"), + }; Ok(askama_axum::into_response(&result)) } diff --git a/wallet_core/gba_hc_converter/src/gba/encryption.rs b/wallet_core/gba_hc_converter/src/gba/encryption.rs index 66faa8360..515190ee2 100644 --- a/wallet_core/gba_hc_converter/src/gba/encryption.rs +++ b/wallet_core/gba_hc_converter/src/gba/encryption.rs @@ -1,4 +1,7 @@ -use std::path::{Path, PathBuf}; +use std::{ + future::Future, + path::{Path, PathBuf}, +}; use aes_gcm::{ aead::{Aead, Nonce}, @@ -7,6 +10,7 @@ use aes_gcm::{ use hmac::{Hmac, Mac}; use rand_core::OsRng; use sha2::Sha256; +use tokio::fs::DirEntry; use crate::gba::error::Error; @@ -43,6 +47,36 @@ pub async fn decrypt_bytes_from_dir( } } +pub async fn count_files_in_dir(path: &Path) -> Result { + let count = iterate_encrypted_files(path, |_| async { Ok(()) }).await?; + Ok(count) +} + +pub async fn clear_files_in_dir(path: &Path) -> Result { + let count = iterate_encrypted_files( + path, + |entry| async move { Ok(tokio::fs::remove_file(entry.path()).await?) }, + ) + .await?; + Ok(count) +} + +async fn iterate_encrypted_files(path: &Path, f: F) -> Result +where + F: Fn(DirEntry) -> Fut, + Fut: Future>, +{ + let mut count = 0; + let mut entries = tokio::fs::read_dir(path).await?; + while let Some(entry) = entries.next_entry().await? { + if entry.file_type().await?.is_file() && entry.path().extension().is_some_and(|ext| ext == "aes") { + f(entry).await?; + count += 1; + } + } + Ok(count) +} + fn filename(hmac_key: &Key, path: &Path, name: &str) -> PathBuf { let hmac = name_to_encoded_hash(name, hmac_key); path.join(format!("{}.aes", &hmac)) diff --git a/wallet_core/gba_hc_converter/src/haal_centraal.rs b/wallet_core/gba_hc_converter/src/haal_centraal.rs index bc65f8037..228786b78 100644 --- a/wallet_core/gba_hc_converter/src/haal_centraal.rs +++ b/wallet_core/gba_hc_converter/src/haal_centraal.rs @@ -102,7 +102,7 @@ fn csv_path(name: &str) -> PathBuf { #[nutype( validate(predicate = Bsn::validate), - derive(Deserialize, Serialize, Clone, Debug, Display, AsRef) + derive(Deserialize, Serialize, Clone, Debug, Display, AsRef, PartialEq) )] pub struct Bsn(String); diff --git a/wallet_core/gba_hc_converter/templates/index.askama b/wallet_core/gba_hc_converter/templates/index.askama index 464e2a763..5186eec1c 100644 --- a/wallet_core/gba_hc_converter/templates/index.askama +++ b/wallet_core/gba_hc_converter/templates/index.askama @@ -3,44 +3,55 @@ {% block content %}
-

Enter BSN

+

GBA-V preloading for NL Wallet

+
+ +
+
+ Status + + + {{ preloaded_count }} +
+ +
- - {% if let Some(token) = authenticity_token %} - - {% endif %} - - -
-
+
+ Preload data - {% match msg %} - {% when Some with (msg) %} -
-

Result:

-

{{ msg }}

-
- -
-
- {% when None %} - {% endmatch %} - - {% match error %} - {% when Some with (error_msg) %} -
-

Error:

-

{{ error_msg }}

-
- + + + + + + + + + +
+ +
- {% when None %} - {% endmatch %} + +
+
+
+ Clear data + + + + + + + +
+
+
{% endblock %} diff --git a/wallet_core/gba_hc_converter/templates/result.askama b/wallet_core/gba_hc_converter/templates/result.askama new file mode 100644 index 000000000..2a3d5b06d --- /dev/null +++ b/wallet_core/gba_hc_converter/templates/result.askama @@ -0,0 +1,17 @@ +{% extends "base.askama" %} + +{% block content %} +
+
+

GBA preloading for NL Wallet

+
+ +
+

Result

+

{{ msg }}

+
+ +
+
+
+{% endblock %} From 8c131dbd57db57670b17b73695e6dff815cea012 Mon Sep 17 00:00:00 2001 From: Jippe Holwerda Date: Wed, 23 Oct 2024 15:50:13 +0200 Subject: [PATCH 2/7] Use strict CSP header --- deploy/kubernetes/gba-fetch-frontend-ingress.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/deploy/kubernetes/gba-fetch-frontend-ingress.yaml b/deploy/kubernetes/gba-fetch-frontend-ingress.yaml index 9d0f7e5a4..527d8e643 100644 --- a/deploy/kubernetes/gba-fetch-frontend-ingress.yaml +++ b/deploy/kubernetes/gba-fetch-frontend-ingress.yaml @@ -10,7 +10,12 @@ metadata: nginx.ingress.kubernetes.io/auth-tls-verify-depth: '1' nginx.ingress.kubernetes.io/configuration-snippet: | proxy_set_header Cert-Serial $ssl_client_serial; - + more_set_headers "Strict-Transport-Security: max-age=31536000; includeSubDomains"; + more_set_headers "Referrer-Policy: no-referrer"; + more_set_headers "X-Content-Type-Options: nosniff"; + more_set_headers "X-Frame-Options: deny"; + more_set_headers "Permissions-Policy: camera=(), microphone=()"; + more_set_headers "Content-Security-Policy: default-src 'none'; script-src 'none'; style-src 'none'; img-src 'self'; font-src 'none'; frame-src 'none'; connect-src 'none'; object-src 'none'; form-action 'self'; base-uri 'self'; frame-ancestors 'none';"; spec: ingressClassName: nginx rules: From 9f40e631c6602bffd6aa173492b8eeb17ad9184d Mon Sep 17 00:00:00 2001 From: Jippe Holwerda Date: Wed, 23 Oct 2024 15:55:38 +0200 Subject: [PATCH 3/7] Add logging to gba_fetch_frontend --- .../src/bin/gba_fetch_frontend.rs | 35 ++++++++++++------- .../gba_hc_converter/src/gba/client.rs | 2 ++ .../gba_hc_converter/src/gba/encryption.rs | 5 ++- .../gba_hc_converter/src/haal_centraal.rs | 2 +- 4 files changed, 29 insertions(+), 15 deletions(-) diff --git a/wallet_core/gba_hc_converter/src/bin/gba_fetch_frontend.rs b/wallet_core/gba_hc_converter/src/bin/gba_fetch_frontend.rs index bc8db3670..3f7d9a2d2 100644 --- a/wallet_core/gba_hc_converter/src/bin/gba_fetch_frontend.rs +++ b/wallet_core/gba_hc_converter/src/bin/gba_fetch_frontend.rs @@ -17,7 +17,7 @@ use nutype::nutype; use serde::Deserialize; use tokio::net::TcpListener; use tower_http::trace::TraceLayer; -use tracing::{debug, level_filters::LevelFilter, warn}; +use tracing::{debug, info, level_filters::LevelFilter, warn}; use tracing_subscriber::EnvFilter; use gba_hc_converter::{ @@ -30,16 +30,10 @@ use gba_hc_converter::{ settings::{PreloadedSettings, RunMode, Settings}, }; -// Cannot use #[tokio::main], see: https://docs.sentry.io/platforms/rust/#async-main-function -fn main() -> anyhow::Result<()> { +#[tokio::main] +async fn main() -> anyhow::Result<()> { let settings = Settings::new()?; - // Retain [`ClientInitGuard`] - let _guard = settings - .sentry - .as_ref() - .map(|sentry| sentry.init(sentry::release_name!())); - let builder = tracing_subscriber::fmt().with_env_filter( EnvFilter::builder() .with_default_directive(LevelFilter::INFO.into()) @@ -51,10 +45,7 @@ fn main() -> anyhow::Result<()> { builder.init(); } - tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build()? - .block_on(async { serve(settings).await }) + serve(settings).await } #[nutype(derive(Debug, From, AsRef))] @@ -171,6 +162,7 @@ async fn index(State(state): State>, token: CsrfToken) -> async fn fetch( State(state): State>, token: CsrfToken, + headers: HeaderMap, Form(payload): Form, ) -> Result { token.verify(&payload.authenticity_token).map_err(|err| anyhow!(err))?; @@ -182,6 +174,11 @@ async fn fetch( let bsn = Bsn::try_new(payload.bsn).map_err(|err| anyhow!(err))?; let path = &state.base_path.join(&state.preloaded_settings.xml_path); + info!( + "Preloading data using certificate having serial: {}", + certificate_serial_from_headers(&headers)? + ); + let xml = state .http_client .vraag(&bsn) @@ -209,6 +206,7 @@ async fn fetch( async fn clear( State(state): State>, token: CsrfToken, + headers: HeaderMap, Form(payload): Form, ) -> Result { token.verify(&payload.authenticity_token).map_err(|err| anyhow!(err))?; @@ -217,6 +215,11 @@ async fn clear( return Err(anyhow!("Confirmation text is not correct"))?; } + info!( + "Clearing all preloaded data using certificate having serial: {}", + certificate_serial_from_headers(&headers)? + ); + let path = &state.base_path.join(&state.preloaded_settings.xml_path); let count = clear_files_in_dir(path).await.map_err(|err| anyhow!(err))?; @@ -226,3 +229,9 @@ async fn clear( Ok(askama_axum::into_response(&result)) } + +fn certificate_serial_from_headers(headers: &HeaderMap) -> Result<&str> { + headers.get("Cert-Serial").map_or(Ok("unknown"), |serial| { + Ok(serial.to_str().map_err(|err| anyhow!(err))?) + }) +} diff --git a/wallet_core/gba_hc_converter/src/gba/client.rs b/wallet_core/gba_hc_converter/src/gba/client.rs index ff960cc46..23c86c4b2 100644 --- a/wallet_core/gba_hc_converter/src/gba/client.rs +++ b/wallet_core/gba_hc_converter/src/gba/client.rs @@ -146,8 +146,10 @@ where if let Some(bytes) = decrypted { let xml = String::from_utf8(bytes)?; + info!("Using preloaded data"); Ok(Some(xml)) } else { + info!("No preloaded data found"); self.client.vraag(bsn).await } } diff --git a/wallet_core/gba_hc_converter/src/gba/encryption.rs b/wallet_core/gba_hc_converter/src/gba/encryption.rs index 515190ee2..170968a54 100644 --- a/wallet_core/gba_hc_converter/src/gba/encryption.rs +++ b/wallet_core/gba_hc_converter/src/gba/encryption.rs @@ -11,6 +11,7 @@ use hmac::{Hmac, Mac}; use rand_core::OsRng; use sha2::Sha256; use tokio::fs::DirEntry; +use tracing::debug; use crate::gba::error::Error; @@ -25,9 +26,9 @@ pub async fn encrypt_bytes_to_dir( output_path: &Path, basename: &str, ) -> Result<(), Error> { + debug!("encrypting bytes to dir"); let ciphertext = encrypt_bytes(encryption_key, bytes)?; tokio::fs::write(filename(hmac_key, output_path, basename), ciphertext).await?; - Ok(()) } @@ -41,8 +42,10 @@ pub async fn decrypt_bytes_from_dir( if filename.exists() { let bytes = tokio::fs::read(filename).await?; let decrypted = decrypt_bytes(decryption_key, &bytes)?; + debug!("decrypting bytes from dir"); Ok(Some(decrypted)) } else { + debug!("file to decrypt not found"); Ok(None) } } diff --git a/wallet_core/gba_hc_converter/src/haal_centraal.rs b/wallet_core/gba_hc_converter/src/haal_centraal.rs index 228786b78..bc65f8037 100644 --- a/wallet_core/gba_hc_converter/src/haal_centraal.rs +++ b/wallet_core/gba_hc_converter/src/haal_centraal.rs @@ -102,7 +102,7 @@ fn csv_path(name: &str) -> PathBuf { #[nutype( validate(predicate = Bsn::validate), - derive(Deserialize, Serialize, Clone, Debug, Display, AsRef, PartialEq) + derive(Deserialize, Serialize, Clone, Debug, Display, AsRef) )] pub struct Bsn(String); From 848779d2f66934c460a14370e2d96cfaf8e2175e Mon Sep 17 00:00:00 2001 From: Jippe Holwerda Date: Thu, 24 Oct 2024 13:36:31 +0200 Subject: [PATCH 4/7] Even more restrictive CSP header --- deploy/kubernetes/gba-fetch-frontend-ingress.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/kubernetes/gba-fetch-frontend-ingress.yaml b/deploy/kubernetes/gba-fetch-frontend-ingress.yaml index 527d8e643..13e19424a 100644 --- a/deploy/kubernetes/gba-fetch-frontend-ingress.yaml +++ b/deploy/kubernetes/gba-fetch-frontend-ingress.yaml @@ -15,7 +15,7 @@ metadata: more_set_headers "X-Content-Type-Options: nosniff"; more_set_headers "X-Frame-Options: deny"; more_set_headers "Permissions-Policy: camera=(), microphone=()"; - more_set_headers "Content-Security-Policy: default-src 'none'; script-src 'none'; style-src 'none'; img-src 'self'; font-src 'none'; frame-src 'none'; connect-src 'none'; object-src 'none'; form-action 'self'; base-uri 'self'; frame-ancestors 'none';"; + more_set_headers "Content-Security-Policy: default-src 'none'; form-action 'self'; base-uri 'none'; frame-ancestors 'none';"; spec: ingressClassName: nginx rules: From 01203150fc929e9549a267a9345da7d180ffb9cf Mon Sep 17 00:00:00 2001 From: Jippe Holwerda Date: Thu, 24 Oct 2024 14:08:52 +0200 Subject: [PATCH 5/7] Change GET form action to anchor --- wallet_core/gba_hc_converter/templates/result.askama | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/wallet_core/gba_hc_converter/templates/result.askama b/wallet_core/gba_hc_converter/templates/result.askama index 2a3d5b06d..cf4447df9 100644 --- a/wallet_core/gba_hc_converter/templates/result.askama +++ b/wallet_core/gba_hc_converter/templates/result.askama @@ -9,9 +9,7 @@

Result

{{ msg }}

-
- -
+ Go back
{% endblock %} From 13d435ea471a81987ebe1ba9ca860898f2b7ffe5 Mon Sep 17 00:00:00 2001 From: Jippe Holwerda Date: Thu, 24 Oct 2024 15:51:04 +0200 Subject: [PATCH 6/7] Created custom extractor for Cert-Serial header --- .../src/bin/gba_fetch_frontend.rs | 73 ++++++++++++++----- .../gba_hc_converter/templates/base.askama | 2 +- .../gba_hc_converter/templates/result.askama | 2 +- 3 files changed, 57 insertions(+), 20 deletions(-) diff --git a/wallet_core/gba_hc_converter/src/bin/gba_fetch_frontend.rs b/wallet_core/gba_hc_converter/src/bin/gba_fetch_frontend.rs index 3f7d9a2d2..127c477fc 100644 --- a/wallet_core/gba_hc_converter/src/bin/gba_fetch_frontend.rs +++ b/wallet_core/gba_hc_converter/src/bin/gba_fetch_frontend.rs @@ -4,7 +4,8 @@ use aes_gcm::Aes256Gcm; use anyhow::anyhow; use askama::Template; use axum::{ - extract::{Request, State}, + async_trait, + extract::{FromRequestParts, Request, State}, middleware, middleware::Next, response::{IntoResponse, Response}, @@ -12,7 +13,7 @@ use axum::{ Form, Router, }; use axum_csrf::{CsrfConfig, CsrfLayer, CsrfToken}; -use http::{HeaderMap, StatusCode}; +use http::{request::Parts, HeaderValue, StatusCode}; use nutype::nutype; use serde::Deserialize; use tokio::net::TcpListener; @@ -30,6 +31,8 @@ use gba_hc_converter::{ settings::{PreloadedSettings, RunMode, Settings}, }; +const CERT_SERIAL_HEADER: &str = "Cert-Serial"; + #[tokio::main] async fn main() -> anyhow::Result<()> { let settings = Settings::new()?; @@ -111,11 +114,51 @@ async fn serve(settings: Settings) -> anyhow::Result<()> { Ok(()) } -async fn check_auth(headers: HeaderMap, request: Request, next: Next) -> StdResult { +#[nutype(derive(Debug, Default), default = "unknown", validate(not_empty))] +struct CertSerial(String); + +impl TryFrom<&HeaderValue> for CertSerial { + type Error = Error; + + fn try_from(value: &HeaderValue) -> StdResult { + Ok(CertSerial::try_new(value.to_str().map_err(|err| anyhow!(err))?.to_string()).map_err(|err| anyhow!(err))?) + } +} + +struct ExtractCertSerial(Option); + +#[async_trait] +impl FromRequestParts for ExtractCertSerial +where + S: Send + Sync, +{ + type Rejection = (StatusCode, String); + + async fn from_request_parts(parts: &mut Parts, _state: &S) -> StdResult { + parts + .headers + .get(CERT_SERIAL_HEADER) + .map(|header| { + header + .to_str() + .map_err(anyhow::Error::from) + .and_then(|value| CertSerial::try_new(value).map_err(anyhow::Error::from)) + }) + .transpose() + .map(ExtractCertSerial) + .map_err(|err| (StatusCode::BAD_REQUEST, err.to_string())) + } +} + +async fn check_auth( + ExtractCertSerial(cert_serial): ExtractCertSerial, + request: Request, + next: Next, +) -> StdResult { // This assumes an ingress/reverse proxy that uses mutual TLS and sets the `Cert-Serial` header with the value // from the client certificate. This is an extra safeguard against using this endpoint directly. - if !headers.get("Cert-Serial").is_some_and(|s| !s.is_empty()) { - return Err(StatusCode::FORBIDDEN); + if !cert_serial.is_some_and(|s| !s.into_inner().is_empty()) { + return Err((StatusCode::FORBIDDEN, "client certificate missing")); } let response = next.run(request).await; Ok(response) @@ -162,21 +205,21 @@ async fn index(State(state): State>, token: CsrfToken) -> async fn fetch( State(state): State>, token: CsrfToken, - headers: HeaderMap, + ExtractCertSerial(cert_serial): ExtractCertSerial, Form(payload): Form, ) -> Result { token.verify(&payload.authenticity_token).map_err(|err| anyhow!(err))?; if payload.bsn != payload.repeat_bsn { - return Err(anyhow!("BSN's do not match"))?; + return Err(anyhow!("BSNs do not match"))?; } let bsn = Bsn::try_new(payload.bsn).map_err(|err| anyhow!(err))?; let path = &state.base_path.join(&state.preloaded_settings.xml_path); info!( - "Preloading data using certificate having serial: {}", - certificate_serial_from_headers(&headers)? + "Preloading data using certificate having serial: {:?}", + cert_serial.unwrap_or_default() ); let xml = state @@ -206,7 +249,7 @@ async fn fetch( async fn clear( State(state): State>, token: CsrfToken, - headers: HeaderMap, + ExtractCertSerial(cert_serial): ExtractCertSerial, Form(payload): Form, ) -> Result { token.verify(&payload.authenticity_token).map_err(|err| anyhow!(err))?; @@ -216,8 +259,8 @@ async fn clear( } info!( - "Clearing all preloaded data using certificate having serial: {}", - certificate_serial_from_headers(&headers)? + "Clearing all preloaded data using certificate having serial: {:?}", + cert_serial.unwrap_or_default() ); let path = &state.base_path.join(&state.preloaded_settings.xml_path); @@ -229,9 +272,3 @@ async fn clear( Ok(askama_axum::into_response(&result)) } - -fn certificate_serial_from_headers(headers: &HeaderMap) -> Result<&str> { - headers.get("Cert-Serial").map_or(Ok("unknown"), |serial| { - Ok(serial.to_str().map_err(|err| anyhow!(err))?) - }) -} diff --git a/wallet_core/gba_hc_converter/templates/base.askama b/wallet_core/gba_hc_converter/templates/base.askama index f3a56415f..0cb6b7a73 100644 --- a/wallet_core/gba_hc_converter/templates/base.askama +++ b/wallet_core/gba_hc_converter/templates/base.askama @@ -6,7 +6,7 @@ name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" /> - {% block title %}GBA preloading for NL Wallet{% endblock %} + {% block title %}GBA-V preloading for NL Wallet{% endblock %} {% block styles %}{% endblock %} {% block scripts %}{% endblock %} diff --git a/wallet_core/gba_hc_converter/templates/result.askama b/wallet_core/gba_hc_converter/templates/result.askama index cf4447df9..18fc4af0f 100644 --- a/wallet_core/gba_hc_converter/templates/result.askama +++ b/wallet_core/gba_hc_converter/templates/result.askama @@ -3,7 +3,7 @@ {% block content %}
-

GBA preloading for NL Wallet

+

GBA-V preloading for NL Wallet

From ef7e5c3a8b06c6760b3ae115d52d0cbed8cd4609 Mon Sep 17 00:00:00 2001 From: Jippe Holwerda Date: Thu, 24 Oct 2024 16:27:17 +0200 Subject: [PATCH 7/7] Cleanup unused From implementation --- .../gba_hc_converter/src/bin/gba_fetch_frontend.rs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/wallet_core/gba_hc_converter/src/bin/gba_fetch_frontend.rs b/wallet_core/gba_hc_converter/src/bin/gba_fetch_frontend.rs index 69074c69f..5e2db5a4c 100644 --- a/wallet_core/gba_hc_converter/src/bin/gba_fetch_frontend.rs +++ b/wallet_core/gba_hc_converter/src/bin/gba_fetch_frontend.rs @@ -13,7 +13,7 @@ use axum::{ Form, Router, }; use axum_csrf::{CsrfConfig, CsrfLayer, CsrfToken}; -use http::{request::Parts, HeaderValue, StatusCode}; +use http::{request::Parts, StatusCode}; use nutype::nutype; use serde::Deserialize; use tokio::net::TcpListener; @@ -43,7 +43,6 @@ async fn main() -> anyhow::Result<()> { .from_env_lossy(), ); - let settings = Settings::new()?; if settings.structured_logging { builder.json().init(); } else { @@ -119,14 +118,6 @@ async fn serve(settings: Settings) -> anyhow::Result<()> { #[nutype(derive(Debug, Default), default = "unknown", validate(not_empty))] struct CertSerial(String); -impl TryFrom<&HeaderValue> for CertSerial { - type Error = Error; - - fn try_from(value: &HeaderValue) -> StdResult { - Ok(CertSerial::try_new(value.to_str().map_err(|err| anyhow!(err))?.to_string()).map_err(|err| anyhow!(err))?) - } -} - struct ExtractCertSerial(Option); #[async_trait]