From 98e346c0c87e6feac580a6312c7a7f9958e8fd25 Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Thu, 20 Jul 2023 11:53:57 -0400 Subject: [PATCH] Replace altool with notarytool --- .../applenotarization/applenotarization.go | 126 ++++++------------ 1 file changed, 44 insertions(+), 82 deletions(-) diff --git a/pkg/packagekit/applenotarization/applenotarization.go b/pkg/packagekit/applenotarization/applenotarization.go index 37d82e89d..4409dfaeb 100644 --- a/pkg/packagekit/applenotarization/applenotarization.go +++ b/pkg/packagekit/applenotarization/applenotarization.go @@ -8,12 +8,9 @@ package applenotarization import ( "bytes" "context" - "crypto/rand" - "encoding/hex" - "errors" + "encoding/json" "fmt" "os/exec" - "regexp" "strings" "github.com/go-kit/kit/log" @@ -44,79 +41,10 @@ func New( } -var duplicateSubmitRegexp = regexp.MustCompile(`ERROR ITMS-90732: "The software asset has already been uploaded. The upload ID is ([0-9a-fA-F-]+)"`) - -var retryableErrorStrings = []string{ - "Message:Unable to find requested file(s): metadata.xml", -} - -const ( - maxSubmitTries = 5 -) - // Submit an file to apple's notarization service. Returns the uuid of // the submission func (n *Notarizer) Submit(ctx context.Context, filePath string, primaryBundleId string) (string, error) { - logger := log.With(ctxlog.FromContext(ctx), "caller", "applenotarization.Submit") - - // TODO check file extension here - // zip,pkg,dmg - - // Sometimes submit fails. Retry a couple times. - for attempt := 1; attempt <= maxSubmitTries; attempt++ { - - // According to a support thread on apple, the bundle-id passed to - // altool's notarize is unrelated to the actual software. It is only - // used to for something in local storage. As such, add a nonce to - // ensure nothing is conflicting. - // https://developer.apple.com/forums/thread/677739 - bundleId := primaryBundleId + "." + randomNonce() - - response, err := n.runAltool(ctx, []string{ - "--notarize-app", - "--primary-bundle-id", bundleId, - "--file", filePath, - }) - - if err != nil { - level.Error(logger).Log( - "msg", "error getting notarize-app. Will retry", - "attempt", attempt, - "err", err, - "error-messages", fmt.Sprintf("%+v", response.ProductErrors), - ) - continue - } - - // retryable errors - if len(response.ProductErrors) > 0 { - for _, e := range retryableErrorStrings { - if strings.Contains(response.ProductErrors[0].Message, e) { - level.Error(logger).Log( - "msg", "error submitting for notarization. Will retry", - "attempt", attempt, - "error-messages", fmt.Sprintf("%+v", response.ProductErrors), - ) - continue - } - } - } - - // duplicate submission err, treat as success. - if len(response.ProductErrors) == 1 { - matches := duplicateSubmitRegexp.FindStringSubmatch(response.ProductErrors[0].Message) - if len(matches) == 2 { - return matches[1], nil - } - } - - if err == nil { - return response.NotarizationUpload.RequestUUID, nil - } - } - - // Falling out of the for loop means we never succeeded - return "", errors.New("Did not successfully submit for notarization") + return n.runNotarytool(ctx, filePath) } // Check the notarization status of a uuid @@ -155,6 +83,48 @@ func (n *Notarizer) Check(ctx context.Context, uuid string) (string, error) { func Staple(ctx context.Context) { } +func (n *Notarizer) runNotarytool(ctx context.Context, file string) (string, error) { + logger := log.With(ctxlog.FromContext(ctx), "caller", "applenotarization.runNotarytool") + + baseArgs := []string{ + "notarytool", + "submit", + file, + "--apple-id", n.username, + "--password", n.password, + "--team-id", n.account, + "--output-format", "json", + "--no-wait", + "--timeout", "3m", + } + + cmd := exec.CommandContext(ctx, "xcrun", baseArgs...) + + out, err := cmd.CombinedOutput() + if err != nil { + return "", fmt.Errorf("notarizing error: error `%w`, output `%s`", err, string(out)) + } + + type notarizationResponse struct { + Message string `json:"message"` + ID string `json:"id"` + Path string `json:"path"` + } + var r notarizationResponse + if err := json.Unmarshal(out, &r); err != nil { + return "", fmt.Errorf("could not unmarshal notarization response: %w", err) + } + + level.Debug(logger).Log( + "msg", "successfully submitted for notarization", + "response_msg", r.Message, + "response_uuid", r.ID, + "response_path", r.Path, + ) + + return r.ID, nil +} + func (n *Notarizer) runAltool(ctx context.Context, cmdArgs []string) (*notarizationResponse, error) { logger := log.With(ctxlog.FromContext(ctx), "caller", "applenotarization.runAltool") @@ -197,11 +167,3 @@ func (n *Notarizer) runAltool(ctx context.Context, cmdArgs []string) (*notarizat return response, cmdErr } - -// randomNonce returns a short random hex string. -func randomNonce() string { - buff := make([]byte, 3) - rand.Read(buff) - str := hex.EncodeToString(buff) - return str -}