mirror of
https://github.com/chatmail/core.git
synced 2026-04-24 08:56:29 +03:00
Refactor qr module
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
|
||||
use anyhow::{bail, ensure, format_err, Context as _, Result};
|
||||
use anyhow::{bail, ensure, Context as _, Result};
|
||||
use async_std::path::PathBuf;
|
||||
use deltachat_derive::{FromSql, ToSql};
|
||||
use itertools::Itertools;
|
||||
@@ -1339,12 +1339,11 @@ fn cat_fingerprint(
|
||||
impl Context {
|
||||
/// determine whether the specified addr maps to the/a self addr
|
||||
pub async fn is_self_addr(&self, addr: &str) -> Result<bool> {
|
||||
let self_addr = self
|
||||
.get_config(Config::ConfiguredAddr)
|
||||
.await?
|
||||
.ok_or_else(|| format_err!("Not configured"))?;
|
||||
|
||||
Ok(addr_cmp(self_addr, addr))
|
||||
if let Some(self_addr) = self.get_config(Config::ConfiguredAddr).await? {
|
||||
Ok(addr_cmp(self_addr, addr))
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1491,7 +1490,7 @@ mod tests {
|
||||
#[async_std::test]
|
||||
async fn test_is_self_addr() -> Result<()> {
|
||||
let t = TestContext::new().await;
|
||||
assert!(t.is_self_addr("me@me.org").await.is_err());
|
||||
assert_eq!(t.is_self_addr("me@me.org").await?, false);
|
||||
|
||||
let addr = t.configure_alice().await;
|
||||
assert_eq!(t.is_self_addr("me@me.org").await?, false);
|
||||
|
||||
@@ -68,7 +68,6 @@ pub mod key;
|
||||
mod keyring;
|
||||
pub mod location;
|
||||
mod login_param;
|
||||
pub mod lot;
|
||||
pub mod message;
|
||||
mod mimefactory;
|
||||
pub mod mimeparser;
|
||||
|
||||
181
src/lot.rs
181
src/lot.rs
@@ -1,181 +0,0 @@
|
||||
//! # Legacy generic return values for C API.
|
||||
|
||||
use deltachat_derive::{FromSql, ToSql};
|
||||
|
||||
use crate::key::Fingerprint;
|
||||
use crate::message::MessageState;
|
||||
use crate::summary::{Summary, SummaryPrefix};
|
||||
|
||||
/// An object containing a set of values.
|
||||
/// The meaning of the values is defined by the function returning the object.
|
||||
/// Lot objects are created
|
||||
/// eg. by chatlist.get_summary() or dc_msg_get_summary().
|
||||
///
|
||||
/// *Lot* is used in the meaning *heap* here.
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub struct Lot {
|
||||
pub(crate) text1_meaning: Meaning,
|
||||
pub(crate) text1: Option<String>,
|
||||
pub(crate) text2: Option<String>,
|
||||
pub(crate) timestamp: i64,
|
||||
pub(crate) state: LotState,
|
||||
pub(crate) id: u32,
|
||||
pub(crate) fingerprint: Option<Fingerprint>,
|
||||
pub(crate) invitenumber: Option<String>,
|
||||
pub(crate) auth: Option<String>,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(
|
||||
Debug, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive, ToSql, FromSql,
|
||||
)]
|
||||
pub enum Meaning {
|
||||
None = 0,
|
||||
Text1Draft = 1,
|
||||
Text1Username = 2,
|
||||
Text1Self = 3,
|
||||
}
|
||||
|
||||
impl Default for Meaning {
|
||||
fn default() -> Self {
|
||||
Meaning::None
|
||||
}
|
||||
}
|
||||
|
||||
impl Lot {
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub fn get_text1(&self) -> Option<&str> {
|
||||
self.text1.as_deref()
|
||||
}
|
||||
|
||||
pub fn get_text2(&self) -> Option<&str> {
|
||||
self.text2.as_deref()
|
||||
}
|
||||
|
||||
pub fn get_text1_meaning(&self) -> Meaning {
|
||||
self.text1_meaning
|
||||
}
|
||||
|
||||
pub fn get_state(&self) -> LotState {
|
||||
self.state
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> u32 {
|
||||
self.id
|
||||
}
|
||||
|
||||
pub fn get_timestamp(&self) -> i64 {
|
||||
self.timestamp
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(
|
||||
Debug, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive, ToSql, FromSql,
|
||||
)]
|
||||
pub enum LotState {
|
||||
// Default
|
||||
Undefined = 0,
|
||||
|
||||
// Qr States
|
||||
/// id=contact
|
||||
QrAskVerifyContact = 200,
|
||||
|
||||
/// text1=groupname
|
||||
QrAskVerifyGroup = 202,
|
||||
|
||||
/// id=contact
|
||||
QrFprOk = 210,
|
||||
|
||||
/// id=contact
|
||||
QrFprMismatch = 220,
|
||||
|
||||
/// test1=formatted fingerprint
|
||||
QrFprWithoutAddr = 230,
|
||||
|
||||
/// text1=domain
|
||||
QrAccount = 250,
|
||||
|
||||
/// text1=domain, text2=instance pattern
|
||||
QrWebrtcInstance = 260,
|
||||
|
||||
/// id=contact
|
||||
QrAddr = 320,
|
||||
|
||||
/// text1=text
|
||||
QrText = 330,
|
||||
|
||||
/// text1=URL
|
||||
QrUrl = 332,
|
||||
|
||||
/// text1=error string
|
||||
QrError = 400,
|
||||
|
||||
QrWithdrawVerifyContact = 500,
|
||||
|
||||
/// text1=groupname
|
||||
QrWithdrawVerifyGroup = 502,
|
||||
|
||||
QrReviveVerifyContact = 510,
|
||||
|
||||
/// text1=groupname
|
||||
QrReviveVerifyGroup = 512,
|
||||
|
||||
// Message States
|
||||
MsgInFresh = 10,
|
||||
MsgInNoticed = 13,
|
||||
MsgInSeen = 16,
|
||||
MsgOutPreparing = 18,
|
||||
MsgOutDraft = 19,
|
||||
MsgOutPending = 20,
|
||||
MsgOutFailed = 24,
|
||||
MsgOutDelivered = 26,
|
||||
MsgOutMdnRcvd = 28,
|
||||
}
|
||||
|
||||
impl Default for LotState {
|
||||
fn default() -> Self {
|
||||
LotState::Undefined
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MessageState> for LotState {
|
||||
fn from(s: MessageState) -> Self {
|
||||
use MessageState::*;
|
||||
match s {
|
||||
Undefined => LotState::Undefined,
|
||||
InFresh => LotState::MsgInFresh,
|
||||
InNoticed => LotState::MsgInNoticed,
|
||||
InSeen => LotState::MsgInSeen,
|
||||
OutPreparing => LotState::MsgOutPreparing,
|
||||
OutDraft => LotState::MsgOutDraft,
|
||||
OutPending => LotState::MsgOutPending,
|
||||
OutFailed => LotState::MsgOutFailed,
|
||||
OutDelivered => LotState::MsgOutDelivered,
|
||||
OutMdnRcvd => LotState::MsgOutMdnRcvd,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Summary> for Lot {
|
||||
fn from(summary: Summary) -> Self {
|
||||
let text2 = Some(summary.truncated_text(160).to_string());
|
||||
let (text1, text1_meaning) = match summary.prefix {
|
||||
None => (None, Meaning::None),
|
||||
Some(SummaryPrefix::Draft(text)) => (Some(text), Meaning::Text1Draft),
|
||||
Some(SummaryPrefix::Username(username)) => (Some(username), Meaning::Text1Username),
|
||||
Some(SummaryPrefix::Me(text)) => (Some(text), Meaning::Text1Self),
|
||||
};
|
||||
Self {
|
||||
text1_meaning,
|
||||
text1,
|
||||
text2,
|
||||
timestamp: summary.timestamp,
|
||||
state: summary.state.into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@ mod bobstate;
|
||||
mod qrinvite;
|
||||
|
||||
use bobstate::{BobHandshakeStage, BobState, BobStateHandle};
|
||||
use qrinvite::{QrError, QrInvite};
|
||||
use qrinvite::QrInvite;
|
||||
|
||||
pub const NON_ALPHANUMERIC_WITHOUT_DOT: &AsciiSet = &NON_ALPHANUMERIC.remove(b'.');
|
||||
|
||||
@@ -247,9 +247,6 @@ async fn get_self_fingerprint(context: &Context) -> Option<Fingerprint> {
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum JoinError {
|
||||
#[error("Unknown QR-code: {0}")]
|
||||
QrCode(#[from] QrError),
|
||||
|
||||
#[error("An \"ongoing\" process is already running")]
|
||||
OngoingRunning,
|
||||
|
||||
@@ -293,7 +290,7 @@ async fn securejoin(context: &Context, qr: &str) -> Result<ChatId, JoinError> {
|
||||
========================================================*/
|
||||
|
||||
info!(context, "Requesting secure-join ...",);
|
||||
let qr_scan = check_qr(context, qr).await;
|
||||
let qr_scan = check_qr(context, qr).await?;
|
||||
|
||||
let invite = QrInvite::try_from(qr_scan)?;
|
||||
|
||||
@@ -1146,7 +1143,7 @@ mod tests {
|
||||
async fn test_setup_contact_bad_qr() {
|
||||
let bob = TestContext::new_bob().await;
|
||||
let ret = dc_join_securejoin(&bob.ctx, "not a qr code").await;
|
||||
assert!(matches!(ret, Err(JoinError::QrCode(_))));
|
||||
assert!(ret.is_err());
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
//! 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 with Secure-Join QR-codes so
|
||||
//! that the Secure-Join code can have many more guarantees when dealing with this.
|
||||
//! 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::Result;
|
||||
use anyhow::{bail, Error, Result};
|
||||
|
||||
use crate::key::Fingerprint;
|
||||
use crate::lot::{Lot, LotState};
|
||||
use crate::qr::Qr;
|
||||
|
||||
/// Represents the data from a QR-code scan.
|
||||
///
|
||||
@@ -66,53 +65,38 @@ impl QrInvite {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Lot> for QrInvite {
|
||||
type Error = QrError;
|
||||
impl TryFrom<Qr> for QrInvite {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(lot: Lot) -> Result<Self, Self::Error> {
|
||||
if lot.state != LotState::QrAskVerifyContact && lot.state != LotState::QrAskVerifyGroup {
|
||||
return Err(QrError::UnsupportedProtocol);
|
||||
}
|
||||
if lot.id == 0 {
|
||||
return Err(QrError::MissingContactId);
|
||||
}
|
||||
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,
|
||||
fn try_from(qr: Qr) -> Result<Self> {
|
||||
match qr {
|
||||
Qr::AskVerifyContact {
|
||||
contact_id,
|
||||
fingerprint,
|
||||
invitenumber,
|
||||
authcode,
|
||||
} => Ok(QrInvite::Contact {
|
||||
contact_id,
|
||||
fingerprint,
|
||||
invitenumber,
|
||||
authcode,
|
||||
}),
|
||||
LotState::QrAskVerifyGroup => Ok(QrInvite::Group {
|
||||
contact_id: lot.id,
|
||||
Qr::AskVerifyGroup {
|
||||
grpname,
|
||||
grpid,
|
||||
contact_id,
|
||||
fingerprint,
|
||||
name: lot.text1.ok_or(QrError::MissingGroupName)?,
|
||||
grpid: lot.text2.ok_or(QrError::MissingGroupId)?,
|
||||
invitenumber,
|
||||
authcode,
|
||||
} => Ok(QrInvite::Group {
|
||||
contact_id,
|
||||
fingerprint,
|
||||
name: grpname,
|
||||
grpid,
|
||||
invitenumber,
|
||||
authcode,
|
||||
}),
|
||||
_ => Err(QrError::UnsupportedProtocol),
|
||||
_ => bail!("Unsupported QR type {:?}", qr),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum QrError {
|
||||
#[error("Unsupported protocol in QR-code")]
|
||||
UnsupportedProtocol,
|
||||
#[error("Missing fingerprint")]
|
||||
MissingFingerprint,
|
||||
#[error("Missing invitenumber")]
|
||||
MissingInviteNumber,
|
||||
#[error("Missing auth code")]
|
||||
MissingAuthCode,
|
||||
#[error("Missing group name")]
|
||||
MissingGroupName,
|
||||
#[error("Missing group id")]
|
||||
MissingGroupId,
|
||||
#[error("Missing contact id")]
|
||||
MissingContactId,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user