diff --git a/contrib/release/macos/Liana.app/Contents/Info.plist b/contrib/release/macos/Liana.app/Contents/Info.plist new file mode 100644 index 00000000..46f57151 --- /dev/null +++ b/contrib/release/macos/Liana.app/Contents/Info.plist @@ -0,0 +1,44 @@ + + + + + + + CFBundleName + Liana + + CFBundleDisplayName + Liana + + CFBundleIdentifier + com.wizardsardine.liana + + CFBundleVersion + VERSION_PLACEHOLDER + + CFBundleShortVersionString + VERSION_PLACEHOLDER + + CFBundlePackageType + APPL + + CFBundleSignature + ???? + + CFBundleExecutable + Liana + + LSMinimumSystemVersion + 10.15.0 + + CFBundleIconFile + Liana.icns + + NSPrincipalClass + NSApplication + + LSApplicationCategoryType + public.app-category.finance + + + diff --git a/contrib/release/macos/dmg_template/Liana.app/Contents/PkgInfo b/contrib/release/macos/Liana.app/Contents/PkgInfo similarity index 100% rename from contrib/release/macos/dmg_template/Liana.app/Contents/PkgInfo rename to contrib/release/macos/Liana.app/Contents/PkgInfo diff --git a/contrib/release/macos/Liana.app/Contents/Resources/Liana.icns b/contrib/release/macos/Liana.app/Contents/Resources/Liana.icns new file mode 100644 index 00000000..5fa35a07 Binary files /dev/null and b/contrib/release/macos/Liana.app/Contents/Resources/Liana.icns differ diff --git a/contrib/release/macos/README.md b/contrib/release/macos/README.md new file mode 100644 index 00000000..82074e6c --- /dev/null +++ b/contrib/release/macos/README.md @@ -0,0 +1,84 @@ +# MacOS packaging and distribution + +We distribute the application as a zipped [MacOS app bundle](https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html#//apple_ref/doc/uid/10000123i-CH101-SW5). + +## Notes on codesigning and notarization + +Running a binary on a Mac that was not both codesigned **and** notarized by Apple is a pain. The +user needs to run it. Get an error message. Go to System preferences > Security > authorize the app. +Then try again, and finally be presented a button to open the app. + +In order to avoid that, we've started distributing codesigned binaries starting from version 1.0. +This is the notes i've taken describing the stepped involved in codesigning the produced macOS +binary on a Linux machine, for posterity. This is not cleaned up. + +### Bulk notes from the codesigning experiment + +Create an account at https://developer.apple.com. + +Pay to get into the developer program. Going the organization way is cumbersome. Go the personal +way. They'll ask for a KYC (gov ID). Wait to be accepted. + +Go to "certificates, ids and profiles". Create a new certificate. Select a Developer ID application +certificate to distribute apps outside of the store. + +(We should look into the installer feature later on. Maybe we could bundle a bitcoind there.) + +They ask for a "Certificate Signing Request (CSR)" that you need to generate on your Mac. I don't +have a Mac. Generate it using OpenSSL: +``` +openssl genrsa -out wizardsardine_liana.key 2048 +openssl req -new -sha256 -key wizardsardine_liana.key -out wizardsardine_liana_codesigning.csr -subj "/emailAddress=antoine@wizardsardine.com, CN=Antoine Poinsot, C=FR" +``` +(Note you have no choice in the size or type of the key here, they expect a RSA(2048) key.) + +For the profile type select "G2 Sub-CA". We are using an Xcode newer than 11.4.1 and the codesigning +tool we use supports the new CA. + +Now you get to be able to download your certificate (I've stored it as +"antoine_devid_liana_codesigning.cer"). Thankfully `rcodesign` supports various certificate format, +so we don't even have to convert it to PEM. + +Download `rcodesign`: +``` +curl -OL https://github.com/indygreg/apple-platform-rs/releases/download/apple-codesign%2F0.22.0/apple-codesign-0.22.0-x86_64-unknown-linux-musl.tar.gz +tar -xzf apple-codesign-0.22.0-x86_64-unknown-linux-musl.tar.gz +./apple-codesign-0.22.0-x86_64-unknown-linux-musl/rcodesign --help +``` + +Sign the packaged application using the `sign` command (mind `--code-signature-flags for the +necessary hardened runtime): +``` +./apple-codesign-0.22.0-x86_64-unknown-linux-musl/rcodesign sign --code-signature-flags runtime --pem-source wizardsardine_liana.key --der-source antoine_devid_liana_codesigning.cer Liana.app +``` +You can see the chain of certificates was applied using the `diff-signatures` command against +another bundle. The best way to verify the signature is by using the `codesign` command on a Mac. + +Finally, we need to notarize the app. Follow the instructions at +https://gregoryszorc.com/docs/apple-codesign/main/apple_codesign_rcodesign.html#notarizing-and-stapling: +- Create an API key from https://appstoreconnect.apple.com/ (and *not* a key from + https://developer.apple.com/account/resources/authkeys) +- Download it and encode it into a JSON file using the `encode-app-store-connect-api-key` command +- Use the `notary-submit` command to request notarization + +``` +./apple-codesign-0.22.0-x86_64-unknown-linux-musl/rcodesign notary-submit --max-wait-seconds 600 --api-key-path ./encoded_appstore_api_key.json --staple Liana.app +``` +According to +https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution/customizing_the_notarization_workflow#3087732 +this can take up to a hour. I've experienced more. You can see the status of an existing request +using the `notary-log` command. + + +------- + +Resources: +- https://gist.github.com/jcward/d08b33fc3e6c5f90c18437956e5ccc35 +- https://github.com/achow101/signapple +- https://developer.apple.com/library/archive/technotes/tn2206/_index.html#//apple_ref/doc/uid/DTS40007919 +- https://gregoryszorc.com/docs/apple-codesign/main/index.html +- https://www.apple.com/certificateauthority/ +- https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution + +Resources on packaging an application for MacOS: +- https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html#//apple_ref/doc/uid/10000123i-CH101-SW5 diff --git a/contrib/release/macos/dmg_template/.background/background.tiff b/contrib/release/macos/dmg_template/.background/background.tiff deleted file mode 100644 index 1fb088c8..00000000 Binary files a/contrib/release/macos/dmg_template/.background/background.tiff and /dev/null differ diff --git a/contrib/release/macos/dmg_template/Liana.app/Contents/Info.plist b/contrib/release/macos/dmg_template/Liana.app/Contents/Info.plist deleted file mode 100644 index fdf5b58b..00000000 --- a/contrib/release/macos/dmg_template/Liana.app/Contents/Info.plist +++ /dev/null @@ -1,69 +0,0 @@ - - - - - LSMinimumSystemVersion - 10.15.0 - - LSArchitecturePriority - - x86_64 - - - - - - - CFBundlePackageType - APPL - - CFBundleSupportedPlatforms - - MacOSX - - - CFBundleShortVersionString - VERSION_PLACEHOLDER - - CFBundleVersion - VERSION_PLACEHOLDER - - CFBundleSignature - ???? - - CFBundleExecutable - Liana - - CFBundleName - Liana - - LSHasLocalizedDisplayName - - - CFBundleIdentifier - org.wizardsardine.liana - - CFBundleURLTypes - - - CFBundleTypeRole - Editor - CFBundleURLName - org.wizardsardine.liana - CFBundleURLSchemes - - liana - - - - - NSPrincipalClass - NSApplication - - NSHighResolutionCapable - True - - LSApplicationCategoryType - public.app-category.finance - - diff --git a/contrib/release/macos/gen_dstore.py b/contrib/release/macos/gen_dstore.py deleted file mode 100644 index d9c70ad2..00000000 --- a/contrib/release/macos/gen_dstore.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -Script to generate a .DS_Store within the dmg folder to have a neat fancy window -when installing the software on macOS. - -This was taken and adapted from the Bitcoin Core 'macdeployqtplus' script. -https://github.com/bitcoin/bitcoin/blob/cb32328d1b80d0ccd6eb9532bd8fe4e0a4de385e/contrib/macdeploy/macdeployqtplus -""" - -from ds_store import DSStore -from mac_alias import Alias - - -output_file = ".DS_Store" - -ds = DSStore.open(output_file, "w+") - -ds["."]["bwsp"] = { - "WindowBounds": "{{300, 280}, {500, 343}}", - "PreviewPaneVisibility": False, -} - -icvp = { - "gridOffsetX": 0.0, - "textSize": 12.0, - "viewOptionsVersion": 1, - "backgroundImageAlias": b"\x00\x00\x00\x00\x02\x1e\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd1\x94\\\xb0H+\x00\x05\x00\x00\x00\x98\x0fbackground.tiff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x99\xd19\xb0\xf8\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\r\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b.background\x00\x00\x10\x00\x08\x00\x00\xd1\x94\\\xb0\x00\x00\x00\x11\x00\x08\x00\x00\xd19\xb0\xf8\x00\x00\x00\x01\x00\x04\x00\x00\x00\x98\x00\x0e\x00 \x00\x0f\x00b\x00a\x00c\x00k\x00g\x00r\x00o\x00u\x00n\x00d\x00.\x00t\x00i\x00f\x00f\x00\x0f\x00\x02\x00\x00\x00\x12\x00\x1c/.background/background.tiff\x00\x14\x01\x06\x00\x00\x00\x00\x01\x06\x00\x02\x00\x00\x0cMacintosh HD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xce\x97\xab\xc3H+\x00\x00\x01\x88[\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02u\xab\x8d\xd1\x94\\\xb0devrddsk\xff\xff\xff\xff\x00\x00\t \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07bitcoin\x00\x00\x10\x00\x08\x00\x00\xce\x97\xab\xc3\x00\x00\x00\x11\x00\x08\x00\x00\xd1\x94\\\xb0\x00\x00\x00\x01\x00\x14\x01\x88[\x88\x00\x16\xa9\t\x00\x08\xfaR\x00\x08\xfaQ\x00\x02d\x8e\x00\x0e\x00\x02\x00\x00\x00\x0f\x00\x1a\x00\x0c\x00M\x00a\x00c\x00i\x00n\x00t\x00o\x00s\x00h\x00 \x00H\x00D\x00\x13\x00\x01/\x00\x00\x15\x00\x02\x00\x14\xff\xff\x00\x00\xff\xff\x00\x00", - "backgroundColorBlue": 1.0, - "iconSize": 96.0, - "backgroundColorGreen": 1.0, - "arrangeBy": "none", - "showIconPreview": True, - "gridSpacing": 100.0, - "gridOffsetY": 0.0, - "showItemInfo": False, - "labelOnBottom": True, - "backgroundType": 2, - "backgroundColorRed": 1.0, -} -alias = Alias().from_bytes(icvp["backgroundImageAlias"]) -alias.volume.name = "Liana" -alias.volume.posix_path = "/Volumes/Liana" -icvp["backgroundImageAlias"] = alias.to_bytes() -ds["."]["icvp"] = icvp - -ds["."]["vSrn"] = ("long", 1) - -ds["Applications"]["Iloc"] = (370, 156) -ds["Liana.app"]["Iloc"] = (128, 156) - -ds.flush() -ds.close() diff --git a/contrib/release/release.sh b/contrib/release/release.sh index 86f00faa..179492aa 100755 --- a/contrib/release/release.sh +++ b/contrib/release/release.sh @@ -15,6 +15,11 @@ WINDOWS_DIR_NAME="$LIANA_PREFIX-x86_64-windows-gnu" WINDOWS_ARCHIVE="$WINDOWS_DIR_NAME.zip" MAC_DIR_NAME="$LIANA_PREFIX-x86_64-apple-darwin" MAC_ARCHIVE="$MAC_DIR_NAME.tar.gz" +MAC_CODESIGN="${MAC_CODESIGN:-"0"}" +RCODESIGN_BIN="${RCODESIGN_BIN:-"$PWD/../../macos_codesigning/apple-codesign-0.22.0-x86_64-unknown-linux-musl/rcodesign"}" +CODESIGN_KEY="${CODESIGN_KEY:-"$PWD/../../macos_codesigning/wizardsardine_liana.key"}" +CODESIGN_CERT="${CODESIGN_CERT:-"$PWD/../../macos_codesigning/antoine_devid_liana_codesigning.cer"}" +NOTARY_API_CREDS_FILE="${NOTARY_API_CREDS_FILE:-"$PWD/../../macos_codesigning/encoded_appstore_api_key.json"}" create_dir() { test -d "$1" || mkdir "$1" @@ -48,7 +53,7 @@ TARGET_DIR="$BUILD_DIR" ./contrib/reproducible/docker/docker-build.sh cp "$BUILD_DIR/gui/x86_64-pc-windows-gnu/release/liana-gui.exe" "$RELEASE_DIR/$LIANA_PREFIX.exe" ) -# Create the MacOS archive and the DMG +# Create the MacOS archive and a zipped application bundle of liana-gui. ( cd "$BUILD_DIR" create_dir "$MAC_DIR_NAME" @@ -56,19 +61,18 @@ TARGET_DIR="$BUILD_DIR" ./contrib/reproducible/docker/docker-build.sh tar -czf "$MAC_ARCHIVE" "$MAC_DIR_NAME" cp "$MAC_ARCHIVE" "$RELEASE_DIR" - DMG_DIR="liana-$VERSION" - cp -r ../contrib/release/macos/dmg_template "$DMG_DIR" - sed -i "s/VERSION_PLACEHOLDER/$VERSION/g" "$DMG_DIR/Liana.app/Contents/Info.plist" - ln -s /Applications "$DMG_DIR/Applications" - python3 -m venv venv - . venv/bin/activate - pip install ds_store mac_alias - python3 ../contrib/release/macos/gen_dstore.py - mv .DS_Store "$DMG_DIR/" - cp "$BUILD_DIR/gui/x86_64-apple-darwin/release/liana-gui" "$DMG_DIR/Liana.app/Contents/MacOS/Liana" - DMG_FILE="liana-$VERSION.dmg" - xorrisofs -D -l -V Liana -no-pad -r -dir-mode 0755 -o "$DMG_FILE" "$DMG_DIR" - cp "$DMG_FILE" "$RELEASE_DIR/" + cp -r ../contrib/release/macos/Liana.app ./ + sed -i "s/VERSION_PLACEHOLDER/$VERSION/g" ./Liana.app/Contents/Info.plist + cp "$BUILD_DIR/gui/x86_64-apple-darwin/release/liana-gui" ./Liana.app/Contents/MacOS/Liana + zip -ry Liana-noncodesigned.zip Liana.app + cp ./Liana-noncodesigned.zip "$RELEASE_DIR/" + + if [ "$MAC_CODESIGN" = "1" ]; then + $RCODESIGN_BIN sign --digest sha256 --code-signature-flags runtime --pem-source "$CODESIGN_KEY" --der-source "$CODESIGN_CERT" Liana.app/ + $RCODESIGN_BIN notary-submit --max-wait-seconds 600 --api-key-path "$NOTARY_API_CREDS_FILE" --staple Liana.app + zip -ry Liana.zip Liana.app + cp ./Liana.zip "$RELEASE_DIR/" + fi ) # Finally, sign all the assets diff --git a/contrib/reproducible/docker/docker-build.sh b/contrib/reproducible/docker/docker-build.sh index 6c86dc5b..6a47f2c3 100755 --- a/contrib/reproducible/docker/docker-build.sh +++ b/contrib/reproducible/docker/docker-build.sh @@ -5,6 +5,8 @@ set -ex TARGET_DIR="${TARGET_DIR:-"$PWD/deter_build_target"}" XCODE_PATH="${XCODE_PATH:-"$PWD/Xcode_12.2.xip"}" +XCODE_FILENAME="$(basename $XCODE_PATH)" +XCODE_SHASUM="28d352f8c14a43d9b8a082ac6338dc173cb153f964c6e8fb6ba389e5be528bd0" # Build (only) the Liana GUI on Windows. docker build . -t liana_cross_win -f contrib/reproducible/docker/windows.Dockerfile @@ -22,14 +24,14 @@ docker run --rm -ti \ # Sanity check the given MacOS SDK is the expected one. -if ! $(echo "28d352f8c14a43d9b8a082ac6338dc173cb153f964c6e8fb6ba389e5be528bd0 $(basename $XCODE_PATH)" | sha256sum -c --status); then - echo "No or invalid Xcode SDK found. Need an Xcode_12.2.xip. You can configure the path using \$XCODE_PATH."; +if ! $(echo "$XCODE_SHASUM $(basename $XCODE_PATH)" | sha256sum -c --status); then + echo "No or invalid Xcode SDK found. Need an Xcode_X.Y.xip archive whose hash is $XCODE_SHASUM. You can configure the path using \$XCODE_PATH."; exit 1; fi # Build both the Liana daemon and GUI on MacOS. docker build . -t liana_cross_mac -f contrib/reproducible/docker/macos.Dockerfile -docker run --rm -ti \ +docker run -ti \ -v "$TARGET_DIR":/liana/target \ -v "$TARGET_DIR/gui":/liana/gui/target \ -v "$PWD/contrib/reproducible/docker":/liana/docker \ @@ -43,7 +45,8 @@ docker run --rm -ti \ -v "$PWD/gui/ui/Cargo.lock":/liana/gui/ui/Cargo.lock \ -v "$PWD/gui/ui/src":/liana/gui/ui/src \ -v "$PWD/gui/ui/static":/liana/gui/ui/static \ - -v "$XCODE_PATH":/liana/Xcode_12.2.xip \ + -v "$XCODE_PATH":"/liana/$XCODE_FILENAME" \ + -e XCODE_PATH="/liana/$XCODE_FILENAME" \ liana_cross_mac set +ex diff --git a/contrib/reproducible/docker/macos_cmd.sh b/contrib/reproducible/docker/macos_cmd.sh index d5935a11..e35fa7ec 100755 --- a/contrib/reproducible/docker/macos_cmd.sh +++ b/contrib/reproducible/docker/macos_cmd.sh @@ -6,8 +6,10 @@ set -xe -# Build the SDK and the toolchain using osxcross. It is expected to be located at /liana/Xcode_12.2.xip. -# It's not part of the image to be able to share the Xcode_12.2.xip instead of copying it in the Docker context +test -f "$XCODE_PATH" || exit 1 + +# Build the SDK and the toolchain using osxcross. It is expected to be located at $XCODE_PATH +# It's not part of the image to be able to share the $XCODE_PATH instead of copying it in the Docker context # and then to the image. git clone https://github.com/darosior/osxcross -b dependencies_pinning cd osxcross @@ -15,8 +17,8 @@ git checkout 50e86ebca7d14372febd0af8cd098705049161b9 DARLING_DMG_REVISION=241238313a47d3cf6427ac5a75b7a0311a3a4cb4 \ P7ZIP_REVISION=2f60a51ac3aa2507d36df3c4f58f71a3716b1357 \ PBZX_REVISION=2a4d7c3300c826d918def713a24d25c237c8ed53 \ - XAR_REVISION=c2111a9a9cabc50d2b9c604aff41a481ae3f1989 ./tools/gen_sdk_package_pbzx.sh ../Xcode_12.2.xip -mv MacOSX11.0.sdk.tar.xz tarballs/ + XAR_REVISION=c2111a9a9cabc50d2b9c604aff41a481ae3f1989 ./tools/gen_sdk_package_pbzx.sh "$XCODE_PATH" +mv MacOSX* tarballs/ DARLING_DMG_REVISION=241238313a47d3cf6427ac5a75b7a0311a3a4cb4 \ P7ZIP_REVISION=2f60a51ac3aa2507d36df3c4f58f71a3716b1357 \ PBZX_REVISION=2a4d7c3300c826d918def713a24d25c237c8ed53 \