Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(backup): support export and import of backups on Web, iOS and Android [WPB-10575] #3228

Open
wants to merge 8 commits into
base: epic/multiplatform-backup
Choose a base branch
from

Conversation

vitorhugods
Copy link
Member

@vitorhugods vitorhugods commented Jan 14, 2025

StoryWPB-10575 Cross Platform Backup: Write common backup / restore library


PR Submission Checklist for internal contributors

  • The PR Title

    • conforms to the style of semantic commits messages¹ supported in Wire's Github Workflow²
    • contains a reference JIRA issue number like SQPIT-764
    • answers the question: If merged, this PR will: ... ³
  • The PR Description

    • is free of optional paragraphs and you have filled the relevant parts to the best of your ability

What's new in this PR?

Issues

While creating a unified Backup format for iOS, Web and Android, we realised that encryption and compression logic must also be unified.
So, this PR aims to bring the whole solution together:

  • Export app data / serialise
  • Compress
  • Encrypt the file
  • Decrypt
  • Decompress
  • Import app data / de-serialise

The whole flow is joined together here.

Solutions

Whilst encryption/decryption and serialisation/deserialisation were already implemented, some changes had to be done in these parts to join the whole flow together. However, the logic implemented in previous PRs stay the same.

Pagination

One small change to the current logic is that backup data is now paginated.
As the application exports data, multiple files (pages) are created and memory is released.
Except on Web, where the pages are created but they stay always in memory.

During importing, the process is reversed, and the application can read one file at a time.

Compression

There is no multiplatform zip library for Kotlin
So I had to come up with some solution to bridge this gap.

JS / Web / Browser

The current Web client is using JSZip for zipping/unzipping files. It was possible to embed this solution within the library as well using the NPM dependency and some glue / Kotlin bindings + magic to solve dynamic types.

iOS

I wasn't able to add compression directly to the library. Our current Kotlin version has some bugs when generating Kotlin bindings for objc and therefore I couldn't use ZipArchive to implement it.
My solution is to just delegate this responsibility to the consumer.
iOS app will need to provide a zipper and unzipper in order to use the library.

Android

For the sake of reducing code, I left it exactly like iOS. So kalium:logic will need to provide a zipper and unzipper as well.

Next Steps

More fields

We need to add more fields to the messages, users, conversations, etc. in order to make sure it all works.

File Peeking

I'm raising a smaller PR after this one that will provide "file peeking" capabilities.
This is: read the header of a backup archive and be able to say if self user created it, and if it is encrypted or not.

This way the clients can ask for a password if needed, and abort the importing if self user isn't the one that created the backup.

Polishing

There are some possible improvements in terms of performance, and API will probably change a bit as we gather feedback from clients.

Publishing

The goal is to publish a npm library for web, and a spm (?) artifact for iOS

Testing

For testing code that uses compression, it was straight forward on JS: just use JSZip as normal.
But, for Android/iOS, because I left it as a responsibility of callers, I faked it completely.
Instead of actually zipping stuff, all the FakeZip does is:

  1. Generate a random ID, let's say "X"
  2. Copy all files to a folder called "X"
  3. Create a file and write "X" as its content

Then, when unzipping, the reverse process happens:

  1. Read the "zip" file, with the content = "X"
  2. Find the folder called "X", created during zipping.
  3. Return the path to that folder, as if it was unzipped just now 😆

Test Coverage

  • I have added automated test to this contribution

PR Post Merge Checklist for internal contributors

  • If any soft of configuration variable was introduced by this PR, it has been added to the relevant documents and the CI jobs have been updated.

References
  1. https://sparkbox.com/foundry/semantic_commit_messages
  2. https://github.com/wireapp/.github#usage
  3. E.g. feat(conversation-list): Sort conversations by most emojis in the title #SQPIT-764.

@echoes-hq echoes-hq bot added the echoes: product-roadmap/feature Work contributing to adding a new feature as part of the product roadmap. label Jan 14, 2025
Copy link
Contributor

github-actions bot commented Jan 14, 2025

Test Results

3 367 tests   3 260 ✅  5m 21s ⏱️
  574 suites    107 💤
  574 files        0 ❌

Results for commit 72cdd83.

♻️ This comment has been updated with latest results.

@datadog-wireapp
Copy link

datadog-wireapp bot commented Jan 14, 2025

Datadog Report

Branch report: backup/chore/export-a-new-backup-file
Commit report: 2695811
Test service: kalium-jvm

✅ 0 Failed, 3260 Passed, 107 Skipped, 36.59s Total Time

@codecov-commenter
Copy link

codecov-commenter commented Jan 14, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Please upload report for BASE (epic/multiplatform-backup@ff0f36f). Learn more about missing BASE report.

Additional details and impacted files
@@                     Coverage Diff                      @@
##             epic/multiplatform-backup    #3228   +/-   ##
============================================================
  Coverage                             ?   54.02%           
============================================================
  Files                                ?     1246           
  Lines                                ?    36152           
  Branches                             ?     3656           
============================================================
  Hits                                 ?    19532           
  Misses                               ?    15209           
  Partials                             ?     1411           

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ff0f36f...72cdd83. Read the comment docs.

private var persistedConversationsChunks = 0
private var persistedMessagesChunks = 0

private val backupInfo by lazy {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would having this as a lazy cause it to always have the same time if i create 2 backups after each other
not sure why this have to be from here instead of passing those info to the create backup function

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't really considering the possibility that the same instance of MPBackupExporter could be used for multiple backups.

I was thinking of saying bye bye to it after using it, no reason to keep it around and reuse it.

Comment on lines +22 to +25
internal suspend fun initializeLibSodiumIfNeeded() {
if (!LibsodiumInitializer.isInitialized()) {
LibsodiumInitializer.initialize()
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this function be thread safe or it will never not be called multiple times

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
echoes: product-roadmap/feature Work contributing to adding a new feature as part of the product roadmap. 👕 size: XXL type: feature ✨
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants