diff --git a/.github/workflows/MacOS-pack.yml b/.github/workflows/MacOS-pack.yml index 38a37bc9..cb51bd8a 100644 --- a/.github/workflows/MacOS-pack.yml +++ b/.github/workflows/MacOS-pack.yml @@ -4,7 +4,6 @@ on: push: branches: - master - - fix* paths-ignore: - 'README.md' - 'LICENSE' @@ -36,25 +35,7 @@ jobs: runs-on: ${{ matrix.dist.os }} env: APP_NAME: flameshot - DIR_BULD: build - DIR_PKG: build/src - HELPERS_SCRIPTS_PATH: ../../packaging/macos - # Apple developer identity, example: "Developer ID Application: (code)" - # Note: no signing and notarization will be proceed if this variable is not set - APPLE_DEV_IDENTITY: ${{ secrets.APPLE_DEV_IDENTITY }} - # Apple ID user - APPLE_DEV_USER: ${{ secrets.APPLE_DEV_USER }} - # Apple ID user password - APPLE_DEV_PASS: ${{ secrets.APPLE_DEV_PASS }} - # Apple certificate with private and public keys in base64 format - APPLE_DEVELOPER_ID_APPLICATION_CERT_DATA: ${{ secrets.APPLE_DEVELOPER_ID_APPLICATION_CERT_DATA }} - # Apple certificate password - APPLE_DEVELOPER_ID_APPLICATION_CERT_PASS: ${{ secrets.APPLE_DEVELOPER_ID_APPLICATION_CERT_PASS }} - # Any temporary password for keychain, which will be created on github actions CI - APPLE_TEMP_CI_KEYCHAIN_PASS: ${{ secrets.APPLE_TEMP_CI_KEYCHAIN_PASS }} - # Temporary variable for internal use, it will be set on the "Build dmg" step - NOTARIZATION_CHECK: false - + DIR_BUILD: build steps: - name: Checkout Source code if: github.event_name == 'push' @@ -83,6 +64,9 @@ jobs: echo ${last_committed_tag:1} echo "Details: ${ver_info}" echo "================================" + # This will allow to build pre-preleases without git tag + # echo "VERSION=${last_committed_tag:1}" >> $GITHUB_ENV + echo "VERSION=$(cat CMakeLists.txt |grep 'set.*(.*FLAMESHOT_VERSION' | sed 's/[^0-9.]*//' |sed 's/)//g')" >> $GITHUB_ENV echo "VER_INFO=${ver_info}" >> $GITHUB_ENV - name: Install Qt @@ -90,36 +74,21 @@ jobs: - name: Configure run: | - rm -rf "${DIR_BULD}"/src/flameshot.dmg "${DIR_BULD}"/src/flameshot.app/ - cmake -S . -B "${DIR_BULD}" -DQt6_DIR=$(brew --prefix qt6)/lib/cmake/Qt6 -DUSE_MONOCHROME_ICON=True + rm -rf "${DIR_BUILD}"/src/flameshot.dmg "${DIR_BUILD}"/src/flameshot.app/ + cmake -GNinja -S . -B "${DIR_BUILD}" -DQt6_DIR=$(brew --prefix qt6)/lib/cmake/Qt6 -DUSE_MONOCHROME_ICON=True - name: Compile run: | - cmake --build "${DIR_BULD}" - - - name: Create key-chain and import certificate - run: | - cd "${DIR_PKG}" - ${HELPERS_SCRIPTS_PATH}/create_keychain.sh flameshot + cmake --build "${DIR_BUILD}" - name: Build dmg package run: | - cd "${DIR_PKG}" - ${HELPERS_SCRIPTS_PATH}/sign_qtapp.sh flameshot + cd "${DIR_BUILD}" + ninja create_dmg - name: Artifact Upload uses: actions/upload-artifact@v4 with: name: ${{ env.PRODUCT }}-${{ env.VER_INFO }}-artifact-macos-${{ matrix.dist.arch }} - path: ${{ github.workspace }}/build/src/flameshot.dmg - overwrite: true - - - name: Notarization status - shell: bash - run: | - if [[ "${NOTARIZATION_CHECK}" == "true" ]]; then - echo "Notarization check succeed" - else - echo "::warning Notarization check failed" - # exit 1 - fi + path: ${{ github.workspace }}/build/src/Flameshot-${{ env.VERSION }}.dmg + overwrite: true \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 51801c60..f90e62c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,8 +80,6 @@ if(WIN32) add_definitions(-DFLAMESHOT_VERSION_STRING="${PROJECT_VERSION}") elseif(APPLE) set(Qt6_DIR "$(brew --prefix qt6)/lib/cmake/Qt6/" CACHE PATH "directory where Qt6Config.cmake exists.") - set(CMAKE_MACOSX_BUNDLE ON) - set(CMAKE_MACOSX_RPATH ON) endif() set(RUN_IN_PLACE ${DEFAULT_RUN_IN_PLACE} diff --git a/packaging/macos/Info.plist b/packaging/macos/Info.plist deleted file mode 100644 index 1ae6106a..00000000 --- a/packaging/macos/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleExecutable - Flameshot - CFBundleIconFile - flameshot - CFBundleIdentifier - com.Flameshot.flameshot - CFBundlePackageType - APPL - CFBundleSignature - ???? - LSMinimumSystemVersion - 10.13 - NOTE - This file was generated by Qt/QMake. - NSPrincipalClass - NSApplication - NSSupportsAutomaticGraphicsSwitching - - - diff --git a/packaging/macos/create_dmg.sh b/packaging/macos/create_dmg.sh new file mode 100755 index 00000000..3c53eb20 --- /dev/null +++ b/packaging/macos/create_dmg.sh @@ -0,0 +1,96 @@ +#!/bin/bash + +# Script to create and optionally sign a DMG file +# Usage: create_dmg.sh +# If signing identities are empty, DMG will be created unsigned + +APP_PATH="$1" +DMG_PATH="$2" +APP_SIGN_IDENTITY="$3" +DMG_SIGN_IDENTITY="$4" + +if [ $# -ne 4 ]; then + echo "Usage: create_dmg.sh " + echo "Note: Leave signing identities empty to create unsigned DMG" + exit 1 +fi + +echo "Creating DMG from: $APP_PATH" +echo "Output DMG: $DMG_PATH" + +rm -f "$DMG_PATH" + +TEMP_DIR=$(mktemp -d) +echo "Using temp directory: $TEMP_DIR" + +cp -R "$APP_PATH" "$TEMP_DIR/" + +# Create Applications symlink +ln -s /Applications "$TEMP_DIR/Applications" + +# Calculate size needed for DMG (in KB) +SIZE=$(du -sk "$TEMP_DIR" | cut -f1) +SIZE=$((SIZE + 1000)) # Add some padding + +echo "Creating DMG with size: ${SIZE}k" + +# Create DMG +hdiutil create -srcfolder "$TEMP_DIR" \ + -volname "Flameshot" \ + -fs HFS+ \ + -fsargs "-c c=64,a=16,e=16" \ + -format UDZO \ + -size ${SIZE}k \ + "$DMG_PATH" + +if [ $? -ne 0 ]; then + echo "Failed to create DMG" + rm -rf "$TEMP_DIR" + exit 1 +fi + +echo "DMG created successfully" + +# Sign the DMG (either with identity or ad hoc) +if [ -n "$DMG_SIGN_IDENTITY" ] && [ "$DMG_SIGN_IDENTITY" != "" ]; then + echo "Signing DMG with identity: $DMG_SIGN_IDENTITY" + codesign --force --sign "$DMG_SIGN_IDENTITY" --timestamp "$DMG_PATH" + + if [ $? -eq 0 ]; then + echo "DMG signed with Developer ID" + # Verify signature + echo "Verifying DMG signature..." + codesign --verify --verbose "$DMG_PATH" + else + echo "Failed to sign DMG with identity" + rm -rf "$TEMP_DIR" + exit 1 + fi +else + echo "Signing DMG with ad hoc signature (no identity required)" + codesign --force --sign - "$DMG_PATH" + + if [ $? -eq 0 ]; then + echo "DMG signed with ad hoc signature" + else + echo "Failed to ad hoc sign DMG" + rm -rf "$TEMP_DIR" + exit 1 + fi +fi + +# Clean up +rm -rf "$TEMP_DIR" + +echo "DMG creation complete: $DMG_PATH" + +if [ -z "$DMG_SIGN_IDENTITY" ] || [ "$DMG_SIGN_IDENTITY" = "" ]; then + echo "" + echo "NOTE: This DMG uses ad hoc signing (no Developer ID required)." + echo "Users will see a security warning but can still run the app by:" + echo "1. Right-clicking the app and selecting 'Open'" + echo "2. Or going to System Preferences > Security & Privacy and clicking 'Open Anyway'" + echo "3. The warning only appears on first launch" + echo "" + echo "The app and DMG are properly signed for Apple Silicon requirements." +fi diff --git a/packaging/macos/create_keychain.sh b/packaging/macos/create_keychain.sh deleted file mode 100755 index fb4ca17a..00000000 --- a/packaging/macos/create_keychain.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -# Inspired by -# https://localazy.com/blog/how-to-automatically-sign-macos-apps-using-github-actions - -TEMP_CI_CERT_FILENAME="temp_ci_appleDistribution.p12" - -# Get the following variables from MacOS-pack.yaml: -# APP_NAME -# APPLE_DEV_IDENTITY -# APPLE_DEVELOPER_ID_APPLICATION_CERT_PASS -# APPLE_DEVELOPER_ID_APPLICATION_CERT_DATA -# APPLE_TEMP_CI_KEYCHAIN_PASS - -# For the Community (if no Apple Developer ID available) -if [[ "${APPLE_DEV_IDENTITY}" == "" ]]; then - echo "WARNING: No credentials for signing found" - echo "WARNING: Cannot create keychain for signing" - echo "WARNING: dmg package won't be signed and notarized" - exit 0 -fi - -# create keychain -security create-keychain -p "${APPLE_TEMP_CI_KEYCHAIN_PASS}" build.keychain -security default-keychain -s build.keychain -security unlock-keychain -p "${APPLE_TEMP_CI_KEYCHAIN_PASS}" build.keychain - -# import certificate -[ -r "${TEMP_CI_CERT_FILENAME}" ] && rm "${TEMP_CI_CERT_FILENAME}" -echo "${APPLE_DEVELOPER_ID_APPLICATION_CERT_DATA}" | base64 --decode > "${TEMP_CI_CERT_FILENAME}" -security import "${TEMP_CI_CERT_FILENAME}" -P "${APPLE_DEVELOPER_ID_APPLICATION_CERT_PASS}" -k build.keychain -T /usr/bin/codesign -[ -r "${TEMP_CI_CERT_FILENAME}" ] && rm "${TEMP_CI_CERT_FILENAME}" -security find-identity -v -security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "${APPLE_TEMP_CI_KEYCHAIN_PASS}" build.keychain diff --git a/packaging/macos/flameshot.icns b/packaging/macos/flameshot.icns deleted file mode 100644 index b8db080f..00000000 Binary files a/packaging/macos/flameshot.icns and /dev/null differ diff --git a/packaging/macos/sign_qtapp.sh b/packaging/macos/sign_qtapp.sh deleted file mode 100755 index be49af0f..00000000 --- a/packaging/macos/sign_qtapp.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash -# Inspired by -# https://localazy.com/blog/how-to-automatically-sign-macos-apps-using-github-actions -# https://forum.qt.io/topic/96652/how-to-notarize-qt-application-on-macos/18 - -# Get the following variables from the MacOS-pack.yaml: -# APP_NAME -# APPLE_DEV_IDENTITY -# APPLE_DEV_USER -# APPLE_DEV_PASS - -# For the Community (if no Apple Developer ID available) -if [[ "${APPLE_DEV_IDENTITY}" == "" ]]; then - echo "WARNING: No credentials for signing found" - echo "WARNING: dmg package won't be signed and notarized" - echo "--> Start packaging process" - "$(brew --prefix qt6)/bin/macdeployqt" "${APP_NAME}.app" -dmg - echo "--> Update dmg package links" - "./${HELPERS_SCRIPTS_PATH}/update_package.sh" - exit 0 -fi - -echo "--> Start application signing process" -codesign --sign "${APPLE_DEV_IDENTITY}" --verbose --deep "${APP_NAME}.app" - -echo "--> Start packaging process" -"$(brew --prefix qt6)/bin/macdeployqt" "${APP_NAME}.app" -dmg -sign-for-notarization="${APPLE_DEV_IDENTITY}" - -echo "--> Update dmg package links" -"./${HELPERS_SCRIPTS_PATH}/update_package.sh" - -echo "--> Start dmg signing process" -codesign --sign "${APPLE_DEV_IDENTITY}" --verbose --deep "${APP_NAME}.dmg" - -echo "--> Start Notarization process" -response=$(xcrun altool -t osx -f "${APP_NAME}.dmg" --primary-bundle-id "org.namecheap.${APP_NAME}" --notarize-app -u "${APPLE_DEV_USER}" -p "${APPLE_DEV_PASS}") -requestUUID=$(echo "${response}" | tr ' ' '\n' | tail -1) - -for ((ATTEMPT=5; ATTEMPT>=1; ATTEMPT--)) -do - echo "--> Checking notarization status" - statusCheckResponse=$(xcrun altool --notarization-info "${requestUUID}" -u "${APPLE_DEV_USER}" -p "${APPLE_DEV_PASS}") - - isSuccess=$(echo "${statusCheckResponse}" | grep "success") - isFailure=$(echo "${statusCheckResponse}" | grep "invalid") - - if [[ "${isSuccess}" != "" ]]; then - echo "Notarization done!" - xcrun stapler staple "${APP_NAME}.dmg" - EXIT_CODE=$? - if [ ${EXIT_CODE} -ne 0 ]; then - echo "Stapler failed!" - exit ${EXIT_CODE} - fi - echo "Stapler done!" - break - fi - if [[ "${isFailure}" != "" ]]; then - echo "${statusCheckResponse}" - echo "Notarization failed" - exit 1 - fi - - echo "Notarization not finished yet, sleep 2m then check again..." - for num in {1..12} - do - sleep 10 - echo "Elapsed: ${num}0 sec" - done -done - -if [[ "${ATTEMPT}" == 0 ]]; then - export NOTARIZATION_CHECK="false" - echo "::warning Notarization check failed" -else - export NOTARIZATION_CHECK="true" -fi - -echo "--> Start verify signing process" -codesign -dv --verbose=4 "${APP_NAME}.dmg" diff --git a/packaging/macos/update_package.sh b/packaging/macos/update_package.sh deleted file mode 100755 index 24736d4d..00000000 --- a/packaging/macos/update_package.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/bash - -echo "Change the permission of .dmg file" -hdiutil convert "flameshot.dmg" -format UDRW -o "flameshot_rw.dmg" - -echo "Mount it and save the device" -DEVICE=$(hdiutil attach -readwrite -noverify "flameshot_rw.dmg" | grep -E '^/dev/' | sed 1q | awk '{print $1}') -sleep 5 - -echo "Create the sysmbolic link to application folder" -PATH_AT_VOLUME="/Volumes/flameshot/" -CURRENT_PATH="$(pwd)" -cd "${PATH_AT_VOLUME}" -ln -s /Applications -cd "${CURRENT_PATH}" - -# TODO - add background and icon location. -# https://forum.qt.io/topic/94987/how-can-i-add-symbolic-link-application-and-background-image-in-dmg-package/3 -#echo "copy the background image in to package" -#mkdir -p "${PATH_AT_VOLUME}".background/ -#cp backgroundImage.png "${PATH_AT_VOLUME}".background/ -#echo "done" -# -## tell the Finder to resize the window, set the background, -## change the icon size, place the icons in the right position, etc. -#echo ' -# tell application "Finder" -# tell disk "/Volumes/src:flameshot" -# open -# set current view of container window to icon view -# set toolbar visible of container window to false -# set statusbar visible of container window to false -# set the bounds of container window to {400, 100, 1110, 645} -# set viewOptions to the icon view options of container window -# set arrangement of viewOptions to not arranged -# set icon size of viewOptions to 72 -# set background picture of viewOptions to file ".background:backgroundImage.png" -# set position of item "flameshot.app" of container window to {160, 325} -# set position of item "Applications" of container window to {560, 320} -# close -# open -# update without registering applications -# delay 2 -# end tell -# end tell -#' | osascript -# -#sync - -# unmount it -hdiutil detach "${DEVICE}" -rm -f "flameshot.dmg" - -hdiutil convert "flameshot_rw.dmg" -format UDZO -o "flameshot.dmg" -rm -f "flameshot_rw.dmg" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f408314c..1ae2e268 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -229,12 +229,14 @@ if (USE_WAYLAND_CLIPBOARD) endif() if (APPLE) - set(MACOSX_BUNDLE_IDENTIFIER "org.flameshot") - set_target_properties( - flameshot - PROPERTIES - XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER ${MACOSX_BUNDLE_IDENTIFIER} - ) + set_target_properties(flameshot PROPERTIES + MACOSX_BUNDLE TRUE + MACOSX_BUNDLE_BUNDLE_NAME "Flameshot" + MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} + MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION} + MACOSX_BUNDLE_IDENTIFIER "org.flameshot.Flameshot" + MACOSX_BUNDLE_GUI_IDENTIFIER "org.flameshot.Flameshot" + ) target_link_libraries( flameshot qhotkey @@ -443,18 +445,62 @@ endif () # macdeployqt if (APPLE) - set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/") - execute_process(COMMAND brew --prefix qt5 OUTPUT_VARIABLE QTDIR) - string(REGEX REPLACE "\n$" "" QTDIR "${QTDIR}") - set(MAC_DEPLOY_QT ${QTDIR}/bin/macdeployqt) - if (EXISTS ${MAC_DEPLOY_QT}) - set_source_files_properties(resources/icon.icns PROPERTIES - MACOSX_PACKAGE_LOCATION Resources) +# Code signing settings - optional, set to empty string to skip signing + set(CODE_SIGN_IDENTITY "" CACHE STRING "Code signing identity (leave empty to skip signing)") + set(DMG_SIGN_IDENTITY "" CACHE STRING "DMG signing identity (leave empty to skip signing)") + # Custom target to create DMG (signed or unsigned) + add_custom_target(create_dmg + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/../packaging/macos/create_dmg.sh + "${CMAKE_CURRENT_BINARY_DIR}/Flameshot.app" + "${CMAKE_CURRENT_BINARY_DIR}/Flameshot-${PROJECT_VERSION}.dmg" + "${CODE_SIGN_IDENTITY}" + "${DMG_SIGN_IDENTITY}" + DEPENDS flameshot + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Creating DMG" + VERBATIM + ) + +# Always sign the app bundle (either with identity or ad hoc) + if(CODE_SIGN_IDENTITY AND NOT CODE_SIGN_IDENTITY STREQUAL "") + # Identity-based signing (requires Developer ID) + add_custom_command(TARGET flameshot POST_BUILD + COMMAND codesign --force --deep --sign "${CODE_SIGN_IDENTITY}" + --options runtime --timestamp "$" + COMMENT "Code signing app bundle with ${CODE_SIGN_IDENTITY}" + ) + else() + # Ad hoc signing + add_custom_command(TARGET flameshot POST_BUILD + COMMAND codesign --force --deep --sign - "$" + COMMENT "Ad hoc code signing app bundle (no identity required)" + ) + endif() + # Deploy Qt libraries and dependencies + find_program(MACDEPLOYQT_EXECUTABLE macdeployqt HINTS ${Qt6_DIR}/../../../bin) + + if(MACDEPLOYQT_EXECUTABLE) + add_custom_command(TARGET flameshot POST_BUILD + COMMAND ${MACDEPLOYQT_EXECUTABLE} "$" -verbose=2 + COMMENT "Deploying Qt libraries" + ) + + # Re-sign after macdeployqt (it modifies the bundle) + if(CODE_SIGN_IDENTITY AND NOT CODE_SIGN_IDENTITY STREQUAL "") + add_custom_command(TARGET flameshot POST_BUILD + COMMAND codesign --force --deep --sign "${CODE_SIGN_IDENTITY}" + --options runtime --timestamp "$" + COMMENT "Re-signing app bundle after Qt deployment" + ) + else() + add_custom_command(TARGET flameshot POST_BUILD + COMMAND codesign --force --deep --sign - "$" + COMMENT "Re-signing app bundle after Qt deployment (ad hoc)" + ) + endif() + else() + message(WARNING "macdeployqt not found. App may not run on systems without Qt installed.") + endif() + - set_target_properties(${target} PROPERTIES - MACOSX_BUNDLE TRUE - ) - else () - message("Unable to find executable ${MAC_DEPLOY_QT}.") - endif () endif ()