tfa: derive WebauthnConfigUpdater via api macro
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
		| @ -5,6 +5,7 @@ use anyhow::Error; | |||||||
|  |  | ||||||
| use crate::api2::types::PROXMOX_CONFIG_DIGEST_SCHEMA; | use crate::api2::types::PROXMOX_CONFIG_DIGEST_SCHEMA; | ||||||
| use proxmox::api::{api, Permission, Router, RpcEnvironment, SubdirMap}; | use proxmox::api::{api, Permission, Router, RpcEnvironment, SubdirMap}; | ||||||
|  | use proxmox::api::schema::Updatable; | ||||||
| use proxmox::list_subdirs_api_method; | use proxmox::list_subdirs_api_method; | ||||||
|  |  | ||||||
| use crate::config::tfa::{self, WebauthnConfig, WebauthnConfigUpdater}; | use crate::config::tfa::{self, WebauthnConfig, WebauthnConfigUpdater}; | ||||||
| @ -73,9 +74,9 @@ pub fn update_webauthn_config( | |||||||
|             let digest = proxmox::tools::hex_to_digest(digest)?; |             let digest = proxmox::tools::hex_to_digest(digest)?; | ||||||
|             crate::tools::detect_modified_configuration_file(&digest, &wa.digest()?)?; |             crate::tools::detect_modified_configuration_file(&digest, &wa.digest()?)?; | ||||||
|         } |         } | ||||||
|         webauthn.apply_to(wa); |         wa.update_from::<&str>(webauthn, &[])?; | ||||||
|     } else { |     } else { | ||||||
|         tfa.webauthn = Some(webauthn.build()?); |         tfa.webauthn = Some(WebauthnConfig::try_build_from(webauthn)?); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     tfa::write(&tfa)?; |     tfa::write(&tfa)?; | ||||||
|  | |||||||
| @ -18,6 +18,7 @@ use webauthn_rs::Webauthn; | |||||||
| use webauthn_rs::proto::Credential as WebauthnCredential; | use webauthn_rs::proto::Credential as WebauthnCredential; | ||||||
|  |  | ||||||
| use proxmox::api::api; | use proxmox::api::api; | ||||||
|  | use proxmox::api::schema::{Updatable, Updater}; | ||||||
| use proxmox::sys::error::SysError; | use proxmox::sys::error::SysError; | ||||||
| use proxmox::tools::fs::CreateOptions; | use proxmox::tools::fs::CreateOptions; | ||||||
| use proxmox::tools::tfa::totp::Totp; | use proxmox::tools::tfa::totp::Totp; | ||||||
| @ -87,7 +88,7 @@ pub struct U2fConfig { | |||||||
| } | } | ||||||
|  |  | ||||||
| #[api] | #[api] | ||||||
| #[derive(Clone, Deserialize, Serialize)] | #[derive(Clone, Deserialize, Serialize, Updater)] | ||||||
| #[serde(deny_unknown_fields)] | #[serde(deny_unknown_fields)] | ||||||
| /// Server side webauthn server configuration. | /// Server side webauthn server configuration. | ||||||
| pub struct WebauthnConfig { | pub struct WebauthnConfig { | ||||||
| @ -115,53 +116,6 @@ impl WebauthnConfig { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| // TODO: api macro should be able to generate this struct & impl automatically: |  | ||||||
| #[api] |  | ||||||
| #[derive(Default, Deserialize, Serialize)] |  | ||||||
| #[serde(deny_unknown_fields)] |  | ||||||
| /// Server side webauthn server configuration. |  | ||||||
| pub struct WebauthnConfigUpdater { |  | ||||||
|     /// Relying party name. Any text identifier. |  | ||||||
|     /// |  | ||||||
|     /// Changing this *may* break existing credentials. |  | ||||||
|     rp: Option<String>, |  | ||||||
|  |  | ||||||
|     /// Site origin. Must be a `https://` URL (or `http://localhost`). Should contain the address |  | ||||||
|     /// users type in their browsers to access the web interface. |  | ||||||
|     /// |  | ||||||
|     /// Changing this *may* break existing credentials. |  | ||||||
|     origin: Option<String>, |  | ||||||
|  |  | ||||||
|     /// Relying part ID. Must be the domain name without protocol, port or location. |  | ||||||
|     /// |  | ||||||
|     /// Changing this *will* break existing credentials. |  | ||||||
|     id: Option<String>, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| impl WebauthnConfigUpdater { |  | ||||||
|     pub fn apply_to(self, target: &mut WebauthnConfig) { |  | ||||||
|         if let Some(val) = self.rp { |  | ||||||
|             target.rp = val; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if let Some(val) = self.origin { |  | ||||||
|             target.origin = val; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if let Some(val) = self.id { |  | ||||||
|             target.id = val; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     pub fn build(self) -> Result<WebauthnConfig, Error> { |  | ||||||
|         Ok(WebauthnConfig { |  | ||||||
|             rp: self.rp.ok_or_else(|| format_err!("missing required field: `rp`"))?, |  | ||||||
|             origin: self.origin.ok_or_else(|| format_err!("missing required field: `origin`"))?, |  | ||||||
|             id: self.id.ok_or_else(|| format_err!("missing required field: `origin`"))?, |  | ||||||
|         }) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /// For now we just implement this on the configuration this way. | /// For now we just implement this on the configuration this way. | ||||||
| /// | /// | ||||||
| /// Note that we may consider changing this so `get_origin` returns the `Host:` header provided by | /// Note that we may consider changing this so `get_origin` returns the `Host:` header provided by | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user