Skip to content

Commit

Permalink
added feature: --room-enable-encryption
Browse files Browse the repository at this point in the history
  • Loading branch information
8go committed Nov 26, 2022
1 parent 5e9dac4 commit 9cf5ea5
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 49 deletions.
14 changes: 7 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[package]
name = "matrix-commander"
version = "0.1.17"
version = "0.1.18"
edition = "2021"
description = "simple but convenient CLI-based Matrix client app for sending and receiving"
documentation = "https://docs.rs/matrix-commander"
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,12 @@ Options:
servers that know about the alias(es). The argument '--get-room-info'
can be used to go the other direction, i.e. to find the room aliases
given a room id
--room-enable-encryption [<ROOM>...]
Provide one or more room ids. For each room given encryption will be
enabled. You must be member of the room in order to be able to enable
encryption. Use shortcut '-' to enable encryption in the
pre-configured default room. Enabling an already enabled room will do
nothing and cause no error
--alias [<ALIAS>...]
Provide one or more aliases. --alias is currently used in combination
with --room-dm-create. It is ignored otherwise. Canonical short alias
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.1.17
0.1.18
6 changes: 6 additions & 0 deletions help.txt
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,12 @@ Options:
servers that know about the alias(es). The argument '--get-room-info'
can be used to go the other direction, i.e. to find the room aliases
given a room id
--room-enable-encryption [<ROOM>...]
Provide one or more room ids. For each room given encryption will be
enabled. You must be member of the room in order to be able to enable
encryption. Use shortcut '-' to enable encryption in the
pre-configured default room. Enabling an already enabled room will do
nothing and cause no error
--alias [<ALIAS>...]
Provide one or more aliases. --alias is currently used in combination
with --room-dm-create. It is ignored otherwise. Canonical short alias
Expand Down
Empty file modified scripts/workflow-outline.txt
100755 → 100644
Empty file.
50 changes: 48 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ use crate::mclient::{
logout_local, message, replace_star_with_rooms, restore_credentials, restore_login, room_ban,
room_create, room_forget, room_get_state, room_get_visibility, room_invite, room_join,
room_kick, room_leave, room_resolve_alias, room_unban, rooms, set_avatar, set_avatar_url,
set_display_name, unset_avatar_url, verify,
set_display_name, unset_avatar_url, verify, room_enable_encryption,
};

// import matrix-sdk Client related code related to receiving messages and listening
Expand Down Expand Up @@ -169,6 +169,9 @@ pub enum Error {
#[error("Resolve Room Alias Failed")]
ResolveRoomAliasFailed,

#[error("Enable Encryption Failed")]
EnableEncryptionFailed,

#[error("Room Get Visibility Failed")]
RoomGetVisibilityFailed,

Expand Down Expand Up @@ -1309,6 +1312,15 @@ pub struct Args {
#[arg(long, num_args(0..), value_name = "ALIAS", )]
room_resolve_alias: Vec<String>,

/// Provide one or more room ids. For each room given
/// encryption will be enabled. You must be member of the
/// room in order to be able to enable encryption. Use
/// shortcut '-' to enable encryption in the pre-configured
/// default room. Enabling an already enabled room will
/// do nothing and cause no error.
#[arg(long, num_args(0..), value_name = "ROOM", )]
room_enable_encryption: Vec<String>,

/// Provide one or more aliases. --alias is currently used in
/// combination with --room-dm-create. It is ignored otherwise.
/// Canonical short alias look like 'SomeRoomAlias'.
Expand Down Expand Up @@ -1592,6 +1604,7 @@ impl Args {
room_unban: Vec::new(),
room_kick: Vec::new(),
room_resolve_alias: Vec::new(),
room_enable_encryption: Vec::new(),
alias: Vec::new(),
name: Vec::new(),
topic: Vec::new(),
Expand Down Expand Up @@ -2540,6 +2553,12 @@ pub(crate) async fn cli_room_resolve_alias(client: &Client, ap: &Args) -> Result
crate::room_resolve_alias(client, &ap.room_resolve_alias, ap.output).await
}

/// Handle the --room-enable-encryption CLI argument
pub(crate) async fn cli_room_enable_encryption(client: &Client, ap: &Args) -> Result<(), Error> {
info!("Room-enable-encryption chosen.");
crate::room_enable_encryption(client, &ap.room_enable_encryption, ap.output).await
}

/// Handle the --get-avatar CLI argument
pub(crate) async fn cli_get_avatar(client: &Client, ap: &Args) -> Result<(), Error> {
info!("Get-avatar chosen.");
Expand Down Expand Up @@ -2732,6 +2751,7 @@ async fn main() -> Result<(), Error> {
debug!("room-unban option is {:?}", ap.room_unban);
debug!("room-kick option is {:?}", ap.room_kick);
debug!("room-resolve-alias option is {:?}", ap.room_resolve_alias);
debug!("room-enable-encryption option is {:?}", ap.room_enable_encryption);
debug!("alias option is {:?}", ap.alias);
debug!("name option is {:?}", ap.name);
debug!("topic-create option is {:?}", ap.topic);
Expand Down Expand Up @@ -2764,6 +2784,7 @@ async fn main() -> Result<(), Error> {
};

if !(!ap.login.is_none()
// get actions
|| ap.whoami
|| !ap.verify.is_none()
|| ap.devices
Expand All @@ -2780,6 +2801,7 @@ async fn main() -> Result<(), Error> {
|| ap.get_avatar_url
|| ap.get_display_name
|| ap.get_profile
// set actions
|| !ap.room_create.is_empty()
|| !ap.room_dm_create.is_empty()
|| !ap.room_leave.is_empty()
Expand All @@ -2794,6 +2816,8 @@ async fn main() -> Result<(), Error> {
|| !ap.set_avatar_url.is_none()
|| ap.unset_avatar_url
|| !ap.set_display_name.is_none()
|| !ap.room_enable_encryption.is_empty()
// send and listen actions
|| !ap.message.is_empty()
|| !ap.file.is_empty()
|| ap.listen.is_once()
Expand Down Expand Up @@ -2883,10 +2907,24 @@ async fn main() -> Result<(), Error> {
)
.await; // convert short ids, short aliases and aliases to full room ids
ap.room_forget.retain(|x| !x.trim().is_empty());

convert_to_full_room_aliases(
&mut ap.room_resolve_alias,
ap.creds.as_ref().unwrap().homeserver.host_str().unwrap(),
); // convert short aliases to full aliases

replace_minus_with_default_room(
&mut ap.room_enable_encryption,
&ap.creds.as_ref().unwrap().room_default,
); // convert '-' to default room
convert_to_full_room_ids(
&client,
&mut ap.room_enable_encryption,
ap.creds.as_ref().unwrap().homeserver.host_str().unwrap(),
)
.await; // convert short ids, short aliases and aliases to full room ids
ap.room_enable_encryption.retain(|x| !x.trim().is_empty());

replace_minus_with_default_room(
&mut ap.get_room_info,
&ap.creds.as_ref().unwrap().room_default,
Expand All @@ -2898,7 +2936,8 @@ async fn main() -> Result<(), Error> {
)
.await; // convert short ids, short aliases and aliases to full room ids
ap.get_room_info.retain(|x| !x.trim().is_empty());
replace_minus_with_default_room(

replace_minus_with_default_room(
&mut ap.room_invite,
&ap.creds.as_ref().unwrap().room_default,
); // convert '-' to default room
Expand Down Expand Up @@ -3224,6 +3263,13 @@ async fn main() -> Result<(), Error> {
};
};

if !ap.room_enable_encryption.is_empty() {
match crate::cli_room_enable_encryption(&client, &ap).await {
Ok(ref _n) => debug!("crate::room_enable_encryption successful"),
Err(ref e) => error!("Error: crate::room_enable_encryption reported {}", e),
};
};

// send text message(s)
if !ap.message.is_empty() {
match crate::cli_message(&client, &ap).await {
Expand Down
124 changes: 86 additions & 38 deletions src/mclient.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ use matrix_sdk::{
api::client::room::create_room::v3::RoomPreset,
api::client::room::Visibility,
api::client::uiaa,
events::room::encryption::RoomEncryptionEventContent,
// OwnedRoomOrAliasId, OwnedServerName,
// device_id,
events::room::member::SyncRoomMemberEvent,
Expand All @@ -60,8 +61,12 @@ use matrix_sdk::{
events::room::name::SyncRoomNameEvent,
events::room::power_levels::SyncRoomPowerLevelsEvent,
events::room::topic::SyncRoomTopicEvent,
events::AnyInitialStateEvent,
events::EmptyStateKey,
events::InitialStateEvent,
// events::OriginalMessageLikeEvent,
serde::Raw,
EventEncryptionAlgorithm,
// MxcUri,
// DeviceId,
// room_id, session_id, user_id,
Expand Down Expand Up @@ -131,6 +136,10 @@ pub(crate) async fn convert_to_full_room_ids(
vecstr.retain(|x| !x.trim().is_empty());
for el in vecstr {
el.retain(|c| !c.is_whitespace());
if el.starts_with('@') {
error!("This room alias or id {:?} starts with an at sign. @ are used for user ids, not room id or room aliases. This will fail later.", el);
continue;
}
if !el.starts_with('#') && !el.starts_with('!') {
el.insert(0, '#');
}
Expand Down Expand Up @@ -881,7 +890,22 @@ pub(crate) async fn room_create(
// pub room_version: Option<&'a RoomVersionId>,
// pub topic: Option<&'a str>,
// pub visibility: Visibility, }
let content = RoomEncryptionEventContent::new(EventEncryptionAlgorithm::MegolmV1AesSha2);
let initstateev: InitialStateEvent<RoomEncryptionEventContent>;
initstateev = InitialStateEvent {
content: content,
state_key: EmptyStateKey,
};
let rawinitstateev = Raw::new(&initstateev)?;
// let anyinitstateev: AnyInitialStateEvent =
// matrix_sdk::ruma::events::AnyInitialStateEvent::RoomEncryption(initstateev);
// todo: better alternative? let anyinitstateev2: AnyInitialStateEvent = AnyInitialStateEvent::from(initstateev);

let rawanyinitstateev: Raw<AnyInitialStateEvent> = rawinitstateev.cast();
let mut request = CreateRoomRequest::new();
let initstatevec = vec![rawanyinitstateev];
request.initial_state = &initstatevec;

request.name = to_opt(&names2[i]);
request.room_alias_name = to_opt(&aliases2[i]);
request.topic = to_opt(&topics2[i]);
Expand Down Expand Up @@ -927,44 +951,7 @@ pub(crate) async fn room_create(
jstr.push('}');
println!("{}", jstr);
}

// without sync client will not know that it is in joined rooms list and it will fail, we must sync!
client.sync_once(SyncSettings::new()).await?; // ToDo use std sync_once fn

// Todo: It would be faster and more problematic to enable encryption by using:
// // initial_state = [EnableEncryptionBuilder().as_dict()]
// as done in Python.
// Todo: implement --plain
// Todo: implement --room-enable-encryption
match client.get_joined_room(&response.room_id) {
Some(room) => {
match room.enable_encryption().await {
Ok(_) => {
debug!(
"enable_encryption succeeded for room {:?}.",
response.room_id
);
}
Err(ref e) => {
err_count += 1;
error!("enable_encryption failed for room {:?} with reported error {:?}.", response.room_id, e);
}
}
}
None => {
err_count += 1;
error!(
concat!(
"get_joined_room failed for room {:?}, ",
"room created but it could not be encrypted right now. ",
"This is usually an event-not-having arrived-yet issue. ",
"You can fix this by calling --room-enable-encryption '{}' later ",
"in a separate command."
),
response.room_id, response.room_id
);
}
}
// room_enable_encryption(): no longer needed, already done by setting request.initial_state
}
Err(ref e) => {
err_count += 1;
Expand Down Expand Up @@ -1774,6 +1761,67 @@ pub(crate) async fn room_resolve_alias(
}
}

/// Enable encryption for given room(s).
pub(crate) async fn room_enable_encryption(
client: &Client,
room_ids: &[String], // list of room ids
_output: Output, // how to format output
) -> Result<(), Error> {
debug!("Enable encryption for room(s): rooms={:?}", room_ids);
let mut err_count = 0u32;
// convert Vec of strings into a slice of array of OwnedRoomIds
let mut roomids: Vec<OwnedRoomId> = Vec::new();
for room_id in room_ids {
roomids.push(
match RoomId::parse(<std::string::String as AsRef<str>>::as_ref(room_id)) {
Ok(id) => id,
Err(ref e) => {
error!(
"Error: invalid room id {:?}. Error reported is {:?}.",
room_id, e
);
err_count += 1;
continue;
}
},
);
}
if roomids.is_empty() {
error!("No valid rooms. Cannot enable encryption anywhere. Giving up.");
return Err(Error::EnableEncryptionFailed);
}
// without sync() client will not know that it is in joined rooms list and it will fail, we must sync!
// client.sync_once(SyncSettings::new()).await?; we should have sync-ed before.
for (i, id) in roomids.iter().enumerate() {
debug!("In position {} we have room id {:?}.", i, id,);
match client.get_joined_room(&id) {
Some(room) => match room.enable_encryption().await {
Ok(_) => {
debug!("enable_encryption succeeded for room {:?}.", id);
}
Err(ref e) => {
err_count += 1;
error!(
"enable_encryption failed for room {:?} with reported error {:?}.",
id, e
);
}
},
None => {
err_count += 1;
error!(concat!(
"get_joined_room failed for room {:?}, ",
"Are you member of this room? If you are member of this room try syncing first."), id);
}
}
}
if err_count != 0 {
Err(Error::EnableEncryptionFailed)
} else {
Ok(())
}
}

/// Pre-processing for Delete device(s).
/// This will adjust the lists for special shortcuts such as 'me' and '*'.
/// Get password and user if needed.
Expand Down

0 comments on commit 9cf5ea5

Please sign in to comment.