diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index a060b480fb..08a64f6154 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -705,5 +705,29 @@ }, "emailDesc": { "message": "Verification codes will be emailed to you." + }, + "selfHostedEnvironment": { + "message": "Self-hosted Environment" + }, + "selfHostedEnvironmentFooter": { + "message": "Specify the base URL of your on-premise hosted bitwarden installation." + }, + "customEnvironment": { + "message": "Custom Environment" + }, + "customEnvironmentFooter": { + "message": "For advanced users. You can specify the base URL of each service independently." + }, + "baseUrl": { + "message": "Server URL" + }, + "apiUrl": { + "message": "API Server URL" + }, + "identityUrl": { + "message": "Identity Server URL" + }, + "environmentSaved": { + "message": "The environment URLs have been saved." } } diff --git a/src/background.js b/src/background.js index 37ea7b9d41..0a6b00d725 100644 --- a/src/background.js +++ b/src/background.js @@ -6,7 +6,7 @@ var bg_utilsService = new UtilsService(); var bg_cryptoService = new CryptoService(bg_constantsService); var bg_tokenService = new TokenService(); var bg_appIdService = new AppIdService(); -var bg_apiService = new ApiService(bg_tokenService, bg_appIdService, bg_utilsService, logout); +var bg_apiService = new ApiService(bg_tokenService, bg_appIdService, bg_utilsService, bg_constantsService, logout); var bg_userService = new UserService(bg_tokenService, bg_apiService, bg_cryptoService); var bg_settingsService = new SettingsService(bg_userService); var bg_loginService = new LoginService(bg_cryptoService, bg_userService, bg_apiService, bg_settingsService); diff --git a/src/popup/app/config.js b/src/popup/app/config.js index 7fbabf693b..1f0b5dbf10 100644 --- a/src/popup/app/config.js +++ b/src/popup/app/config.js @@ -90,27 +90,27 @@ data: { authorize: true }, params: { animation: null } }) - .state('tabs.current', { - url: '/current', - templateUrl: 'app/current/views/current.html', - controller: 'currentController' - }) - .state('tabs.vault', { - url: '/vault', - templateUrl: 'app/vault/views/vault.html', - controller: 'vaultController', - params: { syncOnLoad: false } - }) - .state('tabs.settings', { - url: '/settings', - templateUrl: 'app/settings/views/settings.html', - controller: 'settingsController' - }) - .state('tabs.tools', { - url: '/tools', - templateUrl: 'app/tools/views/tools.html', - controller: 'toolsController' - }) + .state('tabs.current', { + url: '/current', + templateUrl: 'app/current/views/current.html', + controller: 'currentController' + }) + .state('tabs.vault', { + url: '/vault', + templateUrl: 'app/vault/views/vault.html', + controller: 'vaultController', + params: { syncOnLoad: false } + }) + .state('tabs.settings', { + url: '/settings', + templateUrl: 'app/settings/views/settings.html', + controller: 'settingsController' + }) + .state('tabs.tools', { + url: '/tools', + templateUrl: 'app/tools/views/tools.html', + controller: 'toolsController' + }) .state('viewFolder', { url: '/view-folder?folderId', @@ -227,6 +227,13 @@ data: { authorize: true }, params: { animation: null } }) + .state('environment', { + url: '/environment', + templateUrl: 'app/settings/views/settingsEnvironment.html', + controller: 'settingsEnvironmentController', + data: { authorize: false }, + params: { animation: null } + }) .state('lock', { url: '/lock', templateUrl: 'app/lock/views/lock.html', diff --git a/src/popup/app/global/home.html b/src/popup/app/global/home.html index d9436ccc46..b4b3f3e933 100644 --- a/src/popup/app/global/home.html +++ b/src/popup/app/global/home.html @@ -1,16 +1,17 @@ -
-
- bitwarden -

{{i18n.loginOrCreateNewAccount}}

- +
+ + Settings + + bitwarden +

{{i18n.loginOrCreateNewAccount}}

+
diff --git a/src/popup/app/settings/settingsEnvironmentController.js b/src/popup/app/settings/settingsEnvironmentController.js new file mode 100644 index 0000000000..ac9c2f6aed --- /dev/null +++ b/src/popup/app/settings/settingsEnvironmentController.js @@ -0,0 +1,51 @@ +angular + .module('bit.settings') + + .controller('settingsEnvironmentController', function ($scope, i18nService, $analytics, constantsService, utilsService, + $window, apiService, toastr) { + $scope.i18n = i18nService; + + utilsService.initListSectionItemListeners($(document), angular); + + $scope.baseUrl = $window.localStorage.getItem(constantsService.baseUrlKey) || ''; + $scope.apiUrl = $window.localStorage.getItem(constantsService.apiUrlKey) || ''; + $scope.identityUrl = $window.localStorage.getItem(constantsService.identityUrlKey) || ''; + + $scope.save = function () { + if ($scope.baseUrl && $scope.baseUrl !== '') { + $scope.baseUrl = formatUrl($scope.baseUrl); + $window.localStorage.setItem(constantsService.baseUrlKey, $scope.baseUrl); + } + else { + $window.localStorage.removeItem(constantsService.baseUrlKey); + } + + if ($scope.apiUrl && $scope.apiUrl !== '') { + $scope.apiUrl = formatUrl($scope.apiUrl); + $window.localStorage.setItem(constantsService.apiUrlKey, $scope.apiUrl); + } + else { + $window.localStorage.removeItem(constantsService.apiUrlKey); + } + + if ($scope.identityUrl && $scope.identityUrl !== '') { + $scope.identityUrl = formatUrl($scope.identityUrl); + $window.localStorage.setItem(constantsService.identityUrlKey, $scope.identityUrl); + } + else { + $window.localStorage.removeItem(constantsService.identityUrlKey); + } + + apiService.setUrls(); + $analytics.eventTrack('Set Environment URLs'); + toastr.success(i18nService.environmentSaved); + }; + + function formatUrl(url) { + url = url.replace(/\/+$/g, ''); + if (!url.startsWith("http://") && !url.startsWith('https://')) { + url = 'https://' + url; + } + return url; + } + }); diff --git a/src/popup/app/settings/views/settingsEnvironment.html b/src/popup/app/settings/views/settingsEnvironment.html new file mode 100644 index 0000000000..7af6f5c71a --- /dev/null +++ b/src/popup/app/settings/views/settingsEnvironment.html @@ -0,0 +1,48 @@ +
+
+ +
+ +
+
{{i18n.settings}}
+
+
+
+
+
+ {{i18n.selfHostedEnvironment}} +
+
+
+ + +
+
+ +
+
+
+ {{i18n.customEnvironment}} +
+
+
+ + +
+
+ + +
+
+ +
+
+
+
diff --git a/src/popup/index.html b/src/popup/index.html index 46c44cc3c8..8b10dc9c86 100644 --- a/src/popup/index.html +++ b/src/popup/index.html @@ -85,6 +85,7 @@ + diff --git a/src/popup/less/components.less b/src/popup/less/components.less index c16ebd6a8a..92a2b98037 100644 --- a/src/popup/less/components.less +++ b/src/popup/less/components.less @@ -375,6 +375,7 @@ border: none; width: 100%; background-color: transparent; + .placeholder-color(#bbbbbb); &:focus { outline: none; diff --git a/src/popup/less/pages.less b/src/popup/less/pages.less index 8aa0dde267..a72936d010 100644 --- a/src/popup/less/pages.less +++ b/src/popup/less/pages.less @@ -17,13 +17,13 @@ img { margin: 0 auto 20px; - width: 220px; + width: 270px; display: block; } } .home-page { - padding: 100px 20px 20px; + padding: 150px 20px 20px; text-align: center; position: relative; height: 100%; @@ -37,6 +37,26 @@ p { font-size: 18px; } + + a.settings-icon { + color: #bbbbbb; + position: absolute; + top: 10px; + left: 10px; + + span { + visibility: hidden; + } + + &:hover { + color: @link-hover-color; + text-decoration: none; + + span { + visibility: visible; + } + } + } } .splash-page { diff --git a/src/services/apiService.js b/src/services/apiService.js index 46ef73b58a..9b072ac606 100644 --- a/src/services/apiService.js +++ b/src/services/apiService.js @@ -1,33 +1,53 @@ -function ApiService(tokenService, appIdService, utilsService, logoutCallback) { - // Desktop - //this.baseUrl = 'http://localhost:4000'; - //this.identityBaseUrl = 'http://localhost:33656'; - - // Desktop HTTPS - //this.baseUrl = 'https://localhost:44377'; - //this.identityBaseUrl = 'https://localhost:44392'; - - // Desktop external - //this.baseUrl = 'http://192.168.1.4:4000'; - //this.identityBaseUrl = 'http://192.168.1.4:33656'; - - // Preview - //this.baseUrl = 'https://preview-api.bitwarden.com'; - //this.identityBaseUrl = 'https://preview-identity.bitwarden.com'; - - // Production - this.baseUrl = 'https://api.bitwarden.com'; - this.identityBaseUrl = 'https://identity.bitwarden.com'; - +function ApiService(tokenService, appIdService, utilsService, constantsService, logoutCallback) { this.tokenService = tokenService; this.logoutCallback = logoutCallback; this.appIdService = appIdService; this.utilsService = utilsService; + this.constantsService = constantsService; initApiService(); + this.setUrls(); } function initApiService() { + ApiService.prototype.setUrls = function () { + var storedBaseUrl = window.localStorage.getItem(this.constantsService.baseUrlKey); + + if (storedBaseUrl) { + this.baseUrl = storedBaseUrl + '/api'; + this.identityBaseUrl = storedBaseUrl + '/identity'; + return; + } + + var storedApiUrl = window.localStorage.getItem(this.constantsService.apiUrlKey); + var storedIdentityUrl = window.localStorage.getItem(this.constantsService.identityUrlKey); + if (storedApiUrl && storedIdentityUrl) { + this.baseUrl = storedApiUrl; + this.identityBaseUrl = storedIdentityUrl; + return; + } + + // Desktop + //this.baseUrl = 'http://localhost:4000'; + //this.identityBaseUrl = 'http://localhost:33656'; + + // Desktop HTTPS + //this.baseUrl = 'https://localhost:44377'; + //this.identityBaseUrl = 'https://localhost:44392'; + + // Desktop external + //this.baseUrl = 'http://192.168.1.4:4000'; + //this.identityBaseUrl = 'http://192.168.1.4:33656'; + + // Preview + //this.baseUrl = 'https://preview-api.bitwarden.com'; + //this.identityBaseUrl = 'https://preview-identity.bitwarden.com'; + + // Production + this.baseUrl = 'https://api.bitwarden.com'; + this.identityBaseUrl = 'https://identity.bitwarden.com'; + }; + // Auth APIs ApiService.prototype.postIdentityToken = function (tokenRequest, success, successWithTwoFactor, error) { diff --git a/src/services/constantsService.js b/src/services/constantsService.js index f2701b3cb0..69524e386f 100644 --- a/src/services/constantsService.js +++ b/src/services/constantsService.js @@ -1,5 +1,8 @@ function ConstantsService(i18nService) { return { + baseUrlKey: 'baseUrl', + apiUrlKey: 'apiUrl', + identityUrlKey: 'identityUrl', disableGaKey: 'disableGa', disableAddLoginNotificationKey: 'disableAddLoginNotification', disableContextMenuItemKey: 'disableContextMenuItem',