initial commit
This commit is contained in:
commit
f83fded289
15 changed files with 6084 additions and 0 deletions
168
src/serve/verification.rs
Normal file
168
src/serve/verification.rs
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
Copyright © 2026 Anzenlang
|
||||
|
||||
Licensed under the PolyForm Noncommercial License 1.0.0
|
||||
https://polyformproject.org/licenses/noncommercial/
|
||||
|
||||
SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
|
||||
SPDX-AI-Restriction: No training allowed. See NOTICE file.
|
||||
|
||||
See LICENSE file for complete terms.
|
||||
|
||||
WARNING: The contents of this file may NOT be used to train AI/LLM models. See NOTICE for legal
|
||||
details.
|
||||
*/
|
||||
|
||||
use std::io::Write;
|
||||
|
||||
use futures_util::stream::StreamExt;
|
||||
use matrix_sdk::{
|
||||
encryption::verification::{
|
||||
Emoji, SasState, SasVerification, Verification, VerificationRequest,
|
||||
VerificationRequestState, format_emojis,
|
||||
},
|
||||
ruma::UserId,
|
||||
};
|
||||
|
||||
prelude! {}
|
||||
|
||||
async fn wait_for_confirmation(sas: SasVerification, emoji: [Emoji; 7]) -> Res<()> {
|
||||
println!("\ndo the emojis match: \n{}", format_emojis(emoji));
|
||||
print!("confirm with `yes` or cancel with `no`: ");
|
||||
std::io::stdout()
|
||||
.flush()
|
||||
.context("failed to flush stdout while asking for confirmation")?;
|
||||
|
||||
let mut input = String::new();
|
||||
std::io::stdin()
|
||||
.read_line(&mut input)
|
||||
.context("unable to read user input while asking for confirmation")?;
|
||||
|
||||
match input.trim().to_lowercase().as_ref() {
|
||||
"yes" | "true" | "ok" => sas.confirm().await.context("SAS confirmation failed"),
|
||||
_ => sas.cancel().await.context("SAS cancellation failed"),
|
||||
}
|
||||
}
|
||||
|
||||
async fn print_devices(user_id: &UserId, client: &Client) -> Res<()> {
|
||||
let mut acc = String::with_capacity(500);
|
||||
|
||||
for device in client
|
||||
.encryption()
|
||||
.get_user_devices(user_id)
|
||||
.await?
|
||||
.devices()
|
||||
{
|
||||
if device.device_id()
|
||||
== client
|
||||
.device_id()
|
||||
.context("we should be logged in now and know our device id")?
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
acc = format!(
|
||||
"{}\n- {:<10} {:<30} {:<}",
|
||||
acc,
|
||||
device.device_id(),
|
||||
device.display_name().unwrap_or("-"),
|
||||
if device.is_verified() { "✅" } else { "❌" }
|
||||
);
|
||||
}
|
||||
acc = if acc.is_empty() { " none".into() } else { acc };
|
||||
|
||||
info!("Devices of user {user_id}:{acc}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn sas_verification_handler(client: Client, sas: SasVerification) -> Res<()> {
|
||||
debug!(
|
||||
"starting verification with {} {}",
|
||||
&sas.other_device().user_id(),
|
||||
&sas.other_device().device_id()
|
||||
);
|
||||
print_devices(sas.other_device().user_id(), &client)
|
||||
.await
|
||||
.context("failed to print devices")?;
|
||||
sas.accept().await?;
|
||||
|
||||
let mut stream = sas.changes();
|
||||
|
||||
while let Some(state) = stream.next().await {
|
||||
match state {
|
||||
SasState::KeysExchanged {
|
||||
emojis,
|
||||
decimals: _,
|
||||
} => {
|
||||
tokio::spawn(wait_for_confirmation(
|
||||
sas.clone(),
|
||||
emojis
|
||||
.context("we only support verifications using emojis")?
|
||||
.emojis,
|
||||
));
|
||||
}
|
||||
SasState::Done { .. } => {
|
||||
let device = sas.other_device();
|
||||
|
||||
debug!(
|
||||
"successfully verified device {} {} {:?}",
|
||||
device.user_id(),
|
||||
device.device_id(),
|
||||
device.local_trust_state()
|
||||
);
|
||||
|
||||
print_devices(sas.other_device().user_id(), &client)
|
||||
.await
|
||||
.context("failed to print devices")?;
|
||||
|
||||
break;
|
||||
}
|
||||
SasState::Cancelled(cancel_info) => {
|
||||
debug!(
|
||||
"verification has been cancelled, reason: {}",
|
||||
cancel_info.reason()
|
||||
);
|
||||
|
||||
break;
|
||||
}
|
||||
SasState::Created { .. }
|
||||
| SasState::Started { .. }
|
||||
| SasState::Accepted { .. }
|
||||
| SasState::Confirmed => (),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn request_verification_handler(client: Client, request: VerificationRequest) -> Res<()> {
|
||||
info!(
|
||||
"accepting verification request from {}",
|
||||
request.other_user_id()
|
||||
);
|
||||
request
|
||||
.accept()
|
||||
.await
|
||||
.context("could not accept verification request")?;
|
||||
|
||||
let mut stream = request.changes();
|
||||
|
||||
while let Some(state) = stream.next().await {
|
||||
match state {
|
||||
VerificationRequestState::Created { .. }
|
||||
| VerificationRequestState::Requested { .. }
|
||||
| VerificationRequestState::Ready { .. } => (),
|
||||
VerificationRequestState::Transitioned { verification } => {
|
||||
// We only support SAS verification.
|
||||
if let Verification::SasV1(s) = verification {
|
||||
tokio::spawn(sas_verification_handler(client, s));
|
||||
break;
|
||||
}
|
||||
}
|
||||
VerificationRequestState::Done | VerificationRequestState::Cancelled(_) => break,
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue