qrcode: Document the qrcode crate.
parent
f49f5f1636
commit
8018b43443
|
@ -4,10 +4,16 @@ version = "0.1.0"
|
||||||
authors = ["Damir Jelić <poljar@termina.org.uk>"]
|
authors = ["Damir Jelić <poljar@termina.org.uk>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
features = ["docs"]
|
||||||
|
rustdoc-args = ["--cfg", "feature=\"docs\""]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["decode_image"]
|
default = ["decode_image"]
|
||||||
decode_image = ["image", "rqrr", "qrcode/image", "qrcode/svg"]
|
decode_image = ["image", "rqrr", "qrcode/image", "qrcode/svg"]
|
||||||
|
|
||||||
|
docs = ["decode_image"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
base64 = "0.13.0"
|
base64 = "0.13.0"
|
||||||
byteorder = "1.4.3"
|
byteorder = "1.4.3"
|
||||||
|
|
|
@ -14,34 +14,48 @@
|
||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// Error type describing errors that happen while QR data is being decoded.
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum DecodingError {
|
pub enum DecodingError {
|
||||||
|
/// Error decoding the QR code.
|
||||||
#[cfg(feature = "decode_image")]
|
#[cfg(feature = "decode_image")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(decode_image)))]
|
#[cfg_attr(feature = "docs", doc(cfg(decode_image)))]
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Qr(#[from] rqrr::DeQRError),
|
Qr(#[from] rqrr::DeQRError),
|
||||||
|
/// The QR code data is missing the mandatory Matrix header.
|
||||||
#[error("the decoded QR code is missing the Matrix header")]
|
#[error("the decoded QR code is missing the Matrix header")]
|
||||||
Header,
|
Header,
|
||||||
|
/// The QR code data is containing an invalid, non UTF-8, flow id.
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Utf8(#[from] std::string::FromUtf8Error),
|
Utf8(#[from] std::string::FromUtf8Error),
|
||||||
|
/// The QR code data is using an unsupported or invalid verification mode.
|
||||||
#[error("the QR code contains an invalid verification mode: {0}")]
|
#[error("the QR code contains an invalid verification mode: {0}")]
|
||||||
Mode(u8),
|
Mode(u8),
|
||||||
|
/// The flow id is not a valid event ID.
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Identifier(#[from] ruma_identifiers::Error),
|
Identifier(#[from] ruma_identifiers::Error),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
|
/// The QR code data does not contain all the necessary fields.
|
||||||
Read(#[from] std::io::Error),
|
Read(#[from] std::io::Error),
|
||||||
|
/// The QR code data uses an invalid shared secret.
|
||||||
#[error("the QR code contains a too short shared secret, length: {0}")]
|
#[error("the QR code contains a too short shared secret, length: {0}")]
|
||||||
SharedSecret(usize),
|
SharedSecret(usize),
|
||||||
|
/// The QR code data uses an invalid or unsupported version.
|
||||||
#[error("the QR code contains an invalid or unsupported version: {0}")]
|
#[error("the QR code contains an invalid or unsupported version: {0}")]
|
||||||
Version(u8),
|
Version(u8),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Error type describing errors that happen while QR data is being encoded.
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum EncodingError {
|
pub enum EncodingError {
|
||||||
|
/// Error generating a QR code from the data, likely because the data
|
||||||
|
/// doesn't fit into a QR code.
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Qr(#[from] qrcode::types::QrError),
|
Qr(#[from] qrcode::types::QrError),
|
||||||
|
/// Error decoding the identity keys as base64.
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Base64(#[from] base64::DecodeError),
|
Base64(#[from] base64::DecodeError),
|
||||||
|
/// Error encoding the given flow id, the flow id is too large.
|
||||||
#[error("The verification flow id length can't be converted into a u16: {0}")]
|
#[error("The verification flow id length can't be converted into a u16: {0}")]
|
||||||
FlowId(#[from] std::num::TryFromIntError),
|
FlowId(#[from] std::num::TryFromIntError),
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,10 +30,12 @@
|
||||||
//! # }
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
#![cfg_attr(feature = "docs", feature(doc_cfg))]
|
||||||
#![deny(
|
#![deny(
|
||||||
missing_debug_implementations,
|
missing_debug_implementations,
|
||||||
dead_code,
|
dead_code,
|
||||||
trivial_casts,
|
trivial_casts,
|
||||||
|
missing_docs,
|
||||||
trivial_numeric_casts,
|
trivial_numeric_casts,
|
||||||
unused_extern_crates,
|
unused_extern_crates,
|
||||||
unused_import_braces,
|
unused_import_braces,
|
||||||
|
|
|
@ -31,10 +31,16 @@ use crate::{
|
||||||
utils::{base_64_encode, to_bytes, to_qr_code, HEADER, MAX_MODE, MIN_SECRET_LEN, VERSION},
|
utils::{base_64_encode, to_bytes, to_qr_code, HEADER, MAX_MODE, MIN_SECRET_LEN, VERSION},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// An enum representing the different modes a QR verification can be in.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum QrVerification {
|
pub enum QrVerification {
|
||||||
|
/// The QR verification is verifying another user
|
||||||
Verification(VerificationData),
|
Verification(VerificationData),
|
||||||
|
/// The QR verification is self-verifying and the current device trusts or
|
||||||
|
/// owns the master key
|
||||||
SelfVerification(SelfVerificationData),
|
SelfVerification(SelfVerificationData),
|
||||||
|
/// The QR verification is self-verifying in which the current device does
|
||||||
|
/// not yet trust the master key
|
||||||
SelfVerificationNoMasterKey(SelfVerificationNoMasterKey),
|
SelfVerificationNoMasterKey(SelfVerificationNoMasterKey),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,6 +81,26 @@ impl TryFrom<Vec<u8>> for QrVerification {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl QrVerification {
|
impl QrVerification {
|
||||||
|
/// Decode and parse an image of a QR code into a `QrVerification`
|
||||||
|
///
|
||||||
|
/// The image will be converted into a grey scale image before decoding is
|
||||||
|
/// attempted
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `image` - The image containing the QR code.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```no_run
|
||||||
|
/// # use matrix_qrcode::{QrVerification, DecodingError};
|
||||||
|
/// # fn main() -> Result<(), DecodingError> {
|
||||||
|
/// use image;
|
||||||
|
///
|
||||||
|
/// let image = image::open("/path/to/my/image.png").unwrap();
|
||||||
|
/// let result = QrVerification::from_image(image)?;
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
#[cfg(feature = "decode_image")]
|
#[cfg(feature = "decode_image")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(decode_image)))]
|
#[cfg_attr(feature = "docs", doc(cfg(decode_image)))]
|
||||||
pub fn from_image(image: DynamicImage) -> Result<Self, DecodingError> {
|
pub fn from_image(image: DynamicImage) -> Result<Self, DecodingError> {
|
||||||
|
@ -82,16 +108,85 @@ impl QrVerification {
|
||||||
Self::decode(image)
|
Self::decode(image)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Decode and parse an grey scale image of a QR code into a
|
||||||
|
/// `QrVerification`
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `image` - The grey scale image containing the QR code.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```no_run
|
||||||
|
/// # use matrix_qrcode::{QrVerification, DecodingError};
|
||||||
|
/// # fn main() -> Result<(), DecodingError> {
|
||||||
|
/// use image;
|
||||||
|
///
|
||||||
|
/// let image = image::open("/path/to/my/image.png").unwrap();
|
||||||
|
/// let image = image.to_luma8();
|
||||||
|
/// let result = QrVerification::from_luma(image)?;
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
#[cfg(feature = "decode_image")]
|
#[cfg(feature = "decode_image")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(decode_image)))]
|
#[cfg_attr(feature = "docs", doc(cfg(decode_image)))]
|
||||||
pub fn from_luma(image: ImageBuffer<Luma<u8>, Vec<u8>>) -> Result<Self, DecodingError> {
|
pub fn from_luma(image: ImageBuffer<Luma<u8>, Vec<u8>>) -> Result<Self, DecodingError> {
|
||||||
Self::decode(image)
|
Self::decode(image)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse the decoded payload of a QR code in byte slice form as a
|
||||||
|
/// `QrVerification`
|
||||||
|
///
|
||||||
|
/// This method is useful if you would like to do your own custom QR code
|
||||||
|
/// decoding.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `bytes` - The raw bytes of a decoded QR code.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// # use matrix_qrcode::{QrVerification, DecodingError};
|
||||||
|
/// # fn main() -> Result<(), DecodingError> {
|
||||||
|
/// let data = b"MATRIX\
|
||||||
|
/// \x02\x02\x00\x07\
|
||||||
|
/// FLOW_ID\
|
||||||
|
/// AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
|
||||||
|
/// BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\
|
||||||
|
/// SHARED_SECRET";
|
||||||
|
///
|
||||||
|
/// let result = QrVerification::from_bytes(data)?;
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, DecodingError> {
|
pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, DecodingError> {
|
||||||
Self::decode_bytes(bytes)
|
Self::decode_bytes(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Encode the `QrVerification` into a `QrCode`.
|
||||||
|
///
|
||||||
|
/// This method turns the `QrVerification` into a QR code that can be
|
||||||
|
/// rendered and presented to be scanned.
|
||||||
|
///
|
||||||
|
/// The encoding can fail if the data doesn't fit into a QR code or if the
|
||||||
|
/// identity keys that should be encoded into the QR code are not valid
|
||||||
|
/// base64.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// # use matrix_qrcode::{QrVerification, DecodingError};
|
||||||
|
/// # fn main() -> Result<(), DecodingError> {
|
||||||
|
/// let data = b"MATRIX\
|
||||||
|
/// \x02\x02\x00\x07\
|
||||||
|
/// FLOW_ID\
|
||||||
|
/// AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
|
||||||
|
/// BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\
|
||||||
|
/// SHARED_SECRET";
|
||||||
|
///
|
||||||
|
/// let result = QrVerification::from_bytes(data)?;
|
||||||
|
/// let encoded = result.to_qr_code().unwrap();
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
pub fn to_qr_code(&self) -> Result<QrCode, EncodingError> {
|
pub fn to_qr_code(&self) -> Result<QrCode, EncodingError> {
|
||||||
match self {
|
match self {
|
||||||
QrVerification::Verification(v) => v.to_qr_code(),
|
QrVerification::Verification(v) => v.to_qr_code(),
|
||||||
|
@ -100,6 +195,30 @@ impl QrVerification {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Encode the `QrVerification` into a vector of bytes that can be encoded
|
||||||
|
/// as a QR code.
|
||||||
|
///
|
||||||
|
/// The encoding can fail if the identity keys that should be encoded are
|
||||||
|
/// not valid base64.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// # use matrix_qrcode::{QrVerification, DecodingError};
|
||||||
|
/// # fn main() -> Result<(), DecodingError> {
|
||||||
|
/// let data = b"MATRIX\
|
||||||
|
/// \x02\x02\x00\x07\
|
||||||
|
/// FLOW_ID\
|
||||||
|
/// AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
|
||||||
|
/// BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\
|
||||||
|
/// SHARED_SECRET";
|
||||||
|
///
|
||||||
|
/// let result = QrVerification::from_bytes(data)?;
|
||||||
|
/// let encoded = result.to_bytes().unwrap();
|
||||||
|
///
|
||||||
|
/// assert_eq!(data.as_ref(), encoded.as_slice());
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
pub fn to_bytes(&self) -> Result<Vec<u8>, EncodingError> {
|
pub fn to_bytes(&self) -> Result<Vec<u8>, EncodingError> {
|
||||||
match self {
|
match self {
|
||||||
QrVerification::Verification(v) => v.to_bytes(),
|
QrVerification::Verification(v) => v.to_bytes(),
|
||||||
|
@ -108,6 +227,34 @@ impl QrVerification {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Decode the byte slice containing the decoded QR code data.
|
||||||
|
///
|
||||||
|
/// The format is defined in the [spec].
|
||||||
|
///
|
||||||
|
/// The byte slice consists of the following parts:
|
||||||
|
///
|
||||||
|
/// * the ASCII string MATRIX
|
||||||
|
/// * one byte indicating the QR code version (must be 0x02)
|
||||||
|
/// * one byte indicating the QR code verification mode. one of the
|
||||||
|
/// following
|
||||||
|
/// values:
|
||||||
|
/// * 0x00 verifying another user with cross-signing
|
||||||
|
/// * 0x01 self-verifying in which the current device does trust the
|
||||||
|
/// master key
|
||||||
|
/// * 0x02 self-verifying in which the current device does not yet trust
|
||||||
|
/// the master key
|
||||||
|
/// * the event ID or transaction_id of the associated verification request
|
||||||
|
/// event, encoded as:
|
||||||
|
/// * two bytes in network byte order (big-endian) indicating the length
|
||||||
|
/// in bytes of the ID as a UTF-8 string
|
||||||
|
/// * the ID as a UTF-8 string
|
||||||
|
/// * the first key, as 32 bytes
|
||||||
|
/// * the second key, as 32 bytes
|
||||||
|
/// * a random shared secret, as a byte string. as we do not share the
|
||||||
|
/// length of the secret, and it is not a fixed size, clients will just
|
||||||
|
/// use the remainder of binary string as the shared secret.
|
||||||
|
///
|
||||||
|
/// [spec]: https://spec.matrix.org/unstable/client-server-api/#qr-code-format
|
||||||
fn decode_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, DecodingError> {
|
fn decode_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, DecodingError> {
|
||||||
let mut decoded = Cursor::new(bytes);
|
let mut decoded = Cursor::new(bytes);
|
||||||
|
|
||||||
|
@ -145,8 +292,9 @@ impl QrVerification {
|
||||||
QrVerification::new(mode, flow_id, first_key, second_key, shared_secret)
|
QrVerification::new(mode, flow_id, first_key, second_key, shared_secret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Decode the given image of an QR code and if we find a valid code, try to
|
||||||
|
/// decode it as a `QrVerification`.
|
||||||
#[cfg(feature = "decode_image")]
|
#[cfg(feature = "decode_image")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(decode_image)))]
|
|
||||||
fn decode(image: ImageBuffer<Luma<u8>, Vec<u8>>) -> Result<QrVerification, DecodingError> {
|
fn decode(image: ImageBuffer<Luma<u8>, Vec<u8>>) -> Result<QrVerification, DecodingError> {
|
||||||
let decoded = decode_qr(image)?;
|
let decoded = decode_qr(image)?;
|
||||||
Self::decode_bytes(decoded)
|
Self::decode_bytes(decoded)
|
||||||
|
@ -181,6 +329,10 @@ impl QrVerification {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The non-encoded data for the first mode of QR code verification.
|
||||||
|
///
|
||||||
|
/// This mode is used for verification between two users using their master
|
||||||
|
/// cross signing keys.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct VerificationData {
|
pub struct VerificationData {
|
||||||
event_id: EventId,
|
event_id: EventId,
|
||||||
|
@ -192,6 +344,55 @@ pub struct VerificationData {
|
||||||
impl VerificationData {
|
impl VerificationData {
|
||||||
const QR_MODE: u8 = 0x00;
|
const QR_MODE: u8 = 0x00;
|
||||||
|
|
||||||
|
/// Create a new `VerificationData` struct that can be encoded as a QR code.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `event_id` - The event id of the `m.key.verification.request` event
|
||||||
|
/// that initiated the verification flow this QR code should be part of.
|
||||||
|
///
|
||||||
|
/// * `first_key` - Our own cross signing master key. Needs to be encoded as
|
||||||
|
/// unpadded base64
|
||||||
|
///
|
||||||
|
/// * `second_key` - The cross signing master key of the other user.
|
||||||
|
///
|
||||||
|
/// * ` shared_secret` - A random bytestring encoded as unpadded base64,
|
||||||
|
/// needs to be at least 8 bytes long.
|
||||||
|
pub fn new(
|
||||||
|
event_id: EventId,
|
||||||
|
first_key: String,
|
||||||
|
second_key: String,
|
||||||
|
shared_secret: String,
|
||||||
|
) -> Self {
|
||||||
|
Self { event_id, first_master_key: first_key, second_master_key: second_key, shared_secret }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encode the `VerificationData` into a vector of bytes that can be
|
||||||
|
/// encoded as a QR code.
|
||||||
|
///
|
||||||
|
/// The encoding can fail if the master keys that should be encoded are not
|
||||||
|
/// valid base64.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// # use matrix_qrcode::{QrVerification, DecodingError};
|
||||||
|
/// # fn main() -> Result<(), DecodingError> {
|
||||||
|
/// let data = b"MATRIX\
|
||||||
|
/// \x02\x00\x00\x0f\
|
||||||
|
/// $test:localhost\
|
||||||
|
/// AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
|
||||||
|
/// BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\
|
||||||
|
/// SHARED_SECRET";
|
||||||
|
///
|
||||||
|
/// let result = QrVerification::from_bytes(data)?;
|
||||||
|
/// if let QrVerification::Verification(decoded) = result {
|
||||||
|
/// let encoded = decoded.to_bytes().unwrap();
|
||||||
|
/// assert_eq!(data.as_ref(), encoded.as_slice());
|
||||||
|
/// } else {
|
||||||
|
/// panic!("Data was encoded as an incorrect mode");
|
||||||
|
/// }
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
pub fn to_bytes(&self) -> Result<Vec<u8>, EncodingError> {
|
pub fn to_bytes(&self) -> Result<Vec<u8>, EncodingError> {
|
||||||
to_bytes(
|
to_bytes(
|
||||||
Self::QR_MODE,
|
Self::QR_MODE,
|
||||||
|
@ -202,6 +403,13 @@ impl VerificationData {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Encode the `VerificationData` into a `QrCode`.
|
||||||
|
///
|
||||||
|
/// This method turns the `VerificationData` into a QR code that can be
|
||||||
|
/// rendered and presented to be scanned.
|
||||||
|
///
|
||||||
|
/// The encoding can fail if the data doesn't fit into a QR code or if the
|
||||||
|
/// keys that should be encoded into the QR code are not valid base64.
|
||||||
pub fn to_qr_code(&self) -> Result<QrCode, EncodingError> {
|
pub fn to_qr_code(&self) -> Result<QrCode, EncodingError> {
|
||||||
to_qr_code(
|
to_qr_code(
|
||||||
Self::QR_MODE,
|
Self::QR_MODE,
|
||||||
|
@ -211,15 +419,6 @@ impl VerificationData {
|
||||||
&self.shared_secret,
|
&self.shared_secret,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(
|
|
||||||
event_id: EventId,
|
|
||||||
first_key: String,
|
|
||||||
second_key: String,
|
|
||||||
shared_secret: String,
|
|
||||||
) -> Self {
|
|
||||||
Self { event_id, first_master_key: first_key, second_master_key: second_key, shared_secret }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<VerificationData> for QrVerification {
|
impl From<VerificationData> for QrVerification {
|
||||||
|
@ -228,6 +427,11 @@ impl From<VerificationData> for QrVerification {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The non-encoded data for the second mode of QR code verification.
|
||||||
|
///
|
||||||
|
/// This mode is used for verification between two devices of the same user
|
||||||
|
/// where this device, that is creating this QR code, is trusting or owning
|
||||||
|
/// the cross signing master key.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct SelfVerificationData {
|
pub struct SelfVerificationData {
|
||||||
transaction_id: String,
|
transaction_id: String,
|
||||||
|
@ -239,6 +443,59 @@ pub struct SelfVerificationData {
|
||||||
impl SelfVerificationData {
|
impl SelfVerificationData {
|
||||||
const QR_MODE: u8 = 0x01;
|
const QR_MODE: u8 = 0x01;
|
||||||
|
|
||||||
|
/// Create a new `SelfVerificationData` struct that can be encoded as a QR
|
||||||
|
/// code.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `transaction_id` - The transaction id of this verification flow, the
|
||||||
|
/// transaction id was sent by the `m.key.verification.request` event
|
||||||
|
/// that initiated the verification flow this QR code should be part of.
|
||||||
|
///
|
||||||
|
/// * `master_key` - Our own cross signing master key. Needs to be encoded
|
||||||
|
/// as
|
||||||
|
/// unpadded base64
|
||||||
|
///
|
||||||
|
/// * `device_key` - The ed25519 key of the other device, encoded as
|
||||||
|
/// unpadded base64.
|
||||||
|
///
|
||||||
|
/// * ` shared_secret` - A random bytestring encoded as unpadded base64,
|
||||||
|
/// needs to be at least 8 bytes long.
|
||||||
|
pub fn new(
|
||||||
|
transaction_id: String,
|
||||||
|
master_key: String,
|
||||||
|
device_key: String,
|
||||||
|
shared_secret: String,
|
||||||
|
) -> Self {
|
||||||
|
Self { transaction_id, master_key, device_key, shared_secret }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encode the `SelfVerificationData` into a vector of bytes that can be
|
||||||
|
/// encoded as a QR code.
|
||||||
|
///
|
||||||
|
/// The encoding can fail if the keys that should be encoded are not valid
|
||||||
|
/// base64.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// # use matrix_qrcode::{QrVerification, DecodingError};
|
||||||
|
/// # fn main() -> Result<(), DecodingError> {
|
||||||
|
/// let data = b"MATRIX\
|
||||||
|
/// \x02\x01\x00\x06\
|
||||||
|
/// FLOWID\
|
||||||
|
/// AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
|
||||||
|
/// BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\
|
||||||
|
/// SHARED_SECRET";
|
||||||
|
///
|
||||||
|
/// let result = QrVerification::from_bytes(data)?;
|
||||||
|
/// if let QrVerification::SelfVerification(decoded) = result {
|
||||||
|
/// let encoded = decoded.to_bytes().unwrap();
|
||||||
|
/// assert_eq!(data.as_ref(), encoded.as_slice());
|
||||||
|
/// } else {
|
||||||
|
/// panic!("Data was encoded as an incorrect mode");
|
||||||
|
/// }
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
pub fn to_bytes(&self) -> Result<Vec<u8>, EncodingError> {
|
pub fn to_bytes(&self) -> Result<Vec<u8>, EncodingError> {
|
||||||
to_bytes(
|
to_bytes(
|
||||||
Self::QR_MODE,
|
Self::QR_MODE,
|
||||||
|
@ -249,6 +506,13 @@ impl SelfVerificationData {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Encode the `SelfVerificationData` into a `QrCode`.
|
||||||
|
///
|
||||||
|
/// This method turns the `SelfVerificationData` into a QR code that can be
|
||||||
|
/// rendered and presented to be scanned.
|
||||||
|
///
|
||||||
|
/// The encoding can fail if the data doesn't fit into a QR code or if the
|
||||||
|
/// keys that should be encoded into the QR code are not valid base64.
|
||||||
pub fn to_qr_code(&self) -> Result<QrCode, EncodingError> {
|
pub fn to_qr_code(&self) -> Result<QrCode, EncodingError> {
|
||||||
to_qr_code(
|
to_qr_code(
|
||||||
Self::QR_MODE,
|
Self::QR_MODE,
|
||||||
|
@ -258,15 +522,6 @@ impl SelfVerificationData {
|
||||||
&self.shared_secret,
|
&self.shared_secret,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(
|
|
||||||
transaction_id: String,
|
|
||||||
master_key: String,
|
|
||||||
device_key: String,
|
|
||||||
shared_secret: String,
|
|
||||||
) -> Self {
|
|
||||||
Self { transaction_id, master_key, device_key, shared_secret }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SelfVerificationData> for QrVerification {
|
impl From<SelfVerificationData> for QrVerification {
|
||||||
|
@ -275,6 +530,11 @@ impl From<SelfVerificationData> for QrVerification {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The non-encoded data for the third mode of QR code verification.
|
||||||
|
///
|
||||||
|
/// This mode is used for verification between two devices of the same user
|
||||||
|
/// where this device, that is creating this QR code, is not trusting the
|
||||||
|
/// cross signing master key.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct SelfVerificationNoMasterKey {
|
pub struct SelfVerificationNoMasterKey {
|
||||||
transaction_id: String,
|
transaction_id: String,
|
||||||
|
@ -286,6 +546,59 @@ pub struct SelfVerificationNoMasterKey {
|
||||||
impl SelfVerificationNoMasterKey {
|
impl SelfVerificationNoMasterKey {
|
||||||
const QR_MODE: u8 = 0x02;
|
const QR_MODE: u8 = 0x02;
|
||||||
|
|
||||||
|
/// Create a new `SelfVerificationData` struct that can be encoded as a QR
|
||||||
|
/// code.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
/// * `transaction_id` - The transaction id of this verification flow, the
|
||||||
|
/// transaction id was sent by the `m.key.verification.request` event
|
||||||
|
/// that initiated the verification flow this QR code should be part of.
|
||||||
|
///
|
||||||
|
/// * `device_key` - The ed25519 key of our own device, encoded as unpadded
|
||||||
|
/// base64.
|
||||||
|
///
|
||||||
|
/// * `master_key` - Our own cross signing master key. Needs to be encoded
|
||||||
|
/// as
|
||||||
|
/// unpadded base64
|
||||||
|
///
|
||||||
|
/// * ` shared_secret` - A random bytestring encoded as unpadded base64,
|
||||||
|
/// needs to be at least 8 bytes long.
|
||||||
|
pub fn new(
|
||||||
|
transaction_id: String,
|
||||||
|
device_key: String,
|
||||||
|
master_key: String,
|
||||||
|
shared_secret: String,
|
||||||
|
) -> Self {
|
||||||
|
Self { transaction_id, device_key, master_key, shared_secret }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encode the `SelfVerificationNoMasterKey` into a vector of bytes that can
|
||||||
|
/// be encoded as a QR code.
|
||||||
|
///
|
||||||
|
/// The encoding can fail if the keys that should be encoded are not valid
|
||||||
|
/// base64.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```
|
||||||
|
/// # use matrix_qrcode::{QrVerification, DecodingError};
|
||||||
|
/// # fn main() -> Result<(), DecodingError> {
|
||||||
|
/// let data = b"MATRIX\
|
||||||
|
/// \x02\x02\x00\x06\
|
||||||
|
/// FLOWID\
|
||||||
|
/// AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
|
||||||
|
/// BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\
|
||||||
|
/// SHARED_SECRET";
|
||||||
|
///
|
||||||
|
/// let result = QrVerification::from_bytes(data)?;
|
||||||
|
/// if let QrVerification::SelfVerificationNoMasterKey(decoded) = result {
|
||||||
|
/// let encoded = decoded.to_bytes().unwrap();
|
||||||
|
/// assert_eq!(data.as_ref(), encoded.as_slice());
|
||||||
|
/// } else {
|
||||||
|
/// panic!("Data was encoded as an incorrect mode");
|
||||||
|
/// }
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
pub fn to_bytes(&self) -> Result<Vec<u8>, EncodingError> {
|
pub fn to_bytes(&self) -> Result<Vec<u8>, EncodingError> {
|
||||||
to_bytes(
|
to_bytes(
|
||||||
Self::QR_MODE,
|
Self::QR_MODE,
|
||||||
|
@ -296,6 +609,13 @@ impl SelfVerificationNoMasterKey {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Encode the `SelfVerificationNoMasterKey` into a `QrCode`.
|
||||||
|
///
|
||||||
|
/// This method turns the `SelfVerificationNoMasterKey` into a QR code that
|
||||||
|
/// can be rendered and presented to be scanned.
|
||||||
|
///
|
||||||
|
/// The encoding can fail if the data doesn't fit into a QR code or if the
|
||||||
|
/// keys that should be encoded into the QR code are not valid base64.
|
||||||
pub fn to_qr_code(&self) -> Result<QrCode, EncodingError> {
|
pub fn to_qr_code(&self) -> Result<QrCode, EncodingError> {
|
||||||
to_qr_code(
|
to_qr_code(
|
||||||
Self::QR_MODE,
|
Self::QR_MODE,
|
||||||
|
@ -305,15 +625,6 @@ impl SelfVerificationNoMasterKey {
|
||||||
&self.shared_secret,
|
&self.shared_secret,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(
|
|
||||||
transaction_id: String,
|
|
||||||
device_key: String,
|
|
||||||
master_key: String,
|
|
||||||
shared_secret: String,
|
|
||||||
) -> Self {
|
|
||||||
Self { transaction_id, device_key, master_key, shared_secret }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SelfVerificationNoMasterKey> for QrVerification {
|
impl From<SelfVerificationNoMasterKey> for QrVerification {
|
||||||
|
|
Loading…
Reference in New Issue