From 2272bcac71933b632f69e83d91c9bbfd7c3bc247 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Fri, 11 Aug 2017 23:23:14 -0400 Subject: [PATCH] licensing options when self hosted --- gulpfile.js | 1 + src/app/services/apiService.js | 8 +- src/app/settings.js | 2 +- src/app/settings/settingsBillingController.js | 23 + src/app/settings/settingsPremiumController.js | 54 +- src/app/settings/views/settingsBilling.html | 8 +- src/app/settings/views/settingsPremium.html | 822 +++++++++--------- 7 files changed, 498 insertions(+), 420 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index b719d287ca..df84dc36bd 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -241,6 +241,7 @@ function config() { createModule: false, constants: _.merge({}, { appSettings: { + selfHosted: false, version: project.version, environment: project.env } diff --git a/src/app/services/apiService.js b/src/app/services/apiService.js index 6f78215268..4cba765e61 100644 --- a/src/app/services/apiService.js +++ b/src/app/services/apiService.js @@ -127,12 +127,16 @@ putKey: { url: _apiUri + '/accounts/key', method: 'POST', params: {} }, 'import': { url: _apiUri + '/accounts/import', method: 'POST', params: {} }, postDelete: { url: _apiUri + '/accounts/delete', method: 'POST', params: {} }, - postPremium: { url: _apiUri + '/accounts/premium', method: 'POST', params: {} }, putStorage: { url: _apiUri + '/accounts/storage', method: 'POST', params: {} }, putPayment: { url: _apiUri + '/accounts/payment', method: 'POST', params: {} }, putCancelPremium: { url: _apiUri + '/accounts/cancel-premium', method: 'POST', params: {} }, putReinstatePremium: { url: _apiUri + '/accounts/reinstate-premium', method: 'POST', params: {} }, - getBilling: { url: _apiUri + '/accounts/billing', method: 'GET', params: {} } + getBilling: { url: _apiUri + '/accounts/billing', method: 'GET', params: {} }, + postPremium: { + url: _apiUri + '/accounts/premium', + method: 'POST', + headers: { 'Content-Type': undefined } + } }); _service.twoFactor = $resource(_apiUri + '/two-factor', {}, { diff --git a/src/app/settings.js b/src/app/settings.js index f610d3b67e..79ef2028d7 100644 --- a/src/app/settings.js +++ b/src/app/settings.js @@ -1,2 +1,2 @@ angular.module("bit") -.constant("appSettings", {"apiUri":"https://api.bitwarden.com","identityUri":"https://identity.bitwarden.com","stripeKey":"pk_live_bpN0P37nMxrMQkcaHXtAybJk","braintreeKey":"production_qfbsv8kc_njj2zjtyngtjmbjd","whitelistDomains":["api.bitwarden.com"],"version":"1.14.3","environment":"Production"}); +.constant("appSettings", {"apiUri":"https://api.bitwarden.com","identityUri":"https://identity.bitwarden.com","stripeKey":"pk_live_bpN0P37nMxrMQkcaHXtAybJk","braintreeKey":"production_qfbsv8kc_njj2zjtyngtjmbjd","whitelistDomains":["api.bitwarden.com"],"selfHosted":false,"version":"1.14.3","environment":"Production"}); diff --git a/src/app/settings/settingsBillingController.js b/src/app/settings/settingsBillingController.js index 79605d8471..39550c494f 100644 --- a/src/app/settings/settingsBillingController.js +++ b/src/app/settings/settingsBillingController.js @@ -6,6 +6,7 @@ $scope.paymentSource = null; $scope.subscription = null; $scope.loading = true; + var license = null; $scope.$on('$viewContentLoaded', function () { load(); @@ -72,6 +73,26 @@ }); }; + $scope.license = function () { + var licenseString = JSON.stringify(license, null, 2); + var licenseBlob = new Blob([licenseString]); + + // IE hack. ref http://msdn.microsoft.com/en-us/library/ie/hh779016.aspx + if (window.navigator.msSaveOrOpenBlob) { + window.navigator.msSaveBlob(licenseBlob, 'bitwarden_premium_license.json'); + } + else { + var a = window.document.createElement('a'); + a.href = window.URL.createObjectURL(licenseBlob, { type: 'text/plain' }); + a.download = 'bitwarden_premium_license.json'; + document.body.appendChild(a); + // IE: "Access is denied". + // ref: https://connect.microsoft.com/IE/feedback/details/797361/ie-10-treats-blob-url-as-cross-origin-and-denies-access + a.click(); + document.body.removeChild(a); + } + }; + function load() { authService.getUserProfile().then(function (profile) { $scope.premium = profile.premium; @@ -87,6 +108,8 @@ var i = 0; + license = billing.License; + $scope.storage = null; if (billing && billing.MaxStorageGb) { $scope.storage = { diff --git a/src/app/settings/settingsPremiumController.js b/src/app/settings/settingsPremiumController.js index bcb8b4dcb4..9305521bc5 100644 --- a/src/app/settings/settingsPremiumController.js +++ b/src/app/settings/settingsPremiumController.js @@ -2,13 +2,15 @@ .module('bit.settings') .controller('settingsPremiumController', function ($scope, $state, apiService, toastr, $analytics, authService, stripe, - constants, $timeout, appSettings) { + constants, $timeout, appSettings, validationService) { authService.getUserProfile().then(function (profile) { if (profile.premium) { return $state.go('backend.user.settingsBilling'); } }); + $scope.selfHosted = appSettings.selfHosted; + var btInstance = null; $scope.storageGbPrice = constants.storageGb.yearlyPrice; $scope.premiumPrice = constants.premium.price; @@ -54,23 +56,43 @@ return $scope.premiumPrice + (($scope.model.additionalStorageGb || 0) * $scope.storageGbPrice); }; - $scope.submit = function (model) { - $scope.submitPromise = getPaymentToken(model).then(function (token) { - if (!token) { - throw 'No payment token.'; + $scope.submit = function (model, form) { + if ($scope.selfHosted) { + var fileEl = document.getElementById('file'); + var files = fileEl.files; + if (!files || !files.length) { + validationService.addError(form, 'file', 'Select a license file.', true); + return; } - var request = { - paymentToken: token, - additionalStorageGb: model.additionalStorageGb - }; + var fd = new FormData(); + fd.append('license', files[0]); - return apiService.accounts.postPremium(request).$promise; - }, function (err) { - throw err; - }).then(function (result) { - return authService.updateProfilePremium(true); - }).then(function () { + $scope.submitPromise = apiService.accounts.postPremium(fd).$promise.then(function (result) { + return finalizePremium(); + }); + } + else { + $scope.submitPromise = getPaymentToken(model).then(function (token) { + if (!token) { + throw 'No payment token.'; + } + + var fd = new FormData(); + fd.append('paymentToken', token); + fd.append('additionalStorageGb', model.additionalStorageGb || 0); + + return apiService.accounts.postPremium(fd).$promise; + }, function (err) { + throw err; + }).then(function (result) { + return finalizePremium(); + }); + } + }; + + function finalizePremium() { + return authService.updateProfilePremium(true).then(function () { $analytics.eventTrack('Signed Up Premium'); return authService.refreshAccessToken(); }).then(function () { @@ -78,7 +100,7 @@ }).then(function () { toastr.success('Premium upgrade complete.', 'Success'); }); - }; + } function getPaymentToken(model) { if ($scope.paymentMethod === 'paypal') { diff --git a/src/app/settings/views/settingsBilling.html b/src/app/settings/views/settingsBilling.html index 2d5bb517d6..f68d8c34e8 100644 --- a/src/app/settings/views/settingsBilling.html +++ b/src/app/settings/views/settingsBilling.html @@ -54,7 +54,7 @@ -
@@ -82,7 +86,7 @@
- -
-
-

Addons

-
-
-
- -

- Your plan comes with 1 GB of encrypted file storage. You can add additional - storage for {{storageGbPrice | currency:"$":0}} per GB /year. -

-
-
- -
+
+
+
+

License

+
+
+

Unlock premium with your license.

+
+ + +

+ Your license file will be named something like bitwarden_premium_license.json +

+
-
-
-

Billing Summary

-
-
- Premium membership: - {{premiumPrice | currency:"$"}}
- Additional storage: - {{model.additionalStorageGb || 0}} GB × {{storageGbPrice | currency:"$"}} = - {{(model.additionalStorageGb || 0) * storageGbPrice | currency:"$"}} -
- -
-
-
-

Payment Information

-
-
- - -
-
-
+
+
+
+

Addons

-
-
-
-
- - -
-
-
- -
    -
  • -
  • -
  • -
  • -
  • -
  • -
-
-
-
-
-
- - -
-
-
-
- - -
-
-
-
- - -
-
-
-
-
-
- - -
-
-
-
- - +
+
+ +

+ Your plan comes with 1 GB of encrypted file storage. You can add additional + storage for {{storageGbPrice | currency:"$":0}} per GB /year. +

+
+
+
-