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

WIP - Add installer downloader and in-app upgrades backend #7583

Draft
wants to merge 34 commits into
base: main
Choose a base branch
from

Conversation

dlon
Copy link
Member

@dlon dlon commented Feb 3, 2025

This PR aims to introduce a minimal installer as well as most of the functionality for in-app upgrades (except UI). This is still a work in progress.

The main things that are missing:

  • Obtain verified version info from the Mullvad API
  • Implement UI correctly/fully
  • Packaging/build scripts

The planned native module for the Electron frontend is not in scope for this PR.

Close DES-1685
Close DES-1684
Close DES-1641
Close DES-1640
Close DES-1571


This change is Reviewable

@dlon dlon requested a review from Serock3 February 3, 2025 14:41
@dlon dlon changed the title WIP - Installer downloader WIP - Add installer downloader and in-app upgrades backend Feb 3, 2025
@dlon dlon force-pushed the installer-downloader branch from 8bdac28 to bf3eeb4 Compare February 4, 2025 08:22
}

impl<SigProgress, AppProgress> HttpAppDownloader<SigProgress, AppProgress> {
const MAX_SIGNATURE_SIZE: usize = 1 * 1024;
Copy link
Contributor

Choose a reason for hiding this comment

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

1* causes a clippy warning

Comment on lines +21 to +22
println!("cargo:rerun-if-changed=loader.manifest");
//res.set_manifest_file("loader.manifest");
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there some manual process here where you need to update the loader.manifest file if it changes. Could that be documented?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, I've just commented it out for testing.

Copy link
Member Author

Choose a reason for hiding this comment

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

To clarify: I'm not sure whether we should elevate as the loader starts or just before installing. In the former case, we need this, since it triggers an elevation prompt.

mullvad-update/src/app.rs Outdated Show resolved Hide resolved
Comment on lines 60 to 52
signature_url: String,
app_url: String,
app_size: usize,
signature_progress_updater: SigProgress,
app_progress_updater: AppProgress,
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: Why flatten the parameters here? You could just have parameters: AppDownloaderParameters<SigProgress, AppProgress>.

Comment on lines +10 to +15
#[derive(Debug)]
pub enum DownloadError {
FetchSignature(anyhow::Error),
FetchApp(anyhow::Error),
Verification(anyhow::Error),
}
Copy link
Contributor

Choose a reason for hiding this comment

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

These error variants are never matched on, and the enum doesn't implement the Error trait, so is there really any point to it? Why not just use anyhow?

mullvad-update/src/fetch.rs Outdated Show resolved Hide resolved
Comment on lines 20 to 56
#[derive(Debug, Clone)]
pub struct Version {
/// Version
pub version: String,
/// URLs to use for downloading the app installer
pub urls: Vec<String>,
/// Size of installer, in bytes
pub size: usize,
/// URLs pointing to app PGP signatures
pub signature_urls: Vec<String>,
}

Copy link
Contributor

@Serock3 Serock3 Feb 4, 2025

Choose a reason for hiding this comment

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

This differs a bit from the specification if the REST format, which I assume is intentional since it isn't active yet and the format is not final.

Just to help me understand better, is there not supposed to be any information in this struct about e.g. architectures, changelogs and signature types, or is that something left for the future?

Copy link
Member Author

Choose a reason for hiding this comment

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

My intention was to keep this public type separate from the data that's deserialized from JSON. The output of this module is "version information that's guaranteed to have been signed by Mullvad, isn't expired, etc., for the current architeture", with all those details hidden.

But yes, it's also not complete.

Copy link
Contributor

@Serock3 Serock3 left a comment

Choose a reason for hiding this comment

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

I get this warning when running cargo check

warning: profiles for the non root package will be ignored, specify profiles at the workspace root:
package:   C:\Users\Sebastian\Documents\Programming\mullvad\installer-downloader\Cargo.toml
workspace: C:\Users\Sebastian\Documents\Programming\mullvad\Cargo.toml

Is the opt level specified in installer-downloader being overwritten by the workspace level?

mullvad-update/src/app.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@Serock3 Serock3 left a comment

Choose a reason for hiding this comment

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

I guess convert-assets.py is not supposed to be tracked in the repository, since we store the converted file, right?

@dlon
Copy link
Member Author

dlon commented Feb 6, 2025

I get this warning when running cargo check

warning: profiles for the non root package will be ignored, specify profiles at the workspace root:
package:   C:\Users\Sebastian\Documents\Programming\mullvad\installer-downloader\Cargo.toml
workspace: C:\Users\Sebastian\Documents\Programming\mullvad\Cargo.toml

Is the opt level specified in installer-downloader being overwritten by the workspace level?

It isn't being correctly applied. This is noted in the toml file. I think it'll be replaced by a build script.

add_file_server_mock(&mut server, "/my_file", file_data);

// Interrupt after exactly half the file has been downloaded
let mut limited_buffer = vec![0u8; file_data.len() / 2].into_boxed_slice();
Copy link
Contributor

Choose a reason for hiding this comment

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

.into_boxed_slice() and the following into_vec() aren't needed. The test compiles and passes when I remove them.

Copy link
Member Author

@dlon dlon Feb 6, 2025

Choose a reason for hiding this comment

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

Does it work without removing vec!? I was sure that it would automatically resize the buffer in that case. I'll try it, but somehow I trust it more knowing it's a fixed size.

Comment on lines +414 to +436
/// Create endpoints that serve a file at `url_path` using range requests
fn add_file_server_mock(server: &mut mockito::Server, url_path: &str, data: &'static [u8]) {
// Respond to head requests with file size
server
.mock("HEAD", url_path)
.with_header(CONTENT_LENGTH, &data.len().to_string())
.create();

// Respond to range requests with file
server
.mock("GET", url_path)
.with_body_from_request(|request| {
let range = request.header(RANGE);
let range = range[0].to_str().expect("expected str");
let (begin, end) = parse_http_range(range).expect("invalid range");

data[begin..=end].to_vec()
})
.create();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Cool mocking crate! Seems like something we could use more

Comment on lines +124 to +137
if active_download.is_some() {
continue;
}
let Some(version_info) = version_info.clone() else {
continue;
};

Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps we should log some warning here?

@dlon
Copy link
Member Author

dlon commented Feb 6, 2025

I guess convert-assets.py is not supposed to be tracked in the repository, since we store the converted file, right?

I think it should because it makes it easier to regenerate them if the SVGs are edited.

@dlon dlon force-pushed the installer-downloader branch from ec26088 to 15fb2cc Compare February 7, 2025 08:48
pub signed: Response,
}

/// Helper class that leaves the signed data untouched
Copy link
Contributor

Choose a reason for hiding this comment

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

:man-gesturing-no:

Suggested change
/// Helper class that leaves the signed data untouched
/// Helper type that leaves the signed data untouched

Comment on lines +14 to +17
/// Beta preface text
pub const BETA_PREFACE_DESC: &str = "Want to try the new Beta version? ";
/// Beta link text
pub const BETA_LINK_TEXT: &str = "Click here!";
Copy link
Contributor

Choose a reason for hiding this comment

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

Is the text really up to date with the design? Shouldn't it say "Want to try out new features? Try our new beta!"

impl AppWindow {
/// Set up UI elements, position them, and register window message handlers
/// Note that some additional setup happens in [Self::on_init]
pub fn layout(mut self) -> Result<Rc<RefCell<AppWindow>>, nwg::NwgError> {
Copy link
Contributor

Choose a reason for hiding this comment

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

The text is much larger than in the design for me

Copy link
Contributor

@Serock3 Serock3 left a comment

Choose a reason for hiding this comment

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

How is the installer supposed to handle rollouts? They should be based on the users accound number, right? How will the installer get ahold of it? If you haven't ever logged in, how do we handle that?

@dlon dlon force-pushed the installer-downloader branch from 11a15f8 to 180ea7d Compare February 7, 2025 16:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants