From dbc2873e82dd56e13025f73281769fff323d32aa Mon Sep 17 00:00:00 2001 From: Lucas Fernandes Nogueira Date: Sun, 27 Mar 2022 16:48:57 -0700 Subject: [PATCH] feat(updater): improve validation and error messages, closes #3761 (#3780) --- .changes/improve-updater-validation.md | 5 + core/tauri/src/updater/core.rs | 372 +++++++++++++++++++------ core/tauri/src/updater/error.rs | 22 +- 3 files changed, 310 insertions(+), 89 deletions(-) create mode 100644 .changes/improve-updater-validation.md diff --git a/.changes/improve-updater-validation.md b/.changes/improve-updater-validation.md new file mode 100644 index 000000000..64c383de7 --- /dev/null +++ b/.changes/improve-updater-validation.md @@ -0,0 +1,5 @@ +--- +"tauri": patch +--- + +Improved the updater response validation and error messages. diff --git a/core/tauri/src/updater/core.rs b/core/tauri/src/updater/core.rs index faf0dd1ab..275ab2abf 100644 --- a/core/tauri/src/updater/core.rs +++ b/core/tauri/src/updater/core.rs @@ -51,7 +51,7 @@ pub struct RemoteRelease { /// Update short description pub body: Option, /// Optional signature for the current platform - pub signature: Option, + pub signature: String, #[cfg(target_os = "windows")] /// Optional: Windows only try to use elevated task pub with_elevated_task: bool, @@ -65,42 +65,47 @@ impl RemoteRelease { let version = match release.get("version") { Some(version) => version .as_str() - .ok_or_else(|| { - Error::RemoteMetadata("Unable to extract `version` from remote server".into()) - })? - .trim_start_matches('v') - .to_string(), - None => release - .get("name") - .ok_or_else(|| Error::RemoteMetadata("Release missing `name` and `version`".into()))? - .as_str() - .ok_or_else(|| { - Error::RemoteMetadata("Unable to extract `name` from remote server`".into()) - })? + .ok_or_else(|| Error::InvalidResponseType("version", "string", version.clone()))? .trim_start_matches('v') .to_string(), + None => { + let name = release + .get("name") + .ok_or(Error::MissingResponseField("version or name"))?; + name + .as_str() + .ok_or_else(|| Error::InvalidResponseType("name", "string", name.clone()))? + .trim_start_matches('v') + .to_string() + } }; // pub_date is required default is: `N/A` if not provided by the remote JSON - let date = release - .get("pub_date") - .and_then(|v| v.as_str()) - .unwrap_or("N/A") - .to_string(); + let date = if let Some(date) = release.get("pub_date") { + date + .as_str() + .map(|d| d.to_string()) + .ok_or_else(|| Error::InvalidResponseType("pub_date", "string", date.clone()))? + } else { + "N/A".into() + }; // body is optional to build our update - let body = release - .get("notes") - .map(|notes| notes.as_str().unwrap_or("").to_string()); - - // signature is optional to build our update - let mut signature = release - .get("signature") - .map(|signature| signature.as_str().unwrap_or("").to_string()); + let body = if let Some(notes) = release.get("notes") { + Some( + notes + .as_str() + .map(|n| n.to_string()) + .ok_or_else(|| Error::InvalidResponseType("notes", "string", notes.clone()))?, + ) + } else { + None + }; let download_url; #[cfg(target_os = "windows")] let with_elevated_task; + let signature; match release.get("platforms") { // @@ -123,38 +128,53 @@ impl RemoteRelease { // use provided signature if available signature = current_target_data .get("signature") - .map(|found_signature| found_signature.as_str().unwrap_or("").to_string()); + .ok_or(Error::MissingResponseField("signature")) + .and_then(|signature| { + signature + .as_str() + .ok_or_else(|| Error::InvalidResponseType("signature", "string", signature.clone())) + })?; // Download URL is required - download_url = current_target_data + let url = current_target_data .get("url") - .ok_or_else(|| Error::RemoteMetadata("Release missing `url`".into()))? + .ok_or(Error::MissingResponseField("url"))?; + download_url = url .as_str() - .ok_or_else(|| { - Error::RemoteMetadata("Unable to extract `url` from remote server`".into()) - })? + .ok_or_else(|| Error::InvalidResponseType("url", "string", url.clone()))? .to_string(); #[cfg(target_os = "windows")] { with_elevated_task = current_target_data .get("with_elevated_task") - .and_then(|v| v.as_bool()) - .unwrap_or_default(); + .map(|v| { + v.as_bool().ok_or_else(|| { + Error::InvalidResponseType("with_elevated_task", "boolean", v.clone()) + }) + }) + .unwrap_or(Ok(false))?; } } else { // make sure we have an available platform from the static - return Err(Error::RemoteMetadata("Platform not available".into())); + return Err(Error::TargetNotFound(target.into())); } } // We don't have the `platforms` field announced, let's assume our // download URL is at the root of the JSON. None => { - download_url = release + signature = release + .get("signature") + .ok_or(Error::MissingResponseField("signature")) + .and_then(|signature| { + signature + .as_str() + .ok_or_else(|| Error::InvalidResponseType("signature", "string", signature.clone())) + })?; + let url = release .get("url") - .ok_or_else(|| Error::RemoteMetadata("Release missing `url`".into()))? + .ok_or(Error::MissingResponseField("url"))?; + download_url = url .as_str() - .ok_or_else(|| { - Error::RemoteMetadata("Unable to extract `url` from remote server`".into()) - })? + .ok_or_else(|| Error::InvalidResponseType("url", "string", url.clone()))? .to_string(); #[cfg(target_os = "windows")] { @@ -171,7 +191,7 @@ impl RemoteRelease { date, download_url, body, - signature, + signature: signature.to_string(), #[cfg(target_os = "windows")] with_elevated_task, }) @@ -356,13 +376,11 @@ impl<'a, R: Runtime> UpdateBuilder<'a, R> { // Last error is cleaned on success -- shouldn't be triggered if // we have a successful call if let Some(error) = last_error { - return Err(Error::Network(error.to_string())); + return Err(error); } // Extracted remote metadata - let final_release = remote_release.ok_or_else(|| { - Error::RemoteMetadata("Unable to extract update metadata from the remote server.".into()) - })?; + let final_release = remote_release.ok_or(Error::ReleaseNotFound)?; // did the announced version is greated than our current one? let should_update = @@ -412,7 +430,7 @@ pub struct Update { /// Download URL announced download_url: String, /// Signature announced - signature: Option, + signature: String, #[cfg(target_os = "windows")] /// Optional: Windows only try to use elevated task /// Default to false @@ -521,14 +539,7 @@ impl Update { // We need an announced signature by the server // if there is no signature, bail out. - if let Some(signature) = &self.signature { - // we make sure the archive is valid and signed with the private key linked with the publickey - verify_signature(&mut archive_buffer, signature, &pub_key)?; - } else { - // We have a public key inside our source file, but not announced by the server, - // we assume this update is NOT valid. - return Err(Error::MissingUpdaterSignature); - } + verify_signature(&mut archive_buffer, &self.signature, &pub_key)?; #[cfg(feature = "updater")] { @@ -816,7 +827,9 @@ pub fn extract_path_from_executable(env: &Env, executable_path: &Path) -> PathBu // Convert base64 to string and prevent failing fn base64_to_string(base64_string: &str) -> Result { let decoded_string = &decode(base64_string)?; - let result = from_utf8(decoded_string)?.to_string(); + let result = from_utf8(decoded_string) + .map_err(|_| Error::SignatureUtf8(base64_string.into()))? + .to_string(); Ok(result) } @@ -868,19 +881,19 @@ mod test { "platforms": { "darwin-aarch64": { "signature": "dW50cnVzdGVkIGNvbW1lbnQ6IHNpZ25hdHVyZSBmcm9tIHRhdXJpIHNlY3JldCBrZXkKUldUTE5QWWxkQnlZOVJZVGdpKzJmRWZ0SkRvWS9TdFpqTU9xcm1mUmJSSG5OWVlwSklrWkN1SFpWbmh4SDlBcTU3SXpjbm0xMmRjRkphbkpVeGhGcTdrdzlrWGpGVWZQSWdzPQp0cnVzdGVkIGNvbW1lbnQ6IHRpbWVzdGFtcDoxNTkyOTE1MDU3CWZpbGU6L1VzZXJzL3J1bm5lci9ydW5uZXJzLzIuMjYzLjAvd29yay90YXVyaS90YXVyaS90YXVyaS9leGFtcGxlcy9jb21tdW5pY2F0aW9uL3NyYy10YXVyaS90YXJnZXQvZGVidWcvYnVuZGxlL29zeC9hcHAuYXBwLnRhci5negp4ZHFlUkJTVnpGUXdDdEhydTE5TGgvRlVPeVhjTnM5RHdmaGx3c0ZPWjZXWnFwVDRNWEFSbUJTZ1ZkU1IwckJGdmlwSzJPd00zZEZFN2hJOFUvL1FDZz09Cg==", - "url": "https://github.com/lemarier/tauri-test/releases/download/v1.0.0/app.app.tar.gz" + "url": "https://github.com/tauri-apps/updater-test/releases/download/v1.0.0/app.app.tar.gz" }, "darwin-x86_64": { "signature": "dW50cnVzdGVkIGNvbW1lbnQ6IHNpZ25hdHVyZSBmcm9tIHRhdXJpIHNlY3JldCBrZXkKUldUTE5QWWxkQnlZOVJZVGdpKzJmRWZ0SkRvWS9TdFpqTU9xcm1mUmJSSG5OWVlwSklrWkN1SFpWbmh4SDlBcTU3SXpjbm0xMmRjRkphbkpVeGhGcTdrdzlrWGpGVWZQSWdzPQp0cnVzdGVkIGNvbW1lbnQ6IHRpbWVzdGFtcDoxNTkyOTE1MDU3CWZpbGU6L1VzZXJzL3J1bm5lci9ydW5uZXJzLzIuMjYzLjAvd29yay90YXVyaS90YXVyaS90YXVyaS9leGFtcGxlcy9jb21tdW5pY2F0aW9uL3NyYy10YXVyaS90YXJnZXQvZGVidWcvYnVuZGxlL29zeC9hcHAuYXBwLnRhci5negp4ZHFlUkJTVnpGUXdDdEhydTE5TGgvRlVPeVhjTnM5RHdmaGx3c0ZPWjZXWnFwVDRNWEFSbUJTZ1ZkU1IwckJGdmlwSzJPd00zZEZFN2hJOFUvL1FDZz09Cg==", - "url": "https://github.com/lemarier/tauri-test/releases/download/v1.0.0/app.app.tar.gz" + "url": "https://github.com/tauri-apps/updater-test/releases/download/v1.0.0/app.app.tar.gz" }, "linux-x86_64": { "signature": "dW50cnVzdGVkIGNvbW1lbnQ6IHNpZ25hdHVyZSBmcm9tIHRhdXJpIHNlY3JldCBrZXkKUldUTE5QWWxkQnlZOWZSM29hTFNmUEdXMHRoOC81WDFFVVFRaXdWOUdXUUdwT0NlMldqdXkyaWVieXpoUmdZeXBJaXRqSm1YVmczNXdRL1Brc0tHb1NOTzhrL1hadFcxdmdnPQp0cnVzdGVkIGNvbW1lbnQ6IHRpbWVzdGFtcDoxNTkyOTE3MzQzCWZpbGU6L2hvbWUvcnVubmVyL3dvcmsvdGF1cmkvdGF1cmkvdGF1cmkvZXhhbXBsZXMvY29tbXVuaWNhdGlvbi9zcmMtdGF1cmkvdGFyZ2V0L2RlYnVnL2J1bmRsZS9hcHBpbWFnZS9hcHAuQXBwSW1hZ2UudGFyLmd6CmRUTUM2bWxnbEtTbUhOZGtERUtaZnpUMG5qbVo5TGhtZWE1SFNWMk5OOENaVEZHcnAvVW0zc1A2ajJEbWZUbU0yalRHT0FYYjJNVTVHOHdTQlYwQkF3PT0K", - "url": "https://github.com/lemarier/tauri-test/releases/download/v1.0.0/app.AppImage.tar.gz" + "url": "https://github.com/tauri-apps/updater-test/releases/download/v1.0.0/app.AppImage.tar.gz" }, "windows-x86_64": { "signature": "dW50cnVzdGVkIGNvbW1lbnQ6IHNpZ25hdHVyZSBmcm9tIHRhdXJpIHNlY3JldCBrZXkKUldUTE5QWWxkQnlZOVJHMWlvTzRUSlQzTHJOMm5waWpic0p0VVI2R0hUNGxhQVMxdzBPRndlbGpXQXJJakpTN0toRURtVzBkcm15R0VaNTJuS1lZRWdzMzZsWlNKUVAzZGdJPQp0cnVzdGVkIGNvbW1lbnQ6IHRpbWVzdGFtcDoxNTkyOTE1NTIzCWZpbGU6RDpcYVx0YXVyaVx0YXVyaVx0YXVyaVxleGFtcGxlc1xjb21tdW5pY2F0aW9uXHNyYy10YXVyaVx0YXJnZXRcZGVidWdcYXBwLng2NC5tc2kuemlwCitXa1lQc3A2MCs1KzEwZnVhOGxyZ2dGMlZqbjBaVUplWEltYUdyZ255eUF6eVF1dldWZzFObStaVEQ3QU1RS1lzcjhDVU4wWFovQ1p1QjJXbW1YZUJ3PT0K", - "url": "https://github.com/lemarier/tauri-test/releases/download/v1.0.0/app.x64.msi.zip" + "url": "https://github.com/tauri-apps/updater-test/releases/download/v1.0.0/app.x64.msi.zip" } } }"#.into() @@ -926,15 +939,6 @@ mod test { ) } - fn generate_sample_bad_json() -> String { - r#"{ - "version": "v0.0.3", - "notes": "Blablaa", - "date": "2020-02-20T15:41:00Z", - "download_link": "https://github.com/lemarier/tauri-test/releases/download/v0.0.1/update3.tar.gz" - }"#.into() - } - #[test] fn simple_http_updater() { let _m = mockito::mock("GET", "/") @@ -992,10 +996,10 @@ mod test { assert!(updater.should_update); assert_eq!(updater.version, "2.0.0"); - assert_eq!(updater.signature, Some("dW50cnVzdGVkIGNvbW1lbnQ6IHNpZ25hdHVyZSBmcm9tIHRhdXJpIHNlY3JldCBrZXkKUldUTE5QWWxkQnlZOVJHMWlvTzRUSlQzTHJOMm5waWpic0p0VVI2R0hUNGxhQVMxdzBPRndlbGpXQXJJakpTN0toRURtVzBkcm15R0VaNTJuS1lZRWdzMzZsWlNKUVAzZGdJPQp0cnVzdGVkIGNvbW1lbnQ6IHRpbWVzdGFtcDoxNTkyOTE1NTIzCWZpbGU6RDpcYVx0YXVyaVx0YXVyaVx0YXVyaVxleGFtcGxlc1xjb21tdW5pY2F0aW9uXHNyYy10YXVyaVx0YXJnZXRcZGVidWdcYXBwLng2NC5tc2kuemlwCitXa1lQc3A2MCs1KzEwZnVhOGxyZ2dGMlZqbjBaVUplWEltYUdyZ255eUF6eVF1dldWZzFObStaVEQ3QU1RS1lzcjhDVU4wWFovQ1p1QjJXbW1YZUJ3PT0K".into())); + assert_eq!(updater.signature, "dW50cnVzdGVkIGNvbW1lbnQ6IHNpZ25hdHVyZSBmcm9tIHRhdXJpIHNlY3JldCBrZXkKUldUTE5QWWxkQnlZOVJHMWlvTzRUSlQzTHJOMm5waWpic0p0VVI2R0hUNGxhQVMxdzBPRndlbGpXQXJJakpTN0toRURtVzBkcm15R0VaNTJuS1lZRWdzMzZsWlNKUVAzZGdJPQp0cnVzdGVkIGNvbW1lbnQ6IHRpbWVzdGFtcDoxNTkyOTE1NTIzCWZpbGU6RDpcYVx0YXVyaVx0YXVyaVx0YXVyaVxleGFtcGxlc1xjb21tdW5pY2F0aW9uXHNyYy10YXVyaVx0YXJnZXRcZGVidWdcYXBwLng2NC5tc2kuemlwCitXa1lQc3A2MCs1KzEwZnVhOGxyZ2dGMlZqbjBaVUplWEltYUdyZ255eUF6eVF1dldWZzFObStaVEQ3QU1RS1lzcjhDVU4wWFovQ1p1QjJXbW1YZUJ3PT0K"); assert_eq!( updater.download_url, - "https://github.com/lemarier/tauri-test/releases/download/v1.0.0/app.x64.msi.zip" + "https://github.com/tauri-apps/updater-test/releases/download/v1.0.0/app.x64.msi.zip" ); } @@ -1181,21 +1185,227 @@ mod test { assert!(updater.should_update); } + #[test] + fn http_updater_invalid_remote_data() { + let invalid_signature = r#"{ + "version": "v0.0.3", + "notes": "Blablaa", + "pub_date": "2020-02-20T15:41:00Z", + "url": "https://github.com/tauri-apps/updater-test/releases/download/v0.0.1/update3.tar.gz", + "signature": true + }"#; + let invalid_version = r#"{ + "version": 5, + "notes": "Blablaa", + "pub_date": "2020-02-20T15:41:00Z", + "url": "https://github.com/tauri-apps/updater-test/releases/download/v0.0.1/update3.tar.gz", + "signature": "x" + }"#; + let invalid_name = r#"{ + "name": false, + "notes": "Blablaa", + "pub_date": "2020-02-20T15:41:00Z", + "url": "https://github.com/tauri-apps/updater-test/releases/download/v0.0.1/update3.tar.gz", + "signature": "x" + }"#; + let invalid_date = r#"{ + "version": "1.0.0", + "notes": "Blablaa", + "pub_date": 345645646, + "url": "https://github.com/tauri-apps/updater-test/releases/download/v0.0.1/update3.tar.gz", + "signature": "x" + }"#; + let invalid_notes = r#"{ + "version": "v0.0.3", + "notes": ["bla", "bla"], + "pub_date": "2020-02-20T15:41:00Z", + "url": "https://github.com/tauri-apps/updater-test/releases/download/v0.0.1/update3.tar.gz", + "signature": "x" + }"#; + let invalid_url = r#"{ + "version": "v0.0.3", + "notes": "Blablaa", + "pub_date": "2020-02-20T15:41:00Z", + "url": ["https://github.com/tauri-apps/updater-test/releases/download/v0.0.1/update3.tar.gz", "https://github.com/tauri-apps/updater-test/releases/download/v0.0.1/update3.tar.gz"], + "signature": "x" + }"#; + let invalid_platform_signature = r#"{ + "version": "v0.0.3", + "notes": "Blablaa", + "pub_date": "2020-02-20T15:41:00Z", + "platforms": { + "test-target": { + "url": "https://github.com/tauri-apps/updater-test/releases/download/v0.0.1/update3.tar.gz", + "signature": { + "test-target": "x" + } + } + } + }"#; + let invalid_platform_url = r#"{ + "version": "v0.0.3", + "notes": "Blablaa", + "pub_date": "2020-02-20T15:41:00Z", + "platforms": { + "test-target": { + "url": { + "first": "https://github.com/tauri-apps/updater-test/releases/download/v0.0.1/update3.tar.gz" + } + "signature": "x" + } + } + }"#; + + let test_cases = [ + ( + invalid_signature, + Box::new(|e| matches!(e, Error::InvalidResponseType("signature", "string", _))) + as Box bool>, + ), + ( + invalid_version, + Box::new(|e| matches!(e, Error::InvalidResponseType("version", "string", _))) + as Box bool>, + ), + ( + invalid_name, + Box::new(|e| matches!(e, Error::InvalidResponseType("name", "string", _))) + as Box bool>, + ), + ( + invalid_date, + Box::new(|e| matches!(e, Error::InvalidResponseType("pub_date", "string", _))) + as Box bool>, + ), + ( + invalid_notes, + Box::new(|e| matches!(e, Error::InvalidResponseType("notes", "string", _))) + as Box bool>, + ), + ( + invalid_url, + Box::new(|e| matches!(e, Error::InvalidResponseType("url", "string", _))) + as Box bool>, + ), + ( + invalid_platform_signature, + Box::new(|e| matches!(e, Error::InvalidResponseType("signature", "string", _))) + as Box bool>, + ), + ( + invalid_platform_url, + Box::new(|e| matches!(e, Error::InvalidResponseType("url", "string", _))) + as Box bool>, + ), + ]; + + for (response, validator) in test_cases { + let _m = mockito::mock("GET", "/") + .with_status(200) + .with_header("content-type", "application/json") + .with_body(response) + .create(); + + let app = crate::test::mock_app(); + let check_update = block!(builder(app.handle()) + .url(mockito::server_url()) + .current_version("0.0.1") + .target("test-target") + .build()); + if let Err(e) = check_update { + validator(e); + } else { + panic!("unexpected Ok response"); + } + } + } + #[test] fn http_updater_missing_remote_data() { - let _m = mockito::mock("GET", "/") - .with_status(200) - .with_header("content-type", "application/json") - .with_body(generate_sample_bad_json()) - .create(); + let missing_signature = r#"{ + "version": "v0.0.3", + "notes": "Blablaa", + "pub_date": "2020-02-20T15:41:00Z", + "url": "https://github.com/tauri-apps/updater-test/releases/download/v0.0.1/update3.tar.gz" + }"#; + let missing_version = r#"{ + "notes": "Blablaa", + "pub_date": "2020-02-20T15:41:00Z", + "url": "https://github.com/tauri-apps/updater-test/releases/download/v0.0.1/update3.tar.gz", + "signature": "x" + }"#; + let missing_url = r#"{ + "version": "v0.0.3", + "notes": "Blablaa", + "pub_date": "2020-02-20T15:41:00Z", + "signature": "x" + }"#; + let missing_target = r#"{ + "version": "v0.0.3", + "notes": "Blablaa", + "pub_date": "2020-02-20T15:41:00Z", + "platforms": { + "unknown-target": { + "url": "https://github.com/tauri-apps/updater-test/releases/download/v0.0.1/update3.tar.gz", + "signature": "x" + } + } + }"#; + let missing_platform_signature = r#"{ + "version": "v0.0.3", + "notes": "Blablaa", + "pub_date": "2020-02-20T15:41:00Z", + "platforms": { + "test-target": { + "url": "https://github.com/tauri-apps/updater-test/releases/download/v0.0.1/update3.tar.gz" + } + } + }"#; + let missing_platform_url = r#"{ + "version": "v0.0.3", + "notes": "Blablaa", + "pub_date": "2020-02-20T15:41:00Z", + "platforms": { + "test-target": { + "signature": "x" + } + } + }"#; - let app = crate::test::mock_app(); - let check_update = block!(builder(app.handle()) - .url(mockito::server_url()) - .current_version("0.0.1") - .build()); + let test_cases = [ + (missing_signature, Error::MissingResponseField("signature")), + ( + missing_version, + Error::MissingResponseField("version or name"), + ), + (missing_url, Error::MissingResponseField("url")), + (missing_target, Error::TargetNotFound("test-target".into())), + ( + missing_platform_signature, + Error::MissingResponseField("signature"), + ), + (missing_platform_url, Error::MissingResponseField("url")), + ]; - assert!(check_update.is_err()); + for (response, error) in test_cases { + let _m = mockito::mock("GET", "/") + .with_status(200) + .with_header("content-type", "application/json") + .with_body(response) + .create(); + + let app = crate::test::mock_app(); + let check_update = block!(builder(app.handle()) + .url(mockito::server_url()) + .current_version("0.0.1") + .target("test-target") + .build()); + if let Err(e) = check_update { + assert_eq!(e.to_string(), error.to_string()); + } else { + panic!("unexpected Ok response"); + } + } } // run complete process on mac only for now as we don't have diff --git a/core/tauri/src/updater/error.rs b/core/tauri/src/updater/error.rs index 320c407c8..46782c65a 100644 --- a/core/tauri/src/updater/error.rs +++ b/core/tauri/src/updater/error.rs @@ -24,17 +24,17 @@ pub enum Error { #[error("Signature decoding error: {0}")] Base64(#[from] base64::DecodeError), /// UTF8 Errors in signature. - #[error("Signature encoding error: {0}")] - Utf8(#[from] std::str::Utf8Error), + #[error("The signature {0} could not be decoded, please check if it is a valid base64 string. The signature must be the contents of the `.sig` file generated by the Tauri bundler, as a string.")] + SignatureUtf8(String), /// Tauri utils, mainly extract and file move. #[error("Tauri API error: {0}")] TauriApi(#[from] crate::api::Error), /// Network error. #[error("Network error: {0}")] Network(String), - /// Metadata (JSON) error. - #[error("Remote JSON error: {0}")] - RemoteMetadata(String), + /// Could not fetch a valid response from the server. + #[error("Could not fetch a valid release JSON from the remote")] + ReleaseNotFound, /// Error building updater. #[error("Unable to prepare the updater: {0}")] Builder(String), @@ -44,13 +44,19 @@ pub enum Error { /// Updater is not supported for current operating system or platform. #[error("Unsupported operating system or platform")] UnsupportedPlatform, - /// Public key found in `tauri.conf.json` but no signature announced remotely. - #[error("Signature not available, skipping update")] - MissingUpdaterSignature, + /// The platform was not found on the updater JSON response. + #[error("the platform `{0}` was not found on the response `platforms` object")] + TargetNotFound(String), /// Triggered when there is NO error and the two versions are equals. /// On client side, it's important to catch this error. #[error("No updates available")] UpToDate, + /// The server did not include the signature field. + #[error("the `{0}` field was not set on the updater response")] + MissingResponseField(&'static str), + /// The updater responded with an invalid signature type. + #[error("the updater response field `{0}` type is invalid, expected {1} but found {2}")] + InvalidResponseType(&'static str, &'static str, serde_json::Value), } pub type Result = std::result::Result;