youtubebeat/vendor/github.com/elastic/beats/dev-tools/mage/keychain.go

160 lines
4.6 KiB
Go

// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package mage
import (
"log"
"regexp"
"strconv"
"strings"
"sync"
"github.com/magefile/mage/sh"
"github.com/pkg/errors"
)
var _appleKeychain = &appleKeychain{}
type appleKeychain struct{}
// SigningIdentity represents a key pair (public/private) that can be used for
// signing.
type SigningIdentity struct {
ID string
Description string
}
// ListIdentities queries the keychain to get a list of signing identities
// (certificate + private key).
func (k *appleKeychain) ListIdentities() ([]SigningIdentity, error) {
var re = regexp.MustCompile(`(?m)^\s*\d+\)\s+(\w+)\s+"(.+)"$`)
out, err := sh.Output("security", "find-identity", "-v")
if err != nil {
return nil, err
}
var idents []SigningIdentity
ids := map[string]struct{}{}
for _, match := range re.FindAllStringSubmatch(out, -1) {
ident := SigningIdentity{ID: match[1], Description: match[2]}
// Deduplicate
if _, found := ids[ident.ID]; found {
continue
}
idents = append(idents, ident)
ids[ident.ID] = struct{}{}
}
return idents, nil
}
// AppleSigningInfo indicate if signing is enabled and specifies the identities
// to use for signing applications and installers.
type AppleSigningInfo struct {
Sign bool
App SigningIdentity
Installer SigningIdentity
}
var (
appleSigningInfoValue *AppleSigningInfo
appleSigningInfoErr error
appleSigningInfoOnce sync.Once
)
// GetAppleSigningInfo returns the signing identities used for code signing
// apps and installers.
//
// Environment Variables
//
// APPLE_SIGNING_ENABLED - Must be set to true to enable signing. Defaults to
// false.
//
// APPLE_SIGNING_IDENTITY_INSTALLER - filter for selecting the signing identity
// for installers.
//
// APPLE_SIGNING_IDENTITY_APP - filter for selecting the signing identity
// for apps.
func GetAppleSigningInfo() (*AppleSigningInfo, error) {
appleSigningInfoOnce.Do(func() {
appleSigningInfoValue, appleSigningInfoErr = getAppleSigningInfo()
})
return appleSigningInfoValue, appleSigningInfoErr
}
func getAppleSigningInfo() (*AppleSigningInfo, error) {
var (
signingEnabled, _ = strconv.ParseBool(EnvOr("APPLE_SIGNING_ENABLED", "false"))
identityInstaller = strings.ToLower(EnvOr("APPLE_SIGNING_IDENTITY_INSTALLER", "Developer ID Installer"))
identityApp = strings.ToLower(EnvOr("APPLE_SIGNING_IDENTITY_APP", "Developer ID Application"))
)
if !signingEnabled {
return &AppleSigningInfo{Sign: false}, nil
}
idents, err := _appleKeychain.ListIdentities()
if err != nil {
return nil, err
}
var install, app []SigningIdentity
for _, ident := range idents {
id, desc := strings.ToLower(ident.ID), strings.ToLower(ident.Description)
if strings.Contains(id, identityInstaller) || strings.Contains(desc, identityInstaller) {
install = append(install, ident)
}
if strings.Contains(id, identityApp) || strings.Contains(desc, identityApp) {
app = append(app, ident)
}
}
if len(install) == 1 && len(app) == 1 {
log.Printf("Apple Code Signing Identities:\n App: %+v\n Installer: %+v", app[0], install[0])
return &AppleSigningInfo{
Sign: true,
Installer: install[0],
App: app[0],
}, nil
}
if len(install) > 1 {
return nil, errors.Errorf("found multiple installer signing identities "+
"that match '%v'. Set a more specific APPLE_SIGNING_IDENTITY_INSTALLER "+
"value that will select one of %+v", identityInstaller, install)
}
if len(app) > 1 {
return nil, errors.Errorf("found multiple installer signing identities "+
"that match '%v'. Set a more specific APPLE_SIGNING_IDENTITY_APP "+
"value that will select one of %+v", identityApp, app)
}
if len(install) == 0 || len(app) == 0 {
return nil, errors.Errorf("apple signing was requested with " +
"APPLE_SIGNING_ENABLED=true, but the required signing identities " +
"for app and installer were not found")
}
return &AppleSigningInfo{Sign: false}, nil
}