Building Electron Apps
Figuring out how to build SIGNED electron apps was kind of a challenge.
Windows
First, you need a signing key. I got one from SSL.com for an EV Certificate. It came with a Pin # and a Yubikey. To do the signing, I gotta insert the Yubikey and at one point it’ll prompt for the pin.
So here’s the code:
windows_cert = "../company.chained.crt"
./node_modules/.bin/electron-builder -w
osslsigncode sign -verbose -pkcs11engine /usr/local/mac-dev/lib/engines-1.1/libpkcs11.dylib -pkcs11module /Library/OpenSC/lib/opensc-pkcs11.so -h sha256 -n "App Name" -key '01' -in "./dist/App Setup $(version).exe" -out "./dist/App $(version).signed.exe" -certs $(windows_cert)
rm "./dist/App $(version).exe"
mv "./dist/App $(version).signed.exe" "./dist/App $(version).exe"
I had to install the dependencies OpenSC and libpkcs, but outside of that it was fine.
Mac
This is a little harder, it was more of a trial and error process too. And I have a few rules in the Makefile:
version = "1.1"
appleid = "example""
applepassword = "example"
app_cert = "CERT"
pkg_cert = "Developer ID Installer: CERT ID"
provisionprofilepath = "./example.provisionprofile"
tmp_id_path = "./dist/tmp.id"
mac:
make mac_app
make mac_pkg
# build sign and notarize
mac_app:
./node_modules/.bin/electron-builder -m
make mac_app_sign
make mac_app_notarize
sleep 5s
make notarize_wait id=$$(cat $(tmp_id_path))
make mac_app_staple
mac_pkg:
pkgbuild --version $(version) --install-location /Applications --component ./dist/mac/Example.app ./dist/mac/Example-$(version)-tmp.pkg
productsign --sign $(pkg_cert) "./dist/mac/Example-$(version)-tmp.pkg" "./dist/mac/Example-$(version).pkg"
rm "./dist/mac/Example-$(version)-tmp.pkg"
make mac_pkg_notarize
sleep 5s
make notarize_wait id=$$(cat $(tmp_id_path))
make mac_pkg_staple
mac_app_sign:
cp $(provisionprofilepath) "../dist/mac/Example.app/Contents/embedded.provisionprofile"
codesign --sign $(app_cert) --force --timestamp --options runtime --entitlements ../build/entitlements.mas.inherit.plist "../dist/mac/Example.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libGLESv2.dylib"
codesign --sign $(app_cert) --force --timestamp --options runtime --entitlements ../build/entitlements.mas.inherit.plist "../dist/mac/Example.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libEGL.dylib"
codesign --sign $(app_cert) --force --timestamp --options runtime --entitlements ../build/entitlements.mas.inherit.plist "../dist/mac/Example.app/Contents/Frameworks/Electron Framework.framework"
codesign --sign $(app_cert) --force --timestamp --options runtime --entitlements ../build/entitlements.mas.inherit.plist "../dist/mac/Example.app/Contents/Frameworks/ReactiveCocoa.framework"
codesign --sign $(app_cert) --force --timestamp --options runtime --entitlements ../build/entitlements.mas.inherit.plist "../dist/mac/Example.app/Contents/Frameworks/Squirrel.framework"
codesign --sign $(app_cert) --force --timestamp --options runtime --entitlements ../build/entitlements.mas.inherit.plist "../dist/mac/Example.app/Contents/Frameworks/Mantle.framework"
codesign --sign $(app_cert) --force --timestamp --options runtime --entitlements ../build/entitlements.mas.plist "../dist/mac/Example.app"
mac_app_notarize:
ditto -c -k --keepParent "./dist/mac/Example.app/" "./dist/mac/Example.zip"
xcrun altool --notarize-app --primary-bundle-id com.example.bundle -u "$(appleid)" -f "../dist/mac/Example.zip" -p "$(applepassword)" | sed "s/.*RequestUUID = \([A-Za-z0-9-]*\).*/\1/g" | sed -n 2p > $(tmp_id_path)
mac_app_staple:
xcrun stapler staple "../dist/mac/Example.app"
mac_pkg_notarize:
xcrun altool --notarize-app --primary-bundle-id com.example.bundle -u "$(appleid)" -f "../dist/mac/Example-$(version).pkg" -p "$(applepassword)" | sed "s/.*RequestUUID = \([A-Za-z0-9-]*\).*/\1/g" | sed -n 2p > $(tmp_id_path)
# has to be its own command since notarizing is asynchronous
mac_pkg_staple:
xcrun stapler staple "../dist/mac/Example-$(version).pkg"
notarize_info:
xcrun altool --notarization-info $(id) -u $(appleid) -p $(applepassword)
notarize_wait:
@while echo $$(make notarize_info id=$(id)) | grep -q "Status: in progress"; do \
echo "Waiting for Notarization to complete..."; \
sleep 30s; \
done; \
@if echo $$(make notarize_info id=$(id)) | grep -q "Status: success" ; then \
echo "NOTARIZATION: Success"; \
exit 0; \
else \
echo "NOTARIZATION: Failure"; \
exit 1; \
fi; \
list_certs:
security find-identity -v -p codesigning
The hardest part was the mac_app_sign body, as to find out everything that needing signing, I had to submit it to apple for approval, and then an automated response will tell you everything that wasn’t signed. I’ve also truncated it for many of the dependencies.