pub struct Notarizer { /* private fields */ }
Expand description

An entity for performing notarizations.

Notarization works by uploading content to Apple, waiting for Apple to inspect and react to that upload, then downloading a notarization “ticket” from Apple and incorporating it into the entity being signed.

Implementations§

Construct an instance from an API issuer ID and API key.

Examples found in repository?
src/cli.rs (line 1907)
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
fn notarizer_from_args(args: &ArgMatches) -> Result<Notarizer, AppleCodesignError> {
    let api_key_path = args.get_one::<PathBuf>("api_key_path");
    let api_issuer = args.get_one::<String>("api_issuer");
    let api_key = args.get_one::<String>("api_key");

    if let Some(api_key_path) = api_key_path {
        Notarizer::from_api_key(api_key_path)
    } else if let (Some(issuer), Some(key)) = (api_issuer, api_key) {
        Notarizer::from_api_key_id(issuer, key)
    } else {
        Err(AppleCodesignError::NotarizeNoAuthCredentials)
    }
}

Construct an instance from a file containing a JSON encoded API key.

Examples found in repository?
src/cli.rs (line 1905)
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
fn notarizer_from_args(args: &ArgMatches) -> Result<Notarizer, AppleCodesignError> {
    let api_key_path = args.get_one::<PathBuf>("api_key_path");
    let api_issuer = args.get_one::<String>("api_issuer");
    let api_key = args.get_one::<String>("api_key");

    if let Some(api_key_path) = api_key_path {
        Notarizer::from_api_key(api_key_path)
    } else if let (Some(issuer), Some(key)) = (api_issuer, api_key) {
        Notarizer::from_api_key_id(issuer, key)
    } else {
        Err(AppleCodesignError::NotarizeNoAuthCredentials)
    }
}

Attempt to notarize an asset defined by a filesystem path.

The type of path is sniffed out and the appropriate notarization routine is called.

Examples found in repository?
src/cli.rs (line 1953)
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
fn command_notary_submit(args: &ArgMatches) -> Result<(), AppleCodesignError> {
    let path = PathBuf::from(
        args.get_one::<String>("path")
            .expect("clap should have validated arguments"),
    );
    let staple = args.get_flag("staple");
    let wait = args.get_flag("wait") || staple;

    let wait_limit = if wait {
        Some(notarizer_wait_duration(args)?)
    } else {
        None
    };
    let notarizer = notarizer_from_args(args)?;

    let upload = notarizer.notarize_path(&path, wait_limit)?;

    if staple {
        match upload {
            crate::notarization::NotarizationUpload::UploadId(_) => {
                panic!(
                    "NotarizationUpload::UploadId should not be returned if we waited successfully"
                );
            }
            crate::notarization::NotarizationUpload::NotaryResponse(_) => {
                let stapler = crate::stapling::Stapler::new()?;
                stapler.staple_path(&path)?;
            }
        }
    }

    Ok(())
}

Attempt to notarize an on-disk bundle.

If wait_limit is provided, we will wait for the upload to finish processing. Otherwise, this returns as soon as the upload is performed.

Examples found in repository?
src/notarization.rs (line 184)
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
    pub fn notarize_path(
        &self,
        path: &Path,
        wait_limit: Option<Duration>,
    ) -> Result<NotarizationUpload, AppleCodesignError> {
        match PathType::from_path(path)? {
            PathType::Bundle => {
                let bundle = DirectoryBundle::new_from_path(path)
                    .map_err(AppleCodesignError::DirectoryBundle)?;
                self.notarize_bundle(&bundle, wait_limit)
            }
            PathType::Xar => self.notarize_flat_package(path, wait_limit),
            PathType::Zip => self.notarize_flat_package(path, wait_limit),
            PathType::Dmg => self.notarize_dmg(path, wait_limit),
            PathType::MachO | PathType::Other => Err(AppleCodesignError::NotarizeUnsupportedPath(
                path.to_path_buf(),
            )),
        }
    }

Attempt to notarize a DMG file.

Examples found in repository?
src/notarization.rs (line 188)
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
    pub fn notarize_path(
        &self,
        path: &Path,
        wait_limit: Option<Duration>,
    ) -> Result<NotarizationUpload, AppleCodesignError> {
        match PathType::from_path(path)? {
            PathType::Bundle => {
                let bundle = DirectoryBundle::new_from_path(path)
                    .map_err(AppleCodesignError::DirectoryBundle)?;
                self.notarize_bundle(&bundle, wait_limit)
            }
            PathType::Xar => self.notarize_flat_package(path, wait_limit),
            PathType::Zip => self.notarize_flat_package(path, wait_limit),
            PathType::Dmg => self.notarize_dmg(path, wait_limit),
            PathType::MachO | PathType::Other => Err(AppleCodesignError::NotarizeUnsupportedPath(
                path.to_path_buf(),
            )),
        }
    }

Attempt to notarize a flat package (.pkg) installer or a .zip file.

Examples found in repository?
src/notarization.rs (line 186)
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
    pub fn notarize_path(
        &self,
        path: &Path,
        wait_limit: Option<Duration>,
    ) -> Result<NotarizationUpload, AppleCodesignError> {
        match PathType::from_path(path)? {
            PathType::Bundle => {
                let bundle = DirectoryBundle::new_from_path(path)
                    .map_err(AppleCodesignError::DirectoryBundle)?;
                self.notarize_bundle(&bundle, wait_limit)
            }
            PathType::Xar => self.notarize_flat_package(path, wait_limit),
            PathType::Zip => self.notarize_flat_package(path, wait_limit),
            PathType::Dmg => self.notarize_dmg(path, wait_limit),
            PathType::MachO | PathType::Other => Err(AppleCodesignError::NotarizeUnsupportedPath(
                path.to_path_buf(),
            )),
        }
    }
