diff --git a/Gruntfile.js b/Gruntfile.js index 23f0bc1..0c4ecc6 100755 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,339 +1,355 @@ var path = require('path'); var execFile = require('child_process').execFile; var packagejson = require('./package.json'); -var electron = require('electron-prebuilt'); +var electron = require('electron'); -module.exports = function (grunt) { - require('load-grunt-tasks')(grunt); - var target = grunt.option('target') || 'development'; - var beta = grunt.option('beta') || false; - var alpha = grunt.option('alpha') || false; - var env = process.env; - env.NODE_PATH = '..:' + env.NODE_PATH; - env.NODE_ENV = target; +module.exports = function(grunt) { + require('load-grunt-tasks')(grunt); + var target = grunt.option('target') || 'development'; + var beta = grunt.option('beta') || false; + var alpha = grunt.option('alpha') || false; + var env = process.env; + env.NODE_PATH = '..:' + env.NODE_PATH; + env.NODE_ENV = target; - var version = function (str) { - var match = str.match(/(\d+\.\d+\.\d+)/); - return match ? match[1] : null; - }; + var version = function(str) { + var match = str.match(/(\d+\.\d+\.\d+)/); + return match ? match[1] : null; + }; - var BASENAME = 'VPN.ht'; - var APPNAME = BASENAME; + var clear = function(str) { + return str.replace(/ /g, '\\ ').replace(/\(/g, '\\(').replace(/\)/g, '\\)'); + }; - if (alpha) { - APPNAME += ' (Alpha)'; - } else if (beta) { - APPNAME += ' (Beta)'; - } + var BASENAME = 'VPN.ht'; + var APPNAME = BASENAME; - var OSX_OUT = './dist'; - var OSX_OUT_X64 = OSX_OUT + '/' + APPNAME + '-darwin-x64'; - var OSX_FILENAME = OSX_OUT_X64 + '/' + APPNAME + '.app'; + if (alpha) { + APPNAME += ' (Alpha)'; + } else if (beta) { + APPNAME += ' (Beta)'; + } - var OSX_DIST_X64 = OSX_OUT + '/' + APPNAME + '-' + packagejson.version + '.pkg'; + var OSX_OUT = './dist'; + var OSX_OUT_X64 = OSX_OUT + '/' + APPNAME + '-darwin-x64'; + var OSX_FILENAME = OSX_OUT_X64 + '/' + APPNAME + '.app'; - grunt.initConfig({ - IDENTITY: 'Developer ID Application: David Lemarier', - APPNAME: APPNAME, - APPNAME_ESCAPED: APPNAME.replace(/ /g, '\\ ').replace(/\(/g,'\\(').replace(/\)/g,'\\)'), - OSX_OUT: OSX_OUT, - OSX_OUT_ESCAPED: OSX_OUT.replace(/ /g, '\\ ').replace(/\(/g,'\\(').replace(/\)/g,'\\)'), - OSX_OUT_X64: OSX_OUT_X64, - OSX_FILENAME: OSX_FILENAME, - OSX_FILENAME_ESCAPED: OSX_FILENAME.replace(/ /g, '\\ ').replace(/\(/g,'\\(').replace(/\)/g,'\\)'), - OSX_DIST_X64: OSX_DIST_X64, - OSX_DIST_X64_ESCAPED: OSX_DIST_X64.replace(/ /g, '\\ ').replace(/\(/g,'\\(').replace(/\)/g,'\\)'), - // electron - electron: { - windows: { - options: { - name: BASENAME, - dir: 'build/', - out: 'dist', - version: packagejson['electron-version'], - platform: 'win32', - arch: 'ia32', - asar: true, - icon: 'util/vpnht.ico' - } - }, - osx: { - options: { - name: APPNAME, - dir: 'build/', - out: 'dist', - version: packagejson['electron-version'], - platform: 'darwin', - arch: 'x64', - asar: true, - 'app-bundle-id': 'ht.vpn.desktop', - 'app-version': packagejson.version - } - } - }, + var OSX_DIST_X64 = OSX_OUT + '/' + APPNAME + '-' + packagejson.version + '.pkg'; - prompt: { - 'create-windows-installer': { - options: { - questions: [ - { - config: 'certificatePassword', - type: 'password', - message: 'Certificate Password: ' + grunt.initConfig({ + IDENTITY: 'Developer ID Application: David Lemarier', + APPNAME: APPNAME, + APPNAME_ESCAPED: clear(APPNAME), + OSX_OUT: OSX_OUT, + OSX_OUT_ESCAPED: clear(OSX_OUT), + OSX_OUT_X64: OSX_OUT_X64, + OSX_FILENAME: OSX_FILENAME, + OSX_FILENAME_ESCAPED: clear(OSX_FILENAME), + OSX_DIST_X64: OSX_DIST_X64, + OSX_DIST_X64_ESCAPED: clear(OSX_DIST_X64), + // electron + electron: { + windows: { + options: { + name: BASENAME, + dir: 'build/', + out: 'dist', + version: packagejson['electron-version'], + platform: 'win32', + arch: 'ia32', + asar: true, + icon: 'util/vpnht.ico' + } + }, + osx: { + options: { + name: APPNAME, + dir: 'build/', + out: 'dist', + version: packagejson['electron-version'], + platform: 'darwin', + arch: 'x64', + asar: true, + 'app-bundle-id': 'ht.vpn.desktop', + 'app-version': packagejson.version + } } - ] - } - } - }, - - rcedit: { - exes: { - files: [{ - expand: true, - cwd: 'dist/' + BASENAME + '-win32-ia32', - src: [BASENAME + '.exe'] - }], - options: { - icon: 'util/vpnht.ico', - 'file-version': packagejson.version, - 'product-version': packagejson.version, - 'version-string': { - 'CompanyName': 'VPN.ht Limited', - 'ProductVersion': packagejson.version, - 'ProductName': APPNAME, - 'FileDescription': APPNAME, - 'InternalName': BASENAME + '.exe', - 'OriginalFilename': BASENAME + '.exe', - 'LegalCopyright': 'Copyright 2015 VPN.ht Limited. All rights reserved.' - } - } - } - }, - - 'create-windows-installer': { - config: { - appDirectory: path.join(__dirname, 'dist/' + BASENAME + '-win32-ia32'), - outputDirectory: path.join(__dirname, 'dist'), - authors: 'VPN.ht Limited', - loadingGif: 'util/loading.gif', - setupIcon: 'util/setup.ico', - iconUrl: 'https://raw.githubusercontent.com/vpnht/desktop/master/util/vpnht.ico', - description: APPNAME, - title: APPNAME, - exe: BASENAME + '.exe', - version: packagejson.version } - }, + }, - // images - copy: { - dev: { - files: [{ - expand: true, - cwd: '.', - src: ['package.json', 'settings.json', 'index.html'], - dest: 'build/' - }, { - expand: true, - cwd: 'images/', - src: ['**/*'], - dest: 'build/' - }, { - expand: true, - cwd: 'fonts/', - src: ['**/*'], - dest: 'build/' - }, { - cwd: 'node_modules/', - src: Object.keys(packagejson.dependencies).map(function (dep) { return dep + '/**/*';}), - dest: 'build/node_modules/', - expand: true - }] - }, - windows: { - files: [{ - expand: true, - cwd: 'resources/bin/win32', - src: ['**/*'], - dest: 'dist/' + BASENAME + '-win32-ia32/resources/bin' - }, { - expand: true, - cwd: 'resources/config', - src: ['**/*', '!**/*.ovpn'], - dest: 'dist/' + BASENAME + '-win32-ia32/resources/config' - }, { - expand: true, - cwd: 'resources/log', - src: ['**/*'], - dest: 'dist/' + BASENAME + '-win32-ia32/resources/log' - }], - options: { - mode: true - } - }, - osx: { - files: [{ - expand: true, - cwd: 'resources/bin/darwin', - src: ['**/*'], - dest: '<%= OSX_FILENAME %>/Contents/Resources/bin/' - }, { - expand: true, - cwd: 'resources/config', - src: ['**/*', '!**/*.ovpn'], - dest: '<%= OSX_FILENAME %>/Contents/Resources/config/' - }, { - expand: true, - cwd: 'resources/log', - src: ['**/*'], - dest: '<%= OSX_FILENAME %>/Contents/Resources/log/' - }, { - src: 'util/vpnht.icns', - dest: '<%= OSX_FILENAME %>/Contents/Resources/atom.icns' - }], - options: { - mode: true - } - } - }, + prompt: { + 'create-windows-installer': { + options: { + questions: [{ + config: 'certificatePassword', + type: 'password', + message: 'Certificate Password: ' + }] + } + } + }, - rename: { - installer: { - src: 'dist/Setup.exe', - dest: 'dist/' + BASENAME + 'Setup-' + packagejson.version + '-Windows-Alpha.exe' - } - }, + rcedit: { + exes: { + files: [{ + expand: true, + cwd: 'dist/' + BASENAME + '-win32-ia32', + src: [BASENAME + '.exe'] + }], + options: { + icon: 'util/vpnht.ico', + 'file-version': packagejson.version, + 'product-version': packagejson.version, + 'version-string': { + 'CompanyName': 'VPN.ht Limited', + 'ProductVersion': packagejson.version, + 'ProductName': APPNAME, + 'FileDescription': APPNAME, + 'InternalName': BASENAME + '.exe', + 'OriginalFilename': BASENAME + '.exe', + 'LegalCopyright': 'Copyright 2015 VPN.ht Limited. All rights reserved.' + } + } + } + }, - // styles - less: { - options: { - sourceMapFileInline: true - }, - dist: { - files: { - 'build/main.css': 'styles/main.less' - } - } - }, + 'create-windows-installer': { + config: { + appDirectory: path.join(__dirname, 'dist/' + BASENAME + '-win32-ia32'), + outputDirectory: path.join(__dirname, 'dist'), + authors: 'VPN.ht Limited', + loadingGif: 'util/loading.gif', + setupIcon: 'util/setup.ico', + iconUrl: 'https://raw.githubusercontent.com/vpnht/desktop/master/util/vpnht.ico', + description: APPNAME, + title: APPNAME, + exe: BASENAME + '.exe', + version: packagejson.version + } + }, - // javascript - babel: { - options: { - sourceMap: 'inline', - blacklist: 'regenerator' - }, - dist: { - files: [{ - expand: true, - cwd: 'src/', - src: ['**/*.js'], - dest: 'build/', - }] - } - }, + // images + copy: { + dev: { + files: [{ + expand: true, + cwd: '.', + src: ['package.json', 'settings.json', 'index.html'], + dest: 'build/' + }, { + expand: true, + cwd: 'images/', + src: ['**/*'], + dest: 'build/' + }, { + expand: true, + cwd: 'fonts/', + src: ['**/*'], + dest: 'build/' + }, { + expand: true, + cwd: 'translations/', + src: ['**/*'], + dest: 'build/translations' + }, { + cwd: 'node_modules/', + src: Object.keys(packagejson.dependencies).map(function (dep) { return dep + '/**/*';}), + dest: 'build/node_modules/', + expand: true + }] + }, + release: { + files: [{ + cwd: 'node_modules/', + src: [ + '**/*', + '!*grunt*', + '!*babel*', + '!*gulp*' + ], + dest: 'build/node_modules/', + expand: true + }] + }, + windows: { + files: [{ + expand: true, + cwd: 'resources/bin/win32', + src: ['**/*'], + dest: 'dist/' + BASENAME + '-win32-ia32/resources/bin' + }, { + expand: true, + cwd: 'resources/config', + src: ['**/*', '!**/*.ovpn'], + dest: 'dist/' + BASENAME + '-win32-ia32/resources/config' + }, { + expand: true, + cwd: 'resources/log', + src: ['**/*'], + dest: 'dist/' + BASENAME + '-win32-ia32/resources/log' + }], + options: { + mode: true + } + }, + osx: { + files: [{ + expand: true, + cwd: 'resources/bin/darwin', + src: ['**/*'], + dest: '<%= OSX_FILENAME %>/Contents/Resources/bin/' + }, { + expand: true, + cwd: 'resources/config', + src: ['**/*', '!**/*.ovpn'], + dest: '<%= OSX_FILENAME %>/Contents/Resources/config/' + }, { + expand: true, + cwd: 'resources/log', + src: ['**/*'], + dest: '<%= OSX_FILENAME %>/Contents/Resources/log/' + }, { + src: 'util/vpnht.icns', + dest: '<%= OSX_FILENAME %>/Contents/Resources/atom.icns' + }], + options: { + mode: true + } + } + }, - shell: { - electron: { - command: electron + ' ' + 'build', - options: { - async: true, - execOptions: { - env: env - } - } - }, - sign: { - options: { - failOnError: false, + // styles + less: { + options: { + sourceMapFileInline: true + }, + dist: { + files: { + 'build/main.css': 'styles/main.less' + } + } }, - command: [ - 'codesign --deep -v -f -s "<%= IDENTITY %>" <%= OSX_FILENAME_ESCAPED %>/Contents/Frameworks/*', - 'codesign -v -f -s "<%= IDENTITY %>" <%= OSX_FILENAME_ESCAPED %>', - 'codesign -vvv --display <%= OSX_FILENAME_ESCAPED %>', - 'codesign -v --verify <%= OSX_FILENAME_ESCAPED %>' - ].join(' && '), - }, - macdist: { - options: { - failOnError: false, + + // javascript + babel: { + options: { + sourceMap: 'inline', + presets: ['es2015', 'react'] + }, + dist: { + files: [{ + expand: true, + cwd: 'src/', + src: ['**/*.js'], + dest: 'build/', + }] + } }, - command: [ - 'util/mac/mac-dist', - 'codesign -v -f -s "<%= IDENTITY %>" <%= OSX_DIST_X64 %>', - 'codesign -vvv --display <%= OSX_DIST_X64 %>', - 'codesign -v --verify <%= OSX_DIST_X64 %>' - ].join(' && '), - }, - macdistci: { - options: { - failOnError: false, + + shell: { + electron: { + command: electron + ' ' + 'build', + options: { + async: true, + execOptions: { + env: env + } + } + }, + sign: { + options: { + failOnError: false, + }, + command: [ + 'codesign --deep -v -f -s "<%= IDENTITY %>" <%= OSX_FILENAME_ESCAPED %>/Contents/Frameworks/*', + 'codesign -v -f -s "<%= IDENTITY %>" <%= OSX_FILENAME_ESCAPED %>', + 'codesign -vvv --display <%= OSX_FILENAME_ESCAPED %>', + 'codesign -v --verify <%= OSX_FILENAME_ESCAPED %>' + ].join(' && '), + }, + macdist: { + options: { + failOnError: false, + }, + command: [ + 'util/mac/mac-dist', + 'codesign -v -f -s "<%= IDENTITY %>" <%= OSX_DIST_X64 %>', + 'codesign -vvv --display <%= OSX_DIST_X64 %>', + 'codesign -v --verify <%= OSX_DIST_X64 %>' + ].join(' && '), + }, + macdistci: { + options: { + failOnError: false, + }, + command: [ + 'util/mac/linux-dist' + ].join(' && '), + }, + zip: { + command: 'ditto -c -k --sequesterRsrc --keepParent <%= OSX_FILENAME_ESCAPED %> dist/' + BASENAME + '-' + packagejson.version + '-Mac.zip', + }, + makensis: { + command: 'makensis util/windows/installer.nsi', + } }, - command: [ - 'util/mac/linux-dist' - ].join(' && '), - }, - zip: { - command: 'ditto -c -k --sequesterRsrc --keepParent <%= OSX_FILENAME_ESCAPED %> dist/' + BASENAME + '-' + packagejson.version + '-Mac.zip', - }, - makensis: { - command: 'makensis util/windows/installer.nsi', - } - }, - clean: { - release: ['build/', 'dist/'], - }, + clean: { + release: ['build/', 'dist/'], + }, - compress: { - windows: { - options: { - archive: './dist/' + BASENAME + '-' + packagejson.version + '-Windows-Alpha.zip', - mode: 'zip' + compress: { + windows: { + options: { + archive: './dist/' + BASENAME + '-' + packagejson.version + '-Windows-Alpha.zip', + mode: 'zip' + }, + files: [{ + expand: true, + dot: true, + cwd: './dist/VPN.ht-win32-ia32', + src: '**/*' + }] + }, }, - files: [{ - expand: true, - dot: true, - cwd: './dist/VPN.ht-win32-ia32', - src: '**/*' - }] - }, - }, - // livereload - watchChokidar: { - options: { - spawn: true - }, - livereload: { - options: {livereload: true}, - files: ['build/**/*'] - }, - js: { - files: ['src/**/*.js'], - tasks: ['newer:babel'] - }, - less: { - files: ['styles/**/*.less'], - tasks: ['less'] - }, - copy: { - files: ['images/*', 'index.html', 'fonts/*'], - tasks: ['newer:copy:dev'] - } - } - }); + // livereload + watchChokidar: { + options: { + spawn: true + }, + livereload: { + options: { + livereload: true + }, + files: ['build/**/*'] + }, + js: { + files: ['src/**/*.js'], + tasks: ['newer:babel'] + }, + less: { + files: ['styles/**/*.less'], + tasks: ['less'] + }, + copy: { + files: ['images/*', 'index.html', 'fonts/*'], + tasks: ['newer:copy:dev'] + } + } + }); - grunt.registerTask('default', ['newer:babel', 'less', 'newer:copy:dev', 'shell:electron', 'watchChokidar']); + grunt.registerTask('default', ['newer:babel', 'less', 'newer:copy:dev', 'shell:electron', 'watchChokidar']); - if (process.platform === 'win32') { - grunt.registerTask('release', ['clean:release', 'babel', 'less', 'copy:dev', 'electron:windows', 'copy:windows', 'rcedit:exes', 'compress']); - } else { - grunt.registerTask('release', ['clean:release', 'babel', 'less', 'copy:dev', 'electron:osx', 'copy:osx', 'shell:sign', 'shell:zip', 'shell:macdist']); - } + if (process.platform === 'win32') { + grunt.registerTask('release', ['clean:release', 'babel', 'less', 'copy:dev', 'copy:release', 'electron:windows', 'copy:windows', 'rcedit:exes', 'compress']); + } else { + grunt.registerTask('release', ['clean:release', 'babel', 'less', 'copy:dev', 'copy:release', 'electron:osx', 'copy:osx', 'shell:sign', 'shell:zip', 'shell:macdist']); + } - grunt.registerTask('ci', ['clean:release', 'babel', 'less', 'copy:dev', 'electron:osx', 'electron:windows', 'copy:osx', 'copy:windows', 'rcedit:exes', 'shell:sign', 'shell:macdistci', 'shell:makensis']); + grunt.registerTask('ci', ['clean:release', 'babel', 'less', 'copy:dev', 'copy:release', 'electron:osx', 'electron:windows', 'copy:osx', 'copy:windows', 'rcedit:exes', 'shell:sign', 'shell:macdistci', 'shell:makensis']); - process.on('SIGINT', function () { - grunt.task.run(['shell:electron:kill']); - process.exit(1); - }); -}; + process.on('SIGINT', function() { + grunt.task.run(['shell:electron:kill']); + process.exit(1); + }); +}; \ No newline at end of file diff --git a/images/monster-left.png b/images/monster-left.png new file mode 100644 index 0000000..e59400b Binary files /dev/null and b/images/monster-left.png differ diff --git a/images/monster-right.png b/images/monster-right.png new file mode 100644 index 0000000..9ddd3c1 Binary files /dev/null and b/images/monster-right.png differ diff --git a/index.html b/index.html index 7751988..5f19415 100755 --- a/index.html +++ b/index.html @@ -1,11 +1,15 @@ - - + + + VPN.ht - - + + + +
- - + + + \ No newline at end of file diff --git a/package.json b/package.json index e76e467..93e98fa 100644 --- a/package.json +++ b/package.json @@ -1,82 +1,82 @@ { - "name": "VPN.ht", - "version": "0.0.3", - "author": "VPN.ht", - "description": "Simple VPN.ht Client.", - "homepage": "https://vpn.ht/", - "main": "browser.js", - "repository": { - "type": "git", - "url": "git@github.com:vpnht/desktop.git" - }, - "bugs": "https://github.com/vpnht/desktop/issues", - "scripts": { - "start": "grunt", - "release": "grunt release" - }, - "license": "GPL-3.0", - "electron-version": "0.33.3", - "dependencies": { - "alt": "0.17.3", - "autoupdater": "vpnht/autoupdater", - "bluebird": "2.10.1", - "bugsnag-js": "2.4.7", - "classnames": "2.1.3", - "exec": "0.2.0", - "get-port": "1.0.0", - "is-running": "1.0.5", - "jquery": "2.1.4", - "lodash": "3.10.1", - "mixpanel": "kitematic/mixpanel-node", - "node-cache": "3.0.0", - "node-openvpn": "VPNht/node-openvpn", - "node-uuid": "1.4.3", - "object-assign": "4.0.1", - "osx-release": "1.1.0", - "react": "0.13.3", - "react-bootstrap": "^0.20.3", - "react-retina-image": "1.3.3", - "react-router": "0.13.3", - "react-select": "0.6.11", - "request": "2.55.0", - "validator": "4.0.6", - "windows-service-manager": "vpnht/windows-service-manager", - "winreg": "0.0.12", - "xps": "^1.0.2", - "yargs": "^3.27.0" - }, - "devDependencies": { - "async": "^1.4.2", - "babel": "^5.1.10", - "grunt": "^0.4.5", - "grunt-babel": "^5.0.1", - "grunt-chmod": "^1.0.3", - "grunt-cli": "^0.1.13", - "grunt-contrib-clean": "^0.6.0", - "grunt-contrib-compress": "^0.13.0", - "grunt-contrib-copy": "^0.8.0", - "grunt-contrib-less": "^1.0.1", - "grunt-contrib-watch-chokidar": "^1.0.0", - "grunt-curl": "^2.2.0", - "grunt-download-electron": "^2.1.1", - "grunt-electron": "^2.0.0", - "grunt-electron-installer": "^1.0.3", - "grunt-if-missing": "^1.0.0", - "grunt-newer": "^1.1.1", - "grunt-plistbuddy": "^0.1.1", - "grunt-prompt": "^1.3.0", - "grunt-rcedit": "^0.3.1", - "grunt-rename": "^0.1.4", - "grunt-shell": "^1.1.2", - "grunt-shell-spawn": "^0.3.8", - "load-grunt-tasks": "^3.2.0", - "minimist": "^1.1.1", - "react-tools": "^0.13.1", - "run-sequence": "^1.0.2", - "shell-escape": "^0.2.0", - "source-map-support": "^0.3.2" - }, - "optionalDependencies": { - "electron-prebuilt": "^0.33.3" - } -} + "name": "VPN.ht", + "version": "0.0.3", + "author": "VPN.ht", + "description": "Simple VPN.ht Client.", + "homepage": "https://vpn.ht/", + "main": "browser.js", + "repository": { + "type": "git", + "url": "git@github.com:vpnht/desktop.git" + }, + "bugs": "https://github.com/vpnht/desktop/issues", + "scripts": { + "start": "grunt", + "release": "grunt release" + }, + "engines": { + "node": ">=6.0.0", + "npm": ">=3.0.0" + }, + "license": "GPL-3.0", + "electron-version": "1.4.4", + "dependencies": { + "alt": "0.18.6", + "autoupdater": "vpnht/autoupdater", + "bugsnag-js": "3.0.6", + "classnames": "2.2.5", + "get-port": "2.1.0", + "is-running": "2.1.0", + "jquery": "3.1.1", + "lodash": "4.16.4", + "mixpanel": "kitematic/mixpanel-node", + "node-openvpn": "VPNht/node-openvpn", + "node-uuid": "1.4.7", + "osx-release": "1.1.0", + "react": "15.x.x", + "react-bootstrap": "0.30.x", + "react-dom": "15.x.x", + "react-retina-image": "2.x.x", + "react-router": "0.13.x", + "react-select": "v1.0.0-rc.1", + "request": "2.76.0", + "windows-service-manager": "vpnht/windows-service-manager", + "winreg": "1.2.2", + "xps": "^1.0.2", + "yargs": "6.3.0" + }, + "devDependencies": { + "async": "^2.1.2", + "babel-core": "^6.0.0", + "babel-preset-es2015": "^6.0.0", + "babel-preset-react": "^6.0.0", + "grunt": "^1.0.1", + "grunt-babel": "^6.0.0", + "grunt-chmod": "^1.1.1", + "grunt-cli": "^1.2.0", + "grunt-contrib-clean": "^1.0.0", + "grunt-contrib-compress": "^1.3.0", + "grunt-contrib-copy": "^1.0.0", + "grunt-contrib-less": "^1.4.0", + "grunt-contrib-watch-chokidar": "^1.0.0", + "grunt-curl": "^2.2.0", + "grunt-download-electron": "^2.1.4", + "grunt-electron": "^5.0.0", + "grunt-electron-installer": "^2.1.0", + "grunt-if-missing": "^1.0.1", + "grunt-newer": "^1.2.0", + "grunt-plistbuddy": "^0.2.0", + "grunt-prompt": "^1.3.3", + "grunt-rcedit": "^0.7.0", + "grunt-shell": "^2.0.0", + "grunt-shell-spawn": "^0.3.10", + "load-grunt-tasks": "^3.5.2", + "minimist": "^1.2.0", + "run-sequence": "^1.2.2", + "shell-escape": "^0.2.0", + "source-map-support": "^0.4.5" + }, + "optionalDependencies": { + "electron": "^1.4.4" + } +} \ No newline at end of file diff --git a/src/actions/AccountServerActions.js b/src/actions/AccountServerActions.js index 43152a5..98d0673 100644 --- a/src/actions/AccountServerActions.js +++ b/src/actions/AccountServerActions.js @@ -2,13 +2,13 @@ import alt from '../alt'; class AccountServerActions { - constructor () { - this.generateActions( - 'loggedin', - 'loggedout' - ); - } + constructor() { + this.generateActions( + 'loggedin', + 'loggedout' + ); + } } -export default alt.createActions(AccountServerActions); +export default alt.createActions(AccountServerActions); \ No newline at end of file diff --git a/src/actions/ServerActions.js b/src/actions/ServerActions.js index 6801f88..81d884b 100644 --- a/src/actions/ServerActions.js +++ b/src/actions/ServerActions.js @@ -1,9 +1,9 @@ -var alt = require('../alt') +import alt from '../alt' class ServerActions { - constructor() { - this.generateActions('receiveAll') - } + constructor() { + this.generateActions('receiveAll') + } } -module.exports = alt.createActions(ServerActions) +module.exports = alt.createActions(ServerActions) \ No newline at end of file diff --git a/src/actions/VPNActions.js b/src/actions/VPNActions.js index 52a62ea..e7c8163 100644 --- a/src/actions/VPNActions.js +++ b/src/actions/VPNActions.js @@ -1,6 +1,6 @@ var vpnUtil; -import ipc from 'ipc'; +import {ipcRenderer} from 'electron'; import alt from '../alt'; import log from '../stores/LogStore'; import Settings from '../utils/SettingsUtil'; @@ -8,108 +8,119 @@ import Credentials from '../utils/CredentialsUtil'; class VPNActions { - constructor () { - this.generateActions( - 'newIp', // called when we received a new ip - 'bytecount', - 'processStarted', - 'processKilled' - ); - } - - connect (args) { - - // set tray in connecting state - ipc.send('vpn.connecting'); - - vpnUtil = require('../utils/VPNUtil'); - this.dispatch(); - - vpnUtil.connect(args) - .then(() => { - log.info('VPNAction.connect() done'); - // update tray - ipc.send('vpn.connected'); - this.actions.connected(); - }) - .catch((error) => { - console.log(error); - log.error('Unable to launch process'); - this.actions.disconnected(); - - }); - } - - disconnect () { - - vpnUtil = require('../utils/VPNUtil'); - this.dispatch(); - vpnUtil.disconnect() - .then(() => { - - log.info('Waiting EXITING state'); - - }) - .catch((error) => { - - log.error('Unable to disconnect'); - console.log(error); - - }); - } - - checkIp () { - var helpers = require('../utils/VPNHelpers'); - this.dispatch(); - helpers.updateIp() - .then(() => { - - log.info('IP Updated'); - - }) - .catch((error) => { - - log.error('Unable to update ip'); - console.log(error); - - }); - } - - invalidCredentials () { - this.dispatch(); - alert("Invalid credentials") - } - - appReady () { - this.dispatch(); - if (Settings.get('connectLaunch') === 'true' && Credentials._config()) { - log.info('Auto-connect on launch') - this.actions.connect({ - username: Credentials.get().username, - password: Credentials.get().password, - server: Settings.get('server') || 'hub.vpn.ht' - }); + constructor() { + this.generateActions( + 'newIp', // called when we received a new ip + 'bytecount', + 'processStarted', + 'processKilled' + ); } - } + connect(args) { + return function(dispatch) { + // set tray in connecting state + ipcRenderer.send('vpn.connecting'); + + vpnUtil = require('../utils/VPNUtil'); + dispatch(); + + vpnUtil.connect(args) + .then(() => { + log.info('VPNAction.connect() done'); + // update tray + ipcRenderer.send('vpn.connected'); + this.connected(); + }) + .catch((error) => { + console.log(error); + log.error('Unable to launch process'); + this.disconnected(); + + }); + }; + } + + disconnect() { + return function(dispatch) { + vpnUtil = require('../utils/VPNUtil'); + dispatch(); + vpnUtil.disconnect() + .then(() => { + + log.info('Waiting EXITING state'); - // used by tray - disconnected() { - this.dispatch(); - ipc.send('vpn.disconnected'); + }) + .catch((error) => { - // on windows we need to stop the service - if (process.platform == 'win32') { - require('../utils/Util').exec(['net', 'stop', 'openvpnservice']) + log.error('Unable to disconnect'); + console.log(error); + + }); + }; } - } - connected() { - this.dispatch(); - ipc.send('vpn.connected'); - } + checkIp() { + return function(dispatch) { + var helpers = require('../utils/VPNHelpers'); + dispatch(); + helpers.updateIp() + .then(() => { + + log.info('IP Updated'); + + }) + .catch((error) => { + + log.error('Unable to update IP'); + console.log(error); + + }); + }; + } + + invalidCredentials() { + return function(dispatch) { + dispatch(); + alert('Invalid credentials'); + }; + } + + appReady() { + return function(dispatch) { + dispatch(); + if (Settings.get('connectLaunch') === 'true' && Credentials._config()) { + log.info('Auto-connect on launch'); + this.connect({ + username: Credentials.get().username, + password: Credentials.get().password, + server: Settings.get('server') || 'hub.vpn.ht' + }); + } + }; + } + + // used by tray + disconnected() { + return function(dispatch) { + dispatch(); + ipcRenderer.send('vpn.disconnected'); + + // on windows we need to stop the service + if (process.platform == 'win32') { + require('../utils/Util').exec(['net', 'stop', 'openvpnservice']) + } + }; + } + + connected() { + return function(dispatch) { + dispatch(); + ipcRenderer.send('vpn.connected'); + }; + } } -export default alt.createActions(VPNActions); +export default alt.createActions(VPNActions); \ No newline at end of file diff --git a/src/alt.js b/src/alt.js index bd2bdab..f492ae5 100755 --- a/src/alt.js +++ b/src/alt.js @@ -1,2 +1,2 @@ import Alt from 'alt'; -export default new Alt(); +export default new Alt(); \ No newline at end of file diff --git a/src/app-tray.js b/src/app-tray.js index 62934c6..299a225 100644 --- a/src/app-tray.js +++ b/src/app-tray.js @@ -1,7 +1,4 @@ -import Menu from 'menu'; -import MenuItem from 'menu-item'; -import Tray from 'tray'; -import ipc from 'ipc'; +import {Menu, MenuItem, ipcMain, Tray} from 'electron'; var trayMenuDisconnected = null; var trayMenuConnected = null; @@ -10,103 +7,106 @@ var trayMenuConnecting = null; // Define a function to set up our tray icon exports.init = function(helper) { - // Disconnected State - trayMenuDisconnected = new Menu(); - trayMenuDisconnected.append(new MenuItem({ - label: 'Toggle VPN.ht', - click: helper.toggleVisibility - })); - trayMenuDisconnected.append(new MenuItem({ - type: 'separator' - })); - trayMenuDisconnected.append(new MenuItem({ - label: 'Connect', - click: helper.connect - })); - trayMenuDisconnected.append(new MenuItem({ - label: 'Disconnect', - enabled: false - })); - trayMenuDisconnected.append(new MenuItem({ - type: 'separator' - })); - trayMenuDisconnected.append(new MenuItem({ - label: 'Quit', - click: helper.quit - })); + ipcMain.on('localization.ready', function localize(e, arg) { + let t = JSON.parse(arg); - // Connected State - trayMenuConnected = new Menu(); - trayMenuConnected.append(new MenuItem({ - label: 'Show Window', - click: helper.toggleVisibility - })); - trayMenuConnected.append(new MenuItem({ - type: 'separator' - })); - trayMenuConnected.append(new MenuItem({ - label: 'Connect', - enabled: false - })); - trayMenuConnected.append(new MenuItem({ - label: 'Disconnect', - click: helper.disconnect - })); - trayMenuConnected.append(new MenuItem({ - type: 'separator' - })); - trayMenuConnected.append(new MenuItem({ - label: 'Quit', - click: helper.quit - })); + // Disconnected State + trayMenuDisconnected = new Menu(); + trayMenuDisconnected.append(new MenuItem({ + label: t['Toggle'] + ' VPN.ht', + click: helper.toggleVisibility + })); + trayMenuDisconnected.append(new MenuItem({ + type: 'separator' + })); + trayMenuDisconnected.append(new MenuItem({ + label: t['Connect'], + click: helper.connect + })); + trayMenuDisconnected.append(new MenuItem({ + label: t['Disconnect'], + enabled: false + })); + trayMenuDisconnected.append(new MenuItem({ + type: 'separator' + })); + trayMenuDisconnected.append(new MenuItem({ + label: t['Quit'], + click: helper.quit + })); - // Connecting State - trayMenuConnecting = new Menu(); - trayMenuConnecting.append(new MenuItem({ - label: 'Show Window', - click: helper.toggleVisibility - })); - trayMenuConnecting.append(new MenuItem({ - type: 'separator' - })); - trayMenuConnecting.append(new MenuItem({ - label: 'Cancel connecting...', - click: helper.disconnect - })); - trayMenuConnecting.append(new MenuItem({ - label: 'Disconnect', - enabled: false - })); - trayMenuConnecting.append(new MenuItem({ - type: 'separator' - })); - trayMenuConnecting.append(new MenuItem({ - label: 'Quit', - click: helper.quit - })); + // Connected State + trayMenuConnected = new Menu(); + trayMenuConnected.append(new MenuItem({ + label: t['Show Window'], + click: helper.toggleVisibility + })); + trayMenuConnected.append(new MenuItem({ + type: 'separator' + })); + trayMenuConnected.append(new MenuItem({ + label: t['Connect'], + enabled: false + })); + trayMenuConnected.append(new MenuItem({ + label: t['Disconnect'], + click: helper.disconnect + })); + trayMenuConnected.append(new MenuItem({ + type: 'separator' + })); + trayMenuConnected.append(new MenuItem({ + label: t['Quit'], + click: helper.quit + })); + // Connecting State + trayMenuConnecting = new Menu(); + trayMenuConnecting.append(new MenuItem({ + label: t['Show Window'], + click: helper.toggleVisibility + })); + trayMenuConnecting.append(new MenuItem({ + type: 'separator' + })); + trayMenuConnecting.append(new MenuItem({ + label: t['Cancel connecting...'], + click: helper.disconnect + })); + trayMenuConnecting.append(new MenuItem({ + label: t['Disconnect'], + enabled: false + })); + trayMenuConnecting.append(new MenuItem({ + type: 'separator' + })); + trayMenuConnecting.append(new MenuItem({ + label: t['Quit'], + click: helper.quit + })); - var tray = new Tray(__dirname + '/tray.png'); - tray.setContextMenu(trayMenuDisconnected); + var tray = new Tray(__dirname + '/tray.png'); + tray.setContextMenu(trayMenuDisconnected); + tray.setToolTip(t['Disconnected']); - tray.on('clicked', helper.toggleVisibility); + tray.on('clicked', helper.toggleVisibility); - ipc.on('vpn.connected', function handleConnected() { - tray.setContextMenu(trayMenuConnected); - tray.setImage(__dirname + '/tray_connected.png'); - tray.setToolTip('Connected'); - }); + ipcMain.on('vpn.connected', function handleConnected() { + tray.setContextMenu(trayMenuConnected); + tray.setImage(__dirname + '/tray_connected.png'); + tray.setToolTip(t['Connected']); + }); - ipc.on('vpn.connecting', function handleConnecting() { - tray.setContextMenu(trayMenuConnecting); - tray.setImage(__dirname + '/tray_connecting.png'); - tray.setToolTip('Connecting...'); - }); + ipcMain.on('vpn.connecting', function handleConnecting() { + tray.setContextMenu(trayMenuConnecting); + tray.setImage(__dirname + '/tray_connecting.png'); + tray.setToolTip(t['Connecting...']); + }); - ipc.on('vpn.disconnected', function handleDisconnected() { - tray.setContextMenu(trayMenuDisconnected); - tray.setImage(__dirname + '/tray.png'); - tray.setToolTip('Disconnected'); - }); - -}; + ipcMain.on('vpn.disconnected', function handleDisconnected() { + tray.setContextMenu(trayMenuDisconnected); + tray.setImage(__dirname + '/tray.png'); + tray.setToolTip(t['Disconnected']); + }); + }); +}; \ No newline at end of file diff --git a/src/app.js b/src/app.js index 5fbca6b..93bf4ff 100755 --- a/src/app.js +++ b/src/app.js @@ -1,7 +1,7 @@ require.main.paths.splice(0, 0, process.env.NODE_PATH); -import remote from 'remote'; +import {remote, ipcRenderer} from 'electron'; import React from 'react'; -import ipc from 'ipc'; +import ReactDOM from 'react-dom'; import metrics from './utils/MetricsUtil'; import VPN from './utils/VPNUtil'; import vpnActions from './actions/VPNActions'; @@ -16,15 +16,16 @@ import log from './stores/LogStore'; import accountStore from './stores/AccountStore'; import utils from './utils/Util'; import Credentials from './utils/CredentialsUtil'; - import Settings from './utils/SettingsUtil'; +import Localization from './utils/localizationUtil'; -var app = remote.require('app'); -var Menu = remote.require('menu'); +var app = remote.app; +var Menu = remote.Menu; // Init process log.initLogs(app.getVersion()); VPN.initCheck(); +Localization.init(); webUtil.addLiveReload(); webUtil.addBugReporting(); webUtil.disableGlobalBackspace(); @@ -32,65 +33,68 @@ Menu.setApplicationMenu(Menu.buildFromTemplate(template())); metrics.track('Started App'); metrics.track('app heartbeat'); setInterval(function() { - metrics.track('app heartbeat'); + metrics.track('app heartbeat'); }, 14400000); var router = Router.create({ - routes: routes + routes: routes }); -router.run(Handler => React.render( < Handler / > , document.body)); +router.run(Handler => ReactDOM.render( < Handler / > , document.getElementById('root'))); routerContainer.set(router); // Default Route router.transitionTo('dashboard'); -ipc.on('application:quitting', () => {}); +ipcRenderer.on('application:quitting', () => {}); + +// Define styles +document.getElementById('root').classList = [process.platform]; // Event fires when the app receives a vpnht:// URL -ipc.on('application:open-url', opts => { - console.log('open', opts); +ipcRenderer.on('application:open-url', opts => { + console.log('open', opts); }); -ipc.on('application:vpn-connect', () => { - if (Credentials._config()) { - vpnActions.connect({ - username: Credentials.get().username, - password: Credentials.get().password, - server: Settings.get('server') || 'hub.vpn.ht' - }); - } else { - log.error('No user/pass saved in the hash.\n\nTIPS: Try to connect manually first to save your data.') - } +ipcRenderer.on('application:vpn-connect', () => { + if (Credentials._config()) { + vpnActions.connect({ + username: Credentials.get().username, + password: Credentials.get().password, + server: Settings.get('server') || 'hub.vpn.ht' + }); + } else { + log.error('No user/pass saved in the hash.\n\nTIPS: Try to connect manually first to save your data.') + } }); -ipc.on('application:vpn-check-disconnect', () => { - if (accountStore.getState().connecting || accountStore.getState().connected) { - log.info('Disconnecting before closing application'); - vpnActions.disconnect(); - } else { - vpnActions.disconnected(); - } +ipcRenderer.on('application:vpn-check-disconnect', () => { + if (accountStore.getState().connecting || accountStore.getState().connected) { + log.info('Disconnecting before closing application'); + vpnActions.disconnect(); + } else { + vpnActions.disconnected(); + } }); -ipc.on('application:vpn-check-sleep', () => { - if (accountStore.getState().connected) { - log.info('Trying to reconnect after sleep'); - if (Credentials._config()) { - vpnActions.connect({ - username: Credentials.get().username, - password: Credentials.get().password, - server: Settings.get('server') || 'hub.vpn.ht' - }); - } else { - log.info('No user/pass saved in the hash, now disconnecting.'); - vpnActions.disconnect(); - } - } +ipcRenderer.on('application:vpn-check-sleep', () => { + if (accountStore.getState().connected) { + log.info('Trying to reconnect after sleep'); + if (Credentials._config()) { + vpnActions.connect({ + username: Credentials.get().username, + password: Credentials.get().password, + server: Settings.get('server') || 'hub.vpn.ht' + }); + } else { + log.info('No user/pass saved in the hash. Disconnecting.'); + vpnActions.disconnect(); + } + } }); -ipc.on('application:vpn-disconnect', () => { - vpnActions.disconnect(); +ipcRenderer.on('application:vpn-disconnect', () => { + vpnActions.disconnect(); }); module.exports = { - router: router -}; + router: router +}; \ No newline at end of file diff --git a/src/browser.js b/src/browser.js index 3316d78..c2b7c96 100755 --- a/src/browser.js +++ b/src/browser.js @@ -1,7 +1,5 @@ -import app from 'app'; -import BrowserWindow from 'browser-window'; +import {app, BrowserWindow, ipcMain, screen, dialog} from 'electron'; import os from 'os'; -import ipc from 'ipc'; import net from 'net'; import fs from 'fs'; import path from 'path'; @@ -9,6 +7,7 @@ import child_process from 'child_process'; import trayTemplate from './app-tray' import Updater from 'autoupdater' import yargs from 'yargs'; +import util from './utils/Util'; let args = yargs(process.argv.slice(1)).wrap(100).argv; @@ -42,7 +41,6 @@ app.on('ready', function() { var checkingQuit = false; var canQuit = false; - var screen = require('screen'); var size = screen.getPrimaryDisplay().workAreaSize; var autoUpdater = new Updater({ currentVersion: app.getVersion() @@ -50,12 +48,12 @@ app.on('ready', function() { var windowSize = { width: 800, - height: 870 - } + height: process.platform === 'win32' ? 900 : 870 + }; - if (size.height < 870) { - windowSize.width = '800'; - windowSize.height = '600'; + if (size.height !== 870) { + windowSize.width = 800; + windowSize.height = 600; } var mainWindow = new BrowserWindow({ @@ -63,23 +61,30 @@ app.on('ready', function() { height: windowSize.height, 'standard-window': false, resizable: false, - frame: false, - show: false + frame: process.platform === 'win32', //only on Windows + show: false, + titleBarStyle: 'hidden-inset', + backgroundColor: '#ededed', // to enable subpixel anti-aliasing, since electron 0.37.3 + webPreferences: { + backgroundThrottling: false // disable throttling rendering when not focused + } }); + //DEBUG: mainWindow.webContents.openDevTools(); + var preventMultipleInstances = function() { var socket = (process.platform === 'win32') ? '\\\\.\\pipe\\vpnht-sock' : path.join(os.tmpdir(), 'vpnht.sock'); var client = net.connect({ path: socket }, function() { var errorMessage = 'Another instance of VPN.ht is already running. Only one instance of the app can be open at a time.' - require('dialog').showMessageBox(mainWindow, { + dialog.showMessageBox(mainWindow, { 'type': 'error', message: errorMessage, buttons: ['OK'] }, function() { client.end(); - app.terminate(); + process.exit(0); }) }).on('error', function(err) { @@ -103,7 +108,7 @@ app.on('ready', function() { }); server.listen(socket); - mainWindow.loadUrl(path.normalize('file://' + path.join(__dirname, 'index.html'))); + mainWindow.loadURL(path.normalize('file://' + path.join(__dirname, 'index.html'))); }); } @@ -115,7 +120,7 @@ app.on('ready', function() { if (!checkingQuit) { checkingQuit = true; mainWindow.webContents.send('application:vpn-check-disconnect'); - ipc.on('vpn.disconnected', () => { + ipcMain.on('vpn.disconnected', () => { canQuit = true; app.quit(); }); @@ -123,7 +128,8 @@ app.on('ready', function() { } }); - require('power-monitor').on('resume', function() { + // powerMonitor cannot be required before 'ready' event is fired: https://github.com/electron/electron/blob/master/docs/api/power-monitor.md + require('electron').powerMonitor.on('resume', function() { mainWindow.webContents.send('application:vpn-check-sleep'); }); @@ -158,7 +164,9 @@ app.on('ready', function() { mainWindow.webContents.on('did-finish-load', function() { + console.log('ready') mainWindow.setTitle('VPN.ht'); + if (!args.hide) { mainWindow.show(); mainWindow.focus(); @@ -184,7 +192,7 @@ app.on('ready', function() { autoUpdater.on("updateReady", function(updaterPath) { console.log("Launching " + updaterPath); - require('dialog').showMessageBox(mainWindow, { + dialog.showMessageBox(mainWindow, { 'type': 'info', message: 'A new version is available, do you want to install now ?', buttons: ['Yes', 'No'] @@ -192,16 +200,16 @@ app.on('ready', function() { if (response === 0) { if (process.platform == 'win32') { - require('./utils/Util').exec('start ' + updaterPath).then(function(stdOut) { + util.exec('start ' + updaterPath).then(function(stdOut) { console.log(stdOut); - app.terminate(); + process.exit(0); }); } else { child_process.spawn('open', [updaterPath], { detached: true, stdio: ['ignore', 'ignore', 'ignore'] }); - app.terminate(); + process.exit(0); } } diff --git a/src/components/About.react.js b/src/components/About.react.js index e796292..e39e5ee 100755 --- a/src/components/About.react.js +++ b/src/components/About.react.js @@ -1,43 +1,59 @@ -import React from 'react/addons'; +import {shell} from 'electron'; +import React from 'react'; import metrics from '../utils/MetricsUtil'; import utils from '../utils/Util'; +import {t} from '../utils/localizationUtil'; import Router from 'react-router'; import RetinaImage from 'react-retina-image'; +import pkJson from '../package'; var packages; try { - packages = utils.packagejson(); + packages = utils.packagejson(); } catch (err) { - packages = {}; + packages = {}; } var Preferences = React.createClass({ - mixins: [Router.Navigation], - getInitialState: function () { - return { - metricsEnabled: metrics.enabled() - }; - }, - handleGoBackClick: function () { - this.goBack(); - metrics.track('Went Back From About'); - }, - render: function () { - return ( -
-
- Go Back -
-
- -

{packages.name}

-

{packages.version}

+ mixins: [Router.Navigation], + getInitialState: function () { + return { + metricsEnabled: metrics.enabled() + }; + }, + handleGoBackClick: function () { + this.goBack(); + metrics.track('Went Back From About'); + }, + handleExternal: function () { + shell.openExternal(pkJson.homepage); + }, + render: function () { + return ( +
+
+ + +
+
+ +

{t('Plug and play!')}

+

{t('You can start using our service, and start surfing in privacy, as soon as you create an account.')}

+
+
+ +

{t('No logs')}

+

{t('You value your privacy. So do we. We don’t keep logs, we don’t know the sites you have visited or the applications you’ve used.')}

+
+
+ +
+ {packages.name} v{packages.version} - {pkJson.homepage} +
+
-
-
-
- ); - } + ); + } }); module.exports = Preferences; diff --git a/src/components/Dashboard.react.js b/src/components/Dashboard.react.js index 1945348..728dbbe 100644 --- a/src/components/Dashboard.react.js +++ b/src/components/Dashboard.react.js @@ -1,4 +1,4 @@ -import React from 'react/addons'; +import React from 'react'; import metrics from '../utils/MetricsUtil'; import Router from 'react-router'; @@ -8,46 +8,44 @@ import ConnectionDetails from './DashboardConnectionDetails.react'; import accountStore from '../stores/AccountStore'; var Preferences = React.createClass({ - mixins: [Router.Navigation], - - getInitialState: function () { - return { - connected: accountStore.getState().connected - }; - }, - - componentDidMount: function () { - accountStore.listen(this.update); - }, - - componentWillUnmount: function () { - accountStore.unlisten(this.update); - }, - - update: function () { - if (this.isMounted()) { - this.setState({ - connected: accountStore.getState().connected - }); - } - }, + mixins: [Router.Navigation], - render: function () { + getInitialState: function() { + return { + connected: accountStore.getState().connected + }; + }, - var toMount = ; - if (this.state.connected) { - toMount = ; - } + componentDidMount: function() { + accountStore.listen(this.update); + }, + + componentWillUnmount: function() { + accountStore.unlisten(this.update); + }, + + update: function() { + if (this.isMounted()) { + this.setState({ + connected: accountStore.getState().connected + }); + } + }, - return ( -
- {toMount} -
- ); + render: function() { - } + var toMount = < Connect / > ; + if (this.state.connected) { + toMount = < ConnectionDetails / > ; + } + + return ( < div className = "content-scroller" + id = "content" > {toMount} < /div> + ); + + } }); -module.exports = Preferences; +module.exports = Preferences; \ No newline at end of file diff --git a/src/components/DashboardConnect.react.js b/src/components/DashboardConnect.react.js index 2daddb4..1d34b54 100644 --- a/src/components/DashboardConnect.react.js +++ b/src/components/DashboardConnect.react.js @@ -1,4 +1,4 @@ -import React from 'react/addons'; +import React from 'react'; import Router from 'react-router'; import myip from '../utils/MyipUtil'; @@ -13,155 +13,174 @@ import ServerItem from './ServerListItem.react'; import Logs from './DashboardLogs.react'; import Settings from '../utils/SettingsUtil'; import Credentials from '../utils/CredentialsUtil'; - -import Cache from 'node-cache'; -let serversCache = new Cache(); +import {t} from '../utils/localizationUtil'; var DashboardConnect = React.createClass({ - mixins: [React.addons.LinkedStateMixin], - - getInitialState: function () { - return { - connecting: accountStore.getState().connecting, - appReady: accountStore.getState().appReady, - username: Credentials.get().username, - password: Credentials.get().password, - saveCredentials: Settings.get('saveCredentials'), - server: Settings.get('server') || 'hub.vpn.ht', - servers: serverStore.getState().servers - }; - }, - - componentDidMount: function () { - accountStore.listen(this.update); - serverStore.listen(this.updateServers); - }, - - componentWillUnmount: function () { - accountStore.unlisten(this.update); - serverStore.unlisten(this.updateServers); - }, - - update: function () { - if (this.isMounted()) { + getInitialState: function () { + return { + connecting: accountStore.getState().connecting, + appReady: accountStore.getState().appReady, + username: Credentials.get().username, + password: Credentials.get().password, + saveCredentials: Settings.get('saveCredentials'), + server: Settings.get('server') || 'hub.vpn.ht', + servers: serverStore.getState().servers + }; + }, + + componentDidMount: function () { + accountStore.listen(this.update); + serverStore.listen(this.updateServers); + }, + + componentWillUnmount: function () { + accountStore.unlisten(this.update); + serverStore.unlisten(this.updateServers); + }, + + update: function () { + if (this.isMounted()) { + this.setState({ + connecting: accountStore.getState().connecting, + appReady: accountStore.getState().appReady + }); + } + }, + + updateServers: function () { + if (this.isMounted()) { + this.setState({ + servers: serverStore.getState().servers + }); + } + }, + + handleChange: function (key) { + return function (e) { + var state = {}; + state[key] = e.target.value; + this.setState(state); + }.bind(this); + }, + + handleConnect: function (e) { + e.preventDefault(); + + if (this.state.connecting) { + VPN.disconnect(); + } else { + if (!this.state.username) { + alert(t('Username should not be left blank')); + } else if (!this.state.password) { + alert(t('Password should not be left blank')); + } else if (!this.state.server) { + alert(t('You should select a server')); + } else { + + // should we save credentials ? + if (this.state.saveCredentials) { + Credentials.save(this.state.username, this.state.password); + } else { + // make sure to flush previous save + Credentials.logout(); + } + + VPN.connect(this.state); + } + } + }, + + handleServer: function (val) { this.setState({ - connecting: accountStore.getState().connecting, - appReady: accountStore.getState().appReady + server: val }); - } - }, - updateServers: function () { - if (this.isMounted()) { + // save for future use + Settings.save('server', val, val.value); + }, + + handleChangeSaveCredentials: function (e) { + var checked = e.target.checked; this.setState({ - servers: serverStore.getState().servers + saveCredentials: checked }); - } - }, - - handleConnect: function (e) { - e.preventDefault(); - - if (this.state.connecting) { - VPN.disconnect(); - } else { - if (!this.state.username) { - alert('Username should not be left blank'); - } else if (!this.state.password) { - alert('Password should not be left blank'); - } else if (!this.state.server) { - alert('You should select a server'); - } else { - // should we save credentials ? - if (this.state.saveCredentials) { - Credentials.save(this.state.username, this.state.password); - } else { - // make sure to flush previous save - Credentials.logout(); - } + // clear username/pw + if (!checked) { + Credentials.logout(); + this.setState({ + username: '', + password: '' + }); + } + + // save for future use + Settings.save('saveCredentials', !!checked); + }, - VPN.connect(this.state); + handleKeyPress: function (e) { + if (e.key === 'Enter') { + this.handleConnect(e); } - } - }, - - handleServer: function (val) { - this.setState({ - server: val - }); - - // save for future use - Settings.save('server', val); - }, - - handleChangeSaveCredentials: function (e) { - var checked = e.target.checked; - this.setState({ - saveCredentials: checked - }); - - // save for future use - Settings.save('saveCredentials', !!checked); - }, - - render: function () { - var currentStatus = 'Loading...'; - if (this.state.appReady) { - if (this.state.connecting) { - currentStatus = 'Connecting...'; - } else { - currentStatus = 'Disconnected'; + }, + + render: function () { + var currentStatus = t('Loading...'); + if (this.state.appReady) { + if (this.state.connecting) { + currentStatus = t('Connecting...'); + } else { + currentStatus = t('Disconnected'); + } } - } return ( -
- -
-

VPN connection status

-
- -

{currentStatus}

+
+ +
+

{t('VPN connection status')}

+
+ +

{currentStatus}

+
+ +
+ +
+

{t('Login')}

+ + +
+ + +
+
+ +
+

{t('Servers')}

+ - -
- - -

Remember my username and password

-
-
- -
-

Servers

-