Skip to content

Commit

Permalink
Merge pull request #295 from ripcurlx/add-macos-notarization-and-cust…
Browse files Browse the repository at this point in the history
…omization

Add customization, signing and notarization for macOS binary
  • Loading branch information
chimp1984 authored May 5, 2022
2 parents 37f3309 + 9a14737 commit ad69a4c
Show file tree
Hide file tree
Showing 23 changed files with 357 additions and 11 deletions.
129 changes: 118 additions & 11 deletions desktopapp/build.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import org.apache.tools.ant.taskdefs.condition.Os

plugins {
id 'bisq.java-library'
id 'application'
Expand Down Expand Up @@ -102,25 +104,17 @@ tasks.jpackage {
destination = "$buildDir/$distsDirName"
input = "$buildDir/$libsDirName"
licenseFile = "../LICENSE"
// resourceDir = --resource-dir <resource dir path> // TODO
runtimeImage = System.getProperty("java.home")
temp = jpackageTempDir
// launchers = --add-launcher <name>=<property file> // TODO add multiple launchers? desktopapp / satoshiapp

winMenu = true
winDirChooser = true
// winUpgradeUuid = win-upgrade-uuid <id string> // TODO
// winMenuGroup = --win-menu-group <menu group name> // TODO
winShortcut = true
winPerUserInstall = true
winPerUserInstall = false
winConsole = false

// macPackageIdentifier = --mac-package-identifier <ID string> // TODO
// macPackageName = --mac-package-name <name string> // TODO
// macPackageSigningPrefix = --mac-package-signing-prefix <prefix string> // TODO
macSign = false
// macSigningKeychain = --mac-signing-keychain <file path> // TODO
// macSigningKeyUserName = --mac-signing-key-user-name <team name> // TODO
macPackageName = 'Bisq 2'

linuxPackageName = 'bisq2'
linuxDebMaintainer = 'noreply@bisq.network'
Expand All @@ -135,7 +129,18 @@ tasks.jpackage {
mac {
// Avoid error "The first number in an app-version cannot be zero or negative."
appVersion = appVersion.startsWith('0') ? '1.0.0' : appVersion
// icon = "icons/icons.icns" // TODO
icon = "package/macosx/Bisq 2.icns"
resourceDir = "package/macosx"

if (project.hasProperty("signBinary")) {
macSign = true
// Env variable can be set by calling "export BISQ2_PACKAGE_SIGNING_IDENTITY='Some value'"
String envVariableSigningID = "$System.env.BISQ2_PACKAGE_SIGNING_IDENTITY"
// e.g. network.bisq2.CAT is used when binaries are built by @ripcurlx
String envVariablePrimaryBundleId = "$System.env.BISQ2_PRIMARY_BUNDLE_ID"
macPackageIdentifier = "${envVariablePrimaryBundleId}"
macSigningKeyUserName = "${envVariableSigningID}"
}
}

linux {
Expand All @@ -146,6 +151,11 @@ tasks.jpackage {
// icon = "icons/icons.ico" // TODO
}

windows {
icon = "package/windows/Bisq 2.ico"
resourceDir = "package/windows"
}

additionalParameters = ['--verbose']

javaOptions = []
Expand All @@ -162,5 +172,102 @@ tasks.jpackage {
println "The binaries and checksums are ready:"
FileCollection collection = layout.files { binariesFolderPath.listFiles() }
collection.collect { it.path }.sort().each { println it }

if(project.hasProperty("signBinary")) {

String packagePath = "${destination}/${appName}-${appVersion}"

if (Os.isFamily(Os.FAMILY_WINDOWS)) {
packagePath += ".exe"

// Set the necessary permissions before calling signtool
executeCmd("\"attrib -R \"${packagePath}\"\"")

// In addition to the groovy quotes around the string, the entire Windows command must also be surrounded
// by quotes, plus each path inside the command has to be quoted as well
// Reason for this is that the path to the called executable contains spaces
// See https://stackoverflow.com/questions/6376113/how-do-i-use-spaces-in-the-command-prompt/6378038#6378038
executeCmd("\"\"C:\\Program Files (x86)\\Windows Kits\\10\\App Certification Kit\\signtool.exe\" sign /v /fd SHA256 /a \"${packagePath}\"\"")
} else if (Os.isFamily(Os.FAMILY_MAC)) {

// e.g. network.bisq2.CAT is used when binaries are built by @ripcurlx
String envVariablePrimaryBundleId = "$System.env.BISQ2_PRIMARY_BUNDLE_ID"

// Upload for notarization
// See https://developer.apple.com/documentation/xcode/notarizing_macos_software_before_distribution/customizing_the_notarization_workflow#3087734
String envVariableAcUsername = "$System.env.BISQ2_PACKAGE_NOTARIZATION_AC_USERNAME"
String envVariableAscProvider = "$System.env.BISQ2_PACKAGE_NOTARIZATION_ASC_PROVIDER"
packagePath += ".dmg"

def uploadForNotarizationOutput = executeCmd("xcrun altool --notarize-app" +
" --primary-bundle-id '${envVariablePrimaryBundleId}'" +
" --username '${envVariableAcUsername}'" +
" --password '@keychain:AC_PASSWORD'" +
" --asc-provider '${envVariableAscProvider}'" +
" --file '${packagePath}'")

def requestUUID = uploadForNotarizationOutput.split('RequestUUID = ')[1].trim()
println "Extracted RequestUUID: " + requestUUID

// Every 1 minute, check the status
def notarizationEndedInSuccess = false
def notarizationEndedInFailure = false
while (!(notarizationEndedInSuccess || notarizationEndedInFailure)) {
println "Current time is:"
executeCmd('date')
println "Waiting for 1 minute..."
sleep(1 * 60 * 1000)

println "Checking notarization status"

def checkNotarizationStatusOutput = executeCmd("xcrun altool --notarization-info" +
" '${requestUUID}'" +
" --username '${envVariableAcUsername}'" +
" --password '@keychain:AC_PASSWORD'")

notarizationEndedInSuccess = checkNotarizationStatusOutput.contains('success')
notarizationEndedInFailure = checkNotarizationStatusOutput.contains('invalid')
}

if (notarizationEndedInFailure) {
ant.fail('Notarization failed, aborting')
}

if (notarizationEndedInSuccess) {
println "Notarization was successful"

// Staple ticket on dmg
executeCmd("xcrun stapler staple" +
" '${packagePath}'")
}
}
}
}
}

def executeCmd(String cmd) {
String shell
String shellArg
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
shell = 'cmd'
shellArg = '/c'
} else {
shell = 'bash'
shellArg = '-c'
}

println "Executing command:\n${cmd}\n"
// See "Executing External Processes" section of
// http://docs.groovy-lang.org/next/html/documentation/
def commands = [shell, shellArg, cmd]
def process = commands.execute(null, project.rootDir)
def result
if (process.waitFor() == 0) {
result = process.text
println "Command output (stdout):\n${result}"
} else {
result = process.err.text
println "Command output (stderr):\n${result}"
}
return result
}
Binary file added desktopapp/package/linux/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added desktopapp/package/macosx/Bisq 2-background.tiff
Binary file not shown.
41 changes: 41 additions & 0 deletions desktopapp/package/macosx/Bisq 2-dmg-setup.scpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
tell application "Finder"
tell disk "Bisq 2"
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 pathbar visible of container window to false

-- size of window should match size of background (1034x641)
set the bounds of container window to {400, 100, 1434, 741}

set theViewOptions to the icon view options of container window
set arrangement of theViewOptions to not arranged
set icon size of theViewOptions to 128
set background picture of theViewOptions to file ".background:background.tiff"

-- Create alias for install location
make new alias file at container window to POSIX file "/Applications" with properties {name:"Applications"}

set allTheFiles to the name of every item of container window
repeat with theFile in allTheFiles
set theFilePath to POSIX Path of theFile
if theFilePath is "/Bisq 2.app"
-- Position application location
set position of item theFile of container window to {345, 343}
else if theFilePath is "/Applications"
-- Position install location
set position of item theFile of container window to {677, 343}
else
-- Move all other files far enough to be not visible if user has "show hidden files" option set
set position of item theFile of container window to {1000, 0}
end
end repeat

close
open
update without registering applications
delay 5
end tell
end tell

Binary file added desktopapp/package/macosx/Bisq 2-volume.icns
Binary file not shown.
Binary file added desktopapp/package/macosx/Bisq 2.icns
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added desktopapp/package/windows/Bisq 2.ico
Binary file not shown.
Binary file not shown.
Binary file not shown.
165 changes: 165 additions & 0 deletions desktopapp/package/windows/main.wxs
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">

<?ifdef JpIsSystemWide ?>
<?define JpInstallScope="perMachine"?>
<?else?>
<?define JpInstallScope="perUser"?>
<?endif?>

<?define JpProductLanguage=1033 ?>
<?define JpInstallerVersion=200 ?>
<?define JpCompressedMsi=yes ?>

<?ifdef JpAllowUpgrades ?>
<?define JpUpgradeVersionOnlyDetectUpgrade="no"?>
<?else?>
<?define JpUpgradeVersionOnlyDetectUpgrade="yes"?>
<?endif?>
<?ifdef JpAllowDowngrades ?>
<?define JpUpgradeVersionOnlyDetectDowngrade="no"?>
<?else?>
<?define JpUpgradeVersionOnlyDetectDowngrade="yes"?>
<?endif?>

<?include $(var.JpConfigDir)/overrides.wxi ?>

<?define ImageDir="$(var.JpConfigDir)/../../../../package/windows/images"?>

<Product
Id="$(var.JpProductCode)"
Name="$(var.JpAppName)"
Language="$(var.JpProductLanguage)"
Version="$(var.JpAppVersion)"
Manufacturer="$(var.JpAppVendor)"
UpgradeCode="$(var.JpProductUpgradeCode)">

<Package
Description="$(var.JpAppDescription)"
Manufacturer="$(var.JpAppVendor)"
InstallerVersion="$(var.JpInstallerVersion)"
Compressed="$(var.JpCompressedMsi)"
InstallScope="$(var.JpInstallScope)" Platform="x64"
/>

<Media Id="1" Cabinet="Data.cab" EmbedCab="yes" />

<Upgrade Id="$(var.JpProductUpgradeCode)">
<UpgradeVersion
OnlyDetect="$(var.JpUpgradeVersionOnlyDetectUpgrade)"
Property="JP_UPGRADABLE_FOUND"
Maximum="$(var.JpAppVersion)"
MigrateFeatures="yes"
IncludeMaximum="$(var.JpUpgradeVersionOnlyDetectUpgrade)" />
<UpgradeVersion
OnlyDetect="$(var.JpUpgradeVersionOnlyDetectDowngrade)"
Property="JP_DOWNGRADABLE_FOUND"
Minimum="$(var.JpAppVersion)"
MigrateFeatures="yes"
IncludeMinimum="$(var.JpUpgradeVersionOnlyDetectDowngrade)" />
</Upgrade>

<?ifndef JpAllowUpgrades ?>
<CustomAction Id="JpDisallowUpgrade" Error="!(loc.DisallowUpgradeErrorMessage)" />
<?endif?>
<?ifndef JpAllowDowngrades ?>
<CustomAction Id="JpDisallowDowngrade" Error="!(loc.DowngradeErrorMessage)" />
<?endif?>

<!-- Standard required root -->
<Directory Id="TARGETDIR" Name="SourceDir"/>

<Feature Id="DefaultFeature" Title="!(loc.MainFeatureTitle)" Level="1">
<ComponentGroupRef Id="Shortcuts"/>
<ComponentGroupRef Id="Files"/>
<ComponentGroupRef Id="FileAssociations"/>
</Feature>

<?ifdef JpInstallDirChooser ?>
<Binary Id="JpCaDll" SourceFile="wixhelper.dll"/>
<CustomAction Id="JpCheckInstallDir" BinaryKey="JpCaDll" DllEntry="CheckInstallDir" />
<?endif?>

<CustomAction Id="JpSetARPINSTALLLOCATION" Property="ARPINSTALLLOCATION" Value="[INSTALLDIR]" />

<?ifdef JpIcon ?>
<Property Id="ARPPRODUCTICON" Value="JpARPPRODUCTICON"/>
<Icon Id="JpARPPRODUCTICON" SourceFile="$(var.JpIcon)"/>
<?endif?>

<WixVariable Id="WixUIBannerBmp" Value="$(var.ImageDir)/WixUIBannerBmp.bmp" />
<WixVariable Id="WixUIDialogBmp" Value="$(var.ImageDir)/WixUIDialogBmp.bmp" />

<UI>
<?ifdef JpInstallDirChooser ?>
<Dialog Id="JpInvalidInstallDir" Width="300" Height="85" Title="[ProductName] Setup" NoMinimize="yes">
<Control Id="JpInvalidInstallDirYes" Type="PushButton" X="100" Y="55" Width="50" Height="15" Default="no" Cancel="no" Text="Yes">
<Publish Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
</Control>
<Control Id="JpInvalidInstallDirNo" Type="PushButton" X="150" Y="55" Width="50" Height="15" Default="yes" Cancel="yes" Text="No">
<Publish Event="NewDialog" Value="InstallDirDlg">1</Publish>
</Control>
<Control Id="Text" Type="Text" X="25" Y="15" Width="250" Height="30" TabSkip="no">
<Text>!(loc.message.install.dir.exist)</Text>
</Control>
</Dialog>

<!--
Run WixUI_InstallDir dialog in the default install directory.
-->
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR"/>
<UIRef Id="WixUI_InstallDir" />

<Publish Dialog="InstallDirDlg" Control="Next" Event="DoAction" Value="JpCheckInstallDir" Order="3">1</Publish>
<Publish Dialog="InstallDirDlg" Control="Next" Event="NewDialog" Value="JpInvalidInstallDir" Order="5">INSTALLDIR_VALID="0"</Publish>
<Publish Dialog="InstallDirDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg" Order="5">INSTALLDIR_VALID="1"</Publish>

<?ifndef JpLicenseRtf ?>
<!--
No license file provided.
Override the dialog sequence in built-in dialog set "WixUI_InstallDir"
to exclude license dialog.
-->
<Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="InstallDirDlg" Order="2">1</Publish>
<Publish Dialog="InstallDirDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg" Order="2">1</Publish>
<?endif?>

<?else?>

<?ifdef JpLicenseRtf ?>
<UIRef Id="WixUI_Minimal" />
<?endif?>

<?endif?>
<!-- Add launch app configuration -->
<Publish Dialog="ExitDialog"
Control="Finish"
Event="DoAction"
Value="LaunchApplication">WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 and NOT Installed</Publish>
</UI>

<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT" Value="Launch $(var.JpAppName)" />
<Property Id="WixShellExecTarget" Value="[INSTALLDIR]/$(var.JpAppName).exe" />
<CustomAction Id="LaunchApplication"
BinaryKey="WixCA"
DllEntry="WixShellExec"
Impersonate="yes" />

<?ifdef JpLicenseRtf ?>
<WixVariable Id="WixUILicenseRtf" Value="$(var.JpLicenseRtf)"/>
<?endif?>

<InstallExecuteSequence>
<Custom Action="JpSetARPINSTALLLOCATION" After="CostFinalize">Not Installed</Custom>
<?ifndef JpAllowUpgrades ?>
<Custom Action="JpDisallowUpgrade" After="FindRelatedProducts">JP_UPGRADABLE_FOUND</Custom>
<?endif?>
<?ifndef JpAllowDowngrades ?>
<Custom Action="JpDisallowDowngrade" After="FindRelatedProducts">JP_DOWNGRADABLE_FOUND</Custom>
<?endif?>
<RemoveExistingProducts Before="CostInitialize"/>
</InstallExecuteSequence>

</Product>
</Wix>
Loading

0 comments on commit ad69a4c

Please sign in to comment.