(feat): more crypto migration

This commit is contained in:
Alois 2026-07-06 00:13:41 +02:00
commit 25caeb852e
5 changed files with 303 additions and 524 deletions

View file

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2024"
[dependencies]
mtp = { git = "https://git.methanium.net/Methanium/mtp.git" }
mtp = { git = "https://git.methanium.net/Methanium/mtp.git", features = ["client"] }
iota-logger = { path = "../iota-logger" }
iota-util = { path = "../iota-util" }
iota-storage = { path = "../iota-storage" }

View file

@ -7,10 +7,7 @@ use iota_storage::util::chats_util::{get_user, mod_user};
use iota_storage::util::communities_util::CommunitiesUtil;
use iota_storage::util::config_util::CONFIG;
use iota_storage::util::{chat_files, chats_util};
use iota_storage::util::e2ee_storage::{
self, EncryptedDeviceSecretQuery, EncryptedMessageQuery,
StoredEncryptedDeviceSecret, StoredEncryptedMessage,
};
use iota_storage::util::e2ee_storage::{self, ChatSecretQuery, StoredChatSecret};
use iota_util::crypto_helper::keyring_from_base64;
use iota_util::crypto_util::{self};
use iota_util::file_util::{get_children, load_file, save_file};
@ -34,8 +31,6 @@ fn typed_container(items: Vec<(DataType, DataValue)>) -> DataValue {
)
}
fn data_string(cv: &CommunicationValue, dt: DataType) -> Option<String> {
cv.get_data(dt)
.as_str()
@ -182,7 +177,7 @@ impl ClientConnection {
return;
}
if cv.is_type(CommunicationType::SetEncryptedDeviceSecret) {
if cv.is_type(CommunicationType::SetChatSecret) {
let sender_id = cv.get_sender().to_string();
if data_string(&cv, DataType::UserId).as_deref() != Some(sender_id.as_str()) {
self.send_message(&error_response(&cv, CommunicationType::ErrorInvalidData)).await;
@ -190,26 +185,27 @@ impl ClientConnection {
}
let now = now_millis_i64();
let record = data_string(&cv, DataType::UserId)
.zip(data_string(&cv, DataType::DeviceId))
.zip(data_string(&cv, DataType::ChatId))
.zip(data_string(&cv, DataType::SecretId))
.zip(data_i64(&cv, DataType::VersionNumber))
.zip(data_bytes(&cv, DataType::EncryptedSecret))
.zip(data_bytes(&cv, DataType::KemCiphertext))
.zip(data_string(&cv, DataType::WrappingScheme))
.map(|(((((user_id, device_id), secret_id), version), encrypted_secret), wrapping_scheme)| {
StoredEncryptedDeviceSecret {
.map(|((((((user_id, chat_id), secret_id), version), encrypted_secret), kem_ciphertext), wrapping_scheme)| {
StoredChatSecret {
user_id,
device_id,
chat_id,
secret_id,
version,
encrypted_secret,
wrapping_public_key_id: data_string(&cv, DataType::WrappingPublicKeyId),
kem_ciphertext,
wrapping_scheme,
created_at: data_i64(&cv, DataType::CreatedAt).unwrap_or(now),
updated_at: now,
}
});
match record.map(e2ee_storage::put_encrypted_device_secret) {
match record.map(e2ee_storage::put_chat_secret) {
Some(Ok(())) => {
self.send_message(&error_response(&cv, CommunicationType::Success)).await;
}
@ -220,7 +216,7 @@ impl ClientConnection {
return;
}
if cv.is_type(CommunicationType::GetEncryptedDeviceSecret) {
if cv.is_type(CommunicationType::GetChatSecret) {
let Some(user_id) = data_string(&cv, DataType::UserId) else {
self.send_message(&error_response(&cv, CommunicationType::ErrorInvalidData)).await;
return;
@ -230,27 +226,29 @@ impl ClientConnection {
self.send_message(&error_response(&cv, CommunicationType::ErrorNotFound)).await;
return;
}
let Some(chat_id) = data_string(&cv, DataType::ChatId) else {
self.send_message(&error_response(&cv, CommunicationType::ErrorInvalidData)).await;
return;
};
match e2ee_storage::get_encrypted_device_secret(EncryptedDeviceSecretQuery {
match e2ee_storage::get_chat_secret(ChatSecretQuery {
user_id,
device_id: data_string(&cv, DataType::DeviceId),
chat_id,
secret_id: data_string(&cv, DataType::SecretId),
}) {
Ok(Some(record)) => {
let mut response = CommunicationValue::new(CommunicationType::EncryptedDeviceSecretResponse)
let response = CommunicationValue::new(CommunicationType::ChatSecretResponse)
.with_id(cv.get_id())
.with_receiver(cv.get_sender())
.add_typed_default(DataType::UserId, DataValue::Str(record.user_id))
.add_typed_default(DataType::DeviceId, DataValue::Str(record.device_id))
.add_typed_default(DataType::ChatId, DataValue::Str(record.chat_id))
.add_typed_default(DataType::SecretId, DataValue::Str(record.secret_id))
.add_typed_default(DataType::VersionNumber, DataValue::SignedNumber(record.version as i128))
.add_typed_default(DataType::EncryptedSecret, DataValue::Bytes(record.encrypted_secret))
.add_typed_default(DataType::KemCiphertext, DataValue::Bytes(record.kem_ciphertext))
.add_typed_default(DataType::WrappingScheme, DataValue::Str(record.wrapping_scheme))
.add_typed_default(DataType::CreatedAt, DataValue::SignedNumber(record.created_at as i128))
.add_typed_default(DataType::UpdatedAt, DataValue::SignedNumber(record.updated_at as i128));
if let Some(value) = record.wrapping_public_key_id {
response = response.add_typed_default(DataType::WrappingPublicKeyId, DataValue::Str(value));
}
self.send_message(&response).await;
}
Ok(None) => {
@ -263,106 +261,16 @@ impl ClientConnection {
return;
}
if cv.is_type(CommunicationType::EncryptedMessage) {
if cv.is_type(CommunicationType::ChatSecretForward) {
let sender_id = cv.get_sender().to_string();
if data_string(&cv, DataType::SenderUserId).as_deref() != Some(sender_id.as_str()) {
let recipient_id = data_string(&cv, DataType::RecipientUserId).unwrap_or_default();
if data_string(&cv, DataType::SenderUserId).as_deref() != Some(sender_id.as_str())
|| recipient_id.is_empty()
{
self.send_message(&error_response(&cv, CommunicationType::ErrorInvalidData)).await;
return;
}
let record = data_string(&cv, DataType::MessageId)
.zip(data_string(&cv, DataType::ConversationId))
.zip(data_string(&cv, DataType::SenderClientId))
.zip(data_string(&cv, DataType::RecipientClientId))
.zip(data_bytes(&cv, DataType::EncryptedPayload))
.map(|((((message_id, conversation_id), sender_client_id), recipient_client_id), encrypted_payload)| {
StoredEncryptedMessage {
message_id,
conversation_id,
sender_client_id,
recipient_client_id,
sender_user_id: data_string(&cv, DataType::SenderUserId),
recipient_user_id: data_string(&cv, DataType::RecipientUserId),
created_at: data_i64(&cv, DataType::CreatedAt).unwrap_or_else(now_millis_i64),
encryption_version: data_i64(&cv, DataType::EncryptionVersion).unwrap_or(1),
encrypted_payload,
}
});
if let Some(record) = record {
let message_id = record.message_id.clone();
let conversation_id = record.conversation_id.clone();
let recipient_client_id = record.recipient_client_id.clone();
match e2ee_storage::put_encrypted_message(record) {
Ok(()) => {
self.send_message(&CommunicationValue::new(CommunicationType::EncryptedMessageAck)
.with_id(cv.get_id())
.with_receiver(cv.get_sender())
.add_typed_default(DataType::MessageId, DataValue::Str(message_id))
.add_typed_default(DataType::ConversationId, DataValue::Str(conversation_id))
.add_typed_default(DataType::RecipientClientId, DataValue::Str(recipient_client_id))
.add_typed_default(DataType::GetTime, DataValue::SignedNumber(now_millis_i64() as i128))
).await;
}
Err(_) => {
self.send_message(&error_response(&cv, CommunicationType::ErrorInvalidData)).await;
}
}
} else {
self.send_message(&error_response(&cv, CommunicationType::ErrorInvalidData)).await;
}
return;
}
if cv.is_type(CommunicationType::EncryptedMessagesGet) {
let requester_user_id = cv.get_sender().to_string();
let limit = data_i64(&cv, DataType::Limit).map(|v| v as i64);
let since = data_i64(&cv, DataType::Since);
let conversation_id = data_string(&cv, DataType::ConversationId);
let peer_client_id = data_string(&cv, DataType::PeerClientId);
match e2ee_storage::get_encrypted_messages(EncryptedMessageQuery {
sender_user_id: data_string(&cv, DataType::SenderUserId),
recipient_client_id: None,
recipient_user_id: Some(requester_user_id.clone()),
conversation_id,
limit,
offset: since.map(|v| v.max(0)),
}) {
Ok(records) => {
let messages = records
.into_iter()
.filter(|record| {
peer_client_id
.as_ref()
.map(|peer| &record.sender_client_id == peer || &record.recipient_client_id == peer)
.unwrap_or(true)
})
.map(|record| {
typed_container(vec![
(DataType::MessageId, DataValue::Str(record.message_id)),
(DataType::ConversationId, DataValue::Str(record.conversation_id)),
(DataType::SenderClientId, DataValue::Str(record.sender_client_id)),
(DataType::RecipientClientId, DataValue::Str(record.recipient_client_id)),
(DataType::SenderUserId, DataValue::Str(record.sender_user_id.unwrap_or_default())),
(DataType::RecipientUserId, DataValue::Str(record.recipient_user_id.unwrap_or_default())),
(DataType::CreatedAt, DataValue::SignedNumber(record.created_at as i128)),
(DataType::EncryptionVersion, DataValue::SignedNumber(record.encryption_version as i128)),
(DataType::EncryptedPayload, DataValue::Bytes(record.encrypted_payload)),
])
})
.collect::<Vec<_>>();
self.send_message(&CommunicationValue::new(CommunicationType::EncryptedMessagesResponse)
.with_id(cv.get_id())
.with_receiver(cv.get_sender())
.add_typed_default(DataType::Messages, DataValue::Array(messages))
.add_typed_default(DataType::HasMore, DataValue::Bool(false))
).await;
}
Err(_) => {
self.send_message(&error_response(&cv, CommunicationType::ErrorInvalidData)).await;
}
}
self.send_message(&cv.with_receiver(recipient_id.parse::<u64>().unwrap_or(0))).await;
return;
}