Skip to content

Commit

Permalink
Codesign OS X app inside the DMG package
Browse files Browse the repository at this point in the history
This PR fixes a frequent issue users were having where opening

`Etcher.app` would result in:



    "Etcher.app" is damaged and can't be opened. You should move it to

    the trash.



Checking the code-signature of the application returned the following

error message:



    $ spctl -a -v Etcher.app

    Etcher.app: invalid signature (code or signature have been modified)



The solution is based on the following paragraphs from Apple's "OS X

Code Signing in Depth" technical note:



https://developer.apple.com/library/mac/technotes/tn2206/_index.html



> Code signing uses extended attributes to store signatures in non-Mach-O

> executables such as script files. If the extended attributes are lost

> then the program's identity will be broken. Thus, when you ship your

> script, you must use a mechanism that preserves extended attributes.

>

> One way to guarantee preservation of extended attributes is by packing

> up your signed code in a read-write disk image (DMG) file before signing

> and then, after signing, converting to read-only. You probably don't

> need to use a disk image until the final package stage so another less

> heavy-handed method would be to use ZIP or XIP files.



In summary, what we now do is:



- Create a temporal read-write DMG image.

- Perform the code-signing *inside* the DMG image.

- Convert the temporal DMG image into a compressed read-only image.



Sadly, this custom workflow doesn't fit in `electron-packager` nor

`electron-builder`, so we had to re-implement the features those

packages provide us in a nice encapsulated way ourselves.



Signed-off-by: Juan Cruz Viotti <[email protected]>
  • Loading branch information
jviotti committed Apr 7, 2016
1 parent 3392a5e commit 77d9fad
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 27 deletions.
94 changes: 87 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
ELECTRON_PACKAGER=./node_modules/.bin/electron-packager
ELECTRON_BUILDER=./node_modules/.bin/electron-builder
ELECTRON_OSX_SIGN=./node_modules/.bin/electron-osx-sign
ELECTRON_IGNORE=$(shell node -e "console.log(require('./package.json').packageIgnore.join('|'))")
ELECTRON_VERSION=0.36.8
ETCHER_VERSION=$(shell node -e "console.log(require('./package.json').version)")
APPLICATION_NAME=$(shell node -e "console.log(require('./package.json').displayName)")
APPLICATION_DESCRIPTION=$(shell node -e "console.log(require('./package.json').description)")
APPLICATION_COPYRIGHT=$(shell node -e "console.log(require('./package.json').copyright)")
COMPANY_NAME="Resinio Ltd"
SIGN_IDENTITY_OSX="Rulemotion Ltd (66H43P8FRG)"
SIGN_IDENTITY_OSX="Developer ID Application: Rulemotion Ltd (66H43P8FRG)"
S3_BUCKET="resin-production-downloads"

sign-win32 = osslsigncode sign \
Expand All @@ -33,10 +34,12 @@ etcher-release/Etcher-darwin-x64: .
--helper-bundle-id="io.resin.etcher-helper" \
--app-bundle-id="io.resin.etcher" \
--app-category-type="public.app-category.developer-tools" \
--sign=$(SIGN_IDENTITY_OSX) \
--icon="assets/icon.icns" \
--overwrite \
--out=$(dir $@)
rm $@/LICENSE
rm $@/LICENSES.chromium.html
rm $@/version

etcher-release/Etcher-linux-x86: .
$(ELECTRON_PACKAGER) . $(APPLICATION_NAME) \
Expand Down Expand Up @@ -105,11 +108,88 @@ etcher-release/Etcher-win32-x64: .
$(call sign-win32,$@/Etcher.exe)

