Merge #489: Macos distribution improvements

4471516bec5c8fd478257197dcf17d70989d208f contrib: document the macOS distribution and codesigning (Antoine Poinsot)
d387ca19915fc4d4494d6be0268005ec3d4689d5 contrib: codesigning for MacOS in the release script (Antoine Poinsot)
1a1e0c245f208487dbec1ffda11c4ca0912e1610 contrib: make the Xcode archive configurable for MacOS builds (Antoine Poinsot)
471ecd296ed6c1d50dfed0cda85f4c4d4d0756ff contrib: distribute on macOS using a zip, not a dmg (Antoine Poinsot)
eade76e3f181c383f376ac27df80bd78e8409754 contrib: add the Liana icon to the macOS distribution bundle (Antoine Poinsot)
eb26e71019f13af5a67745a0826a995bb2d0a612 contrib: cleanup macOS' Info.plist (Antoine Poinsot)

Pull request description:

  Still waiting on the notarization process to complete. But in the meantime, some cleanups of the macOS distribution process (we can now have an app with a nice logo that can be launched just by clicking on it 🎉) and (bulk) documentation of my codesigning experiment.

ACKs for top commit:
  darosior:
    ACK 4471516bec5c8fd478257197dcf17d70989d208f -- Just tested the notarized binary on a mac 🚀

Tree-SHA512: a37711b43f8153844da4b65e77d2bc054ad26f126970a0f2738b1c0fedf9da34318af7ea4795c89ebf393cfbf8a97c9d09563ab35a5c806646b7ca6c767696eb
This commit is contained in:
Antoine Poinsot 2023-05-11 11:22:01 +02:00
commit b55d76af57
No known key found for this signature in database
GPG Key ID: E13FC145CD3F4304
10 changed files with 159 additions and 142 deletions

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="0.9">
<!-- Based on https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html#//apple_ref/doc/uid/10000123i-CH101-SW5 -->
<!-- See also https://github.com/bitcoin/bitcoin/blob/master/share/qt/Info.plist.in as an example. -->
<dict>
<key>CFBundleName</key>
<string>Liana</string>
<key>CFBundleDisplayName</key>
<string>Liana</string>
<key>CFBundleIdentifier</key>
<string>com.wizardsardine.liana</string>
<key>CFBundleVersion</key>
<string>VERSION_PLACEHOLDER</string>
<key>CFBundleShortVersionString</key>
<string>VERSION_PLACEHOLDER</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleExecutable</key>
<string>Liana</string>
<key>LSMinimumSystemVersion</key>
<string>10.15.0</string>
<key>CFBundleIconFile</key>
<string>Liana.icns</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.finance</string>
</dict>
</plist>

View File

@ -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

View File

@ -1,69 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="0.9">
<dict>
<key>LSMinimumSystemVersion</key>
<string>10.15.0</string>
<key>LSArchitecturePriority</key>
<array>
<string>x86_64</string>
</array>
<!-- TODO -->
<!--<key>CFBundleIconFile</key>-->
<!--<string></string>-->
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
<key>CFBundleShortVersionString</key>
<string>VERSION_PLACEHOLDER</string>
<key>CFBundleVersion</key>
<string>VERSION_PLACEHOLDER</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleExecutable</key>
<string>Liana</string>
<key>CFBundleName</key>
<string>Liana</string>
<key>LSHasLocalizedDisplayName</key>
<true/>
<key>CFBundleIdentifier</key>
<string>org.wizardsardine.liana</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>org.wizardsardine.liana</string>
<key>CFBundleURLSchemes</key>
<array>
<string>liana</string>
</array>
</dict>
</array>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSHighResolutionCapable</key>
<string>True</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.finance</string>
</dict>
</plist>

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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 \