mirror of
https://github.com/chatmail/core.git
synced 2026-05-02 12:56:30 +03:00
Move QrInvite out to a submodle
This commit is contained in:
@@ -16,8 +16,7 @@ use crate::context::Context;
|
|||||||
use crate::e2ee::ensure_secret_key_exists;
|
use crate::e2ee::ensure_secret_key_exists;
|
||||||
use crate::events::EventType;
|
use crate::events::EventType;
|
||||||
use crate::headerdef::HeaderDef;
|
use crate::headerdef::HeaderDef;
|
||||||
use crate::key::{self, DcKey, Fingerprint, FingerprintError, SignedPublicKey};
|
use crate::key::{self, DcKey, Fingerprint, SignedPublicKey};
|
||||||
use crate::lot::{Lot, LotState};
|
|
||||||
use crate::message::Message;
|
use crate::message::Message;
|
||||||
use crate::mimeparser::{MimeMessage, SystemMessage};
|
use crate::mimeparser::{MimeMessage, SystemMessage};
|
||||||
use crate::param::Param;
|
use crate::param::Param;
|
||||||
@@ -27,6 +26,10 @@ use crate::sql;
|
|||||||
use crate::stock::StockMessage;
|
use crate::stock::StockMessage;
|
||||||
use crate::token;
|
use crate::token;
|
||||||
|
|
||||||
|
mod qrinvite;
|
||||||
|
|
||||||
|
use qrinvite::{QrError, QrInvite};
|
||||||
|
|
||||||
pub const NON_ALPHANUMERIC_WITHOUT_DOT: &AsciiSet = &NON_ALPHANUMERIC.remove(b'.');
|
pub const NON_ALPHANUMERIC_WITHOUT_DOT: &AsciiSet = &NON_ALPHANUMERIC.remove(b'.');
|
||||||
|
|
||||||
macro_rules! joiner_progress {
|
macro_rules! joiner_progress {
|
||||||
@@ -559,108 +562,6 @@ impl BobHandshakeMsg {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the data from a QR-code scan.
|
|
||||||
///
|
|
||||||
/// There are methods to conveniently access fields present in both variants.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
enum QrInvite {
|
|
||||||
Contact {
|
|
||||||
contact_id: u32,
|
|
||||||
fingerprint: Fingerprint,
|
|
||||||
invitenumber: String,
|
|
||||||
authcode: String,
|
|
||||||
},
|
|
||||||
Group {
|
|
||||||
contact_id: u32,
|
|
||||||
fingerprint: Fingerprint,
|
|
||||||
name: String,
|
|
||||||
grpid: String,
|
|
||||||
invitenumber: String,
|
|
||||||
authcode: String,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl QrInvite {
|
|
||||||
/// The contact ID of the inviter.
|
|
||||||
///
|
|
||||||
/// The actual QR-code contains a URL-encoded email address, but upon scanning this is
|
|
||||||
/// currently translated to a contact ID.
|
|
||||||
fn contact_id(&self) -> u32 {
|
|
||||||
match self {
|
|
||||||
Self::Contact { contact_id, .. } | Self::Group { contact_id, .. } => *contact_id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The fingerprint of the inviter.
|
|
||||||
fn fingerprint(&self) -> &Fingerprint {
|
|
||||||
match self {
|
|
||||||
Self::Contact { fingerprint, .. } | Self::Group { fingerprint, .. } => &fingerprint,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The `INVITENUMBER` of the setup-contact/secure-join protocol.
|
|
||||||
fn invitenumber(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
Self::Contact { invitenumber, .. } | Self::Group { invitenumber, .. } => &invitenumber,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The `AUTH` code of the setup-contact/secure-join protocol.
|
|
||||||
fn authcode(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
Self::Contact { authcode, .. } | Self::Group { authcode, .. } => &authcode,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<Lot> for QrInvite {
|
|
||||||
type Error = QrError;
|
|
||||||
|
|
||||||
fn try_from(lot: Lot) -> Result<Self, Self::Error> {
|
|
||||||
if lot.state != LotState::QrAskVerifyContact && lot.state != LotState::QrAskVerifyGroup {
|
|
||||||
return Err(QrError::UnsupportedProtocol);
|
|
||||||
}
|
|
||||||
let fingerprint = lot.fingerprint.ok_or(QrError::MissingFingerprint)?;
|
|
||||||
let invitenumber = lot.invitenumber.ok_or(QrError::MissingInviteNumber)?;
|
|
||||||
let authcode = lot.auth.ok_or(QrError::MissingAuthCode)?;
|
|
||||||
match lot.state {
|
|
||||||
LotState::QrAskVerifyContact => Ok(QrInvite::Contact {
|
|
||||||
contact_id: lot.id,
|
|
||||||
fingerprint,
|
|
||||||
invitenumber,
|
|
||||||
authcode,
|
|
||||||
}),
|
|
||||||
LotState::QrAskVerifyGroup => Ok(QrInvite::Group {
|
|
||||||
contact_id: lot.id,
|
|
||||||
fingerprint,
|
|
||||||
name: lot.text1.ok_or(QrError::MissingGroupName)?,
|
|
||||||
grpid: lot.text2.ok_or(QrError::MissingGroupId)?,
|
|
||||||
invitenumber,
|
|
||||||
authcode,
|
|
||||||
}),
|
|
||||||
_ => Err(QrError::UnsupportedProtocol),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
|
||||||
pub enum QrError {
|
|
||||||
#[error("Unsupported protocol in QR-code")]
|
|
||||||
UnsupportedProtocol,
|
|
||||||
#[error("Failed to read fingerprint")]
|
|
||||||
InvalidFingerprint(#[from] FingerprintError),
|
|
||||||
#[error("Missing fingerprint")]
|
|
||||||
MissingFingerprint,
|
|
||||||
#[error("Missing invitenumber")]
|
|
||||||
MissingInviteNumber,
|
|
||||||
#[error("Missing auth code")]
|
|
||||||
MissingAuthCode,
|
|
||||||
#[error("Missing group name")]
|
|
||||||
MissingGroupName,
|
|
||||||
#[error("Missing group id")]
|
|
||||||
MissingGroupId,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The next message expected by [`BobState`] in the setup-contact/secure-join protocol.
|
/// The next message expected by [`BobState`] in the setup-contact/secure-join protocol.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
enum SecureJoinStep {
|
enum SecureJoinStep {
|
||||||
115
src/securejoin/qrinvite.rs
Normal file
115
src/securejoin/qrinvite.rs
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
//! Supporting code for the QR-code invite.
|
||||||
|
//!
|
||||||
|
//! QR-codes are decoded into a more general-purpose [`Lot`] struct normally, this struct is
|
||||||
|
//! so general it is not even specific to QR-codes. This makes working with it rather hard,
|
||||||
|
//! so here we have a wrapper type that specifically deals weith Secure-Join QR-codes so
|
||||||
|
//! that the Secure-Join code can have many more guarantees when dealing with this.
|
||||||
|
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
|
||||||
|
use crate::key::{Fingerprint, FingerprintError};
|
||||||
|
use crate::lot::{Lot, LotState};
|
||||||
|
|
||||||
|
/// Represents the data from a QR-code scan.
|
||||||
|
///
|
||||||
|
/// There are methods to conveniently access fields present in both variants.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum QrInvite {
|
||||||
|
Contact {
|
||||||
|
contact_id: u32,
|
||||||
|
fingerprint: Fingerprint,
|
||||||
|
invitenumber: String,
|
||||||
|
authcode: String,
|
||||||
|
},
|
||||||
|
Group {
|
||||||
|
contact_id: u32,
|
||||||
|
fingerprint: Fingerprint,
|
||||||
|
name: String,
|
||||||
|
grpid: String,
|
||||||
|
invitenumber: String,
|
||||||
|
authcode: String,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl QrInvite {
|
||||||
|
/// The contact ID of the inviter.
|
||||||
|
///
|
||||||
|
/// The actual QR-code contains a URL-encoded email address, but upon scanning this is
|
||||||
|
/// currently translated to a contact ID.
|
||||||
|
pub fn contact_id(&self) -> u32 {
|
||||||
|
match self {
|
||||||
|
Self::Contact { contact_id, .. } | Self::Group { contact_id, .. } => *contact_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The fingerprint of the inviter.
|
||||||
|
pub fn fingerprint(&self) -> &Fingerprint {
|
||||||
|
match self {
|
||||||
|
Self::Contact { fingerprint, .. } | Self::Group { fingerprint, .. } => &fingerprint,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The `INVITENUMBER` of the setup-contact/secure-join protocol.
|
||||||
|
pub fn invitenumber(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Self::Contact { invitenumber, .. } | Self::Group { invitenumber, .. } => &invitenumber,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The `AUTH` code of the setup-contact/secure-join protocol.
|
||||||
|
pub fn authcode(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
Self::Contact { authcode, .. } | Self::Group { authcode, .. } => &authcode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Lot> for QrInvite {
|
||||||
|
type Error = QrError;
|
||||||
|
|
||||||
|
fn try_from(lot: Lot) -> Result<Self, Self::Error> {
|
||||||
|
if lot.state != LotState::QrAskVerifyContact && lot.state != LotState::QrAskVerifyGroup {
|
||||||
|
return Err(QrError::UnsupportedProtocol);
|
||||||
|
}
|
||||||
|
let fingerprint = lot.fingerprint.ok_or(QrError::MissingFingerprint)?;
|
||||||
|
let invitenumber = lot.invitenumber.ok_or(QrError::MissingInviteNumber)?;
|
||||||
|
let authcode = lot.auth.ok_or(QrError::MissingAuthCode)?;
|
||||||
|
match lot.state {
|
||||||
|
LotState::QrAskVerifyContact => Ok(QrInvite::Contact {
|
||||||
|
contact_id: lot.id,
|
||||||
|
fingerprint,
|
||||||
|
invitenumber,
|
||||||
|
authcode,
|
||||||
|
}),
|
||||||
|
LotState::QrAskVerifyGroup => Ok(QrInvite::Group {
|
||||||
|
contact_id: lot.id,
|
||||||
|
fingerprint,
|
||||||
|
name: lot.text1.ok_or(QrError::MissingGroupName)?,
|
||||||
|
grpid: lot.text2.ok_or(QrError::MissingGroupId)?,
|
||||||
|
invitenumber,
|
||||||
|
authcode,
|
||||||
|
}),
|
||||||
|
_ => Err(QrError::UnsupportedProtocol),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum QrError {
|
||||||
|
#[error("Unsupported protocol in QR-code")]
|
||||||
|
UnsupportedProtocol,
|
||||||
|
#[error("Failed to read fingerprint")]
|
||||||
|
InvalidFingerprint(#[from] FingerprintError),
|
||||||
|
#[error("Missing fingerprint")]
|
||||||
|
MissingFingerprint,
|
||||||
|
#[error("Missing invitenumber")]
|
||||||
|
MissingInviteNumber,
|
||||||
|
#[error("Missing auth code")]
|
||||||
|
MissingAuthCode,
|
||||||
|
#[error("Missing group name")]
|
||||||
|
MissingGroupName,
|
||||||
|
#[error("Missing group id")]
|
||||||
|
MissingGroupId,
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user