etcher-release/installers/Etcher-darwin-x64.dmg: etcher-release/Etcher-darwin-x64 package.json
$(ELECTRON_BUILDER) "$</$(APPLICATION_NAME).app" \
--platform=osx \
--sign=$(SIGN_IDENTITY_OSX) \
--out=$(dir $@)
mv $(dir $@)Etcher.dmg $@
# Create temporal read-write DMG image
hdiutil create \
-srcfolder $< \
-volname "$(APPLICATION_NAME)" \
-fs HFS+ \
-fsargs "-c c=64,a=16,e=16" \
-format UDRW \
-size 600M $<.dmg
# Mount temporal DMG image, so we can modify it
hdiutil attach $<.dmg -readwrite -noverify
# Wait for a bit to ensure the image is mounted
sleep 2
# Link to /Applications within the DMG
pushd /Volumes/$(APPLICATION_NAME) && ln -s /Applications && popd
# Symlink MacOS/Etcher to MacOS/Electron since for some reason, the Electron
# binary tries to be ran in some systems.
# See https://github.com/Microsoft/vscode/issues/92
cp -p /Volumes/$(APPLICATION_NAME)/$(APPLICATION_NAME).app/Contents/MacOS/Etcher /Volumes/$(APPLICATION_NAME)/$(APPLICATION_NAME).app/Contents/MacOS/Electron
# Set the DMG icon image
# Writing this hexadecimal buffer to the com.apple.FinderInfo
# extended attribute does the trick.
# See https://github.com/LinusU/node-appdmg/issues/14#issuecomment-29080500
cp assets/icon.icns /Volumes/$(APPLICATION_NAME)/.VolumeIcon.icns
xattr -wx com.apple.FinderInfo "0000000000000000040000000000000000000000000000000000000000000000" /Volumes/$(APPLICATION_NAME)
# Configure background image.
# We use tiffutil to create a "Multirepresentation Tiff file".
# This allows us to show the retina and non-retina image when appropriate.
mkdir /Volumes/$(APPLICATION_NAME)/.background
tiffutil -cathidpicheck assets/osx/installer.png assets/osx/[email protected] \
-out /Volumes/$(APPLICATION_NAME)/.background/installer.tiff
# This AppleScript performs the following tasks
# - Set the window basic properties.
# - Set the window size and position.
# - Set the icon size.
# - Arrange the icons.
echo ' \
tell application "Finder" \n\
tell disk "$(APPLICATION_NAME)" \n\
open \n\
set current view of container window to icon view \n\
set toolbar visible of container window to false \n\
set statusbar visible of container window to false \n\
set the bounds of container window to {400, 100, 944, 530} \n\
set viewOptions to the icon view options of container window \n\
set arrangement of viewOptions to not arranged \n\
set icon size of viewOptions to 110 \n\
set background picture of viewOptions to file ".background:installer.tiff" \n\
set position of item "$(APPLICATION_NAME).app" of container window to {140, 225} \n\
set position of item "Applications" of container window to {415, 225} \n\
close \n\
open \n\
update without registering applications \n\
delay 2 \n\
close \n\
end tell \n\
end tell \n\
' | osascript
sync
# Sign the *.app with `electron-osx-sign`
# See https://github.com/electron-userland/electron-osx-sign
$(ELECTRON_OSX_SIGN) /Volumes/$(APPLICATION_NAME)/$(APPLICATION_NAME).app \
--platform darwin \
--verbose \
--identity $(SIGN_IDENTITY_OSX)
# Light signature verification.
# This might pass even if Gatekeeper pass.
codesign --verify --deep --display --verbose=4 \
"/Volumes/$(APPLICATION_NAME)/$(APPLICATION_NAME).app"
# Hard signature check. This represents what users will see.
spctl --ignore-cache --no-cache --assess --type execute --verbose=4 \
"/Volumes/$(APPLICATION_NAME)/$(APPLICATION_NAME).app"
# Unmount temporal DMG image.
hdiutil detach /Volumes/$(APPLICATION_NAME)
# Convert temporal DMG image into a production-ready
# compressed and read-only DMG image.
mkdir -p $(dir $@)
hdiutil convert $<.dmg \
-format UDZO \
-imagekey zlib-level=9 \
-o $@
# Cleanup temporal DMG image.
rm $<.dmg

etcher-release/installers/Etcher-linux-x64.tar.gz: etcher-release/Etcher-linux-x64
mkdir -p $(dir $@)
Expand Down
23 changes: 3 additions & 20 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"lib/scss",
"node_modules/electron-mocha",
"node_modules/electron-builder",
"node_modules/electron-osx-sign",
"node_modules/angular-mocks",
"node_modules/browserify",
"node_modules/gulp*",
Expand All @@ -41,25 +42,6 @@
"node_modules/tmp"
],
"builder": {
"osx": {
"title": "Etcher",
"background": "assets/osx/installer.png",
"icon": "assets/icon.icns",
"icon-size": 110,
"contents": [
{
"x": 415,
"y": 225,
"type": "link",
"path": "/Applications"
},
{
"x": 140,
"y": 225,
"type": "file"
}
]
},
"win": {
"title": "Etcher",
"version": "0.0.1",
Expand Down Expand Up @@ -95,7 +77,8 @@
"angular-mocks": "^1.4.7",
"electron-builder": "^2.6.0",
"electron-mocha": "^0.8.0",
"electron-packager": "^5.1.1",
"electron-osx-sign": "^0.3.0",
"electron-packager": "^6.0.0",
"electron-prebuilt": "^0.36.8",
"gulp": "^3.9.0",
"gulp-jscs": "^3.0.2",
Expand Down

0 comments on commit 77d9fad

Please sign in to comment.