]> git.proxmox.com Git - proxmox-backup.git/blame - src/api2/config/access/tfa.rs
docs: drop blanket statement recommending against remote storage
[proxmox-backup.git] / src / api2 / config / access / tfa.rs
CommitLineData
a670b99d
WB
1//! For now this only has the TFA subdir, which is in this file.
2//! If we add more, it should be moved into a sub module.
3
e6e2927e 4use anyhow::{format_err, Error};
25877d05 5use hex::FromHex;
e6e2927e 6use serde::{Deserialize, Serialize};
a670b99d 7
6ef1b649 8use proxmox_router::list_subdirs_api_method;
e6e2927e
WB
9use proxmox_router::{Permission, Router, RpcEnvironment, SubdirMap};
10use proxmox_schema::api;
a670b99d 11
6227654a
DM
12use pbs_api_types::PROXMOX_CONFIG_DIGEST_SCHEMA;
13
a670b99d
WB
14use crate::config::tfa::{self, WebauthnConfig, WebauthnConfigUpdater};
15
16pub const ROUTER: Router = Router::new()
17 .get(&list_subdirs_api_method!(SUBDIRS))
18 .subdirs(SUBDIRS);
19
20const SUBDIRS: SubdirMap = &[("webauthn", &WEBAUTHN_ROUTER)];
21
22const WEBAUTHN_ROUTER: Router = Router::new()
23 .get(&API_METHOD_GET_WEBAUTHN_CONFIG)
24 .put(&API_METHOD_UPDATE_WEBAUTHN_CONFIG);
25
26#[api(
27 protected: true,
28 input: {
29 properties: {},
30 },
31 returns: {
32 type: WebauthnConfig,
33 optional: true,
34 },
35 access: {
36 permission: &Permission::Anybody,
37 },
38)]
39/// Get the TFA configuration.
40pub fn get_webauthn_config(
41c1a179 41 rpcenv: &mut dyn RpcEnvironment,
a670b99d
WB
42) -> Result<Option<WebauthnConfig>, Error> {
43 let (config, digest) = match tfa::webauthn_config()? {
44 Some(c) => c,
45 None => return Ok(None),
46 };
16f6766a 47 rpcenv["digest"] = hex::encode(digest).into();
a670b99d
WB
48 Ok(Some(config))
49}
50
e6e2927e
WB
51#[api()]
52#[derive(Serialize, Deserialize)]
53#[serde(rename_all = "kebab-case")]
54/// Deletable property name
55pub enum DeletableProperty {
8ab1d131 56 /// Delete the `origin` property.
e6e2927e 57 Origin,
8ab1d131
WB
58
59 /// Delete the `allow_subdomains` property.
60 AllowSubdomains,
e6e2927e
WB
61}
62
a670b99d
WB
63#[api(
64 protected: true,
65 input: {
66 properties: {
67 webauthn: {
68 flatten: true,
69 type: WebauthnConfigUpdater,
70 },
e6e2927e
WB
71 delete: {
72 description: "List of properties to delete.",
73 type: Array,
74 optional: true,
75 items: {
76 type: DeletableProperty,
77 }
78 },
a670b99d
WB
79 digest: {
80 optional: true,
81 schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
82 },
83 },
84 },
85)]
86/// Update the TFA configuration.
87pub fn update_webauthn_config(
88 webauthn: WebauthnConfigUpdater,
e6e2927e 89 delete: Option<Vec<DeletableProperty>>,
a670b99d
WB
90 digest: Option<String>,
91) -> Result<(), Error> {
92 let _lock = tfa::write_lock();
93
94 let mut tfa = tfa::read()?;
95
96 if let Some(wa) = &mut tfa.webauthn {
97 if let Some(ref digest) = digest {
25877d05 98 let digest = <[u8; 32]>::from_hex(digest)?;
9407810f
WB
99 crate::tools::detect_modified_configuration_file(
100 &digest,
9a37bd6c 101 &crate::config::tfa::webauthn_config_digest(wa)?,
9407810f 102 )?;
a670b99d 103 }
e6e2927e
WB
104
105 if let Some(delete) = delete {
106 for delete in delete {
107 match delete {
108 DeletableProperty::Origin => {
109 wa.origin = None;
110 }
8ab1d131
WB
111 DeletableProperty::AllowSubdomains => {
112 wa.allow_subdomains = None;
113 }
e6e2927e
WB
114 }
115 }
116 }
117
118 if let Some(rp) = webauthn.rp {
119 wa.rp = rp;
120 }
121 if webauthn.origin.is_some() {
122 wa.origin = webauthn.origin;
123 }
8ab1d131
WB
124 if webauthn.allow_subdomains.is_some() {
125 wa.allow_subdomains = webauthn.allow_subdomains;
126 }
e6e2927e
WB
127 if let Some(id) = webauthn.id {
128 wa.id = id;
129 }
a670b99d 130 } else {
e6e2927e
WB
131 let rp = webauthn
132 .rp
d20137e5 133 .ok_or_else(|| format_err!("missing property: 'rp'"))?;
e6e2927e
WB
134 let origin = webauthn.origin;
135 let id = webauthn
136 .id
137 .ok_or_else(|| format_err!("missing property: 'id'"))?;
8ab1d131
WB
138 let allow_subdomains = webauthn.allow_subdomains;
139 tfa.webauthn = Some(WebauthnConfig {
140 rp,
141 origin,
142 id,
143 allow_subdomains,
144 });
a670b99d
WB
145 }
146
147 tfa::write(&tfa)?;
148
149 Ok(())
150}