Skip to content

Commit

Permalink
backup: make validation completion fallible
Browse files Browse the repository at this point in the history
  • Loading branch information
akonradi-signal authored Jun 7, 2024
1 parent 38a5f01 commit 53d60eb
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 11 deletions.
1 change: 1 addition & 0 deletions rust/bridge/shared/src/message_backup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ impl From<Error> for MessageBackupValidationError {
fn from(value: Error) -> Self {
match value {
Error::BackupValidation(e) => Self::String(e.to_string()),
Error::BackupCompletion(e) => Self::String(e.to_string()),
Error::Parse(ParseError::Io(e)) => Self::Io(e),
e @ Error::NoFrames
| e @ Error::InvalidProtobuf(_)
Expand Down
46 changes: 42 additions & 4 deletions rust/message-backup/src/backup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::fmt::Debug;
use derive_where::derive_where;
use libsignal_protocol::Aci;

use crate::backup::account_data::{AccountData, AccountDataError};
pub(crate) use crate::backup::account_data::{AccountData, AccountDataError};
use crate::backup::call::{AdHocCall, CallError};
use crate::backup::chat::{ChatData, ChatError, ChatItemError, PinOrder};
use crate::backup::frame::{ChatId, RecipientId};
Expand Down Expand Up @@ -38,6 +38,14 @@ pub struct PartialBackup<M: Method> {
sticker_packs: HashMap<StickerPackId, StickerPack<M>>,
}

pub struct CompletedBackup<M: Method> {
meta: BackupMeta,
account_data: M::Value<AccountData<M>>,
recipients: HashMap<RecipientId, RecipientData<M>>,
chats: ChatsData<M>,
sticker_packs: HashMap<StickerPackId, StickerPack<M>>,
}

#[derive_where(Default)]
struct ChatsData<M: Method> {
items: HashMap<ChatId, ChatData<M>>,
Expand All @@ -47,7 +55,7 @@ struct ChatsData<M: Method> {
#[derive(Debug)]
pub struct Backup {
pub meta: BackupMeta,
pub account_data: Option<AccountData<Store>>,
pub account_data: AccountData<Store>,
pub recipients: HashMap<RecipientId, RecipientData<Store>>,
pub chats: HashMap<ChatId, ChatData<Store>>,
pub sticker_packs: HashMap<StickerPackId, StickerPack<Store>>,
Expand Down Expand Up @@ -91,9 +99,39 @@ pub enum Purpose {
RemoteBackup = 1,
}

impl From<PartialBackup<Store>> for Backup {
fn from(value: PartialBackup<Store>) -> Self {
#[derive(Debug, displaydoc::Display, thiserror::Error)]
pub enum CompletionError {
/// no AccountData frames found
MissingAccountData,
}

impl<M: Method> TryFrom<PartialBackup<M>> for CompletedBackup<M> {
type Error = CompletionError;

fn try_from(value: PartialBackup<M>) -> Result<Self, Self::Error> {
let PartialBackup {
meta,
account_data,
recipients,
chats,
sticker_packs,
} = value;

let account_data = account_data.ok_or(CompletionError::MissingAccountData)?;

Ok(CompletedBackup {
meta,
account_data,
recipients,
chats,
sticker_packs,
})
}
}

impl From<CompletedBackup<Store>> for Backup {
fn from(value: CompletedBackup<Store>) -> Self {
let CompletedBackup {
meta,
account_data,
recipients,
Expand Down
20 changes: 13 additions & 7 deletions rust/message-backup/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ use futures::AsyncRead;
use mediasan_common::AsyncSkip;
use protobuf::Message as _;

use crate::backup::Purpose;
use crate::backup::method::ValidateOnly;
use crate::backup::{CompletedBackup, Purpose};
use crate::frame::{
HmacMismatchError, ReaderFactory, UnvalidatedHmacReader, VerifyHmac, VerifyHmacError,
};
Expand Down Expand Up @@ -42,6 +43,8 @@ pub enum Error {
/// {0}
BackupValidation(#[from] backup::ValidationError),
/// {0}
BackupCompletion(#[from] backup::CompletionError),
/// {0}
Parse(#[from] parse::ParseError),
/// no frames found
NoFrames,
Expand Down Expand Up @@ -81,27 +84,30 @@ impl std::fmt::Display for FoundUnknownField {
}

impl<R> ReadResult<R> {
fn map<T>(self, f: impl FnOnce(R) -> T) -> ReadResult<T> {
fn and_then<T>(self, f: impl FnOnce(R) -> Result<T, Error>) -> ReadResult<T> {
let Self {
result,
found_unknown_fields,
} = self;
ReadResult {
found_unknown_fields,
result: result.map(f),
result: result.and_then(f),
}
}
}

impl<R: AsyncRead + Unpin + VerifyHmac> BackupReader<R> {
pub async fn read_all(self) -> ReadResult<backup::Backup> {
self.collect_all().await.map(Into::into)
self.collect_all()
.await
.and_then(|r| Ok(CompletedBackup::try_from(r)?.into()))
}

pub async fn validate_all(self) -> ReadResult<()> {
self.collect_all()
.await
.map(|_: backup::PartialBackup<backup::method::ValidateOnly>| ())
self.collect_all().await.and_then(|partial| {
let _: CompletedBackup<ValidateOnly> = partial.try_into()?;
Ok(())
})
}

pub async fn collect_all<M: backup::method::Method>(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{
"version": "1",
"backupTimeMs": "1705692409729"
},
{
"recipient": {
"id": "1",
"self": {}
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
no AccountData frames found
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[
{
"version": "1",
"backupTimeMs": "1705692409729"
},
{
"recipient": {
"id": "1",
"self": {}
}
},
{
"account": {
"profileKey": "YQKRq+3DQklInaOaMcmlzZnN0m/1hzLiaONX7gB12dg=",
"accountSettings": {
"phoneNumberSharingMode": "NOBODY"
}
}
},
{
"account": {
"profileKey": "YQKRq+3DQklInaOaMcmlzZnN0m/1hzLiaONX7gB12dg=",
"accountSettings": {
"phoneNumberSharingMode": "NOBODY"
}
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
multiple AccountData frames found
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
"backupTimeMs": "1705692409729",
"version": "1"
},
{
"account": {
"profileKey": "YQKRq+3DQklInaOaMcmlzZnN0m/1hzLiaONX7gB12dg=",
"accountSettings": {
"phoneNumberSharingMode": "NOBODY"
}
}
},
{
"recipient": {
"id": "2",
Expand Down

0 comments on commit 53d60eb

Please sign in to comment.