Present desktop OTP and sensitive outputs

This commit is contained in:
2026-08-10 20:22:59 +02:00
parent 95bb10b4a1
commit 4a54bf7b6a
13 changed files with 1881 additions and 39 deletions

View File

@@ -198,6 +198,9 @@ impl NativeClipboardManager {
pub enum QrError {
EmptyPayload,
PayloadTooLarge,
InvalidImage,
NotFound,
InvalidPayload,
}
impl fmt::Display for QrError {
@@ -205,6 +208,9 @@ impl fmt::Display for QrError {
match self {
Self::EmptyPayload => formatter.write_str("empty data cannot be encoded as a QR code"),
Self::PayloadTooLarge => formatter.write_str("the QR payload is too large"),
Self::InvalidImage => formatter.write_str("the selected file is not a supported image"),
Self::NotFound => formatter.write_str("the image does not contain a QR code"),
Self::InvalidPayload => formatter.write_str("the QR code contains invalid text"),
}
}
}
@@ -233,6 +239,26 @@ impl QrMatrix {
Ok(Self { width, modules })
}
/// Decode the first QR symbol from an encoded image without exposing the
/// secret-derived payload to a presentation adapter.
pub fn decode_image(image: &SecretBytes) -> Result<SecretBytes, QrError> {
let grayscale = image::load_from_memory(image.expose())
.map_err(|_| QrError::InvalidImage)?
.into_luma8();
let mut prepared = rqrr::PreparedImage::prepare_from_greyscale(
grayscale.width() as usize,
grayscale.height() as usize,
|x, y| grayscale.get_pixel(x as u32, y as u32).0[0],
);
let grid = prepared
.detect_grids()
.into_iter()
.next()
.ok_or(QrError::NotFound)?;
let (_, payload) = grid.decode().map_err(|_| QrError::InvalidPayload)?;
Ok(SecretBytes::new(payload.into_bytes()))
}
pub fn width(&self) -> usize {
self.width
}