Skip to content

Commit

Permalink
Replace altool with notarytool
Browse files Browse the repository at this point in the history
  • Loading branch information
RebeccaMahany committed Jul 20, 2023
1 parent 842af7c commit 98e346c
Showing 1 changed file with 44 additions and 82 deletions.
126 changes: 44 additions & 82 deletions pkg/packagekit/applenotarization/applenotarization.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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")

Expand Down Expand Up @@ -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
}

0 comments on commit 98e346c

Please sign in to comment.