mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2026-01-09 01:51:42 +01:00
JBR-5600 Sign macOS binaries using jet-sign
(cherry picked from commit 95ef69df13)
This commit is contained in:
committed by
Vitaly Provodin
parent
2983cc9534
commit
70b07f6e4b
47
jb/project/tools/mac/scripts/codesign.sh
Executable file
47
jb/project/tools/mac/scripts/codesign.sh
Executable file
@@ -0,0 +1,47 @@
|
||||
#!/bin/bash
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" >/dev/null && pwd)"
|
||||
|
||||
source "$SCRIPT_DIR/jetsign-common.sh" || exit 1
|
||||
|
||||
function isMacOsBinary() {
|
||||
file "$1" | grep -q 'Mach-O'
|
||||
}
|
||||
|
||||
function isSigned() {
|
||||
codesign --verify "$1" && ! grep -q Signature=adhoc < <(codesign --display --verbose "$1" 2>&1)
|
||||
}
|
||||
|
||||
# last argument is a path to be signed
|
||||
pathToBeSigned="$(pwd)/${*: -1}"
|
||||
jetSignArgs=("${@:1:$#-1}")
|
||||
if [[ ! -f "$pathToBeSigned" ]]; then
|
||||
echo "$pathToBeSigned is missing or not a file"
|
||||
exit 1
|
||||
elif isSigned "$pathToBeSigned" && ! isForced "${jetSignArgs[@]}" ; then
|
||||
echo "Already signed: $pathToBeSigned"
|
||||
elif [[ "$JETSIGN_CLIENT" == "null" ]]; then
|
||||
echo "JetSign client is missing, cannot proceed with signing"
|
||||
exit 1
|
||||
elif ! isMacOsBinary "$pathToBeSigned" && [[ "$pathToBeSigned" != *.sit ]] && [[ "$pathToBeSigned" != *.tar.gz ]]; then
|
||||
echo "$pathToBeSigned won't be signed, assumed not to be a macOS executable"
|
||||
else
|
||||
if isMacOsBinary "$pathToBeSigned" && ! isSigned "$pathToBeSigned" ; then
|
||||
echo "Unsigned macOS binary: $pathToBeSigned"
|
||||
fi
|
||||
workDir=$(dirname "$pathToBeSigned")
|
||||
pathSigned="$workDir/signed/${pathToBeSigned##*/}"
|
||||
jetSignExtensions=$(jetSignExtensions "${jetSignArgs[@]}")
|
||||
contentType=$(jetSignContentType "$pathToBeSigned")
|
||||
(
|
||||
cd "$workDir" || exit 1
|
||||
"$JETSIGN_CLIENT" -log-format text -denoted-content-type "$contentType" -extensions "$jetSignExtensions" "$pathToBeSigned"
|
||||
# SRE-1223 (Codesign removes execute bits in executable files) workaround
|
||||
chmod "$(stat -f %A "$pathToBeSigned")" "$pathSigned"
|
||||
if isMacOsBinary "$pathSigned"; then
|
||||
isSigned "$pathSigned"
|
||||
fi
|
||||
rm "$pathToBeSigned"
|
||||
mv "$pathSigned" "$pathToBeSigned"
|
||||
rm -rf "$workDir/signed"
|
||||
)
|
||||
fi
|
||||
63
jb/project/tools/mac/scripts/jetsign-common.sh
Executable file
63
jb/project/tools/mac/scripts/jetsign-common.sh
Executable file
@@ -0,0 +1,63 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
function isForced() {
|
||||
for arg in "$@"; do
|
||||
if [[ "$arg" == --force ]]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
function jetSignExtensions() {
|
||||
args=("$@")
|
||||
((lastElementIndex=${#args[@]}-1))
|
||||
for index in "${!args[@]}"; do
|
||||
arg=${args[$index]}
|
||||
case "$arg" in
|
||||
--sign | -s)
|
||||
echo -n 'mac_codesign_identity='
|
||||
continue
|
||||
;;
|
||||
--entitlements)
|
||||
echo -n 'mac_codesign_entitlements='
|
||||
continue
|
||||
;;
|
||||
--options=runtime)
|
||||
echo -n 'mac_codesign_options=runtime'
|
||||
;;
|
||||
--force)
|
||||
echo -n 'mac_codesign_force=true'
|
||||
;;
|
||||
--timestamp | --verbose | -v)
|
||||
continue
|
||||
;;
|
||||
*)
|
||||
echo -n "$arg"
|
||||
;;
|
||||
esac
|
||||
if [[ $index != "$lastElementIndex" ]]; then
|
||||
echo -n ","
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# See jetbrains.sign.util.FileUtil.contentType
|
||||
function jetSignContentType() {
|
||||
case "${1##*/}" in
|
||||
*.sit)
|
||||
echo -n 'application/x-mac-app-zip'
|
||||
;;
|
||||
*.tar.gz)
|
||||
echo -n 'application/x-mac-app-targz'
|
||||
;;
|
||||
*.pkg)
|
||||
echo -n 'application/x-mac-pkg'
|
||||
;;
|
||||
*)
|
||||
echo -n 'application/x-mac-app-bin'
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
41
jb/project/tools/mac/scripts/productsign.sh
Executable file
41
jb/project/tools/mac/scripts/productsign.sh
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/bin/bash
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" >/dev/null && pwd)"
|
||||
|
||||
source "$SCRIPT_DIR/jetsign-common.sh" || exit 1
|
||||
|
||||
function isSigned() {
|
||||
pkgutil --check-signature "$1" && grep -q "signed by a developer certificate" < <(pkgutil --check-signature "$1" 2>&1)
|
||||
}
|
||||
|
||||
# second last argument is a path to be signed
|
||||
pathToBeSigned="$(pwd)/${*:(-2):1}"
|
||||
# last argument is a path to signed file
|
||||
pathOut="$(pwd)/${*:(-1)}"
|
||||
jetSignArgs=("${@:1:$#-2}")
|
||||
if [[ ! -f "$pathToBeSigned" ]]; then
|
||||
echo "$pathToBeSigned is missing or not a file"
|
||||
exit 1
|
||||
elif isSigned "$pathToBeSigned" && ! isForced "${jetSignArgs[@]}" ; then
|
||||
echo "Already signed: $pathToBeSigned"
|
||||
elif [[ "$JETSIGN_CLIENT" == "null" ]]; then
|
||||
echo "JetSign client is missing, cannot proceed with signing"
|
||||
exit 1
|
||||
elif [[ "$pathToBeSigned" != *.pkg ]]; then
|
||||
echo "$pathToBeSigned won't be signed, assumed not to be a macOS package"
|
||||
else
|
||||
if ! isSigned "$pathToBeSigned" ; then
|
||||
echo "Unsigned macOS package: $pathToBeSigned"
|
||||
fi
|
||||
workDir=$(dirname "$pathToBeSigned")
|
||||
pathSigned="$workDir/signed/${pathToBeSigned##*/}"
|
||||
jetSignExtensions=$(jetSignExtensions "${jetSignArgs[@]}")
|
||||
contentType=$(jetSignContentType "$pathToBeSigned")
|
||||
(
|
||||
cd "$workDir" || exit 1
|
||||
"$JETSIGN_CLIENT" -log-format text -denoted-content-type "$contentType" -extensions "$jetSignExtensions" "$pathToBeSigned"
|
||||
isSigned "$pathSigned"
|
||||
rm -f "$pathOut"
|
||||
mv "$pathSigned" "$pathOut"
|
||||
rm -rf "$workDir/signed"
|
||||
)
|
||||
fi
|
||||
@@ -9,6 +9,19 @@ BUNDLE_ID=$3
|
||||
JB_DEVELOPER_CERT=$4
|
||||
JB_INSTALLER_CERT=$5
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" >/dev/null && pwd)"
|
||||
|
||||
# Use JetBrains sign utility if it's available
|
||||
if [[ "${JETSIGN_CLIENT:=}" == "null" ]] || [[ "$JETSIGN_CLIENT" == "" ]]; then
|
||||
JB_SIGN=false
|
||||
SIGN_UTILITY="codesign"
|
||||
PRODUCTSIGN_UTILITY="productsign"
|
||||
else
|
||||
JB_SIGN=true
|
||||
SIGN_UTILITY="$SCRIPT_DIR/codesign.sh"
|
||||
PRODUCTSIGN_UTILITY="$SCRIPT_DIR/productsign.sh"
|
||||
fi
|
||||
|
||||
if [[ -z "$APPLICATION_PATH" ]] || [[ -z "$JB_DEVELOPER_CERT" ]]; then
|
||||
echo "Usage: $0 AppDirectory CertificateID"
|
||||
exit 1
|
||||
@@ -37,13 +50,13 @@ for f in \
|
||||
if [ -d "$APPLICATION_PATH/$f" ]; then
|
||||
find "$APPLICATION_PATH/$f" \
|
||||
-type f \( -name "*.jnilib" -o -name "*.dylib" -o -name "*.so" -o -name "*.tbd" -o -name "*.node" -o -perm +111 \) \
|
||||
-exec codesign --timestamp \
|
||||
-exec "$SIGN_UTILITY" --timestamp \
|
||||
-v -s "$JB_DEVELOPER_CERT" --options=runtime --force \
|
||||
--entitlements entitlements.xml {} \;
|
||||
--entitlements "$SCRIPT_DIR/entitlements.xml" {} \;
|
||||
fi
|
||||
done
|
||||
|
||||
log "Signing libraries in jars in $PWD"
|
||||
log "Signing libraries in jars in $APPLICATION_PATH"
|
||||
|
||||
# todo: add set -euo pipefail; into the inner sh -c
|
||||
# `-e` prevents `grep -q && printf` loginc
|
||||
@@ -61,10 +74,10 @@ find "$APPLICATION_PATH" -name '*.jar' \
|
||||
|
||||
find jarfolder \
|
||||
-type f \( -name "*.jnilib" -o -name "*.dylib" -o -name "*.so" -o -name "*.tbd" -o -name "jattach" \) \
|
||||
-exec codesign --timestamp \
|
||||
-exec "$SIGN_UTILITY" --timestamp \
|
||||
--force \
|
||||
-v -s "$JB_DEVELOPER_CERT" --options=runtime \
|
||||
--entitlements entitlements.xml {} \;
|
||||
--entitlements "$SCRIPT_DIR/entitlements.xml" {} \;
|
||||
|
||||
(cd jarfolder; zip -q -r -o -0 ../jar.jar .)
|
||||
mv jar.jar "$file"
|
||||
@@ -73,14 +86,15 @@ find "$APPLICATION_PATH" -name '*.jar' \
|
||||
rm -rf jarfolder jar.jar
|
||||
|
||||
log "Signing other files..."
|
||||
# shellcheck disable=SC2043
|
||||
for f in \
|
||||
"Contents/Home/bin"; do
|
||||
if [ -d "$APPLICATION_PATH/$f" ]; then
|
||||
find "$APPLICATION_PATH/$f" \
|
||||
-type f \( -name "*.jnilib" -o -name "*.dylib" -o -name "*.so" -o -name "*.tbd" -o -perm +111 \) \
|
||||
-exec codesign --timestamp \
|
||||
-exec "$SIGN_UTILITY" --timestamp \
|
||||
-v -s "$JB_DEVELOPER_CERT" --options=runtime --force \
|
||||
--entitlements entitlements.xml {} \;
|
||||
--entitlements "$SCRIPT_DIR/entitlements.xml" {} \;
|
||||
fi
|
||||
done
|
||||
|
||||
@@ -91,12 +105,23 @@ done
|
||||
# --entitlements entitlements.xml "$APPLICATION_PATH/Contents/MacOS/idea"
|
||||
|
||||
log "Signing whole app..."
|
||||
codesign --timestamp \
|
||||
-v -s "$JB_DEVELOPER_CERT" --options=runtime \
|
||||
--force \
|
||||
--entitlements entitlements.xml "$APPLICATION_PATH"
|
||||
if [ "$JB_SIGN" = true ]; then
|
||||
tar -pczvf tmp-to-sign.tar.gz --exclude='man' -C "$(dirname "$APPLICATION_PATH")" "$(basename "$APPLICATION_PATH")"
|
||||
"$SIGN_UTILITY" --timestamp \
|
||||
-v -s "$JB_DEVELOPER_CERT" --options=runtime \
|
||||
--force \
|
||||
--entitlements "$SCRIPT_DIR/entitlements.xml" tmp-to-sign.tar.gz
|
||||
rm -rf "$APPLICATION_PATH"
|
||||
tar -xzvf tmp-to-sign.tar.gz --directory "$(dirname "$APPLICATION_PATH")"
|
||||
rm -f tmp-to-sign.tar.gz
|
||||
else
|
||||
"$SIGN_UTILITY" --timestamp \
|
||||
-v -s "$JB_DEVELOPER_CERT" --options=runtime \
|
||||
--force \
|
||||
--entitlements "$SCRIPT_DIR/entitlements.xml" "$APPLICATION_PATH"
|
||||
fi
|
||||
|
||||
BUILD_NAME=$(echo $APPLICATION_PATH | awk -F"/" '{ print $2 }')
|
||||
BUILD_NAME="$(basename "$APPLICATION_PATH")"
|
||||
|
||||
log "Creating $APP_NAME.pkg..."
|
||||
rm -rf "$APP_NAME.pkg"
|
||||
@@ -104,7 +129,8 @@ rm -rf "$APP_NAME.pkg"
|
||||
mkdir -p unsigned
|
||||
pkgbuild --identifier $BUNDLE_ID --root $APPLICATION_PATH \
|
||||
--install-location /Library/Java/JavaVirtualMachines/${BUILD_NAME} unsigned/${APP_NAME}.pkg
|
||||
productsign --timestamp --sign "$JB_INSTALLER_CERT" unsigned/${APP_NAME}.pkg ${APP_NAME}.pkg
|
||||
log "Signing $APP_NAME.pkg..."
|
||||
"$PRODUCTSIGN_UTILITY" --timestamp --sign "$JB_INSTALLER_CERT" unsigned/${APP_NAME}.pkg ${APP_NAME}.pkg
|
||||
|
||||
#log "Signing whole app..."
|
||||
#codesign --timestamp \
|
||||
|
||||
@@ -17,7 +17,7 @@ JB_INSTALLER_CERT=$6
|
||||
NOTARIZE=$7
|
||||
BUNDLE_ID=$8
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" >/dev/null && pwd)"
|
||||
|
||||
function log() {
|
||||
echo "$(date '+[%H:%M:%S]') $*"
|
||||
@@ -44,7 +44,7 @@ fi
|
||||
|
||||
log "$INPUT_FILE extracted and removed"
|
||||
|
||||
APP_NAME=$(echo ${INPUT_FILE} | awk -F".tar" '{ print $1 }')
|
||||
APP_NAME=$(basename "$INPUT_FILE" | awk -F".tar" '{ print $1 }')
|
||||
APPLICATION_PATH=$EXPLODED/$(ls $EXPLODED)
|
||||
|
||||
find "$APPLICATION_PATH/Contents/Home/bin" \
|
||||
@@ -73,16 +73,18 @@ if [[ $non_plist -gt 0 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "Unlocking keychain..."
|
||||
# Make sure *.p12 is imported into local KeyChain
|
||||
security unlock-keychain -p "$PASSWORD" "/Users/$USERNAME/Library/Keychains/login.keychain"
|
||||
if [[ "${JETSIGN_CLIENT:=}" == "null" ]] || [[ "$JETSIGN_CLIENT" == "" ]]; then
|
||||
log "Unlocking keychain..."
|
||||
# Make sure *.p12 is imported into local KeyChain
|
||||
security unlock-keychain -p "$PASSWORD" "/Users/$USERNAME/Library/Keychains/login.keychain"
|
||||
fi
|
||||
|
||||
attempt=1
|
||||
limit=3
|
||||
set +e
|
||||
while [[ $attempt -le $limit ]]; do
|
||||
log "Signing (attempt $attempt) $APPLICATION_PATH ..."
|
||||
./sign.sh "$APPLICATION_PATH" "$APP_NAME" "$BUNDLE_ID" "$CODESIGN_STRING" "$JB_INSTALLER_CERT"
|
||||
"$SCRIPT_DIR/sign.sh" "$APPLICATION_PATH" "$APP_NAME" "$BUNDLE_ID" "$CODESIGN_STRING" "$JB_INSTALLER_CERT"
|
||||
ec=$?
|
||||
if [[ $ec -ne 0 ]]; then
|
||||
((attempt += 1))
|
||||
|
||||
Reference in New Issue
Block a user