61 |
62 |
63 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/app/pages/success.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
13 |
29 |
30 |
31 |
32 |
33 |
34 |

35 |
36 |
37 |
38 |
39 |
40 |
41 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/app/src/controllers/auth.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Controller: authCtrl
3 | */
4 |
5 | export default (app, window) => {
6 | return app.controller('authCtrl', ['$scope', 'Uber', function authCtrl($scope, Uber) {
7 | $scope.submit = () => {
8 | if ($scope.authForm.$valid) {
9 | var options = $scope.options;
10 | return Uber.authorize(options);
11 | } else {
12 | window.angular.forEach($scope.authForm.$error.required, function(field) {
13 | field.$setDirty();
14 | });
15 | }
16 | };
17 | }]);
18 | };
19 |
--------------------------------------------------------------------------------
/app/src/controllers/success.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Controller: successCtrl
3 | */
4 |
5 | import { clipboard } from 'electron';
6 |
7 | export default (app, window, access_token) => {
8 | return app.controller('successCtrl', ['$scope', function successCtrl($scope) {
9 | $scope.access_token = access_token;
10 |
11 | $scope.copy = () => {
12 | clipboard.writeText(access_token);
13 |
14 | new Notification('Success', {
15 | body: 'Copied to clipboard.'
16 | });
17 | };
18 | }]);
19 | };
20 |
--------------------------------------------------------------------------------
/app/src/services/uber.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Service: Uber
3 | */
4 |
5 | import crypto from 'crypto';
6 | import querystring from 'querystring';
7 | import { remote, ipcRenderer } from 'electron';
8 |
9 | const BrowserWindow = remote.BrowserWindow;
10 |
11 | export default (app) => {
12 | return app.factory('Uber', ($http) => {
13 | return {
14 | authorize: (options) => {
15 | //Build the OAuth consent page URL
16 | let authWindow = new BrowserWindow({
17 | minWidth: 600,
18 | minHeight: 835,
19 | width: 600,
20 | height: 835,
21 | show: true,
22 | center: true,
23 | resizable: true,
24 | webPreferences: {
25 | nodeIntegration: false
26 | },
27 | titleBarStyle: 'hidden'
28 | });
29 |
30 | // Generate request state
31 | let state = crypto.randomBytes(256).toString('hex')
32 | // Populate data
33 | let data = {
34 | response_type: 'code',
35 | client_id: options.client_id,
36 | scope: options.scope,
37 | state: state,
38 | redirect_uri: options.redirect_url,
39 | };
40 |
41 | let qs = querystring.stringify(data)
42 | let authUrl = 'https://login.uber.com/oauth/v2/authorize?' + qs;
43 |
44 | // Get token
45 | let getAccessToken = (code) => {
46 | let data = {
47 | grant_type: 'authorization_code',
48 | client_id: options.client_id,
49 | client_secret: options.client_secret,
50 | redirect_uri: options.redirect_url,
51 | code: code
52 | };
53 |
54 | let request_data = {
55 | method: 'POST',
56 | url: 'https://login.uber.com/oauth/v2/token',
57 | headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
58 | transformRequest: function(obj) {
59 | var str = [];
60 | for(var p in obj)
61 | str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
62 | return str.join("&");
63 | },
64 | data: data
65 | };
66 |
67 | return $http(request_data)
68 | .success((data, status) => {
69 | if (status === 200) {
70 | return ipcRenderer.send('load-success-page', data.access_token);
71 | }
72 | })
73 | .error(() => {
74 | return ipcRenderer.send('open-error-dialog');
75 | });
76 | };
77 |
78 | let handleCallback = (url) => {
79 | let raw_code = /code=([^&]*)/.exec(url) || null;
80 | let code = (raw_code && raw_code.length > 1) ? raw_code[1] : null;
81 | let error = /\?error=(.+)$/.exec(url);
82 |
83 | if (!code && error) {
84 | // Close the browser if has an error
85 | authWindow.destroy();
86 | return ipcRenderer.send('open-error-dialog');
87 | }
88 |
89 | // If there is a code, proceed to get token from github
90 | if (code) {
91 | authWindow.destroy();
92 | return getAccessToken(code);
93 | }
94 | };
95 |
96 | authWindow.loadURL(authUrl);
97 |
98 | authWindow.webContents.on('will-navigate', (event, url) => {
99 | return handleCallback(url);
100 | });
101 |
102 | authWindow.webContents.on('did-get-redirect-request', (event, oldUrl, newUrl) => {
103 | return handleCallback(newUrl);
104 | });
105 |
106 | // If "Done" button is pressed, hide "Loading"
107 | authWindow.on('close', () => {
108 | authWindow = null;
109 | });
110 | }
111 | };
112 | });
113 | };
114 |
--------------------------------------------------------------------------------
/app/test/bootstrap.spec.js:
--------------------------------------------------------------------------------
1 | import './test_helper';
2 |
3 | let pkg = require('./package.json');
4 |
5 | describe("Bootstrap", function() {
6 |
7 | describe('#MainWindow', function() {
8 |
9 | beforeEach(function() {
10 | return this.app.client.waitUntilWindowLoaded();
11 | });
12 |
13 | it('should open only 1', function() {
14 | return this.app.client.getWindowCount()
15 | .should.eventually.equal(1);
16 | });
17 |
18 | it('should not be minimized', function() {
19 | return this.app.client.browserWindow.isMinimized()
20 | .should.eventually.be.false;
21 | });
22 |
23 | it('should not open the DevTools window', function() {
24 | return this.app.client.browserWindow.isDevToolsOpened()
25 | .should.eventually.be.false;
26 | });
27 |
28 | it('should be visiable', function() {
29 | return this.app.client.browserWindow.isVisible()
30 | .should.eventually.be.true;
31 | });
32 |
33 | it('should be focused', function() {
34 | return this.app.client.browserWindow.isFocused()
35 | .should.eventually.be.true;
36 | });
37 |
38 | it('should have title equals to \'' + pkg.productName + '\'', function() {
39 | return this.app.client.browserWindow.getTitle()
40 | .should.eventually.be.equal(pkg.productName);
41 | });
42 |
43 | });
44 | });
45 |
--------------------------------------------------------------------------------
/app/test/environment.spec.js:
--------------------------------------------------------------------------------
1 | import './test_helper';
2 | import env from '../env';
3 |
4 | describe('Environment', function() {
5 |
6 | it('environment variables should be on their place', function() {
7 | return env.name.should.be.equal('test');
8 | });
9 |
10 | });
11 |
--------------------------------------------------------------------------------
/app/test/test_helper.js:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import electron from 'electron-prebuilt';
3 | import chai from 'chai';
4 | import chaiAsPromised from 'chai-as-promised';
5 | import { Application } from 'spectron';
6 |
7 | chai.use(chaiAsPromised);
8 |
9 | chai.should();
10 |
11 | beforeEach(function () {
12 | let appPath = path.join(__dirname, '..', 'build');
13 |
14 | this.app = new Application({
15 | path: electron,
16 | args: [appPath],
17 | startTimeout: 8000,
18 | chromeDriverLogPath: '/tmp/chromedriver.log',
19 | nodePath: process.env.NODE_PATH
20 | });
21 |
22 | return this.app.start();
23 | });
24 |
25 | beforeEach(function () {
26 | chaiAsPromised.transferPromiseness = this.app.transferPromiseness;
27 | });
28 |
29 | afterEach(function () {
30 | if (this.app && this.app.isRunning()) {
31 | return this.app.stop();
32 | }
33 | });
34 |
--------------------------------------------------------------------------------
/config/env_development.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "development"
3 | }
4 |
--------------------------------------------------------------------------------
/config/env_production.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "production"
3 | }
4 |
--------------------------------------------------------------------------------
/config/env_test.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "test"
3 | }
4 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('./tasks/build/build');
4 | require('./tasks/release/release');
5 | require('./tasks/start');
6 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "devDependencies": {
3 | "asar": "^0.11.0",
4 | "chai": "^3.5.0",
5 | "chai-as-promised": "^5.3.0",
6 | "codeclimate-test-reporter": "^0.3.3",
7 | "devtron": "^1.2.1",
8 | "electron-mocha": "^2.0.0",
9 | "electron-prebuilt": "^1.0.1",
10 | "eslint": "^3.1.1",
11 | "eslint-config-airbnb": "^9.0.1",
12 | "eslint-plugin-import": "^1.11.1",
13 | "fs-jetpack": "^0.9.0",
14 | "gulp": "^3.9.0",
15 | "gulp-batch": "^1.0.5",
16 | "gulp-util": "^3.0.6",
17 | "gulp-watch": "^4.3.5",
18 | "istanbul": "^0.4.4",
19 | "q": "^1.4.1",
20 | "rollup": "^0.26.3",
21 | "spectron": "^3.2.6",
22 | "yargs": "^4.2.0"
23 | },
24 | "optionalDependencies": {
25 | "appdmg": "^0.3.2",
26 | "rcedit": "^0.5.0"
27 | },
28 | "scripts": {
29 | "postinstall": "script/postinstall.sh",
30 | "build": "gulp build",
31 | "release": "gulp release --env=production",
32 | "start": "gulp start",
33 | "pretest": "gulp build --env=test",
34 | "test": "script/test.sh",
35 | "install-native": "node ./tasks/install_native_module",
36 | "clear": "rm -rf '/Users/chrisenytc/Library/Application Support/UbAuth Dev' && rm -rf '/Users/chrisenytc/Library/Application Support/UbAuth'"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/resources/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisenytc/ubauth/296ed101bfa403cee42896add89ed3e3590da5ef/resources/banner.png
--------------------------------------------------------------------------------
/resources/bitcoin-address.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisenytc/ubauth/296ed101bfa403cee42896add89ed3e3590da5ef/resources/bitcoin-address.png
--------------------------------------------------------------------------------
/resources/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisenytc/ubauth/296ed101bfa403cee42896add89ed3e3590da5ef/resources/icon.png
--------------------------------------------------------------------------------
/resources/linux/DEBIAN/control:
--------------------------------------------------------------------------------
1 | Package: {{name}}
2 | Version: {{version}}
3 | Maintainer: {{author}}
4 | Priority: optional
5 | Architecture: amd64
6 | Installed-Size: {{size}}
7 | Description: {{description}}
8 |
--------------------------------------------------------------------------------
/resources/linux/app.desktop:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Version=1.0
3 | Type=Application
4 | Encoding=UTF-8
5 | Name={{productName}}
6 | Comment={{description}}
7 | Exec=/opt/{{name}}/{{name}}
8 | Path=/opt/{{name}}/
9 | Icon=/opt/{{name}}/icon.png
10 | Terminal=false
11 | Categories=Application;
12 |
--------------------------------------------------------------------------------
/resources/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisenytc/ubauth/296ed101bfa403cee42896add89ed3e3590da5ef/resources/logo.png
--------------------------------------------------------------------------------
/resources/osx/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDisplayName
6 | {{productName}}
7 | CFBundleExecutable
8 | {{productName}}
9 | CFBundleIconFile
10 | icon.icns
11 | CFBundleIdentifier
12 | {{identifier}}
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | {{productName}}
17 | CFBundlePackageType
18 | APPL
19 | CFBundleVersion
20 | {{build}}
21 | CFBundleVersionString
22 | {{build}}
23 | CFBundleShortVersionString
24 | {{version}}
25 | CFBundleGetInfoString
26 | {{version}}
27 | LSMinimumSystemVersion
28 | 10.8.0
29 | NSMainNibFile
30 | MainMenu
31 | NSPrincipalClass
32 | AtomApplication
33 | NSSupportsAutomaticGraphicsSwitching
34 |
35 | NSHumanReadableCopyright
36 | {{copyright}}
37 | LSApplicationCategoryType
38 | {{LSApplicationCategoryType}}
39 |
40 |
41 |
--------------------------------------------------------------------------------
/resources/osx/appdmg.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "{{productName}}",
3 | "icon": "{{dmgIcon}}",
4 | "background": "{{dmgBackground}}",
5 | "icon-size": 128,
6 | "contents": [
7 | { "x": 410, "y": 220, "type": "link", "path": "/Applications" },
8 | { "x": 130, "y": 220, "type": "file", "path": "{{appPath}}" }
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/resources/osx/child.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.inherit
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/resources/osx/dmg-background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisenytc/ubauth/296ed101bfa403cee42896add89ed3e3590da5ef/resources/osx/dmg-background.png
--------------------------------------------------------------------------------
/resources/osx/dmg-background@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisenytc/ubauth/296ed101bfa403cee42896add89ed3e3590da5ef/resources/osx/dmg-background@2x.png
--------------------------------------------------------------------------------
/resources/osx/dmg-icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisenytc/ubauth/296ed101bfa403cee42896add89ed3e3590da5ef/resources/osx/dmg-icon.icns
--------------------------------------------------------------------------------
/resources/osx/helper_apps/Info EH.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDisplayName
6 | {{productName}} Helper EH
7 | CFBundleExecutable
8 | {{productName}} Helper EH
9 | CFBundleIdentifier
10 | {{identifier}}.helper.EH
11 | CFBundleName
12 | {{productName}} Helper EH
13 | CFBundlePackageType
14 | APPL
15 | DTSDKName
16 | macosx
17 | LSUIElement
18 |
19 | NSSupportsAutomaticGraphicsSwitching
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/resources/osx/helper_apps/Info NP.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDisplayName
6 | {{productName}} Helper NP
7 | CFBundleExecutable
8 | {{productName}} Helper NP
9 | CFBundleIdentifier
10 | {{identifier}}.helper.NP
11 | CFBundleName
12 | {{productName}} Helper NP
13 | CFBundlePackageType
14 | APPL
15 | DTSDKName
16 | macosx
17 | LSUIElement
18 |
19 | NSSupportsAutomaticGraphicsSwitching
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/resources/osx/helper_apps/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleIdentifier
6 | {{identifier}}.helper
7 | CFBundleName
8 | {{productName}} Helper
9 | CFBundlePackageType
10 | APPL
11 | DTSDKName
12 | macosx
13 | LSUIElement
14 |
15 | NSSupportsAutomaticGraphicsSwitching
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/resources/osx/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisenytc/ubauth/296ed101bfa403cee42896add89ed3e3590da5ef/resources/osx/icon.icns
--------------------------------------------------------------------------------
/resources/osx/parent.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.device.camera
8 |
9 | com.apple.security.device.microphone
10 |
11 | com.apple.security.files.user-selected.read-only
12 |
13 | com.apple.security.files.user-selected.read-write
14 |
15 | com.apple.security.network.client
16 |
17 | com.apple.security.network.server
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/resources/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisenytc/ubauth/296ed101bfa403cee42896add89ed3e3590da5ef/resources/screenshot.png
--------------------------------------------------------------------------------
/resources/windows/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisenytc/ubauth/296ed101bfa403cee42896add89ed3e3590da5ef/resources/windows/icon.ico
--------------------------------------------------------------------------------
/resources/windows/installer.nsi:
--------------------------------------------------------------------------------
1 | ; NSIS packaging/install script
2 | ; Docs: http://nsis.sourceforge.net/Docs/Contents.html
3 |
4 | !include LogicLib.nsh
5 | !include nsDialogs.nsh
6 |
7 | ; --------------------------------
8 | ; Variables
9 | ; --------------------------------
10 |
11 | !define dest "{{dest}}"
12 | !define src "{{src}}"
13 | !define name "{{name}}"
14 | !define productName "{{productName}}"
15 | !define author "{{author}}"
16 | !define version "{{version}}"
17 | !define icon "{{icon}}"
18 | !define setupIcon "{{setupIcon}}"
19 | !define banner "{{banner}}"
20 |
21 | !define exec "{{productName}}.exe"
22 |
23 | !define regkey "Software\${productName}"
24 | !define uninstkey "Software\Microsoft\Windows\CurrentVersion\Uninstall\${productName}"
25 |
26 | !define uninstaller "uninstall.exe"
27 |
28 | ; --------------------------------
29 | ; Installation
30 | ; --------------------------------
31 |
32 | Unicode true
33 | SetCompressor /SOLID lzma
34 |
35 | Name "${productName}"
36 | Icon "${setupIcon}"
37 | OutFile "${dest}"
38 | InstallDir "$PROGRAMFILES\${productName}"
39 | InstallDirRegKey HKLM "${regkey}" ""
40 |
41 | RequestExecutionLevel admin
42 | CRCCheck on
43 | SilentInstall normal
44 |
45 | XPStyle on
46 | ShowInstDetails nevershow
47 | AutoCloseWindow false
48 | WindowIcon off
49 |
50 | Caption "${productName} Setup"
51 | ; Don't add sub-captions to title bar
52 | SubCaption 3 " "
53 | SubCaption 4 " "
54 |
55 | Page custom welcome
56 | Page instfiles
57 |
58 | Var Image
59 | Var ImageHandle
60 |
61 | Function .onInit
62 |
63 | ; Extract banner image for welcome page
64 | InitPluginsDir
65 | ReserveFile "${banner}"
66 | File /oname=$PLUGINSDIR\banner.bmp "${banner}"
67 |
68 | FunctionEnd
69 |
70 | ; Custom welcome page
71 | Function welcome
72 |
73 | nsDialogs::Create 1018
74 |
75 | ${NSD_CreateLabel} 185 1u 210 100% "Welcome to ${productName} version ${version} installer.$\r$\n$\r$\nClick install to begin."
76 |
77 | ${NSD_CreateBitmap} 0 0 170 210 ""
78 | Pop $Image
79 | ${NSD_SetImage} $Image $PLUGINSDIR\banner.bmp $ImageHandle
80 |
81 | nsDialogs::Show
82 |
83 | ${NSD_FreeImage} $ImageHandle
84 |
85 | FunctionEnd
86 |
87 | ; Installation declarations
88 | Section "Install"
89 |
90 | WriteRegStr HKLM "${regkey}" "Install_Dir" "$INSTDIR"
91 | WriteRegStr HKLM "${uninstkey}" "DisplayName" "${productName}"
92 | WriteRegStr HKLM "${uninstkey}" "DisplayIcon" '"$INSTDIR\icon.ico"'
93 | WriteRegStr HKLM "${uninstkey}" "UninstallString" '"$INSTDIR\${uninstaller}"'
94 | WriteRegStr HKLM "${uninstkey}" "Publisher" "${author}"
95 | WriteRegStr HKLM "${uninstkey}" "DisplayVersion" "${version}"
96 |
97 | ; Remove all application files copied by previous installation
98 | RMDir /r "$INSTDIR"
99 |
100 | SetOutPath $INSTDIR
101 |
102 | ; Include all files from /build directory
103 | File /r "${src}\*"
104 |
105 | ; Create start menu shortcut
106 | SetShellVarContext all
107 | CreateShortCut "$SMPROGRAMS\${productName}.lnk" "$INSTDIR\${exec}" "" "$INSTDIR\icon.ico"
108 | ; Create desktop shortcut
109 | CreateShortCut "$DESKTOP\${productName}.lnk" "$INSTDIR\${exec}" "" "$INSTDIR\icon.ico"
110 |
111 | WriteUninstaller "${uninstaller}"
112 |
113 | SectionEnd
114 |
115 | ; --------------------------------
116 | ; Uninstaller
117 | ; --------------------------------
118 |
119 | ShowUninstDetails nevershow
120 |
121 | UninstallCaption "Uninstall ${productName}"
122 | UninstallText "Don't like ${productName} anymore? Hit uninstall button."
123 | UninstallIcon "${icon}"
124 |
125 | UninstPage custom un.confirm un.confirmOnLeave
126 | UninstPage instfiles
127 |
128 | Var RemoveAppDataCheckbox
129 | Var RemoveAppDataCheckbox_State
130 |
131 | ; Custom uninstall confirm page
132 | Function un.confirm
133 |
134 | nsDialogs::Create 1018
135 |
136 | ${NSD_CreateLabel} 1u 1u 100% 24u "If you really want to remove ${productName} from your computer press uninstall button."
137 |
138 | ${NSD_CreateCheckbox} 1u 35u 100% 10u "Remove also my ${productName} personal data"
139 | Pop $RemoveAppDataCheckbox
140 |
141 | nsDialogs::Show
142 |
143 | FunctionEnd
144 |
145 | Function un.confirmOnLeave
146 |
147 | ; Save checkbox state on page leave
148 | ${NSD_GetState} $RemoveAppDataCheckbox $RemoveAppDataCheckbox_State
149 |
150 | FunctionEnd
151 |
152 | ; Uninstall declarations
153 | Section "Uninstall"
154 |
155 | DeleteRegKey HKLM "${uninstkey}"
156 | DeleteRegKey HKLM "${regkey}"
157 |
158 | SetShellVarContext all
159 | Delete "$SMPROGRAMS\${productName}.lnk"
160 | ; Remove desktop shortcut
161 | Delete "$DESKTOP\${productName}.lnk"
162 | ; Remove whole directory from Program Files
163 | RMDir /r "$INSTDIR"
164 |
165 | ; Remove also appData directory generated by your app if user checked this option
166 | ${If} $RemoveAppDataCheckbox_State == ${BST_CHECKED}
167 | RMDir /r "$APPDATA\${productName}"
168 | ${EndIf}
169 |
170 | SectionEnd
171 |
--------------------------------------------------------------------------------
/resources/windows/setup-banner.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisenytc/ubauth/296ed101bfa403cee42896add89ed3e3590da5ef/resources/windows/setup-banner.bmp
--------------------------------------------------------------------------------
/resources/windows/setup-icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chrisenytc/ubauth/296ed101bfa403cee42896add89ed3e3590da5ef/resources/windows/setup-icon.ico
--------------------------------------------------------------------------------
/script/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | echo "Building the package"
4 |
5 | npm run release -- --sign "$CODESIGN_KEY"
6 |
7 | echo "Loading package file"
8 |
9 | PKG=$(cat ./app/package.json)
10 |
11 | echo "Getting app version"
12 |
13 | VERSION=$(echo "$PKG" | jq '.version')
14 |
15 | CLEANED_VERSION=${VERSION//\"}
16 |
17 | echo "Exporting app version"
18 |
19 | export APP_VERSION=${CLEANED_VERSION}
20 |
21 | echo "Deploying version ${APP_VERSION} to GitHub releases. ¯\\_(ツ)_/¯"
22 |
--------------------------------------------------------------------------------
/script/install.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | echo "Updating brew"
4 |
5 | brew update
6 |
7 | echo "Installing jq module"
8 |
9 | brew install jq
10 |
11 | if [[ "$TRAVIS" == true ]]; then
12 | echo "Installing NVM"
13 |
14 | NVM_ROOT="${HOME}/.nvm"
15 | rm -rf "$NVM_ROOT"
16 | git clone https://github.com/creationix/nvm.git "$NVM_ROOT"
17 | # shellcheck disable=SC1090
18 | source "${NVM_ROOT}/nvm.sh"
19 |
20 | echo "Installing node.js"
21 |
22 | nvm install "$NODE_VERSION"
23 | node --version
24 | npm --version
25 | else
26 | bundle install
27 | overcommit --install
28 | fi
29 |
30 | echo "Installing development dependencies"
31 |
32 | npm install
33 |
--------------------------------------------------------------------------------
/script/keychain.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
4 | echo "Exporting Certificate file"
5 | export CERTIFICATE_P12=${TRAVIS_BUILD_DIR}/Certificate.p12;
6 | echo "Decoding Certificate"
7 | echo "$CERTIFICATE_OSX_P12" | base64 -D > "$CERTIFICATE_P12";
8 | echo "Exporting Keychain file"
9 | export KEYCHAIN=${TRAVIS_BUILD_DIR}/build.keychain;
10 | echo "Creating Keychain"
11 | security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN";
12 | echo "Setting Keychain as default"
13 | security default-keychain -s "$KEYCHAIN";
14 | echo "Unlocking Keychain"
15 | security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN";
16 | echo "Importing '${CERTIFICATE_P12}' to '${KEYCHAIN}'"
17 | security import "$CERTIFICATE_P12" -k "$KEYCHAIN" -P "$CERTIFICATE_PASSWORD" -T /usr/bin/codesign;
18 | echo "Certificate imported to '${KEYCHAIN}'"
19 | fi
20 |
--------------------------------------------------------------------------------
/script/postinstall.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | echo "Entering in app directory"
4 |
5 | cd app || exit
6 |
7 | echo "Installing app dependencies"
8 |
9 | npm install
10 |
--------------------------------------------------------------------------------
/script/test.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | echo "Getting node executable path"
4 |
5 | NODE_EXEC_PATH=$(which node)
6 |
7 | echo "Exporting node executable path"
8 |
9 | export NODE_PATH=$NODE_EXEC_PATH
10 |
11 | echo "Running tests"
12 |
13 | istanbul cover electron-mocha -- --ui bdd --timeout 80000 --reporter spec --inline-diffs --bail build
14 |
15 | if [ -f coverage/lcov.info ]; then
16 | codeclimate-test-reporter < coverage/lcov.info
17 | fi
18 |
--------------------------------------------------------------------------------
/tasks/build/build.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Q = require('q');
4 | var gulp = require('gulp');
5 | var watch = require('gulp-watch');
6 | var batch = require('gulp-batch');
7 | var jetpack = require('fs-jetpack');
8 | var asar = require('asar');
9 |
10 | var bundle = require('./bundle');
11 | var generateSpecImportsFile = require('./generate_spec_imports');
12 | var utils = require('../utils');
13 | var pkg = require('../../app/package.json');
14 |
15 | var projectDir = jetpack;
16 | var srcDir = projectDir.cwd('./app');
17 | var destDir = projectDir.cwd('./build');
18 |
19 | var paths = {
20 | copyFromAppDir: [
21 | './node_modules/**',
22 | './helpers/**',
23 | './assets/**',
24 | './**/*.html',
25 | './**/*.+(jpg|png|svg)'
26 | ],
27 | };
28 |
29 | // -------------------------------------
30 | // Tasks
31 | // -------------------------------------
32 |
33 | gulp.task('clean', function () {
34 | return destDir.dirAsync('.', { empty: true });
35 | });
36 |
37 | var copyTask = function () {
38 | return projectDir.copyAsync('app', destDir.path(), {
39 | overwrite: true,
40 | matching: paths.copyFromAppDir
41 | });
42 | };
43 |
44 | gulp.task('copy', ['clean'], copyTask);
45 | gulp.task('copy-watch', ['copy', 'generate']);
46 |
47 | var generateTask = function () {
48 | if (utils.getEnvName() != 'production') {
49 | var deferred = Q.defer();
50 | asar.createPackage(destDir.path(), destDir.path(pkg.productName + '.asar'), function() {
51 | deferred.resolve();
52 | });
53 | return deferred.promise;
54 | }
55 |
56 | return;
57 | };
58 |
59 | gulp.task('generate', ['copy'], generateTask);
60 |
61 | var bundleApplication = function () {
62 | return Q.all([
63 | bundle(srcDir.path('background.js'), destDir.path('background.js')),
64 | bundle(srcDir.path('app.js'), destDir.path('app.js')),
65 | bundle(srcDir.path('src', 'controllers', 'auth.js'), destDir.path('controllers', 'auth.js')),
66 | bundle(srcDir.path('src', 'controllers', 'success.js'), destDir.path('controllers', 'success.js')),
67 | bundle(srcDir.path('src', 'services', 'uber.js'), destDir.path('services', 'uber.js'))
68 | ]);
69 | };
70 |
71 | var bundleSpecs = function () {
72 | return generateSpecImportsFile().then(function (specEntryPointPath) {
73 | return bundle(specEntryPointPath, destDir.path('spec.js'));
74 | });
75 | };
76 |
77 | var bundleTask = function () {
78 | if (utils.getEnvName() === 'test') {
79 | return bundleSpecs()
80 | .then(bundleApplication());
81 | }
82 | return bundleApplication();
83 | };
84 |
85 | gulp.task('bundle', ['clean'], bundleTask);
86 | gulp.task('bundle-watch', ['bundle']);
87 |
88 | gulp.task('environment', ['clean'], function () {
89 | var configFile = 'config/env_' + utils.getEnvName() + '.json';
90 | projectDir.copy(configFile, destDir.path('env.json'));
91 | });
92 |
93 | gulp.task('package-json', ['clean'], function () {
94 | var manifest = srcDir.read('package.json', 'json');
95 |
96 | // Add "dev" suffix to name, so Electron will write all data like cookies
97 | // and localStorage in separate places for production and development.
98 | if (utils.getEnvName() === 'development') {
99 | manifest.name += '-dev';
100 | manifest.productName += ' Dev';
101 | }
102 |
103 | destDir.write('package.json', manifest);
104 | });
105 |
106 | gulp.task('watch', function () {
107 | watch('app/**/*.js', batch(function (events, done) {
108 | gulp.start('bundle-watch', done);
109 | }));
110 | watch(paths.copyFromAppDir, { cwd: 'app' }, batch(function (events, done) {
111 | gulp.start('copy-watch', done);
112 | }));
113 | });
114 |
115 | gulp.task('build', ['bundle', 'environment', 'package-json', 'generate']);
116 |
--------------------------------------------------------------------------------
/tasks/build/bundle.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var pathUtil = require('path');
4 | var jetpack = require('fs-jetpack');
5 | var rollup = require('rollup');
6 | var Q = require('q');
7 |
8 | var nodeBuiltInModules = ['assert', 'buffer', 'child_process', 'cluster',
9 | 'console', 'constants', 'crypto', 'dgram', 'dns', 'domain', 'events',
10 | 'fs', 'http', 'https', 'module', 'net', 'os', 'path', 'process', 'punycode',
11 | 'querystring', 'readline', 'repl', 'stream', 'string_decoder', 'timers',
12 | 'tls', 'tty', 'url', 'util', 'v8', 'vm', 'zlib'];
13 |
14 | var electronBuiltInModules = ['electron'];
15 |
16 | var npmModulesUsedInApp = function () {
17 | var appManifest = require('../../app/package.json');
18 | return Object.keys(appManifest.dependencies);
19 | };
20 |
21 | var generateExternalModulesList = function () {
22 | return [].concat(nodeBuiltInModules, electronBuiltInModules, npmModulesUsedInApp());
23 | };
24 |
25 | module.exports = function (src, dest) {
26 | var deferred = Q.defer();
27 |
28 | rollup.rollup({
29 | entry: src,
30 | external: generateExternalModulesList(),
31 | }).then(function (bundle) {
32 | var jsFile = pathUtil.basename(dest);
33 | var result = bundle.generate({
34 | format: 'cjs',
35 | sourceMap: true,
36 | sourceMapFile: jsFile,
37 | });
38 | // Wrap code in self invoking function so the variables don't
39 | // pollute the global namespace.
40 | var isolatedCode = '(function () {' + result.code + '\n}());';
41 | return Q.all([
42 | jetpack.writeAsync(dest, isolatedCode + '\n//# sourceMappingURL=' + jsFile + '.map'),
43 | jetpack.writeAsync(dest + '.map', result.map.toString()),
44 | ]);
45 | }).then(function () {
46 | deferred.resolve();
47 | }).catch(function (err) {
48 | deferred.reject(err);
49 | });
50 |
51 | return deferred.promise;
52 | };
53 |
--------------------------------------------------------------------------------
/tasks/build/generate_spec_imports.js:
--------------------------------------------------------------------------------
1 | // Spec files are scattered through the whole project. Here we're searching
2 | // for them and generate one entry file which will run all the tests.
3 |
4 | 'use strict';
5 |
6 | var jetpack = require('fs-jetpack');
7 | var srcDir = jetpack.cwd('app');
8 |
9 | var fileName = 'spec.js.autogenerated';
10 | var fileBanner = "// This file is generated automatically.\n"
11 | + "// All your modifications to it will be lost (so don't do it).\n";
12 | var whatToInclude = [
13 | '*.spec.js',
14 | '!node_modules/**',
15 | ];
16 |
17 | module.exports = function () {
18 | return srcDir.findAsync('.', { matching: whatToInclude })
19 | .then(function (specPaths) {
20 | var fileContent = specPaths.map(function (path) {
21 | return 'import "./' + path.replace(/\\/g, '/') + '";';
22 | }).join('\n');
23 | return srcDir.writeAsync(fileName, fileBanner + fileContent);
24 | })
25 | .then(function () {
26 | return srcDir.path(fileName);
27 | });
28 | };
29 |
--------------------------------------------------------------------------------
/tasks/install_native_module.js:
--------------------------------------------------------------------------------
1 | // Install native module from npm and compile it for Electron.
2 | // Usage: npm run install-native -- name_of_native_module
3 |
4 | 'use strict';
5 |
6 | var childProcess = require('child_process');
7 | var Q = require('q');
8 | var appDir = require('fs-jetpack').cwd(__dirname, '../app');
9 | var utils = require('./utils');
10 |
11 | var ensureElectronRebuildInstalled = function () {
12 | var deferred = Q.defer();
13 |
14 | try {
15 | // If require is successful it means module is already installed.
16 | require('electron-rebuild');
17 | deferred.resolve();
18 | } catch (err) {
19 | childProcess.spawn(utils.spawnablePath('npm'), [
20 | 'install', '--save-dev', 'electron-rebuild'
21 | ], {
22 | stdio: 'inherit'
23 | })
24 | .on('error', deferred.reject)
25 | .on('close', deferred.resolve);
26 | }
27 |
28 | return deferred.promise;
29 | };
30 |
31 | var ensurePostinstallRunsElectronRebuild = function () {
32 | var postinstallScript = 'node ../tasks/rebuild_native_modules';
33 |
34 | var appManifest = appDir.read('package.json', 'json');
35 |
36 | if (typeof appManifest.scripts === 'undefined') {
37 | appManifest.scripts = {};
38 | }
39 |
40 | // Let's do it 100% bulletproof and check if programmer didn't
41 | // pust some custom stuff into postinstall script already.
42 | if (typeof appManifest.scripts.postinstall === 'undefined') {
43 | appManifest.scripts.postinstall = postinstallScript;
44 | appDir.write('package.json', appManifest);
45 | } else if (appManifest.scripts.postinstall.indexOf(postinstallScript) === -1) {
46 | appManifest.scripts.postinstall += ' && ' + postinstallScript;
47 | appDir.write('package.json', appManifest);
48 | }
49 |
50 | return Q();
51 | };
52 |
53 | var installNativeModule = function () {
54 | var deferred = Q.defer();
55 | var moduleToInstallAndOtherParams = process.argv.slice(2);
56 |
57 | if (!moduleToInstallAndOtherParams.length === 0) {
58 | deferred.reject('Module name not specified! Correct usage is "npm run install-native -- name_of_native_module" (remember about space after "--").');
59 | } else {
60 | childProcess.spawn(
61 | utils.spawnablePath('npm'),
62 | ['install', '--save'].concat(moduleToInstallAndOtherParams),
63 | {
64 | cwd: appDir.cwd(),
65 | stdio: 'inherit'
66 | }
67 | )
68 | .on('error', deferred.reject)
69 | .on('close', deferred.resolve);
70 | }
71 |
72 | return deferred.promise;
73 | };
74 |
75 | var runRebuild = function () {
76 | var deferred = Q.defer();
77 |
78 | childProcess.spawn(utils.spawnablePath('npm'), [
79 | 'run', 'postinstall'
80 | ], {
81 | cwd: appDir.cwd(),
82 | stdio: 'inherit'
83 | })
84 | .on('error', deferred.reject)
85 | .on('close', deferred.resolve);
86 |
87 | return deferred.promise;
88 | };
89 |
90 | ensureElectronRebuildInstalled()
91 | .then(ensurePostinstallRunsElectronRebuild)
92 | .then(installNativeModule)
93 | .then(runRebuild)
94 | .catch(function (err) {
95 | console.error(err); // eslint-disable-line no-console
96 | });
97 |
--------------------------------------------------------------------------------
/tasks/rebuild_native_modules.js:
--------------------------------------------------------------------------------
1 | // Rebuilds native node modules for Electron.
2 | // More: https://github.com/atom/electron/blob/master/docs/tutorial/using-native-node-modules.md
3 |
4 | 'use strict';
5 |
6 | var path = require('path');
7 | var electron = require('electron-prebuilt');
8 | var electronPackage = require('electron-prebuilt/package.json');
9 | var rebuild = require('electron-rebuild');
10 |
11 | var pathToElectronNativeModules = path.join(__dirname, '../app/node_modules');
12 |
13 | rebuild.shouldRebuildNativeModules(electron)
14 | .then(function (shouldBuild) {
15 | if (!shouldBuild) {
16 | return true;
17 | }
18 |
19 | console.log('Rebuilding native modules for Electron...'); // eslint-disable-line no-console
20 |
21 | return rebuild.installNodeHeaders(electronPackage.version)
22 | .then(function () {
23 | return rebuild.rebuildNativeModules(electronPackage.version, pathToElectronNativeModules);
24 | });
25 | })
26 | .then(function () {
27 | console.log('Rebuilding complete.'); // eslint-disable-line no-console
28 | })
29 | .catch(function (err) {
30 | console.error("Rebuilding error!"); // eslint-disable-line no-console
31 | console.error(err); // eslint-disable-line no-console
32 | });
33 |
--------------------------------------------------------------------------------
/tasks/release/linux.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Q = require('q');
4 | var gulpUtil = require('gulp-util');
5 | var childProcess = require('child_process');
6 | var jetpack = require('fs-jetpack');
7 | var asar = require('asar');
8 | var utils = require('../utils');
9 |
10 | var projectDir;
11 | var releasesDir;
12 | var packName;
13 | var packDir;
14 | var tmpDir;
15 | var readyAppDir;
16 | var manifest;
17 |
18 | var init = function () {
19 | projectDir = jetpack;
20 | tmpDir = projectDir.dir('./tmp', { empty: true });
21 | releasesDir = projectDir.dir('./releases');
22 | manifest = projectDir.read('app/package.json', 'json');
23 | packName = utils.getReleasePackageName(manifest);
24 | packDir = tmpDir.dir(packName);
25 | readyAppDir = packDir.cwd('opt', manifest.name);
26 |
27 | return new Q();
28 | };
29 |
30 | var copyRuntime = function () {
31 | return projectDir.copyAsync('node_modules/electron-prebuilt/dist', readyAppDir.path(), { overwrite: true });
32 | };
33 |
34 | var packageBuiltApp = function () {
35 | var deferred = Q.defer();
36 |
37 | asar.createPackageWithOptions(projectDir.path('build'), readyAppDir.path('resources/app.asar'), {
38 | dot: true
39 | }, function () {
40 | deferred.resolve();
41 | });
42 |
43 | return deferred.promise;
44 | };
45 |
46 | var finalize = function () {
47 | // Create .desktop file from the template
48 | var desktop = projectDir.read('resources/linux/app.desktop');
49 | desktop = utils.replace(desktop, {
50 | name: manifest.name,
51 | productName: manifest.productName,
52 | description: manifest.description,
53 | version: manifest.version,
54 | author: manifest.author
55 | });
56 | packDir.write('usr/share/applications/' + manifest.name + '.desktop', desktop);
57 |
58 | // Copy icon
59 | projectDir.copy('resources/icon.png', readyAppDir.path('icon.png'));
60 |
61 | return new Q();
62 | };
63 |
64 | var renameApp = function () {
65 | return readyAppDir.renameAsync('electron', manifest.name);
66 | };
67 |
68 | var packToDebFile = function () {
69 | var deferred = Q.defer();
70 |
71 | var debFileName = packName + '.deb';
72 | var debPath = releasesDir.path(debFileName);
73 |
74 | gulpUtil.log('Creating DEB package... (' + debFileName + ')');
75 |
76 | // Counting size of the app in KiB
77 | var appSize = Math.round(readyAppDir.inspectTree('.').size / 1024);
78 |
79 | // Preparing debian control file
80 | var control = projectDir.read('resources/linux/DEBIAN/control');
81 | control = utils.replace(control, {
82 | name: manifest.name,
83 | description: manifest.description,
84 | version: manifest.version,
85 | author: manifest.author,
86 | size: appSize
87 | });
88 | packDir.write('DEBIAN/control', control);
89 |
90 | // Build the package...
91 | childProcess.exec('fakeroot dpkg-deb -Zxz --build ' + packDir.path().replace(/\s/g, '\\ ') + ' ' + debPath.replace(/\s/g, '\\ '),
92 | function (error, stdout, stderr) {
93 | if (error || stderr) {
94 | console.log('ERROR while building DEB package:'); // eslint-disable-line no-console
95 | console.log(error); // eslint-disable-line no-console
96 | console.log(stderr); // eslint-disable-line no-console
97 | } else {
98 | gulpUtil.log('DEB package ready!', debPath);
99 | }
100 | deferred.resolve();
101 | });
102 |
103 | return deferred.promise;
104 | };
105 |
106 | var cleanClutter = function () {
107 | return tmpDir.removeAsync('.');
108 | };
109 |
110 | module.exports = function () {
111 | return init()
112 | .then(copyRuntime)
113 | .then(packageBuiltApp)
114 | .then(finalize)
115 | .then(renameApp)
116 | .then(packToDebFile)
117 | .then(cleanClutter)
118 | .catch(console.error); // eslint-disable-line no-console
119 | };
120 |
--------------------------------------------------------------------------------
/tasks/release/osx.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Q = require('q');
4 | var gulpUtil = require('gulp-util');
5 | var jetpack = require('fs-jetpack');
6 | var asar = require('asar');
7 | var utils = require('../utils');
8 | var child_process = require('child_process');
9 |
10 | var projectDir;
11 | var releasesDir;
12 | var tmpDir;
13 | var finalAppDir;
14 | var manifest;
15 |
16 | var init = function () {
17 | projectDir = jetpack;
18 | tmpDir = projectDir.dir('./tmp', { empty: true });
19 | releasesDir = projectDir.dir('./releases');
20 | manifest = projectDir.read('app/package.json', 'json');
21 | finalAppDir = tmpDir.cwd(manifest.productName + '.app');
22 |
23 | return new Q();
24 | };
25 |
26 | var copyRuntime = function () {
27 | return projectDir.copyAsync('node_modules/electron-prebuilt/dist/Electron.app', finalAppDir.path());
28 | };
29 |
30 | var cleanupRuntime = function () {
31 | finalAppDir.remove('Contents/Resources/default_app');
32 | finalAppDir.remove('Contents/Resources/atom.icns');
33 | return new Q();
34 | };
35 |
36 | var packageBuiltApp = function () {
37 | var deferred = Q.defer();
38 |
39 | asar.createPackageWithOptions(projectDir.path('build'), finalAppDir.path('Contents/Resources/app.asar'), {
40 | dot: true
41 | }, function () {
42 | deferred.resolve();
43 | });
44 |
45 | return deferred.promise;
46 | };
47 |
48 | var finalize = function () {
49 | // Prepare main Info.plist
50 | var info = projectDir.read('resources/osx/Info.plist');
51 | info = utils.replace(info, {
52 | productName: manifest.productName,
53 | identifier: manifest.osx.identifier,
54 | version: manifest.version,
55 | build: manifest.osx.build,
56 | copyright: manifest.copyright,
57 | LSApplicationCategoryType: manifest.osx.LSApplicationCategoryType
58 | });
59 | finalAppDir.write('Contents/Info.plist', info);
60 |
61 | // Prepare Info.plist of Helper apps
62 | [' EH', ' NP', ''].forEach(function (helper_suffix) {
63 | info = projectDir.read('resources/osx/helper_apps/Info' + helper_suffix + '.plist');
64 | info = utils.replace(info, {
65 | productName: manifest.productName,
66 | identifier: manifest.identifier
67 | });
68 | finalAppDir.write('Contents/Frameworks/Electron Helper' + helper_suffix + '.app/Contents/Info.plist', info);
69 | });
70 |
71 | // Copy icon
72 | projectDir.copy('resources/osx/icon.icns', finalAppDir.path('Contents/Resources/icon.icns'));
73 |
74 | return new Q();
75 | };
76 |
77 | var renameApp = function () {
78 | // Rename helpers
79 | [' Helper EH', ' Helper NP', ' Helper'].forEach(function (helper_suffix) {
80 | finalAppDir.rename('Contents/Frameworks/Electron' + helper_suffix + '.app/Contents/MacOS/Electron' + helper_suffix, manifest.productName + helper_suffix );
81 | finalAppDir.rename('Contents/Frameworks/Electron' + helper_suffix + '.app', manifest.productName + helper_suffix + '.app');
82 | });
83 | // Rename application
84 | finalAppDir.rename('Contents/MacOS/Electron', manifest.productName);
85 | return new Q();
86 | };
87 |
88 | var signApp = function () {
89 | var identity = utils.getSigningId(manifest);
90 | var MASIdentity = utils.getMASSigningId(manifest);
91 | var MASInstallerIdentity = utils.getMASInstallerSigningId(manifest);
92 |
93 | if (utils.releaseForMAS()) {
94 | if (!MASIdentity || !MASInstallerIdentity) {
95 | gulpUtil.log('--mas-sign and --mas-installer-sign are required to release for Mac App Store!');
96 | process.exit(0);
97 | }
98 | var cmds = [
99 | 'codesign --deep -f -s "' + MASIdentity + '" --entitlements resources/osx/child.plist -v "' + finalAppDir.path() + '/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libffmpeg.dylib"',
100 | 'codesign --deep -f -s "' + MASIdentity + '" --entitlements resources/osx/child.plist -v "' + finalAppDir.path() + '/Contents/Frameworks/Electron Framework.framework/Versions/A/Libraries/libnode.dylib"',
101 | 'codesign --deep -f -s "' + MASIdentity + '" --entitlements resources/osx/child.plist -v "' + finalAppDir.path() + '/Contents/Frameworks/Electron Framework.framework/Versions/A"',
102 | 'codesign --deep -f -s "' + MASIdentity + '" --entitlements resources/osx/child.plist -v "' + finalAppDir.path() + '/Contents/Frameworks/' + manifest.productName + ' Helper.app/"',
103 | 'codesign --deep -f -s "' + MASIdentity + '" --entitlements resources/osx/child.plist -v "' + finalAppDir.path() + '/Contents/Frameworks/' + manifest.productName + ' Helper EH.app/"',
104 | 'codesign --deep -f -s "' + MASIdentity + '" --entitlements resources/osx/child.plist -v "' + finalAppDir.path() + '/Contents/Frameworks/' + manifest.productName + ' Helper NP.app/"'
105 | ];
106 |
107 | if (finalAppDir.exists('Contents/Frameworks/Squirrel.framework/Versions/A')) {
108 | // # Signing a non-MAS build.
109 | cmds.push('codesign --deep -f -s "' + MASIdentity + '" --entitlements resources/osx/child.plist "' + finalAppDir.path() + '/Contents/Frameworks/Mantle.framework/Versions/A"');
110 | cmds.push('codesign --deep -f -s "' + MASIdentity + '" --entitlements resources/osx/child.plist "' + finalAppDir.path() + '/Contents/Frameworks/ReactiveCocoa.framework/Versions/A"');
111 | cmds.push('codesign --deep -f -s "' + MASIdentity + '" --entitlements resources/osx/child.plist "' + finalAppDir.path() + '/Contents/Frameworks/Squirrel.framework/Versions/A"');
112 | }
113 |
114 | cmds.push('codesign -f -s "' + MASIdentity + '" --entitlements resources/osx/parent.plist -v "' + finalAppDir.path() + '"');
115 |
116 | cmds.push('productbuild --component "' + finalAppDir.path() + '" /Applications --sign "' + MASInstallerIdentity + '" "' + releasesDir.path(manifest.productName + '.pkg') + '"');
117 |
118 | /* eslint-disable */
119 | var result = new Q();
120 | cmds.forEach(function (cmd) {
121 | result = result.then(function(result) {
122 | gulpUtil.log('Signing with:', cmd);
123 | return Q.nfcall(child_process.exec, cmd);
124 | });
125 | });
126 | result = result.then(function(result) {
127 | return new Q();
128 | });
129 | return result;
130 | /* eslint-disable */
131 |
132 | } else if (identity) {
133 | var cmd = 'codesign --deep --force --sign "' + identity + '" "' + finalAppDir.path() + '"';
134 | gulpUtil.log('Signing with:', cmd);
135 | return Q.nfcall(child_process.exec, cmd);
136 | } else {
137 | return new Q();
138 | }
139 | };
140 |
141 | var packToDmgFile = function () {
142 | if (utils.releaseForMAS()) {
143 | return new Q();
144 | }
145 |
146 | var deferred = Q.defer();
147 |
148 | var appdmg = require('appdmg');
149 | var dmgName = utils.getReleasePackageName(manifest) + '.dmg';
150 |
151 | // Prepare appdmg config
152 | var dmgManifest = projectDir.read('resources/osx/appdmg.json');
153 | dmgManifest = utils.replace(dmgManifest, {
154 | productName: manifest.productName,
155 | appPath: finalAppDir.path(),
156 | dmgIcon: projectDir.path("resources/osx/dmg-icon.icns"),
157 | dmgBackground: projectDir.path("resources/osx/dmg-background.png")
158 | });
159 | tmpDir.write('appdmg.json', dmgManifest);
160 |
161 | // Delete DMG file with this name if already exists
162 | releasesDir.remove(dmgName);
163 |
164 | gulpUtil.log('Packaging to DMG file... (' + dmgName + ')');
165 |
166 | var readyDmgPath = releasesDir.path(dmgName);
167 | appdmg({
168 | source: tmpDir.path('appdmg.json'),
169 | target: readyDmgPath
170 | })
171 | .on('error', function (err) {
172 | console.error(err); // eslint-disable-line no-console
173 | })
174 | .on('finish', function () {
175 | gulpUtil.log('DMG file ready!', readyDmgPath);
176 | deferred.resolve();
177 | });
178 |
179 | return deferred.promise;
180 | };
181 |
182 | var cleanClutter = function () {
183 | return tmpDir.removeAsync('.');
184 | };
185 |
186 | module.exports = function () {
187 | return init()
188 | .then(copyRuntime)
189 | .then(cleanupRuntime)
190 | .then(packageBuiltApp)
191 | .then(finalize)
192 | .then(renameApp)
193 | .then(signApp)
194 | .then(packToDmgFile)
195 | .then(cleanClutter)
196 | .catch(console.error); // eslint-disable-line no-console
197 | };
198 |
--------------------------------------------------------------------------------
/tasks/release/release.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var gulp = require('gulp');
4 | var utils = require('../utils');
5 |
6 | var releaseForOs = {
7 | osx: require('./osx'),
8 | linux: require('./linux'),
9 | windows: require('./windows'),
10 | };
11 |
12 | gulp.task('release', ['build'], function () {
13 | return releaseForOs[utils.os()]();
14 | });
15 |
--------------------------------------------------------------------------------
/tasks/release/windows.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Q = require('q');
4 | var gulpUtil = require('gulp-util');
5 | var childProcess = require('child_process');
6 | var jetpack = require('fs-jetpack');
7 | var asar = require('asar');
8 | var utils = require('../utils');
9 |
10 | var projectDir;
11 | var tmpDir;
12 | var releasesDir;
13 | var readyAppDir;
14 | var manifest;
15 |
16 | var init = function () {
17 | projectDir = jetpack;
18 | tmpDir = projectDir.dir('./tmp', { empty: true });
19 | releasesDir = projectDir.dir('./releases');
20 | manifest = projectDir.read('app/package.json', 'json');
21 | readyAppDir = tmpDir.cwd(manifest.name);
22 |
23 | return new Q();
24 | };
25 |
26 | var copyRuntime = function () {
27 | return projectDir.copyAsync('node_modules/electron-prebuilt/dist', readyAppDir.path(), { overwrite: true });
28 | };
29 |
30 | var cleanupRuntime = function () {
31 | return readyAppDir.removeAsync('resources/default_app');
32 | };
33 |
34 | var packageBuiltApp = function () {
35 | var deferred = Q.defer();
36 |
37 | asar.createPackageWithOptions(projectDir.path('build'), readyAppDir.path('resources/app.asar'), {
38 | dot: true
39 | }, function () {
40 | deferred.resolve();
41 | });
42 |
43 | return deferred.promise;
44 | };
45 |
46 | var finalize = function () {
47 | var deferred = Q.defer();
48 |
49 | projectDir.copy('resources/windows/icon.ico', readyAppDir.path('icon.ico'));
50 |
51 | // Replace Electron icon for your own.
52 | var rcedit = require('rcedit');
53 | rcedit(readyAppDir.path('electron.exe'), {
54 | 'icon': projectDir.path('resources/windows/icon.ico'),
55 | 'version-string': {
56 | 'ProductName': manifest.productName,
57 | 'FileDescription': manifest.description,
58 | 'ProductVersion': manifest.version,
59 | 'CompanyName': manifest.author, // it might be better to add another field to package.json for this
60 | 'LegalCopyright': manifest.copyright,
61 | 'OriginalFilename': manifest.productName + '.exe'
62 | }
63 | }, function (err) {
64 | if (!err) {
65 | deferred.resolve();
66 | }
67 | });
68 |
69 | return deferred.promise;
70 | };
71 |
72 | var renameApp = function () {
73 | return readyAppDir.renameAsync('electron.exe', manifest.productName + '.exe');
74 | };
75 |
76 | var createInstaller = function () {
77 | var deferred = Q.defer();
78 |
79 | var finalPackageName = utils.getReleasePackageName(manifest) + '.exe';
80 | var installScript = projectDir.read('resources/windows/installer.nsi');
81 |
82 | installScript = utils.replace(installScript, {
83 | name: manifest.name,
84 | productName: manifest.productName,
85 | author: manifest.author,
86 | version: manifest.version,
87 | src: readyAppDir.path(),
88 | dest: releasesDir.path(finalPackageName),
89 | icon: readyAppDir.path('icon.ico'),
90 | setupIcon: projectDir.path('resources/windows/setup-icon.ico'),
91 | banner: projectDir.path('resources/windows/setup-banner.bmp'),
92 | });
93 | tmpDir.write('installer.nsi', installScript);
94 |
95 | gulpUtil.log('Building installer with NSIS... (' + finalPackageName + ')');
96 |
97 | // Remove destination file if already exists.
98 | releasesDir.remove(finalPackageName);
99 |
100 | // Note: NSIS have to be added to PATH (environment variables).
101 | var nsis = childProcess.spawn('makensis', [
102 | tmpDir.path('installer.nsi')
103 | ], {
104 | stdio: 'inherit'
105 | });
106 | nsis.on('error', function (err) {
107 | if (err.message === 'spawn makensis ENOENT') {
108 | throw "Can't find NSIS. Are you sure you've installed it and"
109 | + " added to PATH environment variable?";
110 | } else {
111 | throw err;
112 | }
113 | });
114 | nsis.on('close', function () {
115 | gulpUtil.log('Installer ready!', releasesDir.path(finalPackageName));
116 | deferred.resolve();
117 | });
118 |
119 | return deferred.promise;
120 | };
121 |
122 | var cleanClutter = function () {
123 | return tmpDir.removeAsync('.');
124 | };
125 |
126 | module.exports = function () {
127 | return init()
128 | .then(copyRuntime)
129 | .then(cleanupRuntime)
130 | .then(packageBuiltApp)
131 | .then(finalize)
132 | .then(renameApp)
133 | .then(createInstaller)
134 | .then(cleanClutter)
135 | .catch(console.error); // eslint-disable-line no-console
136 | };
137 |
--------------------------------------------------------------------------------
/tasks/start.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var childProcess = require('child_process');
4 | var electron = require('electron-prebuilt');
5 | var gulp = require('gulp');
6 | var pkg = require('../app/package.json');
7 |
8 | gulp.task('start', ['build', 'watch'], function () {
9 | childProcess.spawn(electron, ['./build/' + pkg.productName + '.asar'], {
10 | stdio: 'inherit'
11 | })
12 | .on('close', function () {
13 | // User closed the app. Kill the host process.
14 | process.exit();
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/tasks/utils.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var argv = require('yargs').argv;
4 | var os = require('os');
5 |
6 | module.exports.os = function () {
7 | switch (os.platform()) {
8 | case 'darwin':
9 | return 'osx';
10 | case 'linux':
11 | return 'linux';
12 | case 'win32':
13 | return 'windows';
14 | }
15 | return 'unsupported';
16 | };
17 |
18 | module.exports.replace = function (str, patterns) {
19 | Object.keys(patterns).forEach(function (pattern) {
20 | var matcher = new RegExp('{{' + pattern + '}}', 'g');
21 | str = str.replace(matcher, patterns[pattern]);
22 | });
23 | return str;
24 | };
25 |
26 | module.exports.getReleasePackageName = function(manifest) {
27 | return module.exports.replace(manifest.packageNameTemplate, {
28 | name: manifest.name,
29 | version: manifest.version,
30 | build: manifest.build,
31 | productName: manifest.productName,
32 | platform: process.platform,
33 | arch: process.arch
34 | });
35 | };
36 |
37 | module.exports.getEnvName = function () {
38 | return argv.env || 'development';
39 | };
40 |
41 | module.exports.getSigningId = function (manifest) {
42 | return argv.sign || (manifest.osx.codeSignIdentitiy ? manifest.osx.codeSignIdentitiy.dmg : undefined);
43 | };
44 |
45 | module.exports.getMASSigningId = function (manifest) {
46 | return argv['mas-sign'] || (manifest.osx.codeSignIdentitiy ? manifest.osx.codeSignIdentitiy.MAS : undefined);
47 | };
48 |
49 | module.exports.getMASInstallerSigningId = function (manifest) {
50 | return argv['mas-installer-sign'] || (manifest.osx.codeSignIdentitiy ? manifest.osx.codeSignIdentitiy.MASInstaller : undefined);
51 | };
52 |
53 | module.exports.releaseForMAS = function () {
54 | return !!argv.mas;
55 | };
56 |
57 | // Fixes https://github.com/nodejs/node-v0.x-archive/issues/2318
58 | module.exports.spawnablePath = function (path) {
59 | if (process.platform === 'win32') {
60 | return path + '.cmd';
61 | }
62 | return path;
63 | };
64 |
--------------------------------------------------------------------------------