Examples found in repository?
src/notarization.rs (line 381)
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
    pub fn wait_on_notarization(
        &self,
        submission_id: &str,
        wait_limit: Duration,
    ) -> Result<notary_api::SubmissionResponse, AppleCodesignError> {
        warn!(
            "waiting up to {}s for package upload {} to finish processing",
            wait_limit.as_secs(),
            submission_id
        );

        let start_time = std::time::Instant::now();

        loop {
            let status = self.get_submission(submission_id)?;

            let elapsed = start_time.elapsed();

            info!(
                "poll state after {}s: {:?}",
                elapsed.as_secs(),
                status.data.attributes.status
            );

            if status.data.attributes.status != notary_api::SubmissionResponseStatus::InProgress {
                warn!("Notary API Server has finished processing the uploaded asset");

                return Ok(status);
            }

            if elapsed >= wait_limit {
                warn!("reached wait limit after {}s", elapsed.as_secs());
                return Err(AppleCodesignError::NotarizeWaitLimitReached);
            }

            std::thread::sleep(self.wait_poll_interval);
        }
    }
Examples found in repository?
src/notarization.rs (line 424)
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
    pub fn wait_on_notarization_and_fetch_log(
        &self,
        submission_id: &str,
        wait_limit: Duration,
    ) -> Result<notary_api::SubmissionResponse, AppleCodesignError> {
        let status = self.wait_on_notarization(submission_id, wait_limit)?;

        let log = self.fetch_notarization_log(submission_id)?;

        for line in serde_json::to_string_pretty(&log)?.lines() {
            warn!("notary log> {}", line);
        }

        Ok(status)
    }

Obtain the processing log from an upload.

Examples found in repository?
src/cli.rs (line 1929)
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
fn command_notary_log(args: &ArgMatches) -> Result<(), AppleCodesignError> {
    let notarizer = notarizer_from_args(args)?;
    let submission_id = args
        .get_one::<String>("submission_id")
        .expect("submission_id is required");

    let log = notarizer.fetch_notarization_log(submission_id)?;

    for line in serde_json::to_string_pretty(&log)?.lines() {
        println!("{line}");
    }

    Ok(())
}
More examples
Hide additional examples
src/notarization.rs (line 426)
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
    pub fn wait_on_notarization_and_fetch_log(
        &self,
        submission_id: &str,
        wait_limit: Duration,
    ) -> Result<notary_api::SubmissionResponse, AppleCodesignError> {
        let status = self.wait_on_notarization(submission_id, wait_limit)?;

        let log = self.fetch_notarization_log(submission_id)?;

        for line in serde_json::to_string_pretty(&log)?.lines() {
            warn!("notary log> {}", line);
        }

        Ok(status)
    }

Waits on an app store package upload and fetches and logs the upload log.

This is just a convenience around [Self::wait_on_app_store_package_upload()] and [Self::fetch_upload_log()].

Examples found in repository?
src/cli.rs (line 1979)
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
fn command_notary_wait(args: &ArgMatches) -> Result<(), AppleCodesignError> {
    let wait_duration = notarizer_wait_duration(args)?;
    let notarizer = notarizer_from_args(args)?;
    let submission_id = args
        .get_one::<String>("submission_id")
        .expect("submission_id is required");

    notarizer.wait_on_notarization_and_fetch_log(submission_id, wait_duration)?;

    Ok(())
}
More examples
Hide additional examples
src/notarization.rs (line 349)
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
    fn upload_s3_and_maybe_wait(
        &self,
        submission: notary_api::NewSubmissionResponse,
        upload_data: UploadKind,
        wait_limit: Option<Duration>,
    ) -> Result<NotarizationUpload, AppleCodesignError> {
        self.upload_s3_package(&submission, upload_data)?;

        let status = if let Some(wait_limit) = wait_limit {
            self.wait_on_notarization_and_fetch_log(&submission.data.id, wait_limit)?
        } else {
            return Ok(NotarizationUpload::UploadId(submission.data.id));
        };

        // Make sure notarization was successful.
        let status = status.into_result()?;

        Ok(NotarizationUpload::NotaryResponse(status))
    }

Trait Implementations§

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more

Auto Trait Implementations§

Blanket Implementations§

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when Debug-formatted.
Causes self to use its LowerExp implementation when Debug-formatted.
Causes self to use its LowerHex implementation when Debug-formatted.
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when Debug-formatted.
Causes self to use its UpperExp implementation when Debug-formatted.
Causes self to use its UpperHex implementation when Debug-formatted.
Formats each item in a sequence. Read more

Returns the argument unchanged.

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Instruments this type with the current Span, returning an Instrumented wrapper. Read more

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe function.
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe function.
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Should always be Self
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release builds.
Calls .tap_borrow() only in debug builds, and is erased in release builds.
Calls .tap_borrow_mut() only in debug builds, and is erased in release builds.
Calls .tap_ref() only in debug builds, and is erased in release builds.
Calls .tap_ref_mut() only in debug builds, and is erased in release builds.
Calls .tap_deref() only in debug builds, and is erased in release builds.
Calls .tap_deref_mut() only in debug builds, and is erased in release builds.
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more