mirror of
https://github.com/chatmail/core.git
synced 2026-04-17 21:46:35 +03:00
This makes the contact ID its own newtype instead of being a plain u32. The change purposefully does not yet try and reap any benefits from this yet, instead aiming for a boring change that's easy to review. Only exception is the ToSql/FromSql as not doing that yet would also have created churn in the database code and it is easier to go straight for the right solution here.
123 lines
3.7 KiB
Rust
123 lines
3.7 KiB
Rust
//! Supporting code for the QR-code invite.
|
|
//!
|
|
//! QR-codes are decoded into a more general-purpose [`Qr`] struct normally. This makes working
|
|
//! with it rather hard, so here we have a wrapper type that specifically deals with Secure-Join
|
|
//! QR-codes so that the Secure-Join code can have more guarantees when dealing with this.
|
|
|
|
use std::convert::TryFrom;
|
|
|
|
use anyhow::{bail, Error, Result};
|
|
|
|
use crate::contact::ContactId;
|
|
use crate::key::Fingerprint;
|
|
use crate::qr::Qr;
|
|
|
|
/// Represents the data from a QR-code scan.
|
|
///
|
|
/// There are methods to conveniently access fields present in both variants.
|
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
|
pub enum QrInvite {
|
|
Contact {
|
|
contact_id: ContactId,
|
|
fingerprint: Fingerprint,
|
|
invitenumber: String,
|
|
authcode: String,
|
|
},
|
|
Group {
|
|
contact_id: ContactId,
|
|
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
|
|
/// translated to a contact ID.
|
|
pub fn contact_id(&self) -> ContactId {
|
|
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<Qr> for QrInvite {
|
|
type Error = Error;
|
|
|
|
fn try_from(qr: Qr) -> Result<Self> {
|
|
match qr {
|
|
Qr::AskVerifyContact {
|
|
contact_id,
|
|
fingerprint,
|
|
invitenumber,
|
|
authcode,
|
|
} => Ok(QrInvite::Contact {
|
|
contact_id,
|
|
fingerprint,
|
|
invitenumber,
|
|
authcode,
|
|
}),
|
|
Qr::AskVerifyGroup {
|
|
grpname,
|
|
grpid,
|
|
contact_id,
|
|
fingerprint,
|
|
invitenumber,
|
|
authcode,
|
|
} => Ok(QrInvite::Group {
|
|
contact_id,
|
|
fingerprint,
|
|
name: grpname,
|
|
grpid,
|
|
invitenumber,
|
|
authcode,
|
|
}),
|
|
_ => bail!("Unsupported QR type {:?}", qr),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl rusqlite::types::ToSql for QrInvite {
|
|
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
|
|
let json = serde_json::to_string(self)
|
|
.map_err(|err| rusqlite::Error::ToSqlConversionFailure(Box::new(err)))?;
|
|
let val = rusqlite::types::Value::Text(json);
|
|
let out = rusqlite::types::ToSqlOutput::Owned(val);
|
|
Ok(out)
|
|
}
|
|
}
|
|
|
|
impl rusqlite::types::FromSql for QrInvite {
|
|
fn column_result(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
|
|
String::column_result(value).and_then(|val| {
|
|
serde_json::from_str(&val)
|
|
.map_err(|err| rusqlite::types::FromSqlError::Other(Box::new(err)))
|
|
})
|
|
}
|
|
}
|