mirror of
https://github.com/bitwarden/browser
synced 2025-12-18 01:03:35 +00:00
licensing options when self hosted
This commit is contained in:
@@ -241,6 +241,7 @@ function config() {
|
|||||||
createModule: false,
|
createModule: false,
|
||||||
constants: _.merge({}, {
|
constants: _.merge({}, {
|
||||||
appSettings: {
|
appSettings: {
|
||||||
|
selfHosted: false,
|
||||||
version: project.version,
|
version: project.version,
|
||||||
environment: project.env
|
environment: project.env
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,12 +127,16 @@
|
|||||||
putKey: { url: _apiUri + '/accounts/key', method: 'POST', params: {} },
|
putKey: { url: _apiUri + '/accounts/key', method: 'POST', params: {} },
|
||||||
'import': { url: _apiUri + '/accounts/import', method: 'POST', params: {} },
|
'import': { url: _apiUri + '/accounts/import', method: 'POST', params: {} },
|
||||||
postDelete: { url: _apiUri + '/accounts/delete', 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: {} },
|
putStorage: { url: _apiUri + '/accounts/storage', method: 'POST', params: {} },
|
||||||
putPayment: { url: _apiUri + '/accounts/payment', method: 'POST', params: {} },
|
putPayment: { url: _apiUri + '/accounts/payment', method: 'POST', params: {} },
|
||||||
putCancelPremium: { url: _apiUri + '/accounts/cancel-premium', method: 'POST', params: {} },
|
putCancelPremium: { url: _apiUri + '/accounts/cancel-premium', method: 'POST', params: {} },
|
||||||
putReinstatePremium: { url: _apiUri + '/accounts/reinstate-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', {}, {
|
_service.twoFactor = $resource(_apiUri + '/two-factor', {}, {
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
angular.module("bit")
|
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"});
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
$scope.paymentSource = null;
|
$scope.paymentSource = null;
|
||||||
$scope.subscription = null;
|
$scope.subscription = null;
|
||||||
$scope.loading = true;
|
$scope.loading = true;
|
||||||
|
var license = null;
|
||||||
|
|
||||||
$scope.$on('$viewContentLoaded', function () {
|
$scope.$on('$viewContentLoaded', function () {
|
||||||
load();
|
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() {
|
function load() {
|
||||||
authService.getUserProfile().then(function (profile) {
|
authService.getUserProfile().then(function (profile) {
|
||||||
$scope.premium = profile.premium;
|
$scope.premium = profile.premium;
|
||||||
@@ -87,6 +108,8 @@
|
|||||||
|
|
||||||
var i = 0;
|
var i = 0;
|
||||||
|
|
||||||
|
license = billing.License;
|
||||||
|
|
||||||
$scope.storage = null;
|
$scope.storage = null;
|
||||||
if (billing && billing.MaxStorageGb) {
|
if (billing && billing.MaxStorageGb) {
|
||||||
$scope.storage = {
|
$scope.storage = {
|
||||||
|
|||||||
@@ -2,13 +2,15 @@
|
|||||||
.module('bit.settings')
|
.module('bit.settings')
|
||||||
|
|
||||||
.controller('settingsPremiumController', function ($scope, $state, apiService, toastr, $analytics, authService, stripe,
|
.controller('settingsPremiumController', function ($scope, $state, apiService, toastr, $analytics, authService, stripe,
|
||||||
constants, $timeout, appSettings) {
|
constants, $timeout, appSettings, validationService) {
|
||||||
authService.getUserProfile().then(function (profile) {
|
authService.getUserProfile().then(function (profile) {
|
||||||
if (profile.premium) {
|
if (profile.premium) {
|
||||||
return $state.go('backend.user.settingsBilling');
|
return $state.go('backend.user.settingsBilling');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$scope.selfHosted = appSettings.selfHosted;
|
||||||
|
|
||||||
var btInstance = null;
|
var btInstance = null;
|
||||||
$scope.storageGbPrice = constants.storageGb.yearlyPrice;
|
$scope.storageGbPrice = constants.storageGb.yearlyPrice;
|
||||||
$scope.premiumPrice = constants.premium.price;
|
$scope.premiumPrice = constants.premium.price;
|
||||||
@@ -54,23 +56,43 @@
|
|||||||
return $scope.premiumPrice + (($scope.model.additionalStorageGb || 0) * $scope.storageGbPrice);
|
return $scope.premiumPrice + (($scope.model.additionalStorageGb || 0) * $scope.storageGbPrice);
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.submit = function (model) {
|
$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 fd = new FormData();
|
||||||
|
fd.append('license', files[0]);
|
||||||
|
|
||||||
|
$scope.submitPromise = apiService.accounts.postPremium(fd).$promise.then(function (result) {
|
||||||
|
return finalizePremium();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
$scope.submitPromise = getPaymentToken(model).then(function (token) {
|
$scope.submitPromise = getPaymentToken(model).then(function (token) {
|
||||||
if (!token) {
|
if (!token) {
|
||||||
throw 'No payment token.';
|
throw 'No payment token.';
|
||||||
}
|
}
|
||||||
|
|
||||||
var request = {
|
var fd = new FormData();
|
||||||
paymentToken: token,
|
fd.append('paymentToken', token);
|
||||||
additionalStorageGb: model.additionalStorageGb
|
fd.append('additionalStorageGb', model.additionalStorageGb || 0);
|
||||||
};
|
|
||||||
|
|
||||||
return apiService.accounts.postPremium(request).$promise;
|
return apiService.accounts.postPremium(fd).$promise;
|
||||||
}, function (err) {
|
}, function (err) {
|
||||||
throw err;
|
throw err;
|
||||||
}).then(function (result) {
|
}).then(function (result) {
|
||||||
return authService.updateProfilePremium(true);
|
return finalizePremium();
|
||||||
}).then(function () {
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function finalizePremium() {
|
||||||
|
return authService.updateProfilePremium(true).then(function () {
|
||||||
$analytics.eventTrack('Signed Up Premium');
|
$analytics.eventTrack('Signed Up Premium');
|
||||||
return authService.refreshAccessToken();
|
return authService.refreshAccessToken();
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
@@ -78,7 +100,7 @@
|
|||||||
}).then(function () {
|
}).then(function () {
|
||||||
toastr.success('Premium upgrade complete.', 'Success');
|
toastr.success('Premium upgrade complete.', 'Success');
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
function getPaymentToken(model) {
|
function getPaymentToken(model) {
|
||||||
if ($scope.paymentMethod === 'paypal') {
|
if ($scope.paymentMethod === 'paypal') {
|
||||||
|
|||||||
@@ -54,7 +54,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-footer" ng-if="!subscription.cancelled || subscription.markedForCancel">
|
<div class="box-footer" ng-if="!loading && subscription && (!subscription.cancelled || subscription.markedForCancel)">
|
||||||
<button type="button" class="btn btn-default btn-flat" ng-click="cancel()"
|
<button type="button" class="btn btn-default btn-flat" ng-click="cancel()"
|
||||||
ng-if="!subscription.cancelled && !subscription.markedForCancel">
|
ng-if="!subscription.cancelled && !subscription.markedForCancel">
|
||||||
Cancel
|
Cancel
|
||||||
@@ -63,6 +63,10 @@
|
|||||||
ng-if="subscription.markedForCancel">
|
ng-if="subscription.markedForCancel">
|
||||||
Reinstate
|
Reinstate
|
||||||
</button>
|
</button>
|
||||||
|
<button type="button" class="btn btn-default btn-flat" ng-click="license()"
|
||||||
|
ng-if="!subscription.cancelled">
|
||||||
|
Download License
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box box-default" ng-if="storage">
|
<div class="box box-default" ng-if="storage">
|
||||||
@@ -82,7 +86,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box-footer" ng-if="!subscription.cancelled">
|
<div class="box-footer" ng-if="subscription && paymentSource && !subscription.cancelled">
|
||||||
<button type="button" class="btn btn-default btn-flat" ng-click="adjustStorage(true)">
|
<button type="button" class="btn btn-default btn-flat" ng-click="adjustStorage(true)">
|
||||||
Add Storage
|
Add Storage
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<h1>Premium<span class="hidden-xs"> Membership</span><small>get started today!</small></h1>
|
<h1>Premium<span class="hidden-xs"> Membership</span><small>get started today!</small></h1>
|
||||||
</section>
|
</section>
|
||||||
<section class="content">
|
<section class="content">
|
||||||
<form name="form" ng-submit="form.$valid && submit(model)" api-form="submitPromise">
|
<form name="form" ng-submit="form.$valid && submit(model, form)" api-form="submitPromise">
|
||||||
<div class="callout callout-danger validation-errors" ng-show="form.$errors">
|
<div class="callout callout-danger validation-errors" ng-show="form.$errors">
|
||||||
<h4>Errors have occurred</h4>
|
<h4>Errors have occurred</h4>
|
||||||
<ul>
|
<ul>
|
||||||
@@ -44,6 +44,29 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div ng-if="selfHosted">
|
||||||
|
<div class="box box-default">
|
||||||
|
<div class="box-header with-border">
|
||||||
|
<h3 class="box-title">License</h3>
|
||||||
|
</div>
|
||||||
|
<div class="box-body">
|
||||||
|
<p>Unlock premium with your license.</p>
|
||||||
|
<div class="form-group" show-error>
|
||||||
|
<label for="file" class="sr-only">License</label>
|
||||||
|
<input type="file" id="file" name="file" accept=".json" />
|
||||||
|
<p class="help-block">
|
||||||
|
Your license file will be named something like <code>bitwarden_premium_license.json</code>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="box-footer">
|
||||||
|
<button type="submit" class="btn btn-primary btn-flat" ng-disabled="form.$loading">
|
||||||
|
<i class="fa fa-refresh fa-spin loading-icon" ng-show="form.$loading"></i>Submit
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div ng-if="!selfHosted">
|
||||||
<div class="box box-default">
|
<div class="box box-default">
|
||||||
<div class="box-header with-border">
|
<div class="box-header with-border">
|
||||||
<h3 class="box-title">Addons</h3>
|
<h3 class="box-title">Addons</h3>
|
||||||
@@ -454,5 +477,6 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
Reference in New Issue
Block a user