Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add customization, signing and notarization for macOS binary #295

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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