diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index e3b3f4f88..760f58d2f 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -2076,6 +2076,10 @@ void dc_stop_ongoing_process (dc_context_t* context); #define DC_QR_TEXT 330 // text1=text #define DC_QR_URL 332 // text1=URL #define DC_QR_ERROR 400 // text1=error string +#define DC_QR_WITHDRAW_VERIFYCONTACT 500 +#define DC_QR_WITHDRAW_VERIFYGROUP 502 // text1=groupname +#define DC_QR_REVIVE_VERIFYCONTACT 510 +#define DC_QR_REVIVE_VERIFYGROUP 512 // text1=groupname /** * Check a scanned QR code. @@ -2097,6 +2101,12 @@ void dc_stop_ongoing_process (dc_context_t* context); * - DC_QR_TEXT with dc_lot_t::text1=Text * - DC_QR_URL with dc_lot_t::text1=URL * - DC_QR_ERROR with dc_lot_t::text1=Error string + * - DC_QR_WITHDRAW_VERIFYCONTACT, DC_QR_WITHDRAW_VERIFYGROUP + * withdraw own qr-codes, with text1=groupname for groups + * to actually withdraw, call dc_set_config_from_qr() with the code. + * - DC_QR_REVIVE_VERIFYCONTACT, DC_QR_REVIVE_VERIFYGROUP, + * revive withdrawn qr-codes, with text1=groupname for groups, + * to actually revive, call dc_set_config_from_qr() with the code. * * @memberof dc_context_t * @param context The context object. diff --git a/src/lot.rs b/src/lot.rs index ed746977f..805567ba0 100644 --- a/src/lot.rs +++ b/src/lot.rs @@ -110,6 +110,16 @@ pub enum LotState { /// text1=error string QrError = 400, + QrWithdrawVerifyContact = 500, + + /// text1=groupname + QrWithdrawVerifyGroup = 502, + + QrReviveVerifyContact = 510, + + /// text1=groupname + QrReviveVerifyGroup = 512, + // Message States MsgInFresh = 10, MsgInNoticed = 13, diff --git a/src/qr.rs b/src/qr.rs index 4954e3f1a..69561a376 100644 --- a/src/qr.rs +++ b/src/qr.rs @@ -6,7 +6,7 @@ use percent_encoding::percent_decode_str; use serde::Deserialize; use std::collections::BTreeMap; -use crate::chat::{self, ChatIdBlocked}; +use crate::chat::{self, get_chat_id_by_grpid, ChatIdBlocked}; use crate::config::Config; use crate::constants::Blocked; use crate::contact::{addr_normalize, may_be_valid_addr, Contact, Origin}; @@ -16,6 +16,7 @@ use crate::log::LogExt; use crate::lot::{Lot, LotState}; use crate::message::Message; use crate::peerstate::Peerstate; +use crate::token; const OPENPGP4FPR_SCHEME: &str = "OPENPGP4FPR:"; // yes: uppercase const DCACCOUNT_SCHEME: &str = "DCACCOUNT:"; @@ -189,6 +190,27 @@ async fn decode_openpgp(context: &Context, qr: &str) -> Lot { lot.fingerprint = Some(fingerprint); lot.invitenumber = invitenumber; lot.auth = auth; + + // scanning own qr-code offers withdraw/revive instead of secure-join + if context.is_self_addr(&addr).await.unwrap_or_default() { + if let Some(ref invitenumber) = lot.invitenumber { + lot.state = + if token::exists(context, token::Namespace::InviteNumber, &*invitenumber).await + { + if lot.state == LotState::QrAskVerifyContact { + LotState::QrWithdrawVerifyContact + } else { + LotState::QrWithdrawVerifyGroup + } + } else { + if lot.state == LotState::QrAskVerifyContact { + LotState::QrReviveVerifyContact + } else { + LotState::QrReviveVerifyGroup + } + } + } + } } else { return format_err!("Missing address").into(); } @@ -275,7 +297,8 @@ async fn set_account_from_qr(context: &Context, qr: &str) -> Result<(), Error> { } pub async fn set_config_from_qr(context: &Context, qr: &str) -> Result<(), Error> { - match check_qr(context, qr).await.state { + let lot = check_qr(context, qr).await; + match lot.state { LotState::QrAccount => set_account_from_qr(context, qr).await, LotState::QrWebrtcInstance => { let val = decode_webrtc_instance(context, qr).text2; @@ -284,6 +307,47 @@ pub async fn set_config_from_qr(context: &Context, qr: &str) -> Result<(), Error .await?; Ok(()) } + LotState::QrWithdrawVerifyContact | LotState::QrWithdrawVerifyGroup => { + token::delete( + context, + token::Namespace::InviteNumber, + lot.invitenumber.unwrap_or_default().as_str(), + ) + .await?; + token::delete( + context, + token::Namespace::Auth, + lot.auth.unwrap_or_default().as_str(), + ) + .await?; + Ok(()) + } + LotState::QrReviveVerifyContact | LotState::QrReviveVerifyGroup => { + let chat_id = if lot.state == LotState::QrReviveVerifyContact { + None + } else { + Some( + get_chat_id_by_grpid(context, &lot.text2.unwrap_or_default()) + .await? + .0, + ) + }; + token::save( + context, + token::Namespace::InviteNumber, + chat_id, + lot.invitenumber.unwrap_or_default(), + ) + .await; + token::save( + context, + token::Namespace::Auth, + chat_id, + lot.auth.unwrap_or_default(), + ) + .await; + Ok(()) + } _ => bail!("qr code does not contain config: {}", qr), } } diff --git a/src/token.rs b/src/token.rs index a0e60d9de..2433f3f36 100644 --- a/src/token.rs +++ b/src/token.rs @@ -111,3 +111,14 @@ pub async fn exists(context: &Context, namespace: Namespace, token: &str) -> boo .await .unwrap_or_default() } + +pub async fn delete(context: &Context, namespace: Namespace, token: &str) -> Result<()> { + context + .sql + .execute( + "DELETE FROM tokens WHERE namespc=? AND token=?;", + paramsv![namespace, token], + ) + .await?; + Ok(()) +}