Add exe signing support to release-tool

* Add automatic portable zip building
* Cleanup build variables
* Align command line parameters between modes
This commit is contained in:
Jonathan White 2018-07-08 19:47:35 -04:00 committed by Jonathan White
parent a025bcd7db
commit 4b51b39a83
2 changed files with 70 additions and 48 deletions

View file

@ -35,13 +35,11 @@ TAG_NAME=""
DOCKER_IMAGE="" DOCKER_IMAGE=""
DOCKER_CONTAINER_NAME="keepassxc-build-container" DOCKER_CONTAINER_NAME="keepassxc-build-container"
CMAKE_OPTIONS="" CMAKE_OPTIONS=""
CPACK_GENERATORS="NSIS;ZIP"
COMPILER="g++" COMPILER="g++"
MAKE_OPTIONS="-j8" MAKE_OPTIONS="-j8"
BUILD_PLUGINS="all" BUILD_PLUGINS="all"
INSTALL_PREFIX="/usr/local" INSTALL_PREFIX="/usr/local"
BUILD_SOURCE_TARBALL=true
BUILD_SNAPSHOT=false
BUILD_SNAPCRAFT=false
ORIG_BRANCH="" ORIG_BRANCH=""
ORIG_CWD="$(pwd)" ORIG_CWD="$(pwd)"
@ -81,7 +79,7 @@ Options:
-v, --version Release version number or name (required) -v, --version Release version number or name (required)
-a, --app-name Application name (default: '${APP_NAME}') -a, --app-name Application name (default: '${APP_NAME}')
-s, --source-dir Source directory (default: '${SRC_DIR}') -s, --source-dir Source directory (default: '${SRC_DIR}')
-g, --gpg-key GPG key used to sign the merge commit and release tag, -k, --key GPG key used to sign the merge commit and release tag,
leave empty to let Git choose your default key leave empty to let Git choose your default key
(default: '${GPG_GIT_KEY}') (default: '${GPG_GIT_KEY}')
-r, --release-branch Source release branch to merge from (default: 'release/VERSION') -r, --release-branch Source release branch to merge from (default: 'release/VERSION')
@ -109,9 +107,12 @@ Options:
The container must not exist already The container must not exist already
--snapcraft Create and use docker image to build snapcraft distribution. --snapcraft Create and use docker image to build snapcraft distribution.
This option has no effect if --docker-image is not set. This option has no effect if --docker-image is not set.
--appsign Perform platform specific App Signing before packaging
-k, --key Specify the App Signing Key/Identity
-c, --cmake-options Additional CMake options for compiling the sources -c, --cmake-options Additional CMake options for compiling the sources
--compiler Compiler to use (default: '${COMPILER}') --compiler Compiler to use (default: '${COMPILER}')
-m, --make-options Make options for compiling sources (default: '${MAKE_OPTIONS}') -m, --make-options Make options for compiling sources (default: '${MAKE_OPTIONS}')
-g, --generators Additional CPack generators (default: )
-i, --install-prefix Install prefix (default: '${INSTALL_PREFIX}') -i, --install-prefix Install prefix (default: '${INSTALL_PREFIX}')
-p, --plugins Space-separated list of plugins to build -p, --plugins Space-separated list of plugins to build
(default: ${BUILD_PLUGINS}) (default: ${BUILD_PLUGINS})
@ -126,7 +127,7 @@ Sign previously compiled release packages with GPG
Options: Options:
-f, --files Files to sign (required) -f, --files Files to sign (required)
-g, --gpg-key GPG key used to sign the files (default: '${GPG_KEY}') -k, --key GPG key used to sign the files (default: '${GPG_KEY}')
-h, --help Show this help -h, --help Show this help
EOF EOF
elif [ "appsign" == "$cmd" ]; then elif [ "appsign" == "$cmd" ]; then
@ -136,8 +137,7 @@ Sign binaries with code signing certificates on Windows and macOS
Options: Options:
-f, --files Files to sign (required) -f, --files Files to sign (required)
-k, --signtool-key Key to be used with signtool (required for Windows EXE) -k, --key Signing Key or Apple Developer ID
-i, --identity Apple Developer ID to be used with codesign (required for macOS APP and DMG)
-h, --help Show this help -h, --help Show this help
EOF EOF
fi fi
@ -437,7 +437,7 @@ merge() {
SRC_DIR="$2" SRC_DIR="$2"
shift ;; shift ;;
-g|--gpg-key) -k|--key|-g|--gpg-key)
GPG_GIT_KEY="$2" GPG_GIT_KEY="$2"
shift ;; shift ;;
@ -515,6 +515,13 @@ merge() {
# build command # build command
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
build() { build() {
local build_source_tarball=true
local build_snapshot=false
local build_snapcraft=false
local build_generators=""
local build_appsign=false
local build_key=""
while [ $# -ge 1 ]; do while [ $# -ge 1 ]; do
local arg="$1" local arg="$1"
case "$arg" in case "$arg" in
@ -542,13 +549,19 @@ build() {
DOCKER_IMAGE="$2" DOCKER_IMAGE="$2"
shift ;; shift ;;
--appsign)
build_appsign=true ;;
-k|--key)
build_key="$2"
shift ;;
--container-name) --container-name)
DOCKER_CONTAINER_NAME="$2" DOCKER_CONTAINER_NAME="$2"
shift ;; shift ;;
--snapcraft) --snapcraft)
BUILD_SNAPCRAFT=true build_snapcraft=true ;;
shift ;;
-c|--cmake-options) -c|--cmake-options)
CMAKE_OPTIONS="$2" CMAKE_OPTIONS="$2"
@ -562,6 +575,10 @@ build() {
MAKE_OPTIONS="$2" MAKE_OPTIONS="$2"
shift ;; shift ;;
-g|--generators)
buil_generators="$2"
shift ;;
-i|--install-prefix) -i|--install-prefix)
INSTALL_PREFIX="$2" INSTALL_PREFIX="$2"
shift ;; shift ;;
@ -571,10 +588,10 @@ build() {
shift ;; shift ;;
-n|--no-source-tarball) -n|--no-source-tarball)
BUILD_SOURCE_TARBALL=false ;; build_source_tarball=false ;;
--snapshot) --snapshot)
BUILD_SNAPSHOT=true ;; build_snapshot=true ;;
-h|--help) -h|--help)
printUsage "build" printUsage "build"
@ -592,7 +609,7 @@ build() {
OUTPUT_DIR="$(realpath "$OUTPUT_DIR")" OUTPUT_DIR="$(realpath "$OUTPUT_DIR")"
if ${BUILD_SNAPSHOT}; then if ${build_snapshot}; then
TAG_NAME="HEAD" TAG_NAME="HEAD"
local branch=`git rev-parse --abbrev-ref HEAD` local branch=`git rev-parse --abbrev-ref HEAD`
logInfo "Using current branch ${branch} to build..." logInfo "Using current branch ${branch} to build..."
@ -618,7 +635,7 @@ build() {
exitError "Failed to create output directory!" exitError "Failed to create output directory!"
fi fi
if ${BUILD_SOURCE_TARBALL}; then if ${build_source_tarball}; then
logInfo "Creating source tarball..." logInfo "Creating source tarball..."
local app_name_lower="$(echo "$APP_NAME" | tr '[:upper:]' '[:lower:]')" local app_name_lower="$(echo "$APP_NAME" | tr '[:upper:]' '[:lower:]')"
local prefix="${app_name_lower}-${RELEASE_NAME}" local prefix="${app_name_lower}-${RELEASE_NAME}"
@ -626,7 +643,7 @@ build() {
git archive --format=tar "$TAG_NAME" --prefix="${prefix}/" --output="${OUTPUT_DIR}/${tarball_name}" git archive --format=tar "$TAG_NAME" --prefix="${prefix}/" --output="${OUTPUT_DIR}/${tarball_name}"
if ! ${BUILD_SNAPSHOT}; then if ! ${build_snapshot}; then
# add .version file to tar # add .version file to tar
mkdir "${prefix}" mkdir "${prefix}"
echo -n ${RELEASE_NAME} > "${prefix}/.version" echo -n ${RELEASE_NAME} > "${prefix}/.version"
@ -638,7 +655,7 @@ build() {
xz -6 "${OUTPUT_DIR}/${tarball_name}" xz -6 "${OUTPUT_DIR}/${tarball_name}"
fi fi
if ! ${BUILD_SNAPSHOT} && [ -e "${OUTPUT_DIR}/build-release" ]; then if ! ${build_snapshot} && [ -e "${OUTPUT_DIR}/build-release" ]; then
logInfo "Cleaning existing build directory..." logInfo "Cleaning existing build directory..."
rm -r "${OUTPUT_DIR}/build-release" 2> /dev/null rm -r "${OUTPUT_DIR}/build-release" 2> /dev/null
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
@ -681,22 +698,38 @@ build() {
# Building on Windows with Msys2 # Building on Windows with Msys2
logInfo "Configuring build..." logInfo "Configuring build..."
cmake -DCMAKE_BUILD_TYPE=Release -DWITH_TESTS=Off -G"MSYS Makefiles" \ cmake -DCMAKE_BUILD_TYPE=Release -DWITH_TESTS=Off -G"MSYS Makefiles" \
-DCMAKE_INSTALL_PREFIX="${INSTALL_PREFIX}" $CMAKE_OPTIONS "$SRC_DIR" -DCMAKE_INSTALL_PREFIX="${INSTALL_PREFIX}" ${CMAKE_OPTIONS} "$SRC_DIR"
logInfo "Compiling and packaging sources..." logInfo "Compiling and packaging sources..."
mingw32-make ${MAKE_OPTIONS} preinstall mingw32-make ${MAKE_OPTIONS} preinstall
# Appsign the executables if desired
if [[ ${build_appsign} && ! -z ${build_key} ]]; then
logInfo "Signing executable files"
appsign "-f" `find src | grep '\.exe'` "-k" "${build_key}"
fi
# Call cpack directly instead of calling make package. # Call cpack directly instead of calling make package.
# This is important because we want to build the MSI when making a # This is important because we want to build the MSI when making a
# release. # release.
cpack -G "NSIS;ZIP;${CPACK_GENERATORS}" cpack -G "${CPACK_GENERATORS};${build_generators}"
mv "./${APP_NAME}-"*.* ../ # Inject the portable config into the zip build and rename
for filename in ${APP_NAME}-*.zip; do
logInfo "Creating portable zip file"
local folder=`echo ${filename} | sed -r 's/(.*)\.zip/\1/'`
python -c 'import zipfile,sys ; zipfile.ZipFile(sys.argv[1],"a").write(sys.argv[2],sys.argv[3])' \
${filename} ${SRC_DIR}/share/keepassxc.ini ${folder}/keepassxc.ini
mv ${filename} ${folder}-portable.zip
done
mv "${APP_NAME}-"*.* ../
else else
mkdir -p "${OUTPUT_DIR}/bin-release" mkdir -p "${OUTPUT_DIR}/bin-release"
# Building on Linux without Docker container # Building on Linux without Docker container
logInfo "Configuring build..." logInfo "Configuring build..."
cmake -DCMAKE_BUILD_TYPE=Release -DWITH_TESTS=Off $CMAKE_OPTIONS \ cmake -DCMAKE_BUILD_TYPE=Release -DWITH_TESTS=Off ${CMAKE_OPTIONS} \
-DCMAKE_INSTALL_PREFIX="${INSTALL_PREFIX}" \ -DCMAKE_INSTALL_PREFIX="${INSTALL_PREFIX}" \
-DKEEPASSXC_DIST_TYPE=AppImage "$SRC_DIR" -DKEEPASSXC_DIST_TYPE=AppImage "$SRC_DIR"
@ -710,7 +743,7 @@ build() {
${SRC_DIR}/AppImage-Recipe.sh "$APP_NAME" "$RELEASE_NAME" ${SRC_DIR}/AppImage-Recipe.sh "$APP_NAME" "$RELEASE_NAME"
fi fi
else else
if [ BUILD_SNAPCRAFT ]; then if [ build_snapcraft ]; then
logInfo "Building snapcraft docker image..." logInfo "Building snapcraft docker image..."
sudo docker image build -t "$DOCKER_IMAGE" "$(realpath "$SRC_DIR")/ci/snapcraft" sudo docker image build -t "$DOCKER_IMAGE" "$(realpath "$SRC_DIR")/ci/snapcraft"
@ -767,7 +800,7 @@ gpgsign() {
shift shift
done ;; done ;;
-g|--gpg-key) -k|--key|-g|--gpg-key)
GPG_KEY="$2" GPG_KEY="$2"
shift ;; shift ;;
@ -817,8 +850,7 @@ gpgsign() {
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
appsign() { appsign() {
local sign_files=() local sign_files=()
local signtool_key local key
local codesign_identity
while [ $# -ge 1 ]; do while [ $# -ge 1 ]; do
local arg="$1" local arg="$1"
@ -829,12 +861,8 @@ appsign() {
shift shift
done ;; done ;;
-k|--signtool-key) -k|--key|-i|--identity)
signtool_key="$2" key="$2"
shift ;;
-i|--identity)
codesign_identity="$2"
shift ;; shift ;;
-h|--help) -h|--help)
@ -849,6 +877,12 @@ appsign() {
shift shift
done done
if [ -z "${key}" ]; then
logError "Missing arguments, --key is required!\n"
printUsage "appsign"
exit 1
fi
if [ -z "${sign_files}" ]; then if [ -z "${sign_files}" ]; then
logError "Missing arguments, --files is required!\n" logError "Missing arguments, --files is required!\n"
printUsage "appsign" printUsage "appsign"
@ -862,12 +896,6 @@ appsign() {
done done
if [ "$(uname -s)" == "Darwin" ]; then if [ "$(uname -s)" == "Darwin" ]; then
if [ -z "${codesign_identity}" ]; then
logError "Missing arguments, --identity is required on macOS!\n"
printUsage "appsign"
exit 1
fi
checkCodesignCommandExists checkCodesignCommandExists
local orig_dir="$(pwd)" local orig_dir="$(pwd)"
@ -887,7 +915,7 @@ appsign() {
fi fi
logInfo "Signing app using codesign..." logInfo "Signing app using codesign..."
codesign --sign "${codesign_identity}" --verbose --deep ./app/KeePassXC.app codesign --sign "${key}" --verbose --deep ./app/KeePassXC.app
if [ 0 -ne $? ]; then if [ 0 -ne $? ]; then
cd "${orig_dir}" cd "${orig_dir}"
@ -912,15 +940,9 @@ appsign() {
done done
elif [ "$(uname -o)" == "Msys" ]; then elif [ "$(uname -o)" == "Msys" ]; then
if [ -z "${signtool_key}" ]; then
logError "Missing arguments, --signtool-key is required on Windows!\n"
printUsage "appsign"
exit 1
fi
checkOsslsigncodeCommandExists checkOsslsigncodeCommandExists
if [[ ! -f "${signtool_key}" ]]; then if [[ ! -f "${key}" ]]; then
exitError "Key file was not found!" exitError "Key file was not found!"
fi fi
@ -931,7 +953,7 @@ appsign() {
if [[ ${f: -4} == ".exe" ]]; then if [[ ${f: -4} == ".exe" ]]; then
logInfo "Signing file '${f}' using osslsigncode..." logInfo "Signing file '${f}' using osslsigncode..."
# output a signed exe; we have to use a different name due to osslsigntool limitations # output a signed exe; we have to use a different name due to osslsigntool limitations
osslsigncode sign -pkcs12 "${signtool_key}" -pass "${password}" -n "KeePassXC" \ osslsigncode sign -pkcs12 "${key}" -pass "${password}" -n "KeePassXC" \
-t "http://timestamp.comodoca.com/authenticode" -in "${f}" -out "${f}.signed" -t "http://timestamp.comodoca.com/authenticode" -in "${f}" -out "${f}.signed"
if [ 0 -ne $? ]; then if [ 0 -ne $? ]; then
@ -947,7 +969,7 @@ appsign() {
# osslsigncode does not succeed at signing MSI files at this time... # osslsigncode does not succeed at signing MSI files at this time...
logInfo "Signing file '${f}' using Microsoft signtool..." logInfo "Signing file '${f}' using Microsoft signtool..."
signtool sign -f "${signtool_key}" -p "${password}" -d "KeePassXC" \ signtool sign -f "${key}" -p "${password}" -d "KeePassXC" \
-t "http://timestamp.comodoca.com/authenticode" "${f}" -t "http://timestamp.comodoca.com/authenticode" "${f}"
if [ 0 -ne $? ]; then if [ 0 -ne $? ]; then

View file

@ -345,7 +345,7 @@ if(MINGW)
string(REGEX REPLACE "-snapshot$" "" KEEPASSXC_VERSION_CLEAN ${KEEPASSXC_VERSION}) string(REGEX REPLACE "-snapshot$" "" KEEPASSXC_VERSION_CLEAN ${KEEPASSXC_VERSION})
set(CPACK_GENERATOR "ZIP;NSIS") set(CPACK_GENERATOR "ZIP;NSIS")
set(CPACK_STRIP_FILES ON) set(CPACK_STRIP_FILES OFF)
set(CPACK_PACKAGE_FILE_NAME "${PROGNAME}-${KEEPASSXC_VERSION}-${OUTPUT_FILE_POSTFIX}") set(CPACK_PACKAGE_FILE_NAME "${PROGNAME}-${KEEPASSXC_VERSION}-${OUTPUT_FILE_POSTFIX}")
set(CPACK_PACKAGE_INSTALL_DIRECTORY ${PROGNAME}) set(CPACK_PACKAGE_INSTALL_DIRECTORY ${PROGNAME})
set(CPACK_PACKAGE_VERSION ${KEEPASSXC_VERSION_CLEAN}) set(CPACK_PACKAGE_VERSION ${KEEPASSXC_VERSION_CLEAN})