mirror of
https://github.com/chatmail/core.git
synced 2026-05-09 01:46:30 +03:00
Merge pull request #1779 from deltachat/share-webrtc-instance
share webrtc-instance via qr-code
This commit is contained in:
@@ -375,12 +375,13 @@ int dc_set_stock_translation(dc_context_t* context, uint32_t stock_i
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set configuration values from a QR code containing an account.
|
* Set configuration values from a QR code.
|
||||||
* Before this function is called, dc_check_qr() should confirm the type of the
|
* Before this function is called, dc_check_qr() should confirm the type of the
|
||||||
* QR code is DC_QR_ACCOUNT.
|
* QR code is DC_QR_ACCOUNT or DC_QR_WEBRTC_INSTANCE.
|
||||||
*
|
*
|
||||||
* Internally, the function will call dc_set_config()
|
* Internally, the function will call dc_set_config() with the appropriate keys,
|
||||||
* at least with the keys `addr` and `mail_pw`.
|
* eg. `addr` and `mail_pw` for DC_QR_ACCOUNT
|
||||||
|
* or `webrtc_instance` for DC_QR_WEBRTC_INSTANCE.
|
||||||
*
|
*
|
||||||
* @memberof dc_context_t
|
* @memberof dc_context_t
|
||||||
* @param context The context object
|
* @param context The context object
|
||||||
@@ -1927,6 +1928,7 @@ void dc_stop_ongoing_process (dc_context_t* context);
|
|||||||
#define DC_QR_FPR_MISMATCH 220 // id=contact
|
#define DC_QR_FPR_MISMATCH 220 // id=contact
|
||||||
#define DC_QR_FPR_WITHOUT_ADDR 230 // test1=formatted fingerprint
|
#define DC_QR_FPR_WITHOUT_ADDR 230 // test1=formatted fingerprint
|
||||||
#define DC_QR_ACCOUNT 250 // text1=domain
|
#define DC_QR_ACCOUNT 250 // text1=domain
|
||||||
|
#define DC_QR_WEBRTC_INSTANCE 260 // text1=domain
|
||||||
#define DC_QR_ADDR 320 // id=contact
|
#define DC_QR_ADDR 320 // id=contact
|
||||||
#define DC_QR_TEXT 330 // text1=text
|
#define DC_QR_TEXT 330 // text1=text
|
||||||
#define DC_QR_URL 332 // text1=URL
|
#define DC_QR_URL 332 // text1=URL
|
||||||
@@ -1945,6 +1947,9 @@ void dc_stop_ongoing_process (dc_context_t* context);
|
|||||||
* - DC_QR_FPR_MISMATCH with dc_lot_t::id=Contact ID
|
* - DC_QR_FPR_MISMATCH with dc_lot_t::id=Contact ID
|
||||||
* - DC_QR_FPR_WITHOUT_ADDR with dc_lot_t::test1=Formatted fingerprint
|
* - DC_QR_FPR_WITHOUT_ADDR with dc_lot_t::test1=Formatted fingerprint
|
||||||
* - DC_QR_ACCOUNT allows creation of an account, dc_lot_t::text1=domain
|
* - DC_QR_ACCOUNT allows creation of an account, dc_lot_t::text1=domain
|
||||||
|
* - DC_QR_WEBRTC_INSTANCE - a shared webrtc-instance
|
||||||
|
* that will be set if dc_set_config_from_qr() is called with the qr-code,
|
||||||
|
* dc_lot_t::text1=domain could be used to ask the user
|
||||||
* - DC_QR_ADDR with dc_lot_t::id=Contact ID
|
* - DC_QR_ADDR with dc_lot_t::id=Contact ID
|
||||||
* - DC_QR_TEXT with dc_lot_t::text1=Text
|
* - DC_QR_TEXT with dc_lot_t::text1=Text
|
||||||
* - DC_QR_URL with dc_lot_t::text1=URL
|
* - DC_QR_URL with dc_lot_t::text1=URL
|
||||||
|
|||||||
@@ -91,6 +91,9 @@ pub enum LotState {
|
|||||||
/// text1=domain
|
/// text1=domain
|
||||||
QrAccount = 250,
|
QrAccount = 250,
|
||||||
|
|
||||||
|
/// text1=domain, text2=instance pattern
|
||||||
|
QrWebrtcInstance = 260,
|
||||||
|
|
||||||
/// id=contact
|
/// id=contact
|
||||||
QrAddr = 320,
|
QrAddr = 320,
|
||||||
|
|
||||||
|
|||||||
94
src/qr.rs
94
src/qr.rs
@@ -12,11 +12,13 @@ use crate::context::Context;
|
|||||||
use crate::error::{bail, ensure, format_err, Error};
|
use crate::error::{bail, ensure, format_err, Error};
|
||||||
use crate::key::Fingerprint;
|
use crate::key::Fingerprint;
|
||||||
use crate::lot::{Lot, LotState};
|
use crate::lot::{Lot, LotState};
|
||||||
|
use crate::message::Message;
|
||||||
use crate::param::*;
|
use crate::param::*;
|
||||||
use crate::peerstate::*;
|
use crate::peerstate::*;
|
||||||
|
|
||||||
const OPENPGP4FPR_SCHEME: &str = "OPENPGP4FPR:"; // yes: uppercase
|
const OPENPGP4FPR_SCHEME: &str = "OPENPGP4FPR:"; // yes: uppercase
|
||||||
const DCACCOUNT_SCHEME: &str = "DCACCOUNT:";
|
const DCACCOUNT_SCHEME: &str = "DCACCOUNT:";
|
||||||
|
const DCWEBRTC_SCHEME: &str = "DCWEBRTC:";
|
||||||
const MAILTO_SCHEME: &str = "mailto:";
|
const MAILTO_SCHEME: &str = "mailto:";
|
||||||
const MATMSG_SCHEME: &str = "MATMSG:";
|
const MATMSG_SCHEME: &str = "MATMSG:";
|
||||||
const VCARD_SCHEME: &str = "BEGIN:VCARD";
|
const VCARD_SCHEME: &str = "BEGIN:VCARD";
|
||||||
@@ -51,6 +53,8 @@ pub async fn check_qr(context: &Context, qr: impl AsRef<str>) -> Lot {
|
|||||||
decode_openpgp(context, qr).await
|
decode_openpgp(context, qr).await
|
||||||
} else if starts_with_ignore_case(qr, DCACCOUNT_SCHEME) {
|
} else if starts_with_ignore_case(qr, DCACCOUNT_SCHEME) {
|
||||||
decode_account(context, qr)
|
decode_account(context, qr)
|
||||||
|
} else if starts_with_ignore_case(qr, DCWEBRTC_SCHEME) {
|
||||||
|
decode_webrtc_instance(context, qr)
|
||||||
} else if qr.starts_with(MAILTO_SCHEME) {
|
} else if qr.starts_with(MAILTO_SCHEME) {
|
||||||
decode_mailto(context, qr).await
|
decode_mailto(context, qr).await
|
||||||
} else if qr.starts_with(SMTP_SCHEME) {
|
} else if qr.starts_with(SMTP_SCHEME) {
|
||||||
@@ -210,6 +214,31 @@ fn decode_account(_context: &Context, qr: &str) -> Lot {
|
|||||||
lot
|
lot
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// scheme: `DCWEBRTC:https://meet.jit.si/$ROOM`
|
||||||
|
#[allow(clippy::indexing_slicing)]
|
||||||
|
fn decode_webrtc_instance(_context: &Context, qr: &str) -> Lot {
|
||||||
|
let payload = &qr[DCWEBRTC_SCHEME.len()..];
|
||||||
|
|
||||||
|
let mut lot = Lot::new();
|
||||||
|
|
||||||
|
let (_type, url) = Message::parse_webrtc_instance(payload);
|
||||||
|
if let Ok(url) = url::Url::parse(&url) {
|
||||||
|
if url.scheme() == "http" || url.scheme() == "https" {
|
||||||
|
lot.state = LotState::QrWebrtcInstance;
|
||||||
|
lot.text1 = url.host_str().map(|x| x.to_string());
|
||||||
|
lot.text2 = Some(payload.to_string())
|
||||||
|
} else {
|
||||||
|
lot.state = LotState::QrError;
|
||||||
|
lot.text1 = Some(format!("Bad scheme for webrtc instance: {}", payload));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lot.state = LotState::QrError;
|
||||||
|
lot.text1 = Some(format!("Invalid webrtc instance: {}", payload));
|
||||||
|
}
|
||||||
|
|
||||||
|
lot
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct CreateAccountResponse {
|
struct CreateAccountResponse {
|
||||||
email: String,
|
email: String,
|
||||||
@@ -220,7 +249,7 @@ struct CreateAccountResponse {
|
|||||||
/// download additional information from the contained url and set the parameters.
|
/// download additional information from the contained url and set the parameters.
|
||||||
/// on success, a configure::configure() should be able to log in to the account
|
/// on success, a configure::configure() should be able to log in to the account
|
||||||
#[allow(clippy::indexing_slicing)]
|
#[allow(clippy::indexing_slicing)]
|
||||||
pub async fn set_config_from_qr(context: &Context, qr: &str) -> Result<(), Error> {
|
async fn set_account_from_qr(context: &Context, qr: &str) -> Result<(), Error> {
|
||||||
let url_str = &qr[DCACCOUNT_SCHEME.len()..];
|
let url_str = &qr[DCACCOUNT_SCHEME.len()..];
|
||||||
|
|
||||||
let response: Result<CreateAccountResponse, surf::Error> =
|
let response: Result<CreateAccountResponse, surf::Error> =
|
||||||
@@ -240,6 +269,20 @@ pub async fn set_config_from_qr(context: &Context, qr: &str) -> Result<(), Error
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn set_config_from_qr(context: &Context, qr: &str) -> Result<(), Error> {
|
||||||
|
match check_qr(context, &qr).await.state {
|
||||||
|
LotState::QrAccount => set_account_from_qr(context, qr).await,
|
||||||
|
LotState::QrWebrtcInstance => {
|
||||||
|
let val = decode_webrtc_instance(context, qr).text2;
|
||||||
|
context
|
||||||
|
.set_config(Config::WebrtcInstance, val.as_deref())
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
_ => bail!("qr code does not contain config: {}", qr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Extract address for the mailto scheme.
|
/// Extract address for the mailto scheme.
|
||||||
///
|
///
|
||||||
/// Scheme: `mailto:addr...?subject=...&body=..`
|
/// Scheme: `mailto:addr...?subject=...&body=..`
|
||||||
@@ -618,6 +661,25 @@ mod tests {
|
|||||||
assert_eq!(res.get_text1().unwrap(), "example.org");
|
assert_eq!(res.get_text1().unwrap(), "example.org");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn test_decode_webrtc_instance() {
|
||||||
|
let ctx = TestContext::new().await;
|
||||||
|
|
||||||
|
let res = check_qr(&ctx.ctx, "DCWEBRTC:basicwebrtc:https://basicurl.com/$ROOM").await;
|
||||||
|
assert_eq!(res.get_state(), LotState::QrWebrtcInstance);
|
||||||
|
assert_eq!(res.get_text1().unwrap(), "basicurl.com");
|
||||||
|
assert_eq!(
|
||||||
|
res.get_text2().unwrap(),
|
||||||
|
"basicwebrtc:https://basicurl.com/$ROOM"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Test it again with mixcased "dcWebRTC:" uri scheme
|
||||||
|
let res = check_qr(&ctx.ctx, "dcWebRTC:https://example.org/").await;
|
||||||
|
assert_eq!(res.get_state(), LotState::QrWebrtcInstance);
|
||||||
|
assert_eq!(res.get_text1().unwrap(), "example.org");
|
||||||
|
assert_eq!(res.get_text2().unwrap(), "https://example.org/");
|
||||||
|
}
|
||||||
|
|
||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
async fn test_decode_account_bad_scheme() {
|
async fn test_decode_account_bad_scheme() {
|
||||||
let ctx = TestContext::new().await;
|
let ctx = TestContext::new().await;
|
||||||
@@ -638,4 +700,34 @@ mod tests {
|
|||||||
assert_eq!(res.get_state(), LotState::QrError);
|
assert_eq!(res.get_state(), LotState::QrError);
|
||||||
assert!(res.get_text1().is_some());
|
assert!(res.get_text1().is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[async_std::test]
|
||||||
|
async fn test_set_config_from_qr() {
|
||||||
|
let ctx = TestContext::new().await;
|
||||||
|
|
||||||
|
assert!(ctx.ctx.get_config(Config::WebrtcInstance).await.is_none());
|
||||||
|
|
||||||
|
let res = set_config_from_qr(&ctx.ctx, "badqr:https://example.org/").await;
|
||||||
|
assert!(!res.is_ok());
|
||||||
|
assert!(ctx.ctx.get_config(Config::WebrtcInstance).await.is_none());
|
||||||
|
|
||||||
|
let res = set_config_from_qr(&ctx.ctx, "https://no.qr").await;
|
||||||
|
assert!(!res.is_ok());
|
||||||
|
assert!(ctx.ctx.get_config(Config::WebrtcInstance).await.is_none());
|
||||||
|
|
||||||
|
let res = set_config_from_qr(&ctx.ctx, "dcwebrtc:https://example.org/").await;
|
||||||
|
assert!(res.is_ok());
|
||||||
|
assert_eq!(
|
||||||
|
ctx.ctx.get_config(Config::WebrtcInstance).await.unwrap(),
|
||||||
|
"https://example.org/"
|
||||||
|
);
|
||||||
|
|
||||||
|
let res =
|
||||||
|
set_config_from_qr(&ctx.ctx, "DCWEBRTC:basicwebrtc:https://foo.bar/?$ROOM&test").await;
|
||||||
|
assert!(res.is_ok());
|
||||||
|
assert_eq!(
|
||||||
|
ctx.ctx.get_config(Config::WebrtcInstance).await.unwrap(),
|
||||||
|
"basicwebrtc:https://foo.bar/?$ROOM&test"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user