restricted webxdc internet access (#3516)

* add request_internet_access manifest option

* test request_internet_access

* update CHANGELOG

* force warning when internet access is enabled

if internet access is enabled,
show a warning instead of the normal summary
(the internet access is currently mainly to test out integrations
as maps for video chat; the summary is dispensable in the cases currently)

* adapt json-rpc's WebxdcMessageInfo
This commit is contained in:
bjoern
2022-09-05 11:45:34 +02:00
committed by GitHub
parent 4b91a88bc9
commit 949370ad63
6 changed files with 92 additions and 8 deletions

View File

@@ -15,6 +15,7 @@
### Changes
- order contact lists by "last seen";
this affects `dc_get_chat_contacts()`, `dc_get_contacts()` and `dc_get_blocked_contacts()` #3562
- add `internet_access` flag to `dc_msg_get_webxdc_info()` #3516
### Fixes
- do not emit notifications for blocked chats #3557

View File

@@ -3763,6 +3763,11 @@ char* dc_msg_get_webxdc_blob (const dc_msg_t* msg, const char*
* URL where the source code of the Webxdc and other information can be found;
* defaults to an empty string.
* Implementations may offer an menu or a button to open this URL.
* - internet_access:
* true if the Webxdc should get full internet access, including Webrtc.
* currently, this is only true for encrypted Webxdc's in the self chat
* that have requested internet access in the manifest.
* this is useful for development and maybe for internal integrations at some point.
*
* @memberof dc_msg_t
* @param msg The webxdc instance.

View File

@@ -33,6 +33,8 @@ pub struct WebxdcMessageInfo {
/// defaults to an empty string.
/// Implementations may offer an menu or a button to open this URL.
source_code_url: Option<String>,
/// True if full internet access should be granted to the app.
internet_access: bool,
}
impl WebxdcMessageInfo {
@@ -47,6 +49,7 @@ impl WebxdcMessageInfo {
document,
summary,
source_code_url,
internet_access,
} = message.get_webxdc_info(context).await?;
Ok(Self {
@@ -55,6 +58,7 @@ impl WebxdcMessageInfo {
document: maybe_empty_string_to_option(document),
summary: maybe_empty_string_to_option(summary),
source_code_url: maybe_empty_string_to_option(source_code_url),
internet_access,
})
}
}

View File

@@ -94,5 +94,9 @@ export type WebxdcMessageInfo={
* defaults to an empty string.
* Implementations may offer an menu or a button to open this URL.
*/
"sourceCodeUrl":(string|null);};
"sourceCodeUrl":(string|null);
/**
* True if full internet access should be granted to the app.
*/
"internetAccess":boolean;};
export type __AllTyps=[string,boolean,Record<string,string>,U32,U32,null,(U32)[],U32,null,(U32|null),(Account)[],U32,Account,U32,string,(ProviderInfo|null),U32,boolean,U32,Record<string,string>,U32,string,(string|null),null,U32,Record<string,(string|null)>,null,U32,string,null,U32,string,Qr,U32,string,(string|null),U32,(string)[],Record<string,(string|null)>,U32,null,U32,null,U32,(U32)[],U32,U32,Usize,U32,string,U32,U32,string,null,U32,(U32|null),(string|null),(U32|null),(ChatListEntry)[],U32,(ChatListEntry)[],Record<U32,ChatListItemFetchResult>,U32,U32,FullChat,U32,U32,null,U32,U32,null,U32,string,string,U32,U32,U32,U32,(U32)[],U32,U32,Message,U32,(U32)[],Record<U32,Message>,U32,U32,Contact,U32,string,(string|null),U32,U32,U32,U32,U32,U32,null,U32,U32,null,U32,(Contact)[],U32,U32,(string|null),(U32)[],U32,U32,(string|null),(Contact)[],U32,(U32)[],Record<U32,Contact>,U32,(U32|null),Viewtype,(Viewtype|null),(Viewtype|null),(U32)[],U32,U32,string,string,null,U32,U32,U32,string,U32,U32,WebxdcMessageInfo,U32,string,U32,U32];

View File

@@ -56,6 +56,7 @@ struct WebxdcManifest {
name: Option<String>,
min_api: Option<u32>,
source_code_url: Option<String>,
request_internet_access: Option<bool>,
}
/// Parsed information from WebxdcManifest and fallbacks.
@@ -66,6 +67,7 @@ pub struct WebxdcInfo {
pub document: String,
pub summary: String,
pub source_code_url: String,
pub internet_access: bool,
}
/// Status Update ID.
@@ -676,6 +678,7 @@ impl Message {
name: None,
min_api: None,
source_code_url: None,
request_internet_access: None,
}
}
} else {
@@ -683,6 +686,7 @@ impl Message {
name: None,
min_api: None,
source_code_url: None,
request_internet_access: None,
}
};
@@ -694,6 +698,10 @@ impl Message {
}
}
let internet_access = manifest.request_internet_access.unwrap_or_default()
&& self.chat_id.is_self_talk(context).await.unwrap_or_default()
&& self.get_showpadlock();
Ok(WebxdcInfo {
name: if let Some(name) = manifest.name {
name
@@ -712,16 +720,20 @@ impl Message {
.get(Param::WebxdcDocument)
.unwrap_or_default()
.to_string(),
summary: self
.param
.get(Param::WebxdcSummary)
.unwrap_or_default()
.to_string(),
summary: if internet_access {
"Dev Mode: Do not enter sensitive data!".to_string()
} else {
self.param
.get(Param::WebxdcSummary)
.unwrap_or_default()
.to_string()
},
source_code_url: if let Some(url) = manifest.source_code_url {
url
} else {
"".to_string()
},
internet_access,
})
}
}
@@ -729,8 +741,8 @@ impl Message {
#[cfg(test)]
mod tests {
use crate::chat::{
add_contact_to_chat, create_group_chat, forward_msgs, resend_msgs, send_msg, send_text_msg,
ChatId, ProtectionStatus,
add_contact_to_chat, create_broadcast_list, create_group_chat, forward_msgs, resend_msgs,
send_msg, send_text_msg, ChatId, ProtectionStatus,
};
use crate::chatlist::Chatlist;
use crate::config::Config;
@@ -1781,6 +1793,19 @@ sth_for_the = "future""#
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_parse_webxdc_manifest_request_internet_access() -> Result<()> {
let result = parse_webxdc_manifest(r#"request_internet_access = 3"#.as_bytes());
assert!(result.is_err());
let manifest = parse_webxdc_manifest(r#" source_code_url="https://foo.org""#.as_bytes())?;
assert_eq!(manifest.request_internet_access, None);
let manifest = parse_webxdc_manifest(r#" request_internet_access=false"#.as_bytes())?;
assert_eq!(manifest.request_internet_access, Some(false));
let manifest = parse_webxdc_manifest(r#"request_internet_access = true"#.as_bytes())?;
assert_eq!(manifest.request_internet_access, Some(true));
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_webxdc_min_api_too_large() -> Result<()> {
let t = TestContext::new_alice().await;
@@ -2191,6 +2216,51 @@ sth_for_the = "future""#
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_webxdc_internet_access() -> Result<()> {
let t = TestContext::new_alice().await;
let self_id = t.get_self_chat().await.id;
let single_id = t.create_chat_with_contact("bob", "bob@e.com").await.id;
let group_id = create_group_chat(&t, ProtectionStatus::Unprotected, "chat").await?;
let broadcast_id = create_broadcast_list(&t).await?;
let mut first_test = true; // only the first test has all conditions for internet access
for e2ee in ["1", "0"] {
t.set_config(Config::E2eeEnabled, Some(e2ee)).await?;
for chat_id in [self_id, single_id, group_id, broadcast_id] {
for internet_xdc in [true, false] {
let mut instance = create_webxdc_instance(
&t,
"foo.xdc",
if internet_xdc {
include_bytes!("../test-data/webxdc/request-internet-access.xdc")
} else {
include_bytes!("../test-data/webxdc/minimal.xdc")
},
)
.await?;
let instance_id = send_msg(&t, chat_id, &mut instance).await?;
t.send_webxdc_status_update(
instance_id,
r#"{"summary":"real summary", "payload": 42}"#,
"descr",
)
.await?;
let instance = Message::load_from_db(&t, instance_id).await?;
let info = instance.get_webxdc_info(&t).await?;
assert_eq!(info.internet_access, first_test);
assert_eq!(info.summary.contains("Do not enter sensitive"), first_test);
assert_eq!(info.summary.contains("real summary"), !first_test);
first_test = false;
}
}
}
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_webxdc_chatlist_summary() -> Result<()> {
let t = TestContext::new_alice().await;

Binary file not shown.