public inbox for pdm-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Shannon Sterz <s.sterz@proxmox.com>
To: pdm-devel@lists.proxmox.com
Subject: [PATCH datacenter-manager 10/17] ui: wizzard: add context if a provided fingerprint did not match remote
Date: Thu, 11 Jun 2026 14:03:20 +0200	[thread overview]
Message-ID: <20260611120327.257523-11-s.sterz@proxmox.com> (raw)
In-Reply-To: <20260611120327.257523-1-s.sterz@proxmox.com>

if a remote's certificate does not match the fingerprint provided by a
user, add a warning to the probe result dialogs.

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
---
 ui/src/remotes/wizard_page_connect.rs | 26 ++++++++++++++++--
 ui/src/remotes/wizard_page_nodes.rs   | 38 +++++++++++++++++++++++++--
 2 files changed, 60 insertions(+), 4 deletions(-)

diff --git a/ui/src/remotes/wizard_page_connect.rs b/ui/src/remotes/wizard_page_connect.rs
index abb2b1da..59031892 100644
--- a/ui/src/remotes/wizard_page_connect.rs
+++ b/ui/src/remotes/wizard_page_connect.rs
@@ -6,9 +6,9 @@ use serde_json::Value;
 use yew::html::IntoEventCallback;
 use yew::virtual_dom::{Key, VComp, VNode};
 
-use pwt::css::{FlexFit, JustifyContent};
+use pwt::css::{FlexFit, FontColor, JustifyContent};
 use pwt::widget::form::{Field, FormContext, FormContextObserver};
-use pwt::widget::{Button, Column, Container, Dialog, InputPanel, Mask, Row, error_message};
+use pwt::widget::{Button, Column, Container, Dialog, Fa, InputPanel, Mask, Row, error_message};
 use pwt::{AsyncAbortGuard, prelude::*};
 use pwt_macros::builder;
 
@@ -81,6 +81,14 @@ impl PdmWizardPageConnect {
             Some(Ok(TlsProbeOutcome::UntrustedCertificate(info))) => info.clone(),
             _ => return None,
         };
+
+        let provided_fp = ctx
+            .props()
+            .info
+            .form_ctx
+            .read()
+            .get_field_text("fingerprint");
+
         Some(
             Dialog::new(tr!("Connection Certificate"))
                 .on_close(link.callback(|_| Msg::ConfirmResult(false)))
@@ -92,6 +100,20 @@ impl PdmWizardPageConnect {
                         .with_child(Container::new().with_child(tr!(
                             "The certificate of the remote server is not trusted."
                         )))
+                        .with_optional_child((!provided_fp.is_empty()).then(||{
+                            Row::new()
+                                .gap(1)
+                                .margin_x(1)
+                                .with_child(
+                                    Fa::new("exclamation-triangle")
+                                        .class(FontColor::Warning)
+                                )
+                                .with_child(tr!(
+                                    "The provided SHA-256 fingerprint ({provided_fp}) did not match \
+                                    the remote certificate's fingerprint.",
+                                    provided_fp
+                                ))
+                        }))
                         .with_child(Container::new().with_child(tr!(
                             "Do you want to trust the certificate and save its fingerprint?"
                         )))
diff --git a/ui/src/remotes/wizard_page_nodes.rs b/ui/src/remotes/wizard_page_nodes.rs
index 15f60404..3428338d 100644
--- a/ui/src/remotes/wizard_page_nodes.rs
+++ b/ui/src/remotes/wizard_page_nodes.rs
@@ -6,8 +6,8 @@ use proxmox_schema::property_string::PropertyString;
 use serde_json::Value;
 use yew::virtual_dom::{VComp, VNode};
 
-use pwt::css::{FlexFit, FontStyle, JustifyContent, Overflow};
-use pwt::widget::{Button, Column, Container, Dialog, Mask, Row, error_message};
+use pwt::css::{FlexFit, FontColor, FontStyle, JustifyContent, Overflow};
+use pwt::widget::{Button, Column, Container, Dialog, Fa, Mask, Row, error_message};
 use pwt::{AsyncAbortGuard, prelude::*};
 use pwt_macros::builder;
 
@@ -74,12 +74,46 @@ impl PdmWizardPageNodes {
                             .padding(2)
                             .class(Overflow::Auto)
                             .children(certificates.into_iter().map(|(hostname, certificate)| {
+                                let nodes =
+                                    ctx.props().info.form_ctx.read().get_field_value("nodes");
+
+                                let provided_fp = if let Some(Value::Array(nodes_list)) = nodes {
+                                    nodes_list
+                                        .into_iter()
+                                        .find_map(|node| {
+                                            serde_json::from_value::<PropertyString<NodeUrl>>(node)
+                                                .ok()
+                                                .and_then(|n| {
+                                                    let node = n.into_inner();
+                                                    (node.hostname == *hostname)
+                                                        .then_some(node.fingerprint)
+                                                })
+                                        })
+                                        .flatten()
+                                } else {
+                                    None
+                                };
+
                                 Column::new()
                                     .with_child(
                                         Container::new().class(FontStyle::TitleSmall).with_child(
                                             format!("{}: {hostname}", tr!("Server Address")),
                                         ),
                                     )
+                                    .with_optional_child(provided_fp.map(|fp| {
+                                        Row::new()
+                                            .gap(1)
+                                            .margin(2)
+                                            .with_child(
+                                                Fa::new("exclamation-triangle")
+                                                    .class(FontColor::Warning),
+                                            )
+                                            .with_child(tr!(
+                                                "The provided SHA-256 fingerprint ({fp}) did not \
+                                                match the remote certificate's fingerprint.",
+                                                fp
+                                            ))
+                                    }))
                                     .with_child(
                                         KVGrid::new()
                                             .class(FlexFit)
-- 
2.47.3





  parent reply	other threads:[~2026-06-11 12:03 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-11 12:03 [RFC cluster/datacenter-manager/manager/proxmox 00/17] TLS Certificate Staging Shannon Sterz
2026-06-11 12:03 ` [PATCH cluster 01/17] setup: allow caller to provide the certificate filename Shannon Sterz
2026-06-11 12:03 ` [PATCH manager 02/17] bin/api: add a new staged certificate when renewing self-signed cert Shannon Sterz
2026-06-11 12:03 ` [PATCH manager 03/17] api: certificates: if node parameter is 'localhost' return local certs Shannon Sterz
2026-06-11 12:03 ` [PATCH proxmox 04/17] client: ignore certificate trust store validation result on fp option Shannon Sterz
2026-06-11 12:03 ` [PATCH proxmox 05/17] pve-api-types: expose certificates info endpoint Shannon Sterz
2026-06-11 12:03 ` [PATCH datacenter-manager 06/17] client: don't short-circuit on valid certificate when tls fp exists Shannon Sterz
2026-06-11 12:03 ` [PATCH datacenter-manager 07/17] client: allow users to update a changed fingerprint interactively Shannon Sterz
2026-06-11 12:03 ` [PATCH datacenter-manager 08/17] cli/api-types: move Fingerprint to common api type crate Shannon Sterz
2026-06-11 12:03 ` [PATCH datacenter-manager 09/17] server: connection: report mismatching fingerprint as untrusted on probe Shannon Sterz
2026-06-11 12:03 ` Shannon Sterz [this message]
2026-06-11 12:03 ` [PATCH datacenter-manager 11/17] ui: wizzard: nodes page: always update fingerprints on user confirmation Shannon Sterz
2026-06-11 12:03 ` [PATCH datacenter-manager 12/17] pdm-api-types: implement ApiType for Fingerprint Shannon Sterz
2026-06-11 12:03 ` [PATCH datacenter-manager 13/17] pdm-api-types: add staged_fingerprints field to NodeUrl Shannon Sterz
2026-06-11 12:03 ` [PATCH datacenter-manager 14/17] server: remotes: lock remotes config when updating it Shannon Sterz
2026-06-11 12:03 ` [PATCH datacenter-manager 15/17] server: connection: rotate in staged fingerprints when encountering them Shannon Sterz
2026-06-11 12:03 ` [PATCH datacenter-manager 16/17] server: api: tasks: move `spawn_aborted_on_shutdown()` to super module Shannon Sterz
2026-06-11 12:03 ` [PATCH datacenter-manager 17/17] server: bin: api: tasks: add task to discover new staged certificates Shannon Sterz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260611120327.257523-11-s.sterz@proxmox.com \
    --to=s.sterz@proxmox.com \
    --cc=pdm-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal