diff --git a/Gruntfile.js b/Gruntfile.js
index f9ed59621..282c8e0fb 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -8,6 +8,21 @@ module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
exec: {
+ get_nwjs_for_pkg: {
+ command: 'if [ ! -d ./cache/0.19.5-pkg/osx64/nwjs.app ]; then cd ./cache; curl https://dl.nwjs.io/v0.19.5-mas-beta/nwjs-mas-v0.19.5-osx-x64.zip --output nwjs.zip; unzip nwjs.zip; mkdir -p ./0.19.5-pkg/osx64; cp -R ./nwjs-mas-v0.19.5-osx-x64/nwjs.app ./0.19.5-pkg/osx64/; fi'
+ },
+ create_others_dist: {
+ command: 'sh webkitbuilds/create-others-dist.sh "<%= pkg.name %>" "<%= pkg.fullVersion %>" "<%= pkg.nameCaseNoSpace %>" "<%= pkg.title %>"'
+ },
+ create_dmg_dist: {
+ command: 'sh webkitbuilds/create-dmg-dist.sh "<%= pkg.name %>" "<%= pkg.fullVersion %>" "<%= pkg.nameCaseNoSpace %>" "<%= pkg.title %>"'
+ },
+ create_pkg_dist: {
+ command: 'sh webkitbuilds/create-pkg-dist.sh "<%= pkg.name %>" "<%= pkg.fullVersion %>" "<%= pkg.nameCaseNoSpace %>" "<%= pkg.title %>"'
+ },
+ sign_desktop_dist: {
+ command: 'sh webkitbuilds/sign-desktop-dist.sh "<%= pkg.name %>" "<%= pkg.fullVersion %>"'
+ },
appConfig: {
command: 'node ./util/buildAppConfig.js'
},
@@ -20,9 +35,6 @@ module.exports = function(grunt) {
cordovaclean: {
command: 'make -C cordova clean'
},
- macos: {
- command: 'sh webkitbuilds/build-macos.sh sign'
- },
coveralls: {
command: 'cat coverage/report-lcov/lcov.info |./node_modules/coveralls/bin/coveralls.js'
},
@@ -61,7 +73,7 @@ module.exports = function(grunt) {
stdin: true,
},
desktopsign: {
- cmd: 'gpg -u E0AE67E7 --output webkitbuilds/<%= pkg.title %>-linux.zip.sig --detach-sig webkitbuilds/<%= pkg.title %>-linux.zip ; gpg -u E0AE67E7 --output webkitbuilds/<%= pkg.title %>.exe.sig --detach-sig webkitbuilds/<%= pkg.title %>.exe'
+ cmd: 'gpg -u E0AE67E7 --output webkitbuilds/others/<%= pkg.title %>-linux.zip.sig --detach-sig webkitbuilds/others/<%= pkg.title %>-linux.zip ; gpg -u E0AE67E7 --output webkitbuilds/others/<%= pkg.title %>.exe.sig --detach-sig webkitbuilds/others/<%= pkg.title %>.exe'
},
desktopverify: {
cmd: 'gpg --verify webkitbuilds/<%= pkg.title %>-linux.zip.sig webkitbuilds/<%= pkg.title %>-linux.zip; gpg --verify webkitbuilds/<%= pkg.title %>.exe.sig webkitbuilds/<%= pkg.title %>.exe'
@@ -233,38 +245,78 @@ module.exports = function(grunt) {
expand: true,
cwd: 'webkitbuilds/',
src: ['.desktop', '../www/img/app/favicon.ico', '../resources/<%= pkg.name %>/linux/512x512.png'],
- dest: 'webkitbuilds/<%= pkg.title %>/linux64/',
+ dest: 'webkitbuilds/others/<%= pkg.title %>/linux64/',
flatten: true,
filter: 'isFile'
}],
}
},
nwjs: {
- options: {
- appName: '<%= pkg.title %>',
- platforms: ['win64', 'osx64', 'linux64'],
- buildDir: './webkitbuilds',
- version: '0.19.5',
- macIcns: './resources/<%= pkg.name %>/mac/app.icns',
- exeIco: './www/img/app/logo.ico',
- macPlist: {
- 'CFBundleURLTypes': [
- {
- 'CFBundleURLName': 'URI Handler',
- 'CFBundleURLSchemes': ['bitcoin', '<%= pkg.name %>']
- }
- ]
- }
+ others: {
+ options: {
+ appName: '<%= pkg.nameCaseNoSpace %>',
+ platforms: ['win64', 'linux64'],
+ buildDir: './webkitbuilds/others',
+ version: '0.19.5',
+ exeIco: './www/img/app/logo.ico'
+ },
+ src: ['./package.json', './www/**/*']
+ },
+ dmg: {
+ options: {
+ appName: '<%= pkg.nameCaseNoSpace %>',
+ platforms: ['osx64'],
+ buildDir: './webkitbuilds/dmg',
+ version: '0.19.5',
+ macIcns: './resources/<%= pkg.name %>/mac/app.icns',
+ exeIco: './www/img/app/logo.ico',
+ macPlist: {
+ 'CFBundleDisplayName': '<%= pkg.title %>',
+ 'CFBundleShortVersionString': '<%= pkg.version %>',
+ 'CFBundleVersion': '<%= pkg.androidVersion %>',
+ 'LSApplicationCategoryType': 'public.app-category.finance',
+ 'CFBundleURLTypes': [
+ {
+ 'CFBundleURLName': 'URI Handler',
+ 'CFBundleURLSchemes': ['bitcoin', '<%= pkg.name %>']
+ }
+ ]
+ }
+ },
+ src: ['./package.json', './www/**/*']
+ },
+ pkg: {
+ options: {
+ appName: '<%= pkg.nameCaseNoSpace %>',
+ platforms: ['osx64'],
+ buildDir: './webkitbuilds/pkg',
+ version: '0.19.5',
+ macIcns: './resources/<%= pkg.name %>/mac/pkg/app.icns',
+ exeIco: './www/img/app/logo.ico',
+ macPlist: {
+ 'CFBundleIdentifier': 'com.bitcoin.mwallet.mac',
+ 'CFBundleDisplayName': '<%= pkg.title %>',
+ 'CFBundleShortVersionString': '<%= pkg.version %>',
+ 'CFBundleVersion': '<%= pkg.androidVersion %>',
+ 'LSApplicationCategoryType': 'public.app-category.finance',
+ 'CFBundleURLTypes': [
+ {
+ 'CFBundleURLName': 'URI Handler',
+ 'CFBundleURLSchemes': ['bitcoin', '<%= pkg.name %>']
+ }
+ ]
+ }
+ },
+ src: ['./package.json', './www/**/*']
},
- src: ['./package.json', './www/**/*']
},
compress: {
linux: {
options: {
- archive: './webkitbuilds/<%= pkg.title %>-linux.zip'
+ archive: './webkitbuilds/others/<%= pkg.title %>-linux.zip'
},
expand: true,
- cwd: './webkitbuilds/<%= pkg.title %>/linux64/',
+ cwd: './webkitbuilds/others/<%= pkg.title %>/linux64/',
src: ['**/*'],
dest: '<%= pkg.title %>-linux/'
}
@@ -283,9 +335,6 @@ module.exports = function(grunt) {
grunt.registerTask('default', ['nggettext_compile', 'exec:appConfig', 'exec:externalServices', 'browserify', 'sass', 'concat', 'copy:ionic_fonts', 'copy:ionic_js']);
grunt.registerTask('prod', ['default', 'uglify']);
grunt.registerTask('translate', ['nggettext_extract']);
- grunt.registerTask('desktop', ['prod', 'nwjs', 'copy:linux', 'compress:linux']);
- grunt.registerTask('osx', ['prod', 'nwjs', 'exec:macos', 'exec:osxsign']);
- grunt.registerTask('osx-debug', ['default', 'nwjs']);
grunt.registerTask('chrome', ['default','exec:chrome']);
grunt.registerTask('wp', ['prod', 'exec:wp']);
grunt.registerTask('wp-copy', ['default', 'exec:wpcopy']);
@@ -297,6 +346,23 @@ module.exports = function(grunt) {
grunt.registerTask('android-debug', ['exec:androiddebug', 'exec:androidrun']);
grunt.registerTask('android', ['exec:android']);
grunt.registerTask('android-release', ['prod', 'exec:android', 'exec:androidsign']);
- grunt.registerTask('desktopsign', ['exec:desktopsign', 'exec:desktopverify']);
+ grunt.registerTask('desktopsign', ['exec:desktopsign', 'exec:desktopverify']);
+ // Build desktop
+ grunt.registerTask('desktop-build', ['desktop-others', 'desktop-osx-dmg', 'desktop-osx-pkg']);
+
+ // Build desktop win64 & linux64
+ grunt.registerTask('desktop-others', ['prod', 'nwjs:others', 'copy:linux', 'exec:create_others_dist']);
+
+ // Build desktop osx pkg
+ grunt.registerTask('desktop-osx-pkg', ['prod', 'exec:get_nwjs_for_pkg', 'nwjs:pkg', 'exec:create_pkg_dist']);
+
+ // Build desktop osx dmg
+ grunt.registerTask('desktop-osx-dmg', ['prod', 'nwjs:dmg', 'exec:create_dmg_dist']);
+
+ // Sign desktop
+ grunt.registerTask('desktop-sign', ['exec:sign_desktop_dist']);
+
+ // Release desktop
+ grunt.registerTask('desktop-release', ['desktop-build', 'desktop-sign']);
};
diff --git a/app-template/apply.js b/app-template/apply.js
index 1aaee94de..143cf57a8 100755
--- a/app-template/apply.js
+++ b/app-template/apply.js
@@ -11,7 +11,10 @@ var templates = {
'ionic.config.json': '/',
'.desktop': 'webkitbuilds/',
'setup-win.iss': 'webkitbuilds/',
- 'build-macos.sh': 'webkitbuilds/',
+ 'create-dmg-dist.sh': 'webkitbuilds/',
+ 'create-others-dist.sh': 'webkitbuilds/',
+ 'create-pkg-dist.sh': 'webkitbuilds/',
+ 'sign-desktop-dist.sh': 'webkitbuilds/',
'manifest.json': 'chrome-app/',
// 'bower.json': '/',
};
diff --git a/app-template/bitcoincom/appConfig.json b/app-template/bitcoincom/appConfig.json
index 7fba677c4..2e9f82d29 100644
--- a/app-template/bitcoincom/appConfig.json
+++ b/app-template/bitcoincom/appConfig.json
@@ -2,7 +2,7 @@
"packageName": "bitcoin.com",
"packageDescription": "Bitcoin.com Wallet",
"packageNameId": "com.bitcoin.mwallet",
- "userVisibleName": "Bitcoin.com",
+ "userVisibleName": "Bitcoin.com Wallet",
"purposeLine": "Bitcoin.com Wallet",
"bundleName": "bitcoincom",
"appUri": "bitcoincom",
@@ -18,7 +18,7 @@
"appDescription": "Bitcoin.com Wallet",
"winAppName": "BitcoinWallet",
"WindowsStoreIdentityName": "18C7659D.Bitcoin.com-SecureBitcoinWallet",
- "WindowsStoreDisplayName": "Bitcoin.com - Secure Bitcoin Wallet",
+ "WindowsStoreDisplayName": "Bitcoin.com Wallet",
"wpPublisherId": "{31cdd08b-457c-413d-b440-f6665eec847d}",
"wpProductId": "{5381aa50-9069-11e4-84cc-293caf9cbdc8}",
"windowsAppId": "804636ee-b017-4cad-8719-e58ac97ffa5c",
diff --git a/app-template/build-macos.sh b/app-template/create-dmg-dist.sh
old mode 100755
new mode 100644
similarity index 84%
rename from app-template/build-macos.sh
rename to app-template/create-dmg-dist.sh
index 5f09bd0b2..5b004e66a
--- a/app-template/build-macos.sh
+++ b/app-template/create-dmg-dist.sh
@@ -1,11 +1,5 @@
#!/bin/bash
-SHOULD_SIGN=$1
-if [ "$SHOULD_SIGN" ]
-then
- echo "Will sign the APP"
-fi
-
# by Andy Maloney
# http://asmaloney.com/2013/07/howto/packaging-a-mac-os-x-application-using-a-dmg/
@@ -16,21 +10,25 @@ if [ -d "$dir" ]; then
fi
# set up your app name, architecture, and background image file name
-APP_NAME="*USERVISIBLENAME*"
+APP_PACKAGE=$1
+APP_VERSION=$2
+APP_NAME=$3
+APP_FULLNAME=$4
+
rm dmg-background.tiff
-ln -s ../resources/*PACKAGENAME*/mac/dmg-background.tiff dmg-background.tiff
+ln -s ../resources/bitcoin.com/mac/dmg-background.tiff dmg-background.tiff
rm volume-icon.icns
-ln -s ../resources/*PACKAGENAME*/mac/volume-icon.icns volume-icon.icns
+ln -s ../resources/bitcoin.com/mac/volume-icon.icns volume-icon.icns
DMG_VOLUME_ICON="volume-icon.icns"
DMG_BACKGROUND_IMG="dmg-background.tiff"
-PATH_NAME="${APP_NAME}/osx64/"
+PATH_NAME="dmg/${APP_NAME}/osx64/"
# you should not need to change these
APP_EXE="${PATH_NAME}${APP_NAME}.app/Contents/MacOS/nwjs"
VOL_NAME="${APP_NAME}"
-DMG_TMP="${VOL_NAME}-temp.dmg"
-DMG_FINAL="${VOL_NAME}.dmg"
+DMG_TMP="dmg/${VOL_NAME}-temp.dmg"
+DMG_FINAL="dmg/${VOL_NAME}.dmg"
STAGING_DIR="tmp"
# Check the background image DPI and convert it if it isn't 72x72
@@ -66,25 +64,6 @@ SIZE=250
if [ $? -ne 0 ]; then
echo "Error: Cannot compute size of staging dir"
exit
- fi
-
-# Sign Code (MATIAS)
-if [ $SHOULD_SIGN ]
-then
- echo "Signing ${APP_NAME} DMG"
-
- export IDENTITY="3rd Party Mac Developer Application: BitPay, Inc. (884JRH5R93)"
-
- # not need for 'out of app store' distribution (?)
-# export PARENT_PLIST=parent.plist
-# export CHILD_PLIST=child.plist
- export APP_PATH=${STAGING_DIR}/${APP_NAME}.app
-
- codesign --deep -s "${IDENTITY}" $APP_PATH"/Contents/Versions/52.0.2743.82/nwjs Helper.app" && echo "Sign 1"
- codesign --deep -s "${IDENTITY}" $APP_PATH"/Contents/Versions/52.0.2743.82/nwjs Framework.framework/Resources/app_mode_loader.app" && echo "Sign 2"
- codesign --deep -s "${IDENTITY}" $APP_PATH && echo "Sign 3"
- echo "Signing Done"
-
fi
# create the temp DMG file
@@ -175,6 +154,14 @@ hdiutil detach "${DEVICE}"
echo "Creating compressed image"
hdiutil convert "${DMG_TMP}" -format UDZO -imagekey zlib-level=9 -o "${DMG_FINAL}"
+export DIST_PATH="dist"
+
+if [ ! -d $DIST_PATH ]; then
+ mkdir $DIST_PATH
+fi
+
+cp -vR "${DMG_FINAL}" "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-osx.dmg"
+
# clean up
rm -rf "${DMG_TMP}"
rm -rf "${STAGING_DIR}"
diff --git a/app-template/create-others-dist.sh b/app-template/create-others-dist.sh
new file mode 100644
index 000000000..c9244b3ba
--- /dev/null
+++ b/app-template/create-others-dist.sh
@@ -0,0 +1,54 @@
+#!/bin/bash
+
+# make sure we are in the correct dir when we double-click a .command file
+dir=${0%/*}
+if [ -d "$dir" ]; then
+ cd "$dir"
+fi
+
+# set up your app name, architecture, and background image file name
+APP_PACKAGE=$1
+APP_VERSION=$2
+APP_NAME=$3
+APP_FULLNAME=$4
+
+export APP_LINUX_PATH="others/${APP_NAME}/linux64"
+export APP_WIN_PATH="others/${APP_NAME}/win64"
+export DIST_PATH="dist"
+
+if [ ! -d $DIST_PATH ]; then
+ mkdir $DIST_PATH
+fi
+
+##
+# LINUX
+
+echo "Building Linux..."
+
+# Building package
+cp -R $APP_LINUX_PATH bitcoin-com-wallet
+tar -cvzf "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-linux-x64.tar.gz" bitcoin-com-wallet
+
+# Clean
+rm -R bitcoin-com-wallet
+
+echo "Linux Done."
+
+
+##
+# WINDOWS
+
+echo "Building Windows..."
+
+# Building package
+cp -R $APP_WIN_PATH bitcoin-com-wallet
+zip -r "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-win-x64.zip" bitcoin-com-wallet
+
+# Clean
+rm -R bitcoin-com-wallet
+
+echo "Windows Done."
+
+echo "Done."
+
+exit
diff --git a/app-template/create-pkg-dist.sh b/app-template/create-pkg-dist.sh
new file mode 100644
index 000000000..c0b4d266d
--- /dev/null
+++ b/app-template/create-pkg-dist.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+# make sure we are in the correct dir when we double-click a .command file
+dir=${0%/*}
+if [ -d "$dir" ]; then
+ cd "$dir"
+fi
+
+# set up your app name, architecture, and background image file name
+APP_PACKAGE=$1
+APP_VERSION=$2
+APP_NAME=$3
+APP_FULLNAME=$4
+
+rm entitlements-child.plist
+ln -s ../resources/bitcoin.com/mac/pkg/entitlements-child.plist entitlements-child.plist
+
+rm entitlements-parent.plist
+ln -s ../resources/bitcoin.com/mac/pkg/entitlements-parent.plist entitlements-parent.plist
+
+rm build.cfg
+ln -s ../resources/bitcoin.com/mac/pkg/build.cfg build.cfg
+
+rm build_mas.py
+ln -s ../resources/bitcoin.com/mac/pkg/build_mas.py build_mas.py
+
+echo "Signing ${APP_NAME}"
+export APP_PATH="pkg/${APP_NAME}/osx64/${APP_NAME}"
+export TMP_PATH="tmp"
+export DIST_PATH="dist"
+
+rm -rf $TMP_PATH
+mkdir $TMP_PATH
+
+if [ ! -d $DIST_PATH ]; then
+ mkdir $DIST_PATH
+fi
+
+python build_mas.py -C build.cfg -O "${TMP_PATH}/${APP_NAME}.app" -I "${APP_PATH}.app" -P "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-osx.pkg"
+
+echo "Signing Done"
+
+echo "Done."
+
+exit
diff --git a/app-template/package-template.json b/app-template/package-template.json
index d679b0b24..232ac7e1f 100644
--- a/app-template/package-template.json
+++ b/app-template/package-template.json
@@ -3,6 +3,7 @@
"description": "*DESCRIPTION*",
"author": "BitPay",
"version": "*VERSION*",
+ "androidVersion": "*ANDROIDVERSION*",
"fullVersion": "*FULLVERSION*",
"keywords": [
"bitcoin",
@@ -14,8 +15,9 @@
],
"main": "www/index.html",
"title": "*USERVISIBLENAME*",
+ "nameCaseNoSpace": "*NAMECASENOSPACE*",
"window": {
- "title": "*USERVISIBLENAME* - *PURPOSELINE*",
+ "title": "*USERVISIBLENAME*",
"icon": "www/img/app/icon.png",
"toolbar": false,
"show": true,
@@ -69,6 +71,8 @@
"grunt-angular-gettext": "^2.2.3",
"grunt-browserify": "^5.0.0",
"grunt-cli": "^1.2.0",
+ "grunt-curl": "^2.4.1",
+ "grunt-zip": "^0.17.1",
"grunt-contrib-compress": "^1.3.0",
"grunt-contrib-concat": "^1.0.1",
"grunt-contrib-copy": "^1.0.0",
@@ -99,15 +103,19 @@
"build:ios-release": "cordova prepare ios && cordova build ios --release",
"build:android-release": "cordova prepare android && cordova build android --release",
"build:windows-release": "cordova prepare windows && cordova build windows --release --arch=\"ARM\"",
- "build:desktop": "grunt desktop",
- "build:osx": "grunt osx",
+ "build:desktop-release": "grunt desktop-release",
+ "build:desktop": "grunt desktop-build",
+ "build:osx-pkg": "grunt desktop-osx-pkg",
+ "build:osx-dmg": "grunt desktop-osx-dmg",
+ "build:others": "grunt desktop-others",
+ "sign:desktop": "grunt desktop-sign",
"open:ios": "open platforms/ios/*.xcodeproj",
"open:android": "open -a open -a /Applications/Android\\ Studio.app platforms/android",
"final:www": "npm run build:www-release",
"final:ios": "npm run final:www && npm run build:ios-release && npm run open:ios",
"final:android": "npm run final:www && npm run build:android-release && npm run sign:android && npm run run:android-release",
"final:windows": "npm run final:www && npm run build:windows-release",
- "final:desktop": "npm run build:desktop && npm run build:osx",
+ "final:desktop": "npm run final:www && npm run build:desktop-release",
"run:android": "cordova run android --device",
"run:android-release": "cordova run android --device --release",
"log:android": "adb logcat | grep chromium",
diff --git a/app-template/sign-desktop-dist.sh b/app-template/sign-desktop-dist.sh
new file mode 100644
index 000000000..e1e5c603c
--- /dev/null
+++ b/app-template/sign-desktop-dist.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+# make sure we are in the correct dir when we double-click a .command file
+dir=${0%/*}
+if [ -d "$dir" ]; then
+ cd "$dir"
+fi
+
+APP_PACKAGE=$1
+APP_VERSION=$2
+export DIST_PATH="dist"
+
+##
+# INIT GPG (YOU NEED THE PRIVATE KEY CONNECTED TO YOUR DESKTOP)
+# gpg --card-edit
+
+##
+# LINUX
+
+# Sig tar.gz
+gpg --yes --output "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-linux-x64.tar.gz.sig" --detach-sig "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-linux-x64.tar.gz"
+gpg --verify "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-linux-x64.tar.gz.sig" "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-linux-x64.tar.gz"
+
+##
+# WINDOWS
+
+# Sig zip
+gpg --yes --output "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-win-x64.zip.sig" --detach-sig "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-win-x64.zip"
+gpg --verify "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-win-x64.zip.sig" "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-win-x64.zip"
+
+##
+# OSX
+
+# Sig dmg
+gpg --yes --output "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-osx.dmg.sig" --detach-sig "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-osx.dmg"
+gpg --verify "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-osx.dmg.sig" "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-osx.dmg"
+
+# Sig pkg
+gpg --yes --output "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-osx.pkg.sig" --detach-sig "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-osx.pkg"
+gpg --verify "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-osx.pkg.sig" "$DIST_PATH/${APP_PACKAGE}-wallet-${APP_VERSION}-osx.pkg"
\ No newline at end of file
diff --git a/resources/bitcoin.com/mac/pkg/app.icns b/resources/bitcoin.com/mac/pkg/app.icns
new file mode 100644
index 000000000..40aa3ea77
Binary files /dev/null and b/resources/bitcoin.com/mac/pkg/app.icns differ
diff --git a/resources/bitcoin.com/mac/pkg/build.cfg b/resources/bitcoin.com/mac/pkg/build.cfg
new file mode 100644
index 000000000..3594a2688
--- /dev/null
+++ b/resources/bitcoin.com/mac/pkg/build.cfg
@@ -0,0 +1,32 @@
+[Sign]
+## [REQUIRED] Your Application Certificate Identity
+ApplicationIdentity = 3rd Party Mac Developer Application: Saint Bitts LLC (299HJ3G3BP)
+## [OPTIONAL] Parent entitlements file
+ParentEntitlements = entitlements-parent.plist
+## [OPTIONAL] Child entitlements file
+ChildEntitlements = entitlements-child.plist
+## [OPTIONAL] Sandbox. Default: Yes
+Sandbox = Yes
+
+[Package]
+## [REQUIRED for --pkg] Your Installer Certificate Identity
+InstallerIdentity = 3rd Party Mac Developer Installer: Saint Bitts LLC (299HJ3G3BP)
+## [OPTIONAL for --pkg] Installation path
+InstallPath = /Applications
+
+[Info.plist]
+## [OPTIONAL] Your app bundle identifier
+CFBundleIdentifier = com.bitcoin.mwallet.mac
+## [REQUIRED] Team ID obtained from Apple Developer -> Membership -> Team ID
+NWTeamID = 299HJ3G3BP
+## Properties of Info.plist will be overwritten in this section.
+
+[Resources]
+## [OPTIONAL] Your custom icon file
+Icon = ../resources/bitcoin.com/mac/pkg/app.icns
+## [OPTIONAL] Locales
+## If Locales is not set, all current locales are preserved.
+## If comma separated locale list (e.g. en,fr,zh_CN) is given, you should have
+## additional [Locale locale_name] section for each locale containing localized strings.
+## Locales not in the list will be removed.
+Locales = en
\ No newline at end of file
diff --git a/resources/bitcoin.com/mac/pkg/build_mas.py b/resources/bitcoin.com/mac/pkg/build_mas.py
new file mode 100755
index 000000000..d067abacd
--- /dev/null
+++ b/resources/bitcoin.com/mac/pkg/build_mas.py
@@ -0,0 +1,253 @@
+#!/usr/bin/env python
+
+import argparse
+import ConfigParser
+import shutil
+import os
+import fnmatch
+import plistlib
+import tempfile
+from datetime import datetime
+import sys
+import io
+
+bundleid = None
+verbose = False
+
+def info(msg):
+ global verbose
+ if verbose:
+ print '[INFO] %s' % msg
+
+def error(msg):
+ print '[ERROR] %s' % msg
+ print '\nFailed.'
+ sys.exit(1)
+
+def system(cmd):
+ info(cmd)
+ os.system(cmd)
+
+def check_options(config, section, required_options, msg):
+ missed_options = []
+
+ for option in required_options:
+ if not config.has_option(section, option):
+ missed_options.append(option)
+
+ if len(missed_options) != 0:
+ error(msg % (section, ', '.join(missed_options)))
+
+def glob(pathname, pattern, returnOnFound=False):
+ matches = []
+ for root, dirnames, filenames in os.walk(pathname):
+ for dirname in fnmatch.filter(dirnames, pattern):
+ if returnOnFound:
+ return os.path.join(root, dirname)
+ matches.append(os.path.join(root, dirname))
+ for filename in fnmatch.filter(filenames, pattern):
+ if returnOnFound:
+ return os.path.join(root, filename)
+ matches.append(os.path.join(root, filename))
+ return matches
+
+def get_bundle_id(args):
+ global bundleid
+ if bundleid is None:
+ plist = plistlib.readPlist(os.path.join(args.output, 'Contents/Info.plist'))
+ bundleid = plist['CFBundleIdentifier']
+ return bundleid
+
+def get_from_info_plist(args, key, default=None):
+ plist = plistlib.readPlist(os.path.join(args.output, 'Contents/Info.plist'))
+ if key in plist:
+ return plist[key]
+ else:
+ return default
+
+def patch_info_plist_file(file, replaces):
+ plist = plistlib.readPlist(file)
+ for (key, val) in replaces:
+ plist[key] = val
+ plistlib.writePlist(plist, file)
+
+def generate_infoplist_strings_file(file, items):
+ with io.open(file, 'w', encoding='utf-16') as fd:
+ for item in items:
+ fd.write(unicode('%s = "%s";\n' % item, 'utf-8'))
+
+def read_config(args):
+ print '\nParsing config file %s' % args.config_file
+ if not os.path.isfile(args.config_file):
+ error('%s does not exist' % args.config_file)
+ config = ConfigParser.SafeConfigParser()
+ config.optionxform = str # set to str to prevent transforming into lower cases
+ config.read(args.config_file)
+ check_options(config, 'Sign', ['ApplicationIdentity'], 'Missed options in [%s]: %s')
+ if args.pkg:
+ check_options(config, 'Package', ['InstallerIdentity'], 'Missed options for --pkg in [%s]: %s')
+ return config
+
+def copy_to_output(args):
+ print '\nCopying %s to %s' % (args.input, args.output)
+ shutil.rmtree(args.output, ignore_errors=True)
+ shutil.copytree(args.input, args.output, symlinks=True) # symblic links are required
+
+def patch_info_plist(config, args):
+ print '\nPatching Info.plist files'
+
+ replaces = []
+ for (key, val) in config.items('Info.plist'):
+ replaces.append((key, val))
+
+ file = os.path.join(args.output, 'Contents/Info.plist')
+ info(file)
+ patch_info_plist_file(file, replaces)
+
+ info_plist_files = glob(os.path.join(args.output, 'Contents/Versions'), 'Info.plist')
+ for file in info_plist_files:
+ if 'nwjs Framework' in file:
+ tmp_replaces = [('CFBundleIdentifier', '%s.framework' % get_bundle_id(args))]
+ elif 'nwjs Helper' in file:
+ tmp_replaces = [('CFBundleIdentifier', '%s.helper' % get_bundle_id(args))]
+ else:
+ error('Cannot patch unknown Info.plist %s' % file)
+ info(file)
+ patch_info_plist_file(file, tmp_replaces)
+
+def patch_locales(config, args):
+ print '\nPatching locales'
+ locales = config.get('Resources', 'Locales').split(',')
+ removed_locales = []
+ generated_locales = []
+ for infoplist_strings_file in glob(os.path.join(args.output, 'Contents/Resources'), 'InfoPlist.strings'):
+ locale_dir = os.path.dirname(infoplist_strings_file)
+ (locale, _) = os.path.splitext(os.path.basename(locale_dir))
+ if locale not in locales:
+ removed_locales.append(locale)
+ shutil.rmtree(locale_dir)
+ elif config.has_section('Locale %s' % locale):
+ generated_locales.append(locale)
+ generate_infoplist_strings_file(infoplist_strings_file, config.items('Locale %s' % locale))
+ else:
+ error('Missing [Locale %s] section' % locale)
+
+ if len(generated_locales) > 0:
+ info('Generated locales for %s' % ', '.join(generated_locales))
+ if len(removed_locales) > 0:
+ info('Removed locales for %s' % ', '.join(removed_locales))
+
+ removed_paks = []
+ for local_pak in glob(os.path.join(args.output, 'Contents/Versions'), 'locale.pak'):
+ locale_dir = os.path.dirname(local_pak)
+ (locale, _) = os.path.splitext(os.path.basename(locale_dir))
+ if locale != 'en' and locale not in locales:
+ removed_paks.append(locale)
+ shutil.rmtree(locale_dir)
+
+ if len(removed_paks) > 0:
+ info('Removed .pak files for %s' % ', '.join(removed_locales))
+
+def patch_icon(config, args):
+ plist = plistlib.readPlist(os.path.join(args.output, 'Contents/Info.plist'))
+ icon = os.path.join(os.path.dirname(args.config_file), config.get('Resources', 'Icon'))
+ dest_icon = os.path.join(args.output, 'Contents/Resources/%s' % plist['CFBundleIconFile'])
+ info('Copying icon from %s to %s' % (icon, dest_icon))
+ shutil.copy2(icon, dest_icon)
+
+def codesign_app(config, args):
+ print '\nCodesigning'
+
+ bundleid = get_bundle_id(args)
+
+ identity = config.get('Sign', 'ApplicationIdentity')
+ sandbox = True
+ if config.has_option('Sign', 'Sandbox'):
+ sandbox = config.getboolean('Sign', 'Sandbox')
+
+ ## sign child frameworks and helpers
+ (_, tmp_child_entitlements) = tempfile.mkstemp()
+ if config.has_option('Sign', 'ChildEntitlements'):
+ child = config.get('Sign', 'ChildEntitlements')
+ child_entitlements = plistlib.readPlist(child)
+ else:
+ child_entitlements = {
+ 'com.apple.security.app-sandbox' : sandbox,
+ 'com.apple.security.inherit' : True
+ }
+
+ plistlib.writePlist(child_entitlements, tmp_child_entitlements)
+ info('Child entitlements: %s' % tmp_child_entitlements)
+ framework = glob(args.output, 'nwjs Framework.framework', returnOnFound=True)
+ system('codesign -f --verbose -s "%s" --entitlements %s --deep "%s"' % (identity, tmp_child_entitlements, framework))
+ helperApp = glob(args.output, 'nwjs Helper.app', returnOnFound=True)
+ system('codesign -f --verbose -s "%s" --entitlements %s --deep "%s"' % (identity, tmp_child_entitlements, helperApp))
+
+ ## sign parent app
+ (_, tmp_parent_entitlements) = tempfile.mkstemp()
+ if config.has_option('Sign', 'ParentEntitlements'):
+ parent = config.get('Sign', 'ParentEntitlements')
+ parent_entitlements = plistlib.readPlist(parent)
+ else:
+ parent_entitlements = {}
+ teamid = get_from_info_plist(args, 'NWTeamID', default=None)
+ if teamid is None:
+ groupid = bundleid
+ else:
+ groupid = '%s.%s' % (teamid, bundleid)
+ parent_entitlements['com.apple.security.app-sandbox'] = sandbox
+ parent_entitlements['com.apple.security.application-groups'] = [groupid]
+ plistlib.writePlist(parent_entitlements, tmp_parent_entitlements)
+
+ info('Parent entitlements: %s' % tmp_parent_entitlements)
+ system('codesign -f --verbose -s "%s" --entitlements %s --deep "%s"' % (identity, tmp_parent_entitlements, args.output))
+
+def productbuild(config, args):
+ print '\nRunning productbuild'
+ installer_identity = config.get('Package', 'InstallerIdentity')
+ if config.has_option('Package', 'InstallPath'):
+ install_path = config.get('Package', 'InstallPath')
+ else:
+ install_path = '/Applications'
+ system('productbuild --component "%s" "%s" --sign "%s" "%s"' % (args.output, install_path, installer_identity, args.pkg))
+
+def main():
+ parser = argparse.ArgumentParser(description='Signing tool for NW.js app')
+ parser.add_argument('-C', '--config-file', default='build.cfg', help='config file. (default: build.cfg)')
+ parser.add_argument('-I', '--input', default='nwjs.app', help='path to input app. (default: nwjs.app)')
+ parser.add_argument('-O', '--output', default='nwjs_output.app', help='path to output app. (default: nwjs_output.app)')
+ parser.add_argument('-S', '--skip-patching', default=False, help='run codesign without patching the app. (default: False)', action='store_true')
+ parser.add_argument('-P', '--pkg', default=None, help='run productbuild to generate .pkg after codesign. (default: None)')
+ parser.add_argument('-V', '--verbose', default=False, help='display detailed information. (default: False)', action='store_true')
+ args = parser.parse_args()
+
+ global verbose
+ verbose = args.verbose
+
+ # read config file
+ config = read_config(args)
+
+ # make a copy
+ copy_to_output(args)
+
+ if not args.skip_patching:
+ # patch Info.plist
+ patch_info_plist(config, args)
+
+ # process resources & locales
+ if config.has_section('Resources'):
+ if config.has_option('Resources', 'Locales'):
+ patch_locales(config, args)
+ if config.has_option('Resources', 'Icon'):
+ patch_icon(config, args)
+
+ # codesign
+ codesign_app(config, args)
+
+ if args.pkg:
+ productbuild(config, args)
+
+ print '\nDone.'
+
+if __name__ == "__main__":
+ main()
diff --git a/resources/bitcoin.com/mac/pkg/entitlements-child.plist b/resources/bitcoin.com/mac/pkg/entitlements-child.plist
new file mode 100644
index 000000000..635e25aac
--- /dev/null
+++ b/resources/bitcoin.com/mac/pkg/entitlements-child.plist
@@ -0,0 +1,10 @@
+
+
+