mirror of
https://github.com/chatmail/core.git
synced 2026-05-17 05:46:30 +03:00
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:
@@ -15,6 +15,7 @@
|
|||||||
### Changes
|
### Changes
|
||||||
- order contact lists by "last seen";
|
- order contact lists by "last seen";
|
||||||
this affects `dc_get_chat_contacts()`, `dc_get_contacts()` and `dc_get_blocked_contacts()` #3562
|
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
|
### Fixes
|
||||||
- do not emit notifications for blocked chats #3557
|
- do not emit notifications for blocked chats #3557
|
||||||
|
|||||||
@@ -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;
|
* URL where the source code of the Webxdc and other information can be found;
|
||||||
* defaults to an empty string.
|
* defaults to an empty string.
|
||||||
* Implementations may offer an menu or a button to open this URL.
|
* 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
|
* @memberof dc_msg_t
|
||||||
* @param msg The webxdc instance.
|
* @param msg The webxdc instance.
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ pub struct WebxdcMessageInfo {
|
|||||||
/// defaults to an empty string.
|
/// defaults to an empty string.
|
||||||
/// Implementations may offer an menu or a button to open this URL.
|
/// Implementations may offer an menu or a button to open this URL.
|
||||||
source_code_url: Option<String>,
|
source_code_url: Option<String>,
|
||||||
|
/// True if full internet access should be granted to the app.
|
||||||
|
internet_access: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WebxdcMessageInfo {
|
impl WebxdcMessageInfo {
|
||||||
@@ -47,6 +49,7 @@ impl WebxdcMessageInfo {
|
|||||||
document,
|
document,
|
||||||
summary,
|
summary,
|
||||||
source_code_url,
|
source_code_url,
|
||||||
|
internet_access,
|
||||||
} = message.get_webxdc_info(context).await?;
|
} = message.get_webxdc_info(context).await?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
@@ -55,6 +58,7 @@ impl WebxdcMessageInfo {
|
|||||||
document: maybe_empty_string_to_option(document),
|
document: maybe_empty_string_to_option(document),
|
||||||
summary: maybe_empty_string_to_option(summary),
|
summary: maybe_empty_string_to_option(summary),
|
||||||
source_code_url: maybe_empty_string_to_option(source_code_url),
|
source_code_url: maybe_empty_string_to_option(source_code_url),
|
||||||
|
internet_access,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,5 +94,9 @@ export type WebxdcMessageInfo={
|
|||||||
* defaults to an empty string.
|
* defaults to an empty string.
|
||||||
* Implementations may offer an menu or a button to open this URL.
|
* 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];
|
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];
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ struct WebxdcManifest {
|
|||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
min_api: Option<u32>,
|
min_api: Option<u32>,
|
||||||
source_code_url: Option<String>,
|
source_code_url: Option<String>,
|
||||||
|
request_internet_access: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parsed information from WebxdcManifest and fallbacks.
|
/// Parsed information from WebxdcManifest and fallbacks.
|
||||||
@@ -66,6 +67,7 @@ pub struct WebxdcInfo {
|
|||||||
pub document: String,
|
pub document: String,
|
||||||
pub summary: String,
|
pub summary: String,
|
||||||
pub source_code_url: String,
|
pub source_code_url: String,
|
||||||
|
pub internet_access: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Status Update ID.
|
/// Status Update ID.
|
||||||
@@ -676,6 +678,7 @@ impl Message {
|
|||||||
name: None,
|
name: None,
|
||||||
min_api: None,
|
min_api: None,
|
||||||
source_code_url: None,
|
source_code_url: None,
|
||||||
|
request_internet_access: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -683,6 +686,7 @@ impl Message {
|
|||||||
name: None,
|
name: None,
|
||||||
min_api: None,
|
min_api: None,
|
||||||
source_code_url: 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 {
|
Ok(WebxdcInfo {
|
||||||
name: if let Some(name) = manifest.name {
|
name: if let Some(name) = manifest.name {
|
||||||
name
|
name
|
||||||
@@ -712,16 +720,20 @@ impl Message {
|
|||||||
.get(Param::WebxdcDocument)
|
.get(Param::WebxdcDocument)
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.to_string(),
|
.to_string(),
|
||||||
summary: self
|
summary: if internet_access {
|
||||||
.param
|
"Dev Mode: Do not enter sensitive data!".to_string()
|
||||||
.get(Param::WebxdcSummary)
|
} else {
|
||||||
.unwrap_or_default()
|
self.param
|
||||||
.to_string(),
|
.get(Param::WebxdcSummary)
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_string()
|
||||||
|
},
|
||||||
source_code_url: if let Some(url) = manifest.source_code_url {
|
source_code_url: if let Some(url) = manifest.source_code_url {
|
||||||
url
|
url
|
||||||
} else {
|
} else {
|
||||||
"".to_string()
|
"".to_string()
|
||||||
},
|
},
|
||||||
|
internet_access,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -729,8 +741,8 @@ impl Message {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::chat::{
|
use crate::chat::{
|
||||||
add_contact_to_chat, create_group_chat, forward_msgs, resend_msgs, send_msg, send_text_msg,
|
add_contact_to_chat, create_broadcast_list, create_group_chat, forward_msgs, resend_msgs,
|
||||||
ChatId, ProtectionStatus,
|
send_msg, send_text_msg, ChatId, ProtectionStatus,
|
||||||
};
|
};
|
||||||
use crate::chatlist::Chatlist;
|
use crate::chatlist::Chatlist;
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
@@ -1781,6 +1793,19 @@ sth_for_the = "future""#
|
|||||||
Ok(())
|
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)]
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
async fn test_webxdc_min_api_too_large() -> Result<()> {
|
async fn test_webxdc_min_api_too_large() -> Result<()> {
|
||||||
let t = TestContext::new_alice().await;
|
let t = TestContext::new_alice().await;
|
||||||
@@ -2191,6 +2216,51 @@ sth_for_the = "future""#
|
|||||||
Ok(())
|
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)]
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
async fn test_webxdc_chatlist_summary() -> Result<()> {
|
async fn test_webxdc_chatlist_summary() -> Result<()> {
|
||||||
let t = TestContext::new_alice().await;
|
let t = TestContext::new_alice().await;
|
||||||
|
|||||||
BIN
test-data/webxdc/request-internet-access.xdc
Normal file
BIN
test-data/webxdc/request-internet-access.xdc
Normal file
Binary file not shown.
Reference in New Issue
Block a user