diff --git a/.travis.yml b/.travis.yml
index 83662df00..acee1fe24 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,6 +8,7 @@ install:
- yarn install
script:
- yarn run generate
+ - yarn prepare-build
- ./node_modules/.bin/build --em.environment=$SIGNAL_ENV --config.mac.bundleVersion='$TRAVIS_BUILD_NUMBER' --publish=never
- ./travis.sh
env:
diff --git a/Gruntfile.js b/Gruntfile.js
index 5ec898f3e..bdab6a77f 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,4 +1,5 @@
var path = require('path');
+var packageJson = require('./package.json');
module.exports = function(grunt) {
'use strict';
@@ -204,23 +205,23 @@ module.exports = function(grunt) {
},
'test-release': {
osx: {
- archive: 'mac/Signal.app/Contents/Resources/app.asar',
- appUpdateYML: 'mac/Signal.app/Contents/Resources/app-update.yml',
- exe: 'mac/Signal.app/Contents/MacOS/Signal'
+ archive: 'mac/' + packageJson.productName + '.app/Contents/Resources/app.asar',
+ appUpdateYML: 'mac/' + packageJson.productName + '.app/Contents/Resources/app-update.yml',
+ exe: 'mac/' + packageJson.productName + '.app/Contents/MacOS/' + packageJson.productName
},
mas: {
archive: 'mas/Signal.app/Contents/Resources/app.asar',
appUpdateYML: 'mac/Signal.app/Contents/Resources/app-update.yml',
- exe: 'mas/Signal.app/Contents/MacOS/Signal'
+ exe: 'mas/' + packageJson.productName + '.app/Contents/MacOS/' + packageJson.productName
},
linux: {
archive: 'linux-unpacked/resources/app.asar',
- exe: 'linux-unpacked/signal-desktop'
+ exe: 'linux-unpacked/' + packageJson.name
},
win: {
archive: 'win-unpacked/resources/app.asar',
appUpdateYML: 'win-unpacked/resources/app-update.yml',
- exe: 'win-unpacked/Signal.exe'
+ exe: 'win-unpacked/' + packageJson.productName + '.exe'
}
},
gitinfo: {} // to be populated by grunt gitinfo
@@ -273,7 +274,6 @@ module.exports = function(grunt) {
require('mkdirp').sync('release');
var fs = require('fs');
var done = this.async();
- var package_json = grunt.config.get('pkg');
var gitinfo = grunt.config.get('gitinfo');
var https = require('https');
@@ -281,7 +281,7 @@ module.exports = function(grunt) {
var keyBase = 'WhisperSystems/Signal-Desktop';
var sha = gitinfo.local.branch.current.SHA;
var files = [{
- zip: 'signal-desktop-' + package_json.version + '.zip',
+ zip: packageJson.name + '-' + packageJson.version + '.zip',
extractedTo: 'linux'
}];
@@ -451,7 +451,7 @@ module.exports = function(grunt) {
return app.client.getTitle();
}).then(function (title) {
// Verify the window's title
- assert.equal(title, 'Signal');
+ assert.equal(title, packageJson.productName);
console.log('title ok');
}).then(function () {
assert(app.chromeDriver.logLines.indexOf('NODE_ENV ' + environment) > -1);
diff --git a/about.html b/about.html
index 93eba7e25..338527a2c 100644
--- a/about.html
+++ b/about.html
@@ -30,6 +30,20 @@ a {
document.write('v', window.config.version);
+
+
+
diff --git a/app/config.js b/app/config.js
index 4939cf05b..047d9c15e 100644
--- a/app/config.js
+++ b/app/config.js
@@ -1,12 +1,9 @@
-const fs = require('fs');
const path = require('path');
-console.log('reading package.json');
-const jsonFile = fs.readFileSync(path.join(__dirname, '..', 'package.json'));
-const package_json = JSON.parse(jsonFile, 'utf-8');
-const environment = package_json.environment || process.env.NODE_ENV || 'development';
+const packageJson = require('../package.json');
-console.log('configuring');
+
+const environment = packageJson.environment || process.env.NODE_ENV || 'development';
// Set environment vars to configure node-config before requiring it
process.env.NODE_ENV = environment;
diff --git a/app/user_config.js b/app/user_config.js
index 164ffe24e..4f77368b5 100644
--- a/app/user_config.js
+++ b/app/user_config.js
@@ -1,9 +1,11 @@
-const app = require('electron').app;
const path = require('path');
+
+const app = require('electron').app;
const ElectronConfig = require('electron-config');
const config = require('./config');
+
// use a separate data directory for development
if (config.has('storageProfile')) {
const userData = path.join(
diff --git a/appveyor.yml b/appveyor.yml
index 249dc1979..671182985 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -16,6 +16,7 @@ build_script:
- node build\grunt.js
- type package.json | findstr /v certificateSubjectName > temp.json
- move temp.json package.json
+ - yarn prepare-build
- node_modules\.bin\build --em.environment=%SIGNAL_ENV% --publish=never
test_script:
diff --git a/aptly.sh b/aptly.sh
index 3646bc189..1f7c08e3a 100755
--- a/aptly.sh
+++ b/aptly.sh
@@ -1,18 +1,40 @@
#!/bin/bash
-# Setup:
+# Setup - creates the local repo which will be mirrored up to S3, then back-fill it. Your
+# future deploys will eliminate all old versions without these backfill steps:
# aptly repo create signal-desktop
+# aptly mirror create -ignore-signatures backfill-mirror https://updates.signal.org/desktop/apt xenial
+# aptly mirror update -ignore-signatures backfill-mirror
+# aptly repo import backfill-mirror signal-desktop signal-desktop signal-desktop-beta
+# aptly repo show -with-packages signal-desktop
+#
+# First run on a machine - uncomment the first two 'aptly publish snapshot' commands,
+# comment the other two. Sets up the two publish channels, one local, one to S3.
+#
+# Testing - comment out the lines with s3:$ENDPOINT to publish only locally. To eliminate
+# effects of testing, remove package from repo, then move back to old snapshot:
+# aptly repo remove signal-desktop signal-desktop_1.0.35_amd64
+# aptly publish switch -gpg-key=57F6FB06 xenial signal-desktop_v1.0.34
#
# Release:
-# VERSION=X.X.X ./aptly.sh
+# NAME=signal-desktop(-beta) VERSION=X.X.X ./aptly.sh
+
+echo "Releasing $NAME build version $VERSION"
REPO=signal-desktop
DISTRO=xenial
ENDPOINT=signal-desktop-apt # Matches endpoint name in .aptly.conf
-DEB_PATH=release
SNAPSHOT=signal-desktop_v$VERSION
GPG_KEYID=57F6FB06
-aptly repo add $REPO $DEB_PATH/$REPO\_$VERSION\_*.deb
+aptly repo add $REPO release/$NAME\_$VERSION\_*.deb
aptly snapshot create $SNAPSHOT from repo $REPO
+
+# run these two only on first release to a given repo from a given machine
+# https://www.aptly.info/doc/aptly/publish/snapshot/
+# aptly publish snapshot -gpg-key=$GPG_KEYID $SNAPSHOT
+# aptly publish snapshot -gpg-key=$GPG_KEYID -config=.aptly.conf $SNAPSHOT s3:$ENDPOINT:
+
+# these update already-published repos, run every time after that
+# https://www.aptly.info/doc/aptly/publish/switch/
aptly publish switch -gpg-key=$GPG_KEYID $DISTRO $SNAPSHOT
aptly publish switch -gpg-key=$GPG_KEYID -config=.aptly.conf $DISTRO s3:$ENDPOINT: $SNAPSHOT
diff --git a/js/background.js b/js/background.js
index bfcb05b31..443df5d26 100644
--- a/js/background.js
+++ b/js/background.js
@@ -14,6 +14,15 @@
var initialLoadComplete = false;
window.owsDesktopApp = {};
+ var title = window.config.name;
+ if (window.config.environment !== 'production') {
+ title += ' - ' + window.config.environment;
+ }
+ if (window.config.appInstance) {
+ title += ' - ' + window.config.appInstance;
+ }
+ window.config.title = window.document.title = title;
+
// start a background worker for ecc
textsecure.startWorker('js/libsignal-protocol-worker.js');
Whisper.KeyChangeListener.init(textsecure.storage.protocol);
diff --git a/js/conversation_controller.js b/js/conversation_controller.js
index 1d6b522d2..9fe2c67bb 100644
--- a/js/conversation_controller.js
+++ b/js/conversation_controller.js
@@ -64,10 +64,10 @@
if (newUnreadCount > 0) {
window.setBadgeCount(newUnreadCount);
- window.document.title = "Signal (" + newUnreadCount + ")";
+ window.document.title = window.config.title + " (" + newUnreadCount + ")";
} else {
window.setBadgeCount(0);
- window.document.title = "Signal";
+ window.document.title = window.config.title;
}
},
startPruning: function() {
diff --git a/js/logging.js b/js/logging.js
index f7a687fe0..b2d864f5b 100644
--- a/js/logging.js
+++ b/js/logging.js
@@ -69,7 +69,12 @@ if (window.console) {
// The mechanics of preparing a log for publish
function getHeader() {
- return window.navigator.userAgent + ' node/' + window.config.node_version;
+ let header = window.navigator.userAgent;
+
+ header += ' node/' + window.config.node_version;
+ header += ' env/' + window.config.environment;
+
+ return header;
}
function getLevel(level) {
diff --git a/main.js b/main.js
index 36f7d2f42..130b0de3f 100644
--- a/main.js
+++ b/main.js
@@ -3,7 +3,7 @@ const url = require('url');
const os = require('os');
const _ = require('lodash');
-const electron = require('electron')
+const electron = require('electron');
const BrowserWindow = electron.BrowserWindow;
const app = electron.app;
@@ -11,20 +11,26 @@ const ipc = electron.ipcMain;
const Menu = electron.Menu;
const shell = electron.shell;
+const packageJson = require('./package.json');
const autoUpdate = require('./app/auto_update');
const windowState = require('./app/window_state');
-console.log('setting AUMID');
-app.setAppUserModelId('org.whispersystems.signal-desktop')
+const aumid = 'org.whispersystems.' + packageJson.name;
+console.log('setting AUMID to ' + aumid);
+app.setAppUserModelId(aumid);
// Keep a global reference of the window object, if you don't, the window will
-// be closed automatically when the JavaScript object is garbage collected.
+// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;
const config = require("./app/config");
-if (config.environment === 'production' && !process.mas) {
+// Very important to put before the single instance check, since it is based on the
+// userData directory.
+const userConfig = require('./app/user_config');
+
+if (!process.mas) {
console.log('making app single instance');
var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) {
// Someone tried to run a second instance, we should focus our window
@@ -36,16 +42,15 @@ if (config.environment === 'production' && !process.mas) {
});
if (shouldQuit) {
- console.log('quitting');
+ console.log('quitting; we are the second instance');
app.quit();
return;
}
}
-const userConfig = require('./app/user_config');
const logging = require('./app/logging');
-// this must be after we set up appPath in user_config.js
+// This must be after we set up appPath in user_config.js, so we know where logs go
logging.initialize();
const logger = logging.getLogger();
@@ -60,6 +65,7 @@ function prepareURL(pathSegments) {
protocol: 'file:',
slashes: true,
query: {
+ name: packageJson.productName,
locale: locale.name,
version: app.getVersion(),
buildExpiration: config.get('buildExpiration'),
@@ -69,6 +75,7 @@ function prepareURL(pathSegments) {
environment: config.environment,
node_version: process.versions.node,
hostname: os.hostname(),
+ appInstance: process.env.NODE_APP_INSTANCE,
}
})
}
diff --git a/package.json b/package.json
index d082d5b24..4d6d825f6 100644
--- a/package.json
+++ b/package.json
@@ -41,6 +41,7 @@
"build": "build --em.environment=$SIGNAL_ENV",
"dist": "npm run generate && npm run build",
"pack": "npm run generate && npm run build -- --dir",
+ "prepare-build": "node prepare_build.js",
"pack-prod": "SIGNAL_ENV=production npm run pack",
"dist-prod": "SIGNAL_ENV=production npm run dist",
"dist-prod-all": "SIGNAL_ENV=production npm run dist -- -mwl",
@@ -51,13 +52,13 @@
"prep-release": "npm run generate && grunt prep-release && npm run build-release && npm run build-mas-release && grunt test-release",
"release-mac": "npm run build-release -- -m --prepackaged release/mac/Signal.app --publish=always",
"release-win": "npm run build-release -- -w --prepackaged release/windows --publish=always",
- "release-lin": "npm run build-release -- -l --prepackaged release/linux && VERSION=$npm_package_version ./aptly.sh",
+ "release-lin": "npm run build-release -- -l --prepackaged release/linux && NAME=$npm_package_name VERSION=$npm_package_version ./aptly.sh",
"release": "npm run release-mac && npm run release-win && npm run release-lin"
},
"build": {
"appId": "org.whispersystems.signal-desktop",
"mac": {
- "artifactName": "${productName}-mac-${version}.${ext}",
+ "artifactName": "${name}-mac-${version}.${ext}",
"category": "public.app-category.social-networking",
"icon": "build/icons/mac/icon.icns",
"publish": [
@@ -81,7 +82,7 @@
},
"win": {
"asarUnpack": "node_modules/spellchecker/vendor/hunspell_dictionaries",
- "artifactName": "${productName}-win-${version}.${ext}",
+ "artifactName": "${name}-win-${version}.${ext}",
"certificateSubjectName": "Signal",
"publisherName": "Signal (Quiet Riddle Ventures, LLC)",
"icon": "build/icons/win/icon.ico",
diff --git a/prepare_build.js b/prepare_build.js
new file mode 100644
index 000000000..06d894f65
--- /dev/null
+++ b/prepare_build.js
@@ -0,0 +1,65 @@
+const fs = require('fs');
+const _ = require('lodash');
+
+const packageJson = require('./package.json');
+const version = packageJson.version;
+const beta = /beta/;
+
+// You might be wondering why this file is necessary. It comes down to our desire to allow
+// side-by-side installation of production and beta builds. Electron-Builder uses
+// top-level data from package.json for many things, like the executable name, the
+// debian package name, the install directory under /opt on linux, etc. We tried
+// adding the ${channel} macro to these values, but Electron-Builder didn't like that.
+
+if (!beta.test(version)) {
+ return;
+}
+
+console.log('prepare_build: updating package.json for beta build');
+
+// -------
+
+const NAME_PATH = 'name';
+const PRODUCTION_NAME = 'signal-desktop';
+const BETA_NAME = 'signal-desktop-beta';
+
+const PRODUCT_NAME_PATH = 'productName';
+const PRODUCTION_PRODUCT_NAME = 'Signal';
+const BETA_PRODUCT_NAME = 'Signal Beta';
+
+const APP_ID_PATH = 'build.appId';
+const PRODUCTION_APP_ID = 'org.whispersystems.signal-desktop';
+const BETA_APP_ID = 'org.whispersystems.signal-desktop-beta';
+
+const STARTUP_WM_CLASS_PATH = 'build.linux.desktop.StartupWMClass';
+const PRODUCTION_STARTUP_WM_CLASS = 'Signal';
+const BETA_STARTUP_WM_CLASS = 'Signal Beta';
+
+
+
+// -------
+
+function checkValue(object, objectPath, expected) {
+ const actual = _.get(object, objectPath)
+ if (actual !== expected) {
+ throw new Error(objectPath + ' was ' + actual + '; expected ' + expected);
+ }
+}
+
+// ------
+
+checkValue(packageJson, NAME_PATH, PRODUCTION_NAME);
+checkValue(packageJson, PRODUCT_NAME_PATH, PRODUCTION_PRODUCT_NAME);
+checkValue(packageJson, APP_ID_PATH, PRODUCTION_APP_ID);
+checkValue(packageJson, STARTUP_WM_CLASS_PATH, PRODUCTION_STARTUP_WM_CLASS);
+
+// -------
+
+_.set(packageJson, NAME_PATH, BETA_NAME);
+_.set(packageJson, PRODUCT_NAME_PATH, BETA_PRODUCT_NAME);
+_.set(packageJson, APP_ID_PATH, BETA_APP_ID);
+_.set(packageJson, STARTUP_WM_CLASS_PATH, BETA_STARTUP_WM_CLASS);
+
+// -------
+
+fs.writeFileSync('./package.json', JSON.stringify(packageJson, null, ' '));