Browse Source

fix(bundler): team ID is now required for notarytool via app password (#7972)

Lucas Fernandes Nogueira 1 year ago
parent
commit
40d340021c

+ 5 - 0
.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.

+ 2 - 1
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<T: UserEvent> GlobalShortcutManager for GlobalShortcutManagerHandle<T> {
 
 pub fn handle_global_shortcut_message(
   message: GlobalShortcutMessage,
-  global_shortcut_manager: &Arc<Mutex<WryShortcutManager>>,
+  global_shortcut_manager: &Rc<Mutex<WryShortcutManager>>,
 ) {
   match message {
     GlobalShortcutMessage::IsRegistered(accelerator, tx) => tx

+ 4 - 4
core/tauri-runtime-wry/src/lib.rs

@@ -249,7 +249,7 @@ pub struct DispatcherMainThreadContext<T: UserEvent> {
   pub window_target: EventLoopWindowTarget<Message<T>>,
   pub web_context: WebContextStore,
   #[cfg(all(desktop, feature = "global-shortcut"))]
-  pub global_shortcut_manager: Arc<Mutex<WryShortcutManager>>,
+  pub global_shortcut_manager: Rc<Mutex<WryShortcutManager>>,
   #[cfg(feature = "clipboard")]
   pub clipboard_manager: Arc<Mutex<Clipboard>>,
   pub windows: Rc<RefCell<HashMap<WebviewId, WindowWrapper>>>,
@@ -1937,7 +1937,7 @@ impl<T: UserEvent> Wry<T> {
     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<RefCell<HashMap<WebviewId, WindowWrapper>>>,
   #[cfg(all(desktop, feature = "global-shortcut"))]
-  pub global_shortcut_manager: Arc<Mutex<WryShortcutManager>>,
+  pub global_shortcut_manager: Rc<Mutex<WryShortcutManager>>,
   #[cfg(all(desktop, feature = "global-shortcut"))]
   pub global_shortcut_manager_handle: &'a GlobalShortcutManagerHandle<T>,
   #[cfg(feature = "clipboard")]
@@ -2320,7 +2320,7 @@ struct UserMessageContext {
   windows: Rc<RefCell<HashMap<WebviewId, WindowWrapper>>>,
   webview_id_map: WebviewIdStore,
   #[cfg(all(desktop, feature = "global-shortcut"))]
-  global_shortcut_manager: Arc<Mutex<WryShortcutManager>>,
+  global_shortcut_manager: Rc<Mutex<WryShortcutManager>>,
   #[cfg(feature = "clipboard")]
   clipboard_manager: Arc<Mutex<Clipboard>>,
   #[cfg(all(desktop, feature = "system-tray"))]

+ 1 - 1
core/tauri/src/manager.rs

@@ -192,7 +192,7 @@ fn replace_csp_nonce(
       .into_iter()
       .map(|n| format!("'nonce-{n}'"))
       .collect::<Vec<String>>();
-    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);

+ 1 - 1
core/tauri/src/window.rs

@@ -1630,7 +1630,7 @@ impl<R: Runtime> Window<R> {
         window_label,
         event,
       })
-      .or_insert_with(Default::default)
+      .or_default()
       .insert(id);
   }
 

+ 1 - 1
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",

+ 4 - 6
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());

+ 6 - 2
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<Vec<PathBuf>> {
         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());
+        }
       }
     }
   }

+ 22 - 15
tooling/bundler/src/bundle/macos/sign.rs

@@ -336,7 +336,7 @@ pub enum NotarizeAuth {
   AppleId {
     apple_id: OsString,
     password: OsString,
-    team_id: Option<OsString>,
+    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<NotarizeAuth> {
+#[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<NotarizeAuth, NotarizeAuthError> {
   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<NotarizeAuth> {
             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())
       }
     }
   }

+ 2 - 2
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.

+ 2 - 3
tooling/cli/src/interface/rust/desktop.rs

@@ -203,9 +203,8 @@ fn build_dev_app<F: FnOnce(ExitStatus, ExitReason) + Send + 'static>(
     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']) {

+ 4 - 6
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());