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 000000000..f72f4135e --- /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 4b3bbb61c..88cc10e23 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 1fb9410a3..9a222c5cf 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 5c9a3490d..a6948afd3 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 212f21047..594ff2de6 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 8a4a03fc4..80d411a36 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 456d37b59..4269825df 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 cae46785d..f931d0ece 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 a08866ed9..b9bdee49d 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 80469612d..f065e79d8 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 a09cc6479..dc6771e6b 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 de520f85d..faf416d2d 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());