From 40d340021c0eab65aa1713807f7564e0698a321e Mon Sep 17 00:00:00 2001 From: Lucas Fernandes Nogueira Date: Fri, 6 Oct 2023 14:33:49 -0300 Subject: [PATCH] fix(bundler): team ID is now required for notarytool via app password (#7972) --- .changes/notarytool-team-id-required.md | 5 +++ core/tauri-runtime-wry/src/global_shortcut.rs | 3 +- core/tauri-runtime-wry/src/lib.rs | 8 ++-- core/tauri/src/manager.rs | 2 +- core/tauri/src/window.rs | 2 +- examples/api/src-tauri/Cargo.lock | 2 +- tooling/bundler/src/bundle/common.rs | 10 ++--- tooling/bundler/src/bundle/macos/app.rs | 8 +++- tooling/bundler/src/bundle/macos/sign.rs | 37 +++++++++++-------- tooling/cli/ENVIRONMENT_VARIABLES.md | 4 +- tooling/cli/src/interface/rust/desktop.rs | 5 +-- tooling/cli/src/lib.rs | 10 ++--- 12 files changed, 54 insertions(+), 42 deletions(-) create mode 100644 .changes/notarytool-team-id-required.md diff --git a/.changes/notarytool-team-id-required.md b/.changes/notarytool-team-id-required.md new file mode 100644 index 000000000000..f72f4135e19a --- /dev/null +++ b/.changes/notarytool-team-id-required.md @@ -0,0 +1,5 @@ +--- +"tauri-bundler": patch:bug +--- + +The `APPLE_TEAM_ID` environment variable is now required for notarization authentication via Apple ID and app-specific password. diff --git a/core/tauri-runtime-wry/src/global_shortcut.rs b/core/tauri-runtime-wry/src/global_shortcut.rs index 4b3bbb61c559..88cc10e23d90 100644 --- a/core/tauri-runtime-wry/src/global_shortcut.rs +++ b/core/tauri-runtime-wry/src/global_shortcut.rs @@ -8,6 +8,7 @@ use std::{ collections::HashMap, error::Error as StdError, fmt, + rc::Rc, sync::{ mpsc::{channel, Sender}, Arc, Mutex, @@ -138,7 +139,7 @@ impl GlobalShortcutManager for GlobalShortcutManagerHandle { pub fn handle_global_shortcut_message( message: GlobalShortcutMessage, - global_shortcut_manager: &Arc>, + global_shortcut_manager: &Rc>, ) { match message { GlobalShortcutMessage::IsRegistered(accelerator, tx) => tx diff --git a/core/tauri-runtime-wry/src/lib.rs b/core/tauri-runtime-wry/src/lib.rs index 1fb9410a34e9..9a222c5cf691 100644 --- a/core/tauri-runtime-wry/src/lib.rs +++ b/core/tauri-runtime-wry/src/lib.rs @@ -249,7 +249,7 @@ pub struct DispatcherMainThreadContext { pub window_target: EventLoopWindowTarget>, pub web_context: WebContextStore, #[cfg(all(desktop, feature = "global-shortcut"))] - pub global_shortcut_manager: Arc>, + pub global_shortcut_manager: Rc>, #[cfg(feature = "clipboard")] pub clipboard_manager: Arc>, pub windows: Rc>>, @@ -1937,7 +1937,7 @@ impl Wry { let web_context = WebContextStore::default(); #[cfg(all(desktop, feature = "global-shortcut"))] - let global_shortcut_manager = Arc::new(Mutex::new(WryShortcutManager::new(&event_loop))); + let global_shortcut_manager = Rc::new(Mutex::new(WryShortcutManager::new(&event_loop))); #[cfg(feature = "clipboard")] let clipboard_manager = Arc::new(Mutex::new(Clipboard::new())); @@ -2307,7 +2307,7 @@ pub struct EventLoopIterationContext<'a, T: UserEvent> { pub webview_id_map: WebviewIdStore, pub windows: Rc>>, #[cfg(all(desktop, feature = "global-shortcut"))] - pub global_shortcut_manager: Arc>, + pub global_shortcut_manager: Rc>, #[cfg(all(desktop, feature = "global-shortcut"))] pub global_shortcut_manager_handle: &'a GlobalShortcutManagerHandle, #[cfg(feature = "clipboard")] @@ -2320,7 +2320,7 @@ struct UserMessageContext { windows: Rc>>, webview_id_map: WebviewIdStore, #[cfg(all(desktop, feature = "global-shortcut"))] - global_shortcut_manager: Arc>, + global_shortcut_manager: Rc>, #[cfg(feature = "clipboard")] clipboard_manager: Arc>, #[cfg(all(desktop, feature = "system-tray"))] diff --git a/core/tauri/src/manager.rs b/core/tauri/src/manager.rs index 5c9a3490d592..a6948afd31f4 100644 --- a/core/tauri/src/manager.rs +++ b/core/tauri/src/manager.rs @@ -192,7 +192,7 @@ fn replace_csp_nonce( .into_iter() .map(|n| format!("'nonce-{n}'")) .collect::>(); - let sources = csp.entry(directive.into()).or_insert_with(Default::default); + let sources = csp.entry(directive.into()).or_default(); let self_source = "'self'".to_string(); if !sources.contains(&self_source) { sources.push(self_source); diff --git a/core/tauri/src/window.rs b/core/tauri/src/window.rs index 212f21047ed8..594ff2de63d3 100644 --- a/core/tauri/src/window.rs +++ b/core/tauri/src/window.rs @@ -1630,7 +1630,7 @@ impl Window { window_label, event, }) - .or_insert_with(Default::default) + .or_default() .insert(id); } diff --git a/examples/api/src-tauri/Cargo.lock b/examples/api/src-tauri/Cargo.lock index 8a4a03fc4b70..80d411a36511 100644 --- a/examples/api/src-tauri/Cargo.lock +++ b/examples/api/src-tauri/Cargo.lock @@ -3529,7 +3529,7 @@ checksum = "fd1ba337640d60c3e96bc6f0638a939b9c9a7f2c316a1598c279828b3d1dc8c5" [[package]] name = "tauri" -version = "1.5.0" +version = "1.5.1" dependencies = [ "anyhow", "base64 0.21.2", diff --git a/tooling/bundler/src/bundle/common.rs b/tooling/bundler/src/bundle/common.rs index 456d37b59adb..4269825dfbcf 100644 --- a/tooling/bundler/src/bundle/common.rs +++ b/tooling/bundler/src/bundle/common.rs @@ -169,9 +169,8 @@ impl CommandExt for Command { let mut lines = stdout_lines_.lock().unwrap(); loop { buf.clear(); - match tauri_utils::io::read_line(&mut stdout, &mut buf) { - Ok(s) if s == 0 => break, - _ => (), + if let Ok(0) = tauri_utils::io::read_line(&mut stdout, &mut buf) { + break; } debug!(action = "stdout"; "{}", String::from_utf8_lossy(&buf)); lines.extend(buf.clone()); @@ -187,9 +186,8 @@ impl CommandExt for Command { let mut lines = stderr_lines_.lock().unwrap(); loop { buf.clear(); - match tauri_utils::io::read_line(&mut stderr, &mut buf) { - Ok(s) if s == 0 => break, - _ => (), + if let Ok(0) = tauri_utils::io::read_line(&mut stderr, &mut buf) { + break; } debug!(action = "stderr"; "{}", String::from_utf8_lossy(&buf)); lines.extend(buf.clone()); diff --git a/tooling/bundler/src/bundle/macos/app.rs b/tooling/bundler/src/bundle/macos/app.rs index cae46785d6be..f931d0ece885 100644 --- a/tooling/bundler/src/bundle/macos/app.rs +++ b/tooling/bundler/src/bundle/macos/app.rs @@ -25,7 +25,7 @@ use super::{ super::common::{self, CommandExt}, icon::create_icns_file, - sign::{notarize, notarize_auth, sign, SignTarget}, + sign::{notarize, notarize_auth, sign, NotarizeAuthError, SignTarget}, }; use crate::Settings; @@ -127,7 +127,11 @@ pub fn bundle_project(settings: &Settings) -> crate::Result> { notarize(app_bundle_path.clone(), auth, settings)?; } Err(e) => { - warn!("skipping app notarization, {}", e.to_string()); + if matches!(e, NotarizeAuthError::MissingTeamId) { + return Err(anyhow::anyhow!("{e}").into()); + } else { + warn!("skipping app notarization, {}", e.to_string()); + } } } } diff --git a/tooling/bundler/src/bundle/macos/sign.rs b/tooling/bundler/src/bundle/macos/sign.rs index a08866ed94e8..b9bdee49d8c2 100644 --- a/tooling/bundler/src/bundle/macos/sign.rs +++ b/tooling/bundler/src/bundle/macos/sign.rs @@ -336,7 +336,7 @@ pub enum NotarizeAuth { AppleId { apple_id: OsString, password: OsString, - team_id: Option, + team_id: OsString, }, ApiKey { key: OsString, @@ -356,17 +356,13 @@ impl NotarytoolCmdExt for Command { apple_id, password, team_id, - } => { - self - .arg("--apple-id") - .arg(apple_id) - .arg("--password") - .arg(password); - if let Some(team_id) = team_id { - self.arg("--team-id").arg(team_id); - } - self - } + } => self + .arg("--apple-id") + .arg(apple_id) + .arg("--password") + .arg(password) + .arg("--team-id") + .arg(team_id), NotarizeAuth::ApiKey { key, key_path, @@ -382,17 +378,28 @@ impl NotarytoolCmdExt for Command { } } -pub fn notarize_auth() -> crate::Result { +#[derive(Debug, thiserror::Error)] +pub enum NotarizeAuthError { + #[error( + "The team ID is now required for notarization with app-specific password as authentication. Please set the `APPLE_TEAM_ID` environment variable. You can find the team ID in https://developer.apple.com/account#MembershipDetailsCard." + )] + MissingTeamId, + #[error(transparent)] + Anyhow(#[from] anyhow::Error), +} + +pub fn notarize_auth() -> Result { match ( var_os("APPLE_ID"), var_os("APPLE_PASSWORD"), var_os("APPLE_TEAM_ID"), ) { - (Some(apple_id), Some(password), team_id) => Ok(NotarizeAuth::AppleId { + (Some(apple_id), Some(password), Some(team_id)) => Ok(NotarizeAuth::AppleId { apple_id, password, team_id, }), + (Some(_apple_id), Some(_password), None) => Err(NotarizeAuthError::MissingTeamId), _ => { match (var_os("APPLE_API_KEY"), var_os("APPLE_API_ISSUER"), var("APPLE_API_KEY_PATH")) { (Some(key), Some(issuer), Ok(key_path)) => { @@ -424,7 +431,7 @@ pub fn notarize_auth() -> crate::Result { Err(anyhow::anyhow!("could not find API key file. Please set the APPLE_API_KEY_PATH environment variables to the path to the {api_key_file_name:?} file").into()) } } - _ => Err(anyhow::anyhow!("no APPLE_ID & APPLE_PASSWORD or APPLE_API_KEY & APPLE_API_ISSUER & APPLE_API_KEY_PATH environment variables found").into()) + _ => Err(anyhow::anyhow!("no APPLE_ID & APPLE_PASSWORD & APPLE_TEAM_ID or APPLE_API_KEY & APPLE_API_ISSUER & APPLE_API_KEY_PATH environment variables found").into()) } } } diff --git a/tooling/cli/ENVIRONMENT_VARIABLES.md b/tooling/cli/ENVIRONMENT_VARIABLES.md index 80469612dfb1..f065e79d8536 100644 --- a/tooling/cli/ENVIRONMENT_VARIABLES.md +++ b/tooling/cli/ENVIRONMENT_VARIABLES.md @@ -23,9 +23,9 @@ These environment variables are inputs to the CLI which may have an equivalent C - `TAURI_KEY_PASSWORD` — The private key password, see `TAURI_PRIVATE_KEY` - `APPLE_CERTIFICATE` — Base64 encoded of the `.p12` certificate for code signing. To get this value, run `openssl base64 -in MyCertificate.p12 -out MyCertificate-base64.txt`. - `APPLE_CERTIFICATE_PASSWORD` — The password you used to export the certificate. -- `APPLE_ID` — The Apple ID used to notarize the application. If this environment variable is provided, `APPLE_PASSWORD` must also be set. Alternatively, `APPLE_API_KEY` and `APPLE_API_ISSUER` can be used to authenticate. +- `APPLE_ID` — The Apple ID used to notarize the application. If this environment variable is provided, `APPLE_PASSWORD` and `APPLE_TEAM_ID` must also be set. Alternatively, `APPLE_API_KEY` and `APPLE_API_ISSUER` can be used to authenticate. - `APPLE_PASSWORD` — The Apple password used to authenticate for application notarization. Required if `APPLE_ID` is specified. An app-specific password can be used. Alternatively to entering the password in plaintext, it may also be specified using a '@keychain:' or '@env:' prefix followed by a keychain password item name or environment variable name. -- `APPLE_TEAM_ID`: Developer team ID. If your Apple ID only belongs to one team then you don’t need to supply a Team ID. However, it’s best practice to include it regardless. That way, joining another team at some point in the future won’t break your notarization workflow. To find your Team ID, go to the [Account](https://developer.apple.com/account) page on the Apple Developer website. +- `APPLE_TEAM_ID`: Developer team ID. To find your Team ID, go to the [Account](https://developer.apple.com/account) page on the Apple Developer website, and check your membership details. - `APPLE_API_KEY` — Alternative to `APPLE_ID` and `APPLE_PASSWORD` for notarization authentication using JWT. - See [creating API keys](https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api) for more information. - `APPLE_API_ISSUER` — Issuer ID. Required if `APPLE_API_KEY` is specified. diff --git a/tooling/cli/src/interface/rust/desktop.rs b/tooling/cli/src/interface/rust/desktop.rs index a09cc6479f2c..dc6771e6b040 100644 --- a/tooling/cli/src/interface/rust/desktop.rs +++ b/tooling/cli/src/interface/rust/desktop.rs @@ -203,9 +203,8 @@ fn build_dev_app( let mut io_stderr = std::io::stderr(); loop { buf.clear(); - match tauri_utils::io::read_line(&mut stderr, &mut buf) { - Ok(s) if s == 0 => break, - _ => (), + if let Ok(0) = tauri_utils::io::read_line(&mut stderr, &mut buf) { + break; } let _ = io_stderr.write_all(&buf); if !buf.ends_with(&[b'\r']) { diff --git a/tooling/cli/src/lib.rs b/tooling/cli/src/lib.rs index de520f85da25..faf416d2d5b4 100644 --- a/tooling/cli/src/lib.rs +++ b/tooling/cli/src/lib.rs @@ -230,9 +230,8 @@ impl CommandExt for Command { let mut lines = stdout_lines_.lock().unwrap(); loop { buf.clear(); - match tauri_utils::io::read_line(&mut stdout, &mut buf) { - Ok(s) if s == 0 => break, - _ => (), + if let Ok(0) = tauri_utils::io::read_line(&mut stdout, &mut buf) { + break; } debug!(action = "stdout"; "{}", String::from_utf8_lossy(&buf)); lines.extend(buf.clone()); @@ -248,9 +247,8 @@ impl CommandExt for Command { let mut lines = stderr_lines_.lock().unwrap(); loop { buf.clear(); - match tauri_utils::io::read_line(&mut stderr, &mut buf) { - Ok(s) if s == 0 => break, - _ => (), + if let Ok(0) = tauri_utils::io::read_line(&mut stderr, &mut buf) { + break; } debug!(action = "stderr"; "{}", String::from_utf8_lossy(&buf)); lines.extend(buf.clone());