mirror of
https://github.com/bitwarden/web
synced 2025-12-06 00:03:28 +00:00
Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbb69bba26 | ||
|
|
c1838b48ff | ||
|
|
d53f40002c | ||
|
|
866954b180 | ||
|
|
befa9cbf08 | ||
|
|
859f44db43 | ||
|
|
cca9c3c561 | ||
|
|
27e68e4c75 | ||
|
|
5c92350ed2 | ||
|
|
b94c62d1e5 | ||
|
|
de888d8a37 | ||
|
|
f8d6816101 | ||
|
|
119c6d5817 | ||
|
|
aaa21daa29 | ||
|
|
10f41bf288 | ||
|
|
91582691d8 | ||
|
|
463efc2254 | ||
|
|
0333354271 | ||
|
|
b85f56c681 | ||
|
|
be491be2cd | ||
|
|
4be4a8115d | ||
|
|
c0eb499f4d | ||
|
|
1b43f3facd | ||
|
|
26d41d3cb9 | ||
|
|
179765f6e4 | ||
|
|
df2e332134 | ||
|
|
2952f9d158 | ||
|
|
3c9face597 | ||
|
|
25f2e9c1b7 | ||
|
|
a6f8e1b9a3 | ||
|
|
d832031cec | ||
|
|
7a1a3ab64d | ||
|
|
19491a684e | ||
|
|
757224287e |
5
ISSUE_TEMPLATE.md
Normal file
5
ISSUE_TEMPLATE.md
Normal file
@@ -0,0 +1,5 @@
|
||||
<!--
|
||||
Please do not submit feature requests. The [Community Forums][1] has a
|
||||
section for submitting, voting for, and discussing product feature requests.
|
||||
[1]: https://community.bitwarden.com
|
||||
-->
|
||||
@@ -1,8 +1,8 @@
|
||||
[](https://ci.appveyor.com/project/bitwarden/web) [](https://hub.docker.com/u/bitwarden/) [](https://gitter.im/bitwarden/Lobby)
|
||||
|
||||
# bitwarden Web
|
||||
# Bitwarden Web Vault
|
||||
|
||||
The bitwarden Web project is an AngularJS application that powers the web vault (https://vault.bitwarden.com/).
|
||||
The Bitwarden web project is an AngularJS application that powers the web vault (https://vault.bitwarden.com/).
|
||||
|
||||
<img src="https://i.imgur.com/rxrykeX.png" alt="" width="791" height="739" />
|
||||
|
||||
|
||||
16
SECURITY.md
16
SECURITY.md
@@ -1,4 +1,4 @@
|
||||
bitwarden believes that working with security researchers across the globe is crucial to keeping our
|
||||
Bitwarden believes that working with security researchers across the globe is crucial to keeping our
|
||||
users safe. If you believe you've found a security issue in our product or service, we encourage you to
|
||||
notify us. We welcome working with you to resolve the issue promptly. Thanks in advance!
|
||||
|
||||
@@ -16,7 +16,7 @@ notify us. We welcome working with you to resolve the issue promptly. Thanks in
|
||||
|
||||
# In-scope
|
||||
|
||||
- Security issues in any current release of bitwarden. This includes the web vault, browser extension,
|
||||
- Security issues in any current release of Bitwarden. This includes the web vault, browser extension,
|
||||
and mobile apps (iOS and Android). Product downloads are available at https://bitwarden.com. Source
|
||||
code is available at https://github.com/bitwarden.
|
||||
|
||||
@@ -24,14 +24,14 @@ notify us. We welcome working with you to resolve the issue promptly. Thanks in
|
||||
|
||||
The following bug classes are out-of scope:
|
||||
|
||||
- Bugs that are already reported on any of bitwarden's issue trackers (https://github.com/bitwarden),
|
||||
- Bugs that are already reported on any of Bitwarden's issue trackers (https://github.com/bitwarden),
|
||||
or that we already know of. Note that some of our issue tracking is private.
|
||||
- Issues in an upstream software dependency (ex: Xamarin, ASP.NET) which are already reported to the
|
||||
upstream maintainer.
|
||||
- Attacks requiring physical access to a user's device.
|
||||
- Self-XSS
|
||||
- Issues related to software or protocols not under bitwarden's control
|
||||
- Vulnerabilities in outdated versions of bitwarden
|
||||
- Issues related to software or protocols not under Bitwarden's control
|
||||
- Vulnerabilities in outdated versions of Bitwarden
|
||||
- Missing security best practices that do not directly lead to a vulnerability
|
||||
- Issues that do not have any impact on the general public
|
||||
|
||||
@@ -39,7 +39,7 @@ While researching, we'd like to ask you to refrain from:
|
||||
|
||||
- Denial of service
|
||||
- Spamming
|
||||
- Social engineering (including phishing) of bitwarden staff or contractors
|
||||
- Any physical attempts against bitwarden property or data centers
|
||||
- Social engineering (including phishing) of Bitwarden staff or contractors
|
||||
- Any physical attempts against Bitwarden property or data centers
|
||||
|
||||
Thank you for helping keep bitwarden and our users safe!
|
||||
Thank you for helping keep Bitwarden and our users safe!
|
||||
|
||||
2
dist/.publish
vendored
2
dist/.publish
vendored
Submodule dist/.publish updated: 1990d717ea...66eacea870
@@ -71,6 +71,7 @@ gulp.task('min:js', ['clean:js'], function () {
|
||||
'!' + paths.minJs,
|
||||
'!' + paths.jsDir + 'fallback*.js',
|
||||
'!' + paths.jsDir + 'u2f-connector.js',
|
||||
'!' + paths.jsDir + 'duo-connector.js',
|
||||
'!' + paths.jsDir + 'duo.js',
|
||||
'!' + paths.jsDir + 'settings.js'
|
||||
], { base: '.' })
|
||||
@@ -335,6 +336,10 @@ gulp.task('dist:move', function () {
|
||||
src: paths.jsDir + 'duo.js',
|
||||
dest: paths.dist + 'js'
|
||||
},
|
||||
{
|
||||
src: paths.jsDir + 'duo-connector.js',
|
||||
dest: paths.dist + 'js'
|
||||
},
|
||||
{
|
||||
src: paths.jsDir + 'settings.js',
|
||||
dest: paths.dist + 'js'
|
||||
@@ -351,6 +356,7 @@ gulp.task('dist:move', function () {
|
||||
paths.webroot + 'u2f-connector.html',
|
||||
paths.webroot + 'duo-connector.html',
|
||||
paths.webroot + 'favicon.ico',
|
||||
paths.webroot + 'manifest.json',
|
||||
paths.webroot + 'app-id.json'
|
||||
],
|
||||
dest: paths.dist
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "bitwarden",
|
||||
"version": "1.22.0",
|
||||
"version": "1.23.0",
|
||||
"env": "Production",
|
||||
"devDependencies": {
|
||||
"connect": "3.6.5",
|
||||
@@ -11,7 +11,7 @@
|
||||
"gulp-less": "3.3.2",
|
||||
"gulp-rename": "1.2.2",
|
||||
"gulp-uglify": "3.0.0",
|
||||
"gulp-gh-pages": "git@github.com:tekd/gulp-gh-pages.git#update-dependency",
|
||||
"gulp-gh-pages": "git+https://github.com/tekd/gulp-gh-pages.git#update-dependency",
|
||||
"gulp-preprocess": "2.0.0",
|
||||
"gulp-ng-annotate": "2.0.0",
|
||||
"gulp-ng-config": "1.5.0",
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
<p class="login-box-msg">
|
||||
Complete logging in with YubiKey.
|
||||
</p>
|
||||
<form name="twoFactorForm" ng-submit="twoFactorForm.$valid && twoFactor(token)" api-form="twoFactorPromise"
|
||||
<form name="twoFactorForm" ng-submit="twoFactorForm.$valid && twoFactor(token)" api-form="twoFactorPromise"
|
||||
autocomplete="off">
|
||||
<div class="callout callout-danger validation-errors" ng-show="twoFactorForm.$errors">
|
||||
<h4>Errors have occurred</h4>
|
||||
@@ -63,7 +63,8 @@
|
||||
</p>
|
||||
<div class="form-group" show-errors>
|
||||
<label for="code" class="sr-only">Token</label>
|
||||
<input type="password" id="code" name="Token" class="form-control" ng-model="token" required api-field />
|
||||
<input type="password" id="code" name="Token" class="form-control" ng-model="token"
|
||||
autocomplete="new-password" required api-field />
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-7">
|
||||
@@ -86,7 +87,7 @@
|
||||
<p class="login-box-msg">
|
||||
Complete logging in with Duo.
|
||||
</p>
|
||||
<form name="twoFactorForm" ng-submit="twoFactorForm.$valid && twoFactor(token)" api-form="twoFactorPromise"
|
||||
<form name="twoFactorForm" ng-submit="twoFactorForm.$valid && twoFactor(token)" api-form="twoFactorPromise"
|
||||
autocomplete="off">
|
||||
<div class="callout callout-danger validation-errors" ng-show="twoFactorForm.$errors">
|
||||
<h4>Errors have occurred</h4>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<p class="text-center"><strong>{{state.params.email}}</strong></p>
|
||||
<p>
|
||||
You've been invited to join the organization listed above.
|
||||
To accept the invitation, you need to log in or create a new bitwarden account.
|
||||
To accept the invitation, you need to log in or create a new Bitwarden account.
|
||||
</p>
|
||||
<hr />
|
||||
<div class="row">
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<i class="fa fa-shield"></i> <b>bit</b>warden
|
||||
</div>
|
||||
<div class="login-box-body">
|
||||
<p class="login-box-msg">Enter your email address below to recover & delete your bitwarden account.</p>
|
||||
<p class="login-box-msg">Enter your email address below to recover & delete your Bitwarden account.</p>
|
||||
<div ng-show="success" class="text-center">
|
||||
<div class="callout callout-success">
|
||||
If your account exists ({{model.email}}) we've sent you an email with further instructions.
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
This will permanently delete your account. This cannot be undone.
|
||||
</div>
|
||||
<p>
|
||||
You have requested to delete your bitwarden account (<b>{{email}}</b>).
|
||||
You have requested to delete your Bitwarden account (<b>{{email}}</b>).
|
||||
Click the button below to confirm and proceed.
|
||||
</p>
|
||||
<button ng-click="delete()" class="btn btn-danger btn-block btn-flat">Delete Account</button>
|
||||
|
||||
@@ -4,7 +4,7 @@ angular
|
||||
.factory('apiInterceptor', function ($injector, $q, toastr, appSettings, utilsService) {
|
||||
return {
|
||||
request: function (config) {
|
||||
if (config.url.indexOf(appSettings.apiUri + '/') > -1) {
|
||||
if (config.url.indexOf(appSettings.apiUri + '/') === 0) {
|
||||
config.headers['Device-Type'] = utilsService.getDeviceType();
|
||||
}
|
||||
|
||||
|
||||
@@ -14,15 +14,13 @@ angular
|
||||
$qProvider.errorOnUnhandledRejections(false);
|
||||
$locationProvider.hashPrefix('');
|
||||
|
||||
// @if false
|
||||
jwtOptionsProvider.config({
|
||||
whiteListedDomains: ['localhost', 'api.bitwarden.com', 'vault.bitwarden.com']
|
||||
whiteListedDomains: ['localhost', 'api.bitwarden.com', 'vault.bitwarden.com', 'haveibeenpwned.com']
|
||||
});
|
||||
// @endif
|
||||
|
||||
var refreshPromise;
|
||||
jwtInterceptorProvider.tokenGetter = /*@ngInject*/ function (options, tokenService, authService) {
|
||||
if (options.url.indexOf(appSettings.apiUri + '/') === -1) {
|
||||
if (options.url.indexOf(appSettings.apiUri + '/') !== 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -154,12 +152,6 @@ angular
|
||||
controller: 'reportsBreachController',
|
||||
data: { pageTitle: 'Data Breach Report' }
|
||||
})
|
||||
.state('backend.user.apps', {
|
||||
url: '^/apps',
|
||||
templateUrl: 'app/views/apps.html',
|
||||
controller: 'appsController',
|
||||
data: { pageTitle: 'Get the Apps' }
|
||||
})
|
||||
.state('backend.org', {
|
||||
templateUrl: 'app/views/organizationLayout.html',
|
||||
abstract: true
|
||||
|
||||
@@ -6,7 +6,7 @@ angular
|
||||
link: function (scope, element) {
|
||||
var listener = function (event, toState, toParams, fromState, fromParams) {
|
||||
// Default title
|
||||
var title = 'bitwarden Web Vault';
|
||||
var title = 'Bitwarden Web Vault';
|
||||
if (toState.data && toState.data.pageTitle) {
|
||||
title = toState.data.pageTitle + ' - ' + title;
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
angular
|
||||
.module('bit.global')
|
||||
|
||||
.controller('appsController', function ($scope, $state) {
|
||||
|
||||
});
|
||||
@@ -26,8 +26,9 @@
|
||||
return;
|
||||
}
|
||||
|
||||
var i;
|
||||
var collectionsDict = {};
|
||||
for (var i = 0; i < decCollections.length; i++) {
|
||||
for (i = 0; i < decCollections.length; i++) {
|
||||
collectionsDict[decCollections[i].id] = decCollections[i];
|
||||
}
|
||||
|
||||
@@ -78,10 +79,17 @@
|
||||
switch (decCiphers[i].type) {
|
||||
case constants.cipherType.login:
|
||||
cipher.type = 'login';
|
||||
cipher.login_uri = decCiphers[i].login.uri;
|
||||
cipher.login_uri = null;
|
||||
cipher.login_username = decCiphers[i].login.username;
|
||||
cipher.login_password = decCiphers[i].login.password;
|
||||
cipher.login_totp = decCiphers[i].login.totp;
|
||||
|
||||
if (decCiphers[i].login.uris && decCiphers[i].login.uris.length) {
|
||||
cipher.login_uri = [];
|
||||
for (j = 0; j < decCiphers[i].login.uris.length; j++) {
|
||||
cipher.login_uri.push(decCiphers[i].login.uris[j].uri);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case constants.cipherType.secureNote:
|
||||
cipher.type = 'note';
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
$scope.options = [
|
||||
{
|
||||
id: 'bitwardencsv',
|
||||
name: 'bitwarden (csv)',
|
||||
name: 'Bitwarden (csv)',
|
||||
featured: true,
|
||||
sort: 1,
|
||||
instructions: $sce.trustAsHtml('Export using the web vault (vault.bitwarden.com). ' +
|
||||
|
||||
@@ -8,7 +8,13 @@
|
||||
$scope.selectedType = constants.cipherType.login.toString();
|
||||
$scope.cipher = {
|
||||
type: constants.cipherType.login,
|
||||
login: {},
|
||||
login: {
|
||||
uris: [{
|
||||
uri: null,
|
||||
match: null,
|
||||
matchValue: null
|
||||
}]
|
||||
},
|
||||
identity: {},
|
||||
card: {},
|
||||
secureNote: {
|
||||
@@ -44,6 +50,42 @@
|
||||
}
|
||||
};
|
||||
|
||||
$scope.addUri = function () {
|
||||
if (!$scope.cipher.login) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$scope.cipher.login.uris) {
|
||||
$scope.cipher.login.uris = [];
|
||||
}
|
||||
|
||||
$scope.cipher.login.uris.push({
|
||||
uri: null,
|
||||
match: null,
|
||||
matchValue: null
|
||||
});
|
||||
};
|
||||
|
||||
$scope.removeUri = function (uri) {
|
||||
if (!$scope.cipher.login || !$scope.cipher.login.uris) {
|
||||
return;
|
||||
}
|
||||
|
||||
var index = $scope.cipher.login.uris.indexOf(uri);
|
||||
if (index > -1) {
|
||||
$scope.cipher.login.uris.splice(index, 1);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.uriMatchChanged = function (uri) {
|
||||
if ((!uri.matchValue && uri.matchValue !== 0) || uri.matchValue === '') {
|
||||
uri.match = null;
|
||||
}
|
||||
else {
|
||||
uri.match = parseInt(uri.matchValue);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.addField = function () {
|
||||
if (!$scope.cipher.fields) {
|
||||
$scope.cipher.fields = [];
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
var fd = new FormData();
|
||||
var blob = new Blob([encValue.data], { type: 'application/octet-stream' });
|
||||
fd.append('data', blob, encValue.fileName);
|
||||
return apiService.ciphers.postAttachment({ id: cipherId }, fd).$promise;
|
||||
return apiService.ciphers.postAttachmentAdmin({ id: cipherId }, fd).$promise;
|
||||
}).then(function (response) {
|
||||
$analytics.eventTrack('Added Attachment');
|
||||
toastr.success('The attachment has been added.');
|
||||
@@ -61,7 +61,7 @@
|
||||
}
|
||||
|
||||
attachment.loading = true;
|
||||
apiService.ciphers.delAttachment({ id: cipherId, attachmentId: attachment.id }).$promise.then(function () {
|
||||
apiService.ciphers.delAttachmentAdmin({ id: cipherId, attachmentId: attachment.id }).$promise.then(function () {
|
||||
attachment.loading = false;
|
||||
$analytics.eventTrack('Deleted Organization Attachment');
|
||||
var index = $scope.cipher.attachments.indexOf(attachment);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
apiService.ciphers.getAdmin({ id: cipherId }, function (cipher) {
|
||||
$scope.cipher = cipherService.decryptCipher(cipher);
|
||||
$scope.useTotp = $scope.cipher.organizationUseTotp;
|
||||
setUriMatchValues();
|
||||
});
|
||||
|
||||
$scope.save = function (model) {
|
||||
@@ -32,6 +33,42 @@
|
||||
}
|
||||
};
|
||||
|
||||
$scope.addUri = function () {
|
||||
if (!$scope.cipher.login) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$scope.cipher.login.uris) {
|
||||
$scope.cipher.login.uris = [];
|
||||
}
|
||||
|
||||
$scope.cipher.login.uris.push({
|
||||
uri: null,
|
||||
match: null,
|
||||
matchValue: null
|
||||
});
|
||||
};
|
||||
|
||||
$scope.removeUri = function (uri) {
|
||||
if (!$scope.cipher.login || !$scope.cipher.login.uris) {
|
||||
return;
|
||||
}
|
||||
|
||||
var index = $scope.cipher.login.uris.indexOf(uri);
|
||||
if (index > -1) {
|
||||
$scope.cipher.login.uris.splice(index, 1);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.uriMatchChanged = function (uri) {
|
||||
if ((!uri.matchValue && uri.matchValue !== 0) || uri.matchValue === '') {
|
||||
uri.match = null;
|
||||
}
|
||||
else {
|
||||
uri.match = parseInt(uri.matchValue);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.addField = function () {
|
||||
if (!$scope.cipher.login.fields) {
|
||||
$scope.cipher.login.fields = [];
|
||||
@@ -98,4 +135,14 @@
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function setUriMatchValues() {
|
||||
if ($scope.cipher.login && $scope.cipher.login.uris) {
|
||||
for (var i = 0; i < $scope.cipher.login.uris.length; i++) {
|
||||
$scope.cipher.login.uris[i].matchValue =
|
||||
$scope.cipher.login.uris[i].match || $scope.cipher.login.uris[i].match === 0 ?
|
||||
$scope.cipher.login.uris[i].match.toString() : '';
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
Loading...
|
||||
</div>
|
||||
<div ng-show="!loading">
|
||||
You plan currently has a total of <b>{{plan.seats}}</b> seats.
|
||||
Your plan currently has a total of <b>{{plan.seats}}</b> seats.
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-footer" ng-if="!selfHosted && !noSubscription && canAdjustSeats">
|
||||
@@ -134,7 +134,7 @@
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<p>
|
||||
You plan has a total of {{storage.maxGb}} GB of encrypted file storage.
|
||||
Your plan has a total of {{storage.maxGb}} GB of encrypted file storage.
|
||||
You are currently using {{storage.currentName}}.
|
||||
</p>
|
||||
<div class="progress" style="margin: 0;">
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
<form name="inviteForm" ng-submit="inviteForm.$valid && submit(model)" api-form="submitPromise" autocomplete="off">
|
||||
<div class="modal-body">
|
||||
<p>
|
||||
Invite a new user to your organization by entering their bitwarden account email address below. If they do not have
|
||||
a bitwarden account already, they will be prompted to create a new account.
|
||||
Invite a new user to your organization by entering their Bitwarden account email address below. If they do not have
|
||||
a Bitwarden account already, they will be prompted to create a new account.
|
||||
</p>
|
||||
<div class="callout callout-danger validation-errors" ng-show="inviteForm.$errors">
|
||||
<h4>Errors have occurred</h4>
|
||||
|
||||
@@ -42,13 +42,20 @@
|
||||
headers: { 'Content-Type': undefined },
|
||||
params: { id: '@id' }
|
||||
},
|
||||
postAttachmentAdmin: {
|
||||
url: _apiUri + '/ciphers/:id/attachment-admin',
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': undefined },
|
||||
params: { id: '@id' }
|
||||
},
|
||||
postShareAttachment: {
|
||||
url: _apiUri + '/ciphers/:id/attachment/:attachmentId/share?organizationId=:orgId',
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': undefined },
|
||||
params: { id: '@id', attachmentId: '@attachmentId', orgId: '@orgId' }
|
||||
},
|
||||
delAttachment: { url: _apiUri + '/ciphers/:id/attachment/:attachmentId/delete', method: 'POST', params: { id: '@id', attachmentId: '@attachmentId' } }
|
||||
delAttachment: { url: _apiUri + '/ciphers/:id/attachment/:attachmentId/delete', method: 'POST', params: { id: '@id', attachmentId: '@attachmentId' } },
|
||||
delAttachmentAdmin: { url: _apiUri + '/ciphers/:id/attachment/:attachmentId/delete-admin', method: 'POST', params: { id: '@id', attachmentId: '@attachmentId' } }
|
||||
});
|
||||
|
||||
_service.organizations = $resource(_apiUri + '/organizations/:id', {}, {
|
||||
|
||||
@@ -30,6 +30,9 @@ angular
|
||||
organizationId: encryptedCipher.OrganizationId,
|
||||
collectionIds: encryptedCipher.CollectionIds || [],
|
||||
'type': encryptedCipher.Type,
|
||||
name: cryptoService.decrypt(encryptedCipher.Name, key),
|
||||
notes: _service.decryptProperty(encryptedCipher.Notes, key, true, false),
|
||||
fields: _service.decryptFields(key, encryptedCipher.Fields),
|
||||
folderId: encryptedCipher.FolderId,
|
||||
favorite: encryptedCipher.Favorite,
|
||||
edit: encryptedCipher.Edit,
|
||||
@@ -38,62 +41,68 @@ angular
|
||||
icon: null
|
||||
};
|
||||
|
||||
var cipherData = encryptedCipher.Data;
|
||||
if (cipherData) {
|
||||
cipher.name = cryptoService.decrypt(cipherData.Name, key);
|
||||
cipher.notes = _service.decryptProperty(cipherData.Notes, key, true, false);
|
||||
cipher.fields = _service.decryptFields(key, cipherData.Fields);
|
||||
|
||||
var dataObj = {};
|
||||
switch (cipher.type) {
|
||||
case constants.cipherType.login:
|
||||
dataObj.uri = _service.decryptProperty(cipherData.Uri, key, true, false);
|
||||
dataObj.username = _service.decryptProperty(cipherData.Username, key, true, false);
|
||||
dataObj.password = _service.decryptProperty(cipherData.Password, key, true, false);
|
||||
dataObj.totp = _service.decryptProperty(cipherData.Totp, key, true, false);
|
||||
cipher.login = dataObj;
|
||||
cipher.icon = 'fa-globe';
|
||||
break;
|
||||
case constants.cipherType.secureNote:
|
||||
dataObj.type = cipherData.Type;
|
||||
cipher.secureNote = dataObj;
|
||||
cipher.icon = 'fa-sticky-note-o';
|
||||
break;
|
||||
case constants.cipherType.card:
|
||||
dataObj.cardholderName = _service.decryptProperty(cipherData.CardholderName, key, true, false);
|
||||
dataObj.number = _service.decryptProperty(cipherData.Number, key, true, false);
|
||||
dataObj.brand = _service.decryptProperty(cipherData.Brand, key, true, false);
|
||||
dataObj.expMonth = _service.decryptProperty(cipherData.ExpMonth, key, true, false);
|
||||
dataObj.expYear = _service.decryptProperty(cipherData.ExpYear, key, true, false);
|
||||
dataObj.code = _service.decryptProperty(cipherData.Code, key, true, false);
|
||||
cipher.card = dataObj;
|
||||
cipher.icon = 'fa-credit-card';
|
||||
break;
|
||||
case constants.cipherType.identity:
|
||||
dataObj.title = _service.decryptProperty(cipherData.Title, key, true, false);
|
||||
dataObj.firstName = _service.decryptProperty(cipherData.FirstName, key, true, false);
|
||||
dataObj.middleName = _service.decryptProperty(cipherData.MiddleName, key, true, false);
|
||||
dataObj.lastName = _service.decryptProperty(cipherData.LastName, key, true, false);
|
||||
dataObj.address1 = _service.decryptProperty(cipherData.Address1, key, true, false);
|
||||
dataObj.address2 = _service.decryptProperty(cipherData.Address2, key, true, false);
|
||||
dataObj.address3 = _service.decryptProperty(cipherData.Address3, key, true, false);
|
||||
dataObj.city = _service.decryptProperty(cipherData.City, key, true, false);
|
||||
dataObj.state = _service.decryptProperty(cipherData.State, key, true, false);
|
||||
dataObj.postalCode = _service.decryptProperty(cipherData.PostalCode, key, true, false);
|
||||
dataObj.country = _service.decryptProperty(cipherData.Country, key, true, false);
|
||||
dataObj.company = _service.decryptProperty(cipherData.Company, key, true, false);
|
||||
dataObj.email = _service.decryptProperty(cipherData.Email, key, true, false);
|
||||
dataObj.phone = _service.decryptProperty(cipherData.Phone, key, true, false);
|
||||
dataObj.ssn = _service.decryptProperty(cipherData.SSN, key, true, false);
|
||||
dataObj.username = _service.decryptProperty(cipherData.Username, key, true, false);
|
||||
dataObj.passportNumber = _service.decryptProperty(cipherData.PassportNumber, key, true, false);
|
||||
dataObj.licenseNumber = _service.decryptProperty(cipherData.LicenseNumber, key, true, false);
|
||||
cipher.identity = dataObj;
|
||||
cipher.icon = 'fa-id-card-o';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
var i;
|
||||
switch (cipher.type) {
|
||||
case constants.cipherType.login:
|
||||
cipher.login = {
|
||||
username: _service.decryptProperty(encryptedCipher.Login.Username, key, true, false),
|
||||
password: _service.decryptProperty(encryptedCipher.Login.Password, key, true, false),
|
||||
totp: _service.decryptProperty(encryptedCipher.Login.Totp, key, true, false),
|
||||
uris: null
|
||||
};
|
||||
if (encryptedCipher.Login.Uris) {
|
||||
cipher.login.uris = [];
|
||||
for (i = 0; i < encryptedCipher.Login.Uris.length; i++) {
|
||||
cipher.login.uris.push({
|
||||
uri: _service.decryptProperty(encryptedCipher.Login.Uris[i].Uri, key, true, false),
|
||||
match: encryptedCipher.Login.Uris[i].Match
|
||||
});
|
||||
}
|
||||
}
|
||||
cipher.icon = 'fa-globe';
|
||||
break;
|
||||
case constants.cipherType.secureNote:
|
||||
cipher.secureNote = {
|
||||
type: encryptedCipher.SecureNote.Type
|
||||
};
|
||||
cipher.icon = 'fa-sticky-note-o';
|
||||
break;
|
||||
case constants.cipherType.card:
|
||||
cipher.card = {
|
||||
cardholderName: _service.decryptProperty(encryptedCipher.Card.CardholderName, key, true, false),
|
||||
number: _service.decryptProperty(encryptedCipher.Card.Number, key, true, false),
|
||||
brand: _service.decryptProperty(encryptedCipher.Card.Brand, key, true, false),
|
||||
expMonth: _service.decryptProperty(encryptedCipher.Card.ExpMonth, key, true, false),
|
||||
expYear: _service.decryptProperty(encryptedCipher.Card.ExpYear, key, true, false),
|
||||
code: _service.decryptProperty(encryptedCipher.Card.Code, key, true, false)
|
||||
};
|
||||
cipher.icon = 'fa-credit-card';
|
||||
break;
|
||||
case constants.cipherType.identity:
|
||||
cipher.identity = {
|
||||
title: _service.decryptProperty(encryptedCipher.Identity.Title, key, true, false),
|
||||
firstName: _service.decryptProperty(encryptedCipher.Identity.FirstName, key, true, false),
|
||||
middleName: _service.decryptProperty(encryptedCipher.Identity.MiddleName, key, true, false),
|
||||
lastName: _service.decryptProperty(encryptedCipher.Identity.LastName, key, true, false),
|
||||
address1: _service.decryptProperty(encryptedCipher.Identity.Address1, key, true, false),
|
||||
address2: _service.decryptProperty(encryptedCipher.Identity.Address2, key, true, false),
|
||||
address3: _service.decryptProperty(encryptedCipher.Identity.Address3, key, true, false),
|
||||
city: _service.decryptProperty(encryptedCipher.Identity.City, key, true, false),
|
||||
state: _service.decryptProperty(encryptedCipher.Identity.State, key, true, false),
|
||||
postalCode: _service.decryptProperty(encryptedCipher.Identity.PostalCode, key, true, false),
|
||||
country: _service.decryptProperty(encryptedCipher.Identity.Country, key, true, false),
|
||||
company: _service.decryptProperty(encryptedCipher.Identity.Company, key, true, false),
|
||||
email: _service.decryptProperty(encryptedCipher.Identity.Email, key, true, false),
|
||||
phone: _service.decryptProperty(encryptedCipher.Identity.Phone, key, true, false),
|
||||
ssn: _service.decryptProperty(encryptedCipher.Identity.SSN, key, true, false),
|
||||
username: _service.decryptProperty(encryptedCipher.Identity.Username, key, true, false),
|
||||
passportNumber: _service.decryptProperty(encryptedCipher.Identity.PassportNumber, key, true, false),
|
||||
licenseNumber: _service.decryptProperty(encryptedCipher.Identity.LicenseNumber, key, true, false)
|
||||
};
|
||||
cipher.icon = 'fa-id-card-o';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!encryptedCipher.Attachments) {
|
||||
@@ -101,7 +110,7 @@ angular
|
||||
}
|
||||
|
||||
cipher.attachments = [];
|
||||
for (var i = 0; i < encryptedCipher.Attachments.length; i++) {
|
||||
for (i = 0; i < encryptedCipher.Attachments.length; i++) {
|
||||
cipher.attachments.push(_service.decryptAttachment(key, encryptedCipher.Attachments[i]));
|
||||
}
|
||||
|
||||
@@ -121,6 +130,7 @@ angular
|
||||
organizationId: encryptedCipher.OrganizationId,
|
||||
collectionIds: encryptedCipher.CollectionIds || [],
|
||||
'type': encryptedCipher.Type,
|
||||
name: _service.decryptProperty(encryptedCipher.Name, key, false, true),
|
||||
folderId: encryptedCipher.FolderId,
|
||||
favorite: encryptedCipher.Favorite,
|
||||
edit: encryptedCipher.Edit,
|
||||
@@ -130,59 +140,56 @@ angular
|
||||
icon: null
|
||||
};
|
||||
|
||||
var cipherData = encryptedCipher.Data;
|
||||
if (cipherData) {
|
||||
cipher.name = _service.decryptProperty(cipherData.Name, key, false, true);
|
||||
|
||||
var dataObj = {};
|
||||
switch (cipher.type) {
|
||||
case constants.cipherType.login:
|
||||
cipher.subTitle = _service.decryptProperty(cipherData.Username, key, true, true);
|
||||
cipher.meta.password = _service.decryptProperty(cipherData.Password, key, true, true);
|
||||
cipher.meta.uri = _service.decryptProperty(cipherData.Uri, key, true, true);
|
||||
setLoginIcon(cipher, cipher.meta.uri, true);
|
||||
break;
|
||||
case constants.cipherType.secureNote:
|
||||
cipher.subTitle = null;
|
||||
cipher.icon = 'fa-sticky-note-o';
|
||||
break;
|
||||
case constants.cipherType.card:
|
||||
cipher.subTitle = '';
|
||||
cipher.meta.number = _service.decryptProperty(cipherData.Number, key, true, true);
|
||||
var brand = _service.decryptProperty(cipherData.Brand, key, true, true);
|
||||
if (brand) {
|
||||
cipher.subTitle = brand;
|
||||
}
|
||||
if (cipher.meta.number && cipher.meta.number.length >= 4) {
|
||||
if (cipher.subTitle !== '') {
|
||||
cipher.subTitle += ', ';
|
||||
}
|
||||
cipher.subTitle += ('*' + cipher.meta.number.substr(cipher.meta.number.length - 4));
|
||||
}
|
||||
cipher.icon = 'fa-credit-card';
|
||||
break;
|
||||
case constants.cipherType.identity:
|
||||
var firstName = _service.decryptProperty(cipherData.FirstName, key, true, true);
|
||||
var lastName = _service.decryptProperty(cipherData.LastName, key, true, true);
|
||||
cipher.subTitle = '';
|
||||
if (firstName) {
|
||||
cipher.subTitle = firstName;
|
||||
}
|
||||
if (lastName) {
|
||||
if (cipher.subTitle !== '') {
|
||||
cipher.subTitle += ' ';
|
||||
}
|
||||
cipher.subTitle += lastName;
|
||||
}
|
||||
cipher.icon = 'fa-id-card-o';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (cipher.subTitle === '') {
|
||||
switch (cipher.type) {
|
||||
case constants.cipherType.login:
|
||||
cipher.subTitle = _service.decryptProperty(encryptedCipher.Login.Username, key, true, true);
|
||||
cipher.meta.password = _service.decryptProperty(encryptedCipher.Login.Password, key, true, true);
|
||||
cipher.meta.uri = null;
|
||||
if (encryptedCipher.Login.Uris && encryptedCipher.Login.Uris.length) {
|
||||
cipher.meta.uri = _service.decryptProperty(encryptedCipher.Login.Uris[0].Uri, key, true, true);
|
||||
}
|
||||
setLoginIcon(cipher, cipher.meta.uri, true);
|
||||
break;
|
||||
case constants.cipherType.secureNote:
|
||||
cipher.subTitle = null;
|
||||
}
|
||||
cipher.icon = 'fa-sticky-note-o';
|
||||
break;
|
||||
case constants.cipherType.card:
|
||||
cipher.subTitle = '';
|
||||
cipher.meta.number = _service.decryptProperty(encryptedCipher.Card.Number, key, true, true);
|
||||
var brand = _service.decryptProperty(encryptedCipher.Card.Brand, key, true, true);
|
||||
if (brand) {
|
||||
cipher.subTitle = brand;
|
||||
}
|
||||
if (cipher.meta.number && cipher.meta.number.length >= 4) {
|
||||
if (cipher.subTitle !== '') {
|
||||
cipher.subTitle += ', ';
|
||||
}
|
||||
cipher.subTitle += ('*' + cipher.meta.number.substr(cipher.meta.number.length - 4));
|
||||
}
|
||||
cipher.icon = 'fa-credit-card';
|
||||
break;
|
||||
case constants.cipherType.identity:
|
||||
var firstName = _service.decryptProperty(encryptedCipher.Identity.FirstName, key, true, true);
|
||||
var lastName = _service.decryptProperty(encryptedCipher.Identity.LastName, key, true, true);
|
||||
cipher.subTitle = '';
|
||||
if (firstName) {
|
||||
cipher.subTitle = firstName;
|
||||
}
|
||||
if (lastName) {
|
||||
if (cipher.subTitle !== '') {
|
||||
cipher.subTitle += ' ';
|
||||
}
|
||||
cipher.subTitle += lastName;
|
||||
}
|
||||
cipher.icon = 'fa-id-card-o';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (cipher.subTitle === '') {
|
||||
cipher.subTitle = null;
|
||||
}
|
||||
|
||||
return cipher;
|
||||
@@ -389,15 +396,24 @@ angular
|
||||
fields: _service.encryptFields(unencryptedCipher.fields, key)
|
||||
};
|
||||
|
||||
var i;
|
||||
switch (cipher.type) {
|
||||
case constants.cipherType.login:
|
||||
var loginData = unencryptedCipher.login;
|
||||
cipher.login = {
|
||||
uri: encryptProperty(loginData.uri, key),
|
||||
username: encryptProperty(loginData.username, key),
|
||||
password: encryptProperty(loginData.password, key),
|
||||
totp: encryptProperty(loginData.totp, key)
|
||||
};
|
||||
if (loginData.uris && loginData.uris.length) {
|
||||
cipher.login.uris = [];
|
||||
for (i = 0; i < loginData.uris.length; i++) {
|
||||
cipher.login.uris.push({
|
||||
uri: encryptProperty(loginData.uris[i].uri, key),
|
||||
match: loginData.uris[i].match
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case constants.cipherType.secureNote:
|
||||
cipher.secureNote = {
|
||||
@@ -444,7 +460,7 @@ angular
|
||||
|
||||
if (unencryptedCipher.attachments && attachments) {
|
||||
cipher.attachments = {};
|
||||
for (var i = 0; i < unencryptedCipher.attachments.length; i++) {
|
||||
for (i = 0; i < unencryptedCipher.attachments.length; i++) {
|
||||
cipher.attachments[unencryptedCipher.attachments[i].id] =
|
||||
cryptoService.encrypt(unencryptedCipher.attachments[i].fileName, key);
|
||||
}
|
||||
|
||||
@@ -540,7 +540,7 @@ angular
|
||||
if (key.macKey && encPieces.length > 2) {
|
||||
var macBytes = forge.util.decode64(encPieces[2]);
|
||||
var computedMacBytes = computeMac(ivBytes + ctBytes, key.macKey, false);
|
||||
if (!macsEqual(key.macKey, macBytes, computedMacBytes)) {
|
||||
if (!macsEqual(macBytes, computedMacBytes)) {
|
||||
console.error('MAC failed.');
|
||||
return null;
|
||||
}
|
||||
@@ -623,6 +623,10 @@ angular
|
||||
throw 'Encryption key unavailable.';
|
||||
}
|
||||
|
||||
if (key.macKey && !macBuf) {
|
||||
throw 'macBuf required for this type of key.';
|
||||
}
|
||||
|
||||
if (encType !== key.encType) {
|
||||
throw 'encType unavailable.';
|
||||
}
|
||||
@@ -646,7 +650,7 @@ angular
|
||||
if (computedMacBuf === null) {
|
||||
return null;
|
||||
}
|
||||
return macsEqualWC(keyBuf.macKey, macBuf, computedMacBuf);
|
||||
return macsEqualWC(macBuf, computedMacBuf);
|
||||
}).then(function (macsMatch) {
|
||||
if (macsMatch === false) {
|
||||
console.error('MAC failed.');
|
||||
@@ -704,7 +708,7 @@ angular
|
||||
if (key && key.macKey && encPieces.length > 1) {
|
||||
var macBytes = forge.util.decode64(encPieces[1]);
|
||||
var computedMacBytes = computeMac(ctBytes, key.macKey, false);
|
||||
if (!macsEqual(key.macKey, macBytes, computedMacBytes)) {
|
||||
if (!macsEqual(macBytes, computedMacBytes)) {
|
||||
console.error('MAC failed.');
|
||||
return null;
|
||||
}
|
||||
@@ -747,10 +751,11 @@ angular
|
||||
|
||||
// Safely compare two MACs in a way that protects against timing attacks (Double HMAC Verification).
|
||||
// ref: https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/february/double-hmac-verification/
|
||||
function macsEqual(macKey, mac1, mac2) {
|
||||
// ref: https://paragonie.com/blog/2015/11/preventing-timing-attacks-on-string-comparison-with-double-hmac-strategy
|
||||
function macsEqual(mac1, mac2) {
|
||||
var hmac = forge.hmac.create();
|
||||
|
||||
hmac.start('sha256', macKey);
|
||||
hmac.start('sha256', getRandomBytes(32));
|
||||
hmac.update(mac1);
|
||||
mac1 = hmac.digest().getBytes();
|
||||
|
||||
@@ -761,11 +766,14 @@ angular
|
||||
return mac1 === mac2;
|
||||
}
|
||||
|
||||
function macsEqualWC(macKeyBuf, mac1Buf, mac2Buf) {
|
||||
function macsEqualWC(mac1Buf, mac2Buf) {
|
||||
var mac1,
|
||||
macKey;
|
||||
|
||||
return window.crypto.subtle.importKey('raw', macKeyBuf, { name: 'HMAC', hash: { name: 'SHA-256' } }, false, ['sign'])
|
||||
var compareKey = new Uint8Array(32);
|
||||
_crypto.getRandomValues(compareKey);
|
||||
|
||||
return window.crypto.subtle.importKey('raw', compareKey.buffer, { name: 'HMAC', hash: { name: 'SHA-256' } }, false, ['sign'])
|
||||
.then(function (key) {
|
||||
macKey = key;
|
||||
return window.crypto.subtle.sign({ name: 'HMAC', hash: { name: 'SHA-256' } }, macKey, mac1Buf);
|
||||
@@ -932,5 +940,15 @@ angular
|
||||
return new Uint8Array(result);
|
||||
}
|
||||
|
||||
function getRandomBytes(byteLength) {
|
||||
var bytes = new Uint32Array(byteLength / 4);
|
||||
_crypto.getRandomValues(bytes);
|
||||
var buffer = forge.util.createBuffer();
|
||||
for (var i = 0; i < bytes.length; i++) {
|
||||
buffer.putInt32(bytes[i]);
|
||||
}
|
||||
return buffer.getBytes();
|
||||
}
|
||||
|
||||
return _service;
|
||||
});
|
||||
@@ -133,7 +133,7 @@
|
||||
var _passwordFieldNames = [
|
||||
'password', 'pass word', 'passphrase', 'pass phrase',
|
||||
'pass', 'code', 'code word', 'codeword',
|
||||
'secret', 'secret word',
|
||||
'secret', 'secret word', 'personpwd',
|
||||
'key', 'keyword', 'key word', 'keyphrase', 'key phrase',
|
||||
'form_pw', 'wppassword', 'pin', 'pwd', 'pw', 'pword', 'passwd',
|
||||
'p', 'serial', 'serial#', 'license key', 'reg #',
|
||||
@@ -146,7 +146,7 @@
|
||||
'user', 'name', 'user name', 'username', 'login name',
|
||||
'email', 'e-mail', 'id', 'userid', 'user id',
|
||||
'login', 'form_loginname', 'wpname', 'mail',
|
||||
'loginid', 'login id', 'log',
|
||||
'loginid', 'login id', 'log', 'personlogin',
|
||||
'first name', 'last name', 'card#', 'account #',
|
||||
'member', 'member #',
|
||||
|
||||
@@ -191,14 +191,10 @@
|
||||
|
||||
function fixUri(uri) {
|
||||
uri = uri.toLowerCase().trim();
|
||||
if (!uri.startsWith('http') && uri.indexOf('.') >= 0) {
|
||||
if (uri.indexOf('://') === -1 && uri.indexOf('.') >= 0) {
|
||||
uri = 'http://' + uri;
|
||||
}
|
||||
|
||||
return trimUri(uri);
|
||||
}
|
||||
|
||||
function trimUri(uri) {
|
||||
if (uri.length > 1000) {
|
||||
return uri.substring(0, 1000);
|
||||
}
|
||||
@@ -206,6 +202,43 @@
|
||||
return uri;
|
||||
}
|
||||
|
||||
function makeUriArray(uri) {
|
||||
if (!uri) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (typeof uri === 'string') {
|
||||
return [{
|
||||
uri: fixUri(uri),
|
||||
match: null
|
||||
}];
|
||||
}
|
||||
|
||||
if (uri.length) {
|
||||
var returnArr = [];
|
||||
for (var i = 0; i < uri.length; i++) {
|
||||
returnArr.push({
|
||||
uri: fixUri(uri[i]),
|
||||
match: null
|
||||
});
|
||||
}
|
||||
return returnArr;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function parseSingleRowCsv(rowData) {
|
||||
if (!rowData || rowData === '') {
|
||||
return null;
|
||||
}
|
||||
var parsedRow = Papa.parse(rowData);
|
||||
if (parsedRow && parsedRow.data && parsedRow.data.length && parsedRow.data[0].length) {
|
||||
return parsedRow.data[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function parseCsvErrors(results) {
|
||||
if (results.errors && results.errors.length) {
|
||||
for (var i = 0; i < results.errors.length; i++) {
|
||||
@@ -360,17 +393,20 @@
|
||||
}
|
||||
}
|
||||
|
||||
switch (value.type) {
|
||||
case 'login': case null: case undefined:
|
||||
var valueType = value.type ? value.type.toLowerCase() : null;
|
||||
switch (valueType) {
|
||||
case 'login':
|
||||
case null:
|
||||
case undefined:
|
||||
cipher.type = constants.cipherType.login;
|
||||
|
||||
var totp = value.login_totp || value.totp;
|
||||
var uri = value.login_uri || value.uri;
|
||||
var uris = parseSingleRowCsv(value.login_uri || value.uri);
|
||||
var username = value.login_username || value.username;
|
||||
var password = value.login_password || value.password;
|
||||
cipher.login = {
|
||||
totp: totp && totp !== '' ? totp : null,
|
||||
uri: uri && uri !== '' ? trimUri(uri) : null,
|
||||
uris: makeUriArray(uris),
|
||||
username: username && username !== '' ? username : null,
|
||||
password: password && password !== '' ? password : null
|
||||
};
|
||||
@@ -487,17 +523,20 @@
|
||||
}
|
||||
}
|
||||
|
||||
switch (value.type) {
|
||||
case 'login': case null: case undefined:
|
||||
var valueType = value.type ? value.type.toLowerCase() : null;
|
||||
switch (valueType) {
|
||||
case 'login':
|
||||
case null:
|
||||
case undefined:
|
||||
cipher.type = constants.cipherType.login;
|
||||
|
||||
var totp = value.login_totp || value.totp;
|
||||
var uri = value.login_uri || value.uri;
|
||||
var uris = parseSingleRowCsv(value.login_uri || value.uri);
|
||||
var username = value.login_username || value.username;
|
||||
var password = value.login_password || value.password;
|
||||
cipher.login = {
|
||||
totp: totp && totp !== '' ? totp : null,
|
||||
uri: uri && uri !== '' ? trimUri(uri) : null,
|
||||
uris: makeUriArray(uris),
|
||||
username: username && username !== '' ? username : null,
|
||||
password: password && password !== '' ? password : null
|
||||
};
|
||||
@@ -684,7 +723,7 @@
|
||||
|
||||
if (cipher.type === constants.cipherType.login) {
|
||||
cipher.login = {
|
||||
uri: value.url && value.url !== '' ? trimUri(value.url) : null,
|
||||
uris: makeUriArray(value.url),
|
||||
username: value.username && value.username !== '' ? value.username : null,
|
||||
password: value.password && value.password !== '' ? value.password : null
|
||||
};
|
||||
@@ -844,6 +883,10 @@
|
||||
fields: null
|
||||
};
|
||||
|
||||
if (!cipher.name || cipher.name === '') {
|
||||
cipher.name = '--';
|
||||
}
|
||||
|
||||
if (card.attr('type') === 'note') {
|
||||
cipher.type = constants.cipherType.secureNote;
|
||||
cipher.secureNote = {
|
||||
@@ -873,7 +916,7 @@
|
||||
cipher.notes += (text + '\n');
|
||||
}
|
||||
else if (type === 'weblogin' || type === 'website') {
|
||||
cipher.login.uri = trimUri(text);
|
||||
cipher.login.uris = makeUriArray(text);
|
||||
}
|
||||
else if (text.length > 200) {
|
||||
cipher.notes += (name + ': ' + text + '\n');
|
||||
@@ -974,7 +1017,7 @@
|
||||
notes: null,
|
||||
name: value[0] && value[0] !== '' ? value[0] : '--',
|
||||
login: {
|
||||
uri: null,
|
||||
uris: null,
|
||||
username: value[2] && value[2] !== '' ? value[2] : null,
|
||||
password: value[3] && value[3] !== '' ? value[3] : null
|
||||
},
|
||||
@@ -990,7 +1033,7 @@
|
||||
|
||||
var cfHeader = customFieldHeaders[j - 4];
|
||||
if (cfHeader.toLowerCase() === 'url' || cfHeader.toLowerCase() === 'uri') {
|
||||
cipher.login.uri = trimUri(cf);
|
||||
cipher.login.uris = makeUriArray(cf);
|
||||
}
|
||||
else {
|
||||
if (!cipher.fields) {
|
||||
@@ -1076,7 +1119,7 @@
|
||||
name: null,
|
||||
type: constants.cipherType.login,
|
||||
login: {
|
||||
uri: null,
|
||||
uris: null,
|
||||
username: null,
|
||||
password: null
|
||||
},
|
||||
@@ -1095,7 +1138,7 @@
|
||||
|
||||
switch (key) {
|
||||
case 'URL':
|
||||
cipher.login.uri = fixUri(value);
|
||||
cipher.login.uris = makeUriArray(value);
|
||||
break;
|
||||
case 'UserName':
|
||||
cipher.login.username = value;
|
||||
@@ -1197,7 +1240,7 @@
|
||||
notes: value.Notes && value.Notes !== '' ? value.Notes : null,
|
||||
name: value.Title && value.Title !== '' ? value.Title : '--',
|
||||
login: {
|
||||
uri: value.URL && value.URL !== '' ? fixUri(value.URL) : null,
|
||||
uris: makeUriArray(value.URL),
|
||||
username: value.Username && value.Username !== '' ? value.Username : null,
|
||||
password: value.Password && value.Password !== '' ? value.Password : null
|
||||
}
|
||||
@@ -1310,7 +1353,7 @@
|
||||
else {
|
||||
cipher.type = constants.cipherType.login;
|
||||
cipher.login = {
|
||||
uri: item.location && item.location !== '' ? fixUri(item.location) : null,
|
||||
uris: makeUriArray(item.location),
|
||||
username: null,
|
||||
password: null,
|
||||
totp: null
|
||||
@@ -1365,7 +1408,7 @@
|
||||
notes: value.notesPlain && value.notesPlain !== '' ? value.notesPlain : '',
|
||||
name: value.title && value.title !== '' ? value.title : '--',
|
||||
login: {
|
||||
uri: null,
|
||||
uris: null,
|
||||
username: null,
|
||||
password: null
|
||||
}
|
||||
@@ -1383,17 +1426,9 @@
|
||||
else if (!cipher.login.username && property === 'username') {
|
||||
cipher.login.username = value[property];
|
||||
}
|
||||
else if (!cipher.login.uri && property === 'urls') {
|
||||
else if (!cipher.login.uris && property === 'urls') {
|
||||
var urls = value[property].split(/(?:\r\n|\r|\n)/);
|
||||
cipher.login.uri = fixUri(urls[0]);
|
||||
|
||||
for (var j = 1; j < urls.length; j++) {
|
||||
if (cipher.notes !== '') {
|
||||
cipher.notes += '\n';
|
||||
}
|
||||
|
||||
cipher.notes += ('url ' + (j + 1) + ': ' + urls[j]);
|
||||
}
|
||||
cipher.login.uris = makeUriArray(urls);
|
||||
}
|
||||
else if (property !== 'ainfo' && property !== 'autosubmit' && property !== 'notesPlain' &&
|
||||
property !== 'ps' && property !== 'scope' && property !== 'tags' && property !== 'title' &&
|
||||
@@ -1437,7 +1472,7 @@
|
||||
notes: null,
|
||||
name: value.name && value.name !== '' ? value.name : '--',
|
||||
login: {
|
||||
uri: value.url && value.url !== '' ? trimUri(value.url) : null,
|
||||
uris: makeUriArray(value.url),
|
||||
username: value.username && value.username !== '' ? value.username : null,
|
||||
password: value.password && value.password !== '' ? value.password : null
|
||||
}
|
||||
@@ -1491,7 +1526,7 @@
|
||||
notes: null,
|
||||
name: getNameFromHost(host),
|
||||
login: {
|
||||
uri: host && host !== '' ? trimUri(host) : null,
|
||||
uris: makeUriArray(host),
|
||||
username: user && user !== '' ? user : null,
|
||||
password: password && password !== '' ? password : null,
|
||||
}
|
||||
@@ -1527,7 +1562,7 @@
|
||||
notes: value[4] && value[4] !== '' ? value[4] : null,
|
||||
name: value[0] && value[0] !== '' ? value[0] : '--',
|
||||
login: {
|
||||
uri: value[3] && value[3] !== '' ? trimUri(value[3]) : null,
|
||||
uris: makeUriArray(value[3]),
|
||||
username: value[1] && value[1] !== '' ? value[1] : null,
|
||||
password: value[2] && value[2] !== '' ? value[2] : null
|
||||
}
|
||||
@@ -1574,7 +1609,7 @@
|
||||
notes: value[5] && value[5] !== '' ? value[5] : null,
|
||||
name: value[1] && value[1] !== '' ? value[1] : '--',
|
||||
login: {
|
||||
uri: value[4] && value[4] !== '' ? trimUri(value[4]) : null,
|
||||
uris: makeUriArray(value[4]),
|
||||
username: value[2] && value[2] !== '' ? value[2] : null,
|
||||
password: value[3] && value[3] !== '' ? value[3] : null
|
||||
},
|
||||
@@ -1682,7 +1717,7 @@
|
||||
notes: notes && notes.text() !== '' ? notes.text() : null,
|
||||
name: accountName && accountName.text() !== '' ? accountName.text() : '--',
|
||||
login: {
|
||||
uri: url && url.text() !== '' ? trimUri(url.text()) : null,
|
||||
uris: url ? makeUriArray(url.text()) : null,
|
||||
username: userId && userId.text() !== '' ? userId.text() : null,
|
||||
password: password && password.text() !== '' ? password.text() : null
|
||||
},
|
||||
@@ -1782,7 +1817,7 @@
|
||||
notes: note && note !== '' ? note : null,
|
||||
fields: null,
|
||||
login: {
|
||||
uri: null,
|
||||
uris: null,
|
||||
password: null,
|
||||
username: null,
|
||||
totp: null
|
||||
@@ -1799,8 +1834,8 @@
|
||||
var field = row[i + 1];
|
||||
var fieldLower = field.toLowerCase();
|
||||
|
||||
if (fieldLower === 'url' && !cipher.login.uri) {
|
||||
cipher.login.uri = trimUri(value);
|
||||
if (fieldLower === 'url' && !cipher.login.uris) {
|
||||
cipher.login.uris = makeUriArray(value);
|
||||
}
|
||||
else if ((fieldLower === 'username' || fieldLower === 'email') && !cipher.login.username) {
|
||||
cipher.login.username = value;
|
||||
@@ -1901,7 +1936,7 @@
|
||||
notes: notes && notesText !== '' ? notesText : null,
|
||||
name: title && title.text() !== '' ? title.text() : '--',
|
||||
login: {
|
||||
uri: url && url.text() !== '' ? trimUri(url.text()) : null,
|
||||
uris: url ? makeUriArray(url.text()) : null,
|
||||
username: username && username.text() !== '' ? username.text() : null,
|
||||
password: password && password.text() !== '' ? password.text() : null
|
||||
}
|
||||
@@ -1963,17 +1998,17 @@
|
||||
favorite: false,
|
||||
notes: null,
|
||||
login: {
|
||||
uri: null,
|
||||
uris: null,
|
||||
password: null,
|
||||
username: null
|
||||
}
|
||||
};
|
||||
|
||||
if (row.length === 2) {
|
||||
cipher.login.uri = fixUri(row[1]);
|
||||
cipher.login.uris = makeUriArray(row[1]);
|
||||
}
|
||||
else if (row.length === 3) {
|
||||
cipher.login.uri = fixUri(row[1]);
|
||||
cipher.login.uris = makeUriArray(row[1]);
|
||||
cipher.login.username = row[2];
|
||||
}
|
||||
else if (row.length === 4) {
|
||||
@@ -1987,7 +2022,7 @@
|
||||
}
|
||||
}
|
||||
else if (row.length === 5) {
|
||||
cipher.login.uri = fixUri(row[1]);
|
||||
cipher.login.uris = makeUriArray(row[1]);
|
||||
cipher.login.username = row[2];
|
||||
cipher.login.password = row[3];
|
||||
cipher.notes = row[4];
|
||||
@@ -2004,7 +2039,7 @@
|
||||
cipher.notes = row[4] + '\n' + row[5];
|
||||
}
|
||||
|
||||
cipher.login.uri = fixUri(row[1]);
|
||||
cipher.login.uris = makeUriArray(row[1]);
|
||||
}
|
||||
else if (row.length === 7) {
|
||||
if (row[2] === '') {
|
||||
@@ -2016,7 +2051,7 @@
|
||||
cipher.notes = row[3] + '\n' + row[4] + '\n' + row[6];
|
||||
}
|
||||
|
||||
cipher.login.uri = fixUri(row[1]);
|
||||
cipher.login.uris = makeUriArray(row[1]);
|
||||
cipher.login.password = row[5];
|
||||
}
|
||||
else {
|
||||
@@ -2043,9 +2078,6 @@
|
||||
if (cipher.notes === '') {
|
||||
cipher.notes = null;
|
||||
}
|
||||
if (cipher.login.uri === '') {
|
||||
cipher.login.uri = null;
|
||||
}
|
||||
|
||||
ciphers.push(cipher);
|
||||
}
|
||||
@@ -2138,7 +2170,7 @@
|
||||
notes: notesText && notesText !== '' ? notesText : null,
|
||||
name: titleText && titleText !== '' ? titleText : '--',
|
||||
login: {
|
||||
uri: linkText && linkText !== '' ? trimUri(linkText) : null,
|
||||
uris: makeUriArray(linkText),
|
||||
username: usernameText && usernameText !== '' ? usernameText : null,
|
||||
password: passwordText && passwordText !== '' ? passwordText : null
|
||||
}
|
||||
@@ -2204,14 +2236,14 @@
|
||||
notes: '',
|
||||
name: value[2] && value[2] !== '' ? value[2] : null,
|
||||
login: {
|
||||
uri: null,
|
||||
uris: null,
|
||||
username: null,
|
||||
password: null
|
||||
}
|
||||
};
|
||||
|
||||
if (value[1] === 'Web Logins') {
|
||||
cipher.login.uri = value[4] && value[4] !== '' ? trimUri(value[4]) : null;
|
||||
cipher.login.uris = makeUriArray(value[4]);
|
||||
cipher.login.username = value[5] && value[5] !== '' ? value[5] : null;
|
||||
cipher.login.password = value[6] && value[6] !== '' ? value[6] : null;
|
||||
cipher.notes = value[3] && value[3] !== '' ? value[3].split('\\n').join('\n') : null;
|
||||
@@ -2289,7 +2321,7 @@
|
||||
notes: value.memo && value.memo !== '' ? value.memo : null,
|
||||
name: value.name && value.name !== '' ? value.name : '--',
|
||||
login: {
|
||||
uri: value.url && value.url !== '' ? trimUri(value.url) : null,
|
||||
uris: makeUriArray(value.url),
|
||||
username: value.login && value.login !== '' ? value.login : null,
|
||||
password: value.password && value.password !== '' ? value.password : null
|
||||
},
|
||||
@@ -2361,7 +2393,7 @@
|
||||
notes: '',
|
||||
name: entry.label && entry.label !== '' ? entry.label.split(' ')[0] : '--',
|
||||
login: {
|
||||
uri: null,
|
||||
uris: null,
|
||||
username: null,
|
||||
password: null
|
||||
},
|
||||
@@ -2389,7 +2421,7 @@
|
||||
cipher.login.username = field.value;
|
||||
break;
|
||||
case 'url':
|
||||
cipher.login.uri = trimUri(field.value);
|
||||
cipher.login.uris = makeUriArray(field.value);
|
||||
break;
|
||||
default:
|
||||
if (!cipher.login.username && isField(field.label, _usernameFieldNames)) {
|
||||
@@ -2452,7 +2484,7 @@
|
||||
notes: null,
|
||||
name: account.label && account.label !== '' ? account.label : account.domain,
|
||||
login: {
|
||||
uri: account.domain && account.domain !== '' ? fixUri(account.domain) : null,
|
||||
uris: makeUriArray(account.domain),
|
||||
username: account.username && account.username !== '' ? account.username : null,
|
||||
password: account.password && account.password !== '' ? account.password : null
|
||||
}
|
||||
@@ -2498,7 +2530,7 @@
|
||||
notes: '',
|
||||
name: outterTable.find('span.caption').text(),
|
||||
login: {
|
||||
uri: null,
|
||||
uris: null,
|
||||
username: null,
|
||||
password: null
|
||||
},
|
||||
@@ -2507,7 +2539,7 @@
|
||||
|
||||
var url = outterTable.find('.subcaption').text();
|
||||
if (url && url !== '') {
|
||||
cipher.login.uri = fixUri(url);
|
||||
cipher.login.uris = makeUriArray(url);
|
||||
}
|
||||
|
||||
var fields = [];
|
||||
@@ -2591,7 +2623,7 @@
|
||||
notes: value.notes && value.notes !== '' ? value.notes : null,
|
||||
name: value.url && value.url !== '' ? urlDomain(value.url) : '--',
|
||||
login: {
|
||||
uri: value.url && value.url !== '' ? trimUri(value.url) : null,
|
||||
uris: makeUriArray(value.url),
|
||||
username: value.username && value.username !== '' ? value.username : null,
|
||||
password: value.password && value.password !== '' ? value.password : null
|
||||
}
|
||||
@@ -2625,7 +2657,7 @@
|
||||
favorite: false,
|
||||
notes: note && note !== '' ? note : null,
|
||||
login: {
|
||||
uri: null,
|
||||
uris: null,
|
||||
password: null,
|
||||
username: null
|
||||
},
|
||||
@@ -2642,8 +2674,8 @@
|
||||
|
||||
var fieldLower = field.toLowerCase();
|
||||
|
||||
if (!cipher.login.uri && isField(field, _uriFieldNames)) {
|
||||
cipher.login.uri = fixUri(value);
|
||||
if (!cipher.login.uris && isField(field, _uriFieldNames)) {
|
||||
cipher.login.uris = makeUriArray(value);
|
||||
}
|
||||
else if (!cipher.login.username && isField(field, _usernameFieldNames)) {
|
||||
cipher.login.username = value;
|
||||
@@ -2700,7 +2732,7 @@
|
||||
notes: '',
|
||||
name: item.name && item.name !== '' ? item.name : '--',
|
||||
login: {
|
||||
uri: item.login_url && item.login_url !== '' ? fixUri(item.login_url) : null,
|
||||
uris: makeUriArray(item.login_url),
|
||||
username: null,
|
||||
password: null
|
||||
},
|
||||
@@ -2844,7 +2876,7 @@
|
||||
notes: value.Notes && value.Notes !== '' ? value.Notes : '',
|
||||
name: value['Secret Name'] && value['Secret Name'] !== '' ? value['Secret Name'] : '--',
|
||||
login: {
|
||||
uri: value['Secret URL'] && value['Secret URL'] !== '' ? fixUri(value['Secret URL']) : null,
|
||||
uris: makeUriArray(value['Secret URL']),
|
||||
username: null,
|
||||
password: null
|
||||
},
|
||||
@@ -2944,14 +2976,14 @@
|
||||
name: value[1] && value[1] !== '' ? value[1] : '--',
|
||||
fields: null,
|
||||
login: {
|
||||
uri: null,
|
||||
uris: null,
|
||||
username: null,
|
||||
password: null
|
||||
}
|
||||
};
|
||||
|
||||
if (type === 'Web Logins' || type === 'Servers' || type === 'Email Accounts') {
|
||||
cipher.login.uri = value[4] && value[4] !== '' ? fixUri(value[4]) : null;
|
||||
cipher.login.uris = makeUriArray(value[4]);
|
||||
cipher.login.username = value[2] && value[2] !== '' ? value[2] : null;
|
||||
cipher.login.password = value[3] && value[3] !== '' ? value[3] : null;
|
||||
parseFieldsToNotes(5, value, cipher);
|
||||
@@ -3009,7 +3041,7 @@
|
||||
favorite: false,
|
||||
notes: row.Notes && row.Notes !== '' ? row.Notes : null,
|
||||
login: {
|
||||
uri: row.Url && row.Url !== '' ? fixUri(row.Url) : null,
|
||||
uris: makeUriArray(row.Url),
|
||||
password: row.Password && row.Password !== '' ? row.Password : null,
|
||||
username: row.UserName && row.UserName !== '' ? row.UserName : null
|
||||
}
|
||||
@@ -3066,7 +3098,7 @@
|
||||
notes: !!getValue('description', value) ? getValue('description', value) : null,
|
||||
name: !!getValue('title', value) ? getValue('title', value) : '--',
|
||||
login: {
|
||||
uri: !!getValue('site', value) ? fixUri(getValue('site', value)) : null,
|
||||
uris: !!getValue('site', value) ? makeUriArray(getValue('site', value)) : null,
|
||||
username: !!getValue('username', value) ? getValue('username', value) : null,
|
||||
password: !!getValue('password', value) ? getValue('password', value) : null
|
||||
}
|
||||
@@ -3140,7 +3172,7 @@
|
||||
notes: '',
|
||||
name: item.display_name.replace('http://', '').replace('https://', ''),
|
||||
login: {
|
||||
uri: fixUri(item.display_name),
|
||||
uris: makeUriArray(item.display_name),
|
||||
username: item.attributes.username_value && item.attributes.username_value !== '' ?
|
||||
item.attributes.username_value : null,
|
||||
password: item.secret && item.secret !== '' ? item.secret : null
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
angular.module("bit")
|
||||
.constant("appSettings", {"apiUri":"/api","identityUri":"/identity","iconsUri":"https://icons.bitwarden.com","stripeKey":"pk_live_bpN0P37nMxrMQkcaHXtAybJk","braintreeKey":"production_qfbsv8kc_njj2zjtyngtjmbjd","selfHosted":false,"version":"1.22.0","environment":"Production"});
|
||||
.constant("appSettings", {"apiUri":"/api","identityUri":"/identity","iconsUri":"https://icons.bitwarden.com","stripeKey":"pk_live_bpN0P37nMxrMQkcaHXtAybJk","braintreeKey":"production_qfbsv8kc_njj2zjtyngtjmbjd","selfHosted":false,"version":"1.22.1","environment":"Production"});
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
.controller('settingsTwoStepAuthenticatorController', function ($scope, apiService, $uibModalInstance, cryptoService,
|
||||
authService, $q, toastr, $analytics, constants, $timeout) {
|
||||
$analytics.eventTrack('settingsTwoStepAuthenticatorController', { category: 'Modal' });
|
||||
var _issuer = 'bitwarden',
|
||||
var _issuer = 'Bitwarden',
|
||||
_profile = null,
|
||||
_masterPasswordHash,
|
||||
_key = null;
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
$analytics.eventTrack('Print Recovery Code');
|
||||
var w = window.open();
|
||||
w.document.write('<div style="font-size: 18px; text-align: center;"><p>bitwarden two-step login recovery code:</p>' +
|
||||
w.document.write('<div style="font-size: 18px; text-align: center;"><p>Bitwarden two-step login recovery code:</p>' +
|
||||
'<code style="font-family: Menlo, Monaco, Consolas, \'Courier New\', monospace;">' + $scope.code + '</code>' +
|
||||
'</div><p style="text-align: center;">' + new Date() + '</p>');
|
||||
w.print();
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
}, function (e) {
|
||||
throw e ? e : 'Error occurred.';
|
||||
}).then(function () {
|
||||
toastr.success('Please log back in. If you are using other bitwarden applications, ' +
|
||||
toastr.success('Please log back in. If you are using other Bitwarden applications, ' +
|
||||
'log out and back in to those as well.', 'Key Updated', { timeOut: 10000 });
|
||||
});
|
||||
};
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<p>
|
||||
You membership has a total of {{storage.maxGb}} GB of encrypted file storage.
|
||||
Your membership has a total of {{storage.maxGb}} GB of encrypted file storage.
|
||||
You are currently using {{storage.currentName}}.
|
||||
</p>
|
||||
<div class="progress" style="margin: 0;">
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<section class="content">
|
||||
<p>
|
||||
If you have the same login across multiple different website domains, you can mark the website as "equivalent".
|
||||
"Global" domains are ones already created for you by bitwarden.
|
||||
"Global" domains are ones already created for you by Bitwarden.
|
||||
</p>
|
||||
<form name="customForm" ng-submit="customForm.$valid && saveCustom()" api-form="customPromise" autocomplete="off">
|
||||
<div class="box box-default">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
</div>
|
||||
<div class="box-body">
|
||||
The recovery code allows you to access your account in the event that you can no longer use your normal
|
||||
two-step login provider (ex. you lose your device). bitwarden support will not be able to assist you if you lose
|
||||
two-step login provider (ex. you lose your device). Bitwarden support will not be able to assist you if you lose
|
||||
access to your account. We recommend you write down or print the recovery code and keep it in a safe place.
|
||||
</div>
|
||||
<div class="box-footer">
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<li ng-repeat="e in submitTwoStepForm.$errors">{{e}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>Enter the bitwarden application information from your Duo Admin panel:</p>
|
||||
<p>Enter the Bitwarden application information from your Duo Admin panel:</p>
|
||||
<div class="form-group" show-errors>
|
||||
<label for="ikey">Integration Key</label>
|
||||
<input type="text" id="ikey" name="IntegrationKey" ng-model="updateModel.ikey" class="form-control"
|
||||
@@ -57,7 +57,7 @@
|
||||
<div class="form-group" show-errors>
|
||||
<label for="skey">Secret Key</label>
|
||||
<input type="password" id="skey" name="SecretKey" ng-model="updateModel.skey" class="form-control"
|
||||
required api-field />
|
||||
required api-field autocomplete="new-password" />
|
||||
</div>
|
||||
<div class="form-group" show-errors>
|
||||
<label for="host">API Hostname</label>
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<div class="callout callout-warning">
|
||||
<h4><i class="fa fa-warning"></i> Warning <i class="fa fa-warning"></i></h4>
|
||||
<p>
|
||||
Due to platform limitations, FIDO U2F cannot be used on all bitwarden applications. You should enable
|
||||
Due to platform limitations, FIDO U2F cannot be used on all Bitwarden applications. You should enable
|
||||
another two-step login provider so that you can access your account when FIDO U2F cannot be used.
|
||||
</p>
|
||||
<p>Supported platforms:</p>
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<div class="callout callout-warning">
|
||||
<h4><i class="fa fa-warning"></i> Warning <i class="fa fa-warning"></i></h4>
|
||||
<p>
|
||||
Due to platform limitations, YubiKeys cannot be used on all bitwarden applications. You should enable
|
||||
Due to platform limitations, YubiKeys cannot be used on all Bitwarden applications. You should enable
|
||||
another two-step login provider so that you can access your account when YubiKeys cannot be used.
|
||||
</p>
|
||||
<p>Supported platforms:</p>
|
||||
@@ -77,7 +77,7 @@
|
||||
{{updateModel.key1.existingKey}}
|
||||
</div>
|
||||
<input type="password" id="key1" name="Key1" ng-model="updateModel.key1.key" class="form-control" api-field
|
||||
ng-show="!updateModel.key1.existingKey" />
|
||||
ng-show="!updateModel.key1.existingKey" autocomplete="new-password" />
|
||||
</div>
|
||||
<div class="form-group" show-errors>
|
||||
<label for="key2">YubiKey #2</label>
|
||||
@@ -88,7 +88,7 @@
|
||||
{{updateModel.key2.existingKey}}
|
||||
</div>
|
||||
<input type="password" id="key2" name="Key2" ng-model="updateModel.key2.key" class="form-control" api-field
|
||||
ng-show="!updateModel.key2.existingKey" />
|
||||
ng-show="!updateModel.key2.existingKey" autocomplete="new-password" />
|
||||
</div>
|
||||
<div class="form-group" show-errors>
|
||||
<label for="key3">YubiKey #3</label>
|
||||
@@ -99,7 +99,7 @@
|
||||
{{updateModel.key3.existingKey}}
|
||||
</div>
|
||||
<input type="password" id="key3" name="Key3" ng-model="updateModel.key3.key" class="form-control" api-field
|
||||
ng-show="!updateModel.key3.existingKey" />
|
||||
ng-show="!updateModel.key3.existingKey" autocomplete="new-password" />
|
||||
</div>
|
||||
<strong>NFC Support</strong>
|
||||
<div class="checkbox">
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<hr />
|
||||
<div class="callout callout-warning">
|
||||
<h4><i class="fa fa-warning"></i> Warning</h4>
|
||||
After updating your encryption key, you are required to log out and back in to all bitwarden applications that you
|
||||
After updating your encryption key, you are required to log out and back in to all Bitwarden applications that you
|
||||
are currently using (such as the mobile app or browser extensions). Failure to log out and back
|
||||
in (which downloads your new encryption key) may result in data corruption. We will attempt to log you out
|
||||
automatically, however it may be delayed.
|
||||
|
||||
@@ -53,8 +53,9 @@
|
||||
login_totp: null
|
||||
};
|
||||
|
||||
var j;
|
||||
if (decCiphers[i].fields) {
|
||||
for (var j = 0; j < decCiphers[i].fields.length; j++) {
|
||||
for (j = 0; j < decCiphers[i].fields.length; j++) {
|
||||
if (!cipher.fields) {
|
||||
cipher.fields = '';
|
||||
}
|
||||
@@ -69,10 +70,16 @@
|
||||
switch (decCiphers[i].type) {
|
||||
case constants.cipherType.login:
|
||||
cipher.type = 'login';
|
||||
cipher.login_uri = decCiphers[i].login.uri;
|
||||
cipher.login_username = decCiphers[i].login.username;
|
||||
cipher.login_password = decCiphers[i].login.password;
|
||||
cipher.login_totp = decCiphers[i].login.totp;
|
||||
|
||||
if (decCiphers[i].login.uris && decCiphers[i].login.uris.length) {
|
||||
cipher.login_uri = [];
|
||||
for (j = 0; j < decCiphers[i].login.uris.length; j++) {
|
||||
cipher.login_uri.push(decCiphers[i].login.uris[j].uri);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case constants.cipherType.secureNote:
|
||||
cipher.type = 'note';
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
$scope.options = [
|
||||
{
|
||||
id: 'bitwardencsv',
|
||||
name: 'bitwarden (csv)',
|
||||
name: 'Bitwarden (csv)',
|
||||
featured: true,
|
||||
sort: 1,
|
||||
instructions: $sce.trustAsHtml('Export using the web vault (vault.bitwarden.com). ' +
|
||||
@@ -243,7 +243,7 @@
|
||||
'python script by Luke Plant to your desktop as <code>pw_helper.py</code>. Open terminal and run ' +
|
||||
'<code>chmod +rx Desktop/pw_helper.py</code> and then ' +
|
||||
'<code>python Desktop/pw_helper.py export Desktop/my_passwords.json</code>. Then upload ' +
|
||||
'the resulting <code>my_passwords.json</code> file here to bitwarden.')
|
||||
'the resulting <code>my_passwords.json</code> file here to Bitwarden.')
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -11,7 +11,13 @@
|
||||
folderId: selectedFolder ? selectedFolder.id : null,
|
||||
favorite: checkedFavorite === true,
|
||||
type: constants.cipherType.login,
|
||||
login: {},
|
||||
login: {
|
||||
uris: [{
|
||||
uri: null,
|
||||
match: null,
|
||||
matchValue: null
|
||||
}]
|
||||
},
|
||||
identity: {},
|
||||
card: {},
|
||||
secureNote: {
|
||||
@@ -44,6 +50,42 @@
|
||||
}
|
||||
};
|
||||
|
||||
$scope.addUri = function () {
|
||||
if (!$scope.cipher.login) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$scope.cipher.login.uris) {
|
||||
$scope.cipher.login.uris = [];
|
||||
}
|
||||
|
||||
$scope.cipher.login.uris.push({
|
||||
uri: null,
|
||||
match: null,
|
||||
matchValue: null
|
||||
});
|
||||
};
|
||||
|
||||
$scope.removeUri = function (uri) {
|
||||
if (!$scope.cipher.login || !$scope.cipher.login.uris) {
|
||||
return;
|
||||
}
|
||||
|
||||
var index = $scope.cipher.login.uris.indexOf(uri);
|
||||
if (index > -1) {
|
||||
$scope.cipher.login.uris.splice(index, 1);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.uriMatchChanged = function (uri) {
|
||||
if ((!uri.matchValue && uri.matchValue !== 0) || uri.matchValue === '') {
|
||||
uri.match = null;
|
||||
}
|
||||
else {
|
||||
uri.match = parseInt(uri.matchValue);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.addField = function () {
|
||||
if (!$scope.cipher.fields) {
|
||||
$scope.cipher.fields = [];
|
||||
|
||||
@@ -205,6 +205,8 @@
|
||||
if (returnVal.action === 'edit') {
|
||||
var index = $scope.ciphers.indexOf(cipher);
|
||||
if (index > -1) {
|
||||
// restore collection ids since those cannot change on edit here.
|
||||
returnVal.data.collectionIds = $rootScope.vaultCiphers[index].collectionIds;
|
||||
$rootScope.vaultCiphers[index] = returnVal.data;
|
||||
}
|
||||
sortScopedCipherData();
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
$scope.cipher = cipherService.decryptCipher(cipher);
|
||||
$scope.readOnly = !$scope.cipher.edit;
|
||||
$scope.useTotp = $scope.useTotp || $scope.cipher.organizationUseTotp;
|
||||
setUriMatchValues();
|
||||
});
|
||||
|
||||
$scope.save = function (model) {
|
||||
@@ -55,6 +56,42 @@
|
||||
}
|
||||
};
|
||||
|
||||
$scope.addUri = function () {
|
||||
if (!$scope.cipher.login) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$scope.cipher.login.uris) {
|
||||
$scope.cipher.login.uris = [];
|
||||
}
|
||||
|
||||
$scope.cipher.login.uris.push({
|
||||
uri: null,
|
||||
match: null,
|
||||
matchValue: null
|
||||
});
|
||||
};
|
||||
|
||||
$scope.removeUri = function (uri) {
|
||||
if (!$scope.cipher.login || !$scope.cipher.login.uris) {
|
||||
return;
|
||||
}
|
||||
|
||||
var index = $scope.cipher.login.uris.indexOf(uri);
|
||||
if (index > -1) {
|
||||
$scope.cipher.login.uris.splice(index, 1);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.uriMatchChanged = function (uri) {
|
||||
if ((!uri.matchValue && uri.matchValue !== 0) || uri.matchValue === '') {
|
||||
uri.match = null;
|
||||
}
|
||||
else {
|
||||
uri.match = parseInt(uri.matchValue);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.addField = function () {
|
||||
if (!$scope.cipher.fields) {
|
||||
$scope.cipher.fields = [];
|
||||
@@ -130,4 +167,14 @@
|
||||
controller: 'premiumRequiredController'
|
||||
});
|
||||
};
|
||||
|
||||
function setUriMatchValues() {
|
||||
if ($scope.cipher.login && $scope.cipher.login.uris) {
|
||||
for (var i = 0; i < $scope.cipher.login.uris.length; i++) {
|
||||
$scope.cipher.login.uris[i].matchValue =
|
||||
$scope.cipher.login.uris[i].match || $scope.cipher.login.uris[i].match === 0 ?
|
||||
$scope.cipher.login.uris[i].match.toString() : '';
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -39,26 +39,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="cipher.type === constants.cipherType.login">
|
||||
<div class="form-group" show-errors>
|
||||
<label for="uri">URI</label>
|
||||
<div class="input-group">
|
||||
<input type="text" id="uri" name="Login.Uri" ng-model="cipher.login.uri" class="form-control"
|
||||
placeholder="http://..." ng-readonly="readOnly" api-field />
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default btn-flat" type="button" uib-tooltip="Copy URI"
|
||||
tooltip-placement="left" ngclipboard ngclipboard-error="clipboardError(e)"
|
||||
data-clipboard-target="#uri">
|
||||
<i class="fa fa-clipboard"></i>
|
||||
</button>
|
||||
<a href="{{cipher.login.uri}}" target="_blank" class="btn btn-default btn-flat"
|
||||
uib-tooltip="Go To Website" tooltip-placement="left">
|
||||
<i class="fa fa-share"></i>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<div class="form-group" show-errors>
|
||||
@@ -87,7 +68,8 @@
|
||||
<label for="password">Password</label>
|
||||
<div class="input-group">
|
||||
<input type="password" id="password" name="Login.Password" ng-model="cipher.login.password"
|
||||
class="form-control monospaced" ng-readonly="readOnly" api-field />
|
||||
class="form-control monospaced" ng-readonly="readOnly" api-field
|
||||
autocomplete="new-password" />
|
||||
<span class="input-group-btn" uib-tooltip="Copy Password" tooltip-placement="left">
|
||||
<button class="btn btn-default btn-flat" type="button" ngclipboard
|
||||
ngclipboard-success="clipboardSuccess(e)" ngclipboard-error="clipboardError(e, true)"
|
||||
@@ -119,6 +101,58 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-repeat="u in cipher.login.uris" ng-if="cipher.login.uris && cipher.login.uris.length">
|
||||
<div class="row">
|
||||
<div class="col-sm-7">
|
||||
<div class="form-group" show-errors>
|
||||
<label for="uri{{$index}}">URI {{$index + 1}}</label>
|
||||
<div class="input-group">
|
||||
<input type="text" id="uri{{$index}}" name="Login.Uris[{{$index}}].Uri"
|
||||
ng-model="u.uri" class="form-control"
|
||||
placeholder="http://..." ng-readonly="readOnly" api-field />
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default btn-flat" type="button" uib-tooltip="Copy URI"
|
||||
tooltip-placement="left" ngclipboard ngclipboard-error="clipboardError(e)"
|
||||
data-clipboard-target="#uri{{$index}}">
|
||||
<i class="fa fa-clipboard"></i>
|
||||
</button>
|
||||
<a href="{{u.uri}}" target="_blank" class="btn btn-default btn-flat"
|
||||
uib-tooltip="Go To Website" tooltip-placement="left">
|
||||
<i class="fa fa-share"></i>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="form-group">
|
||||
<label for="uri_match_{{$index}}">Auto-fill Detection</label>
|
||||
<select id="uri_match_{{$index}}" name="Login.Uris[{{$index}}].Match"
|
||||
class="form-control" ng-model="u.matchValue" ng-change="uriMatchChanged(u)">
|
||||
<option value="">Default</option>
|
||||
<option value="0">Base domain</option>
|
||||
<option value="1">Host</option>
|
||||
<option value="2">Starts with</option>
|
||||
<option value="4">Regular Expression</option>
|
||||
<option value="3">Exact</option>
|
||||
<option value="5">Never</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-1">
|
||||
<br class="hidden-xs" />
|
||||
<a href="#" ng-click="removeUri(u)" stop-click>
|
||||
<i class="fa fa-window-close-o fa-lg"></i>
|
||||
<span class="visible-xs-inline">Remove URI</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="visible-xs-block" />
|
||||
</div>
|
||||
<a href="#" ng-click="addUri()" stop-click>
|
||||
<i class="fa fa-plus-circle"></i> New URI
|
||||
</a>
|
||||
<br /><br />
|
||||
</div>
|
||||
<div ng-if="cipher.type === constants.cipherType.card">
|
||||
<div class="row">
|
||||
@@ -504,7 +538,6 @@
|
||||
<div ng-if="cipher.type === constants.cipherType.secureNote">
|
||||
<!-- Nothing for now -->
|
||||
</div>
|
||||
|
||||
<div class="form-group" show-errors>
|
||||
<label for="notes">Notes</label>
|
||||
<textarea id="notes" name="Notes" class="form-control" ng-model="cipher.notes" api-field
|
||||
|
||||
@@ -33,24 +33,6 @@
|
||||
</div>
|
||||
|
||||
<div ng-if="cipher.type === constants.cipherType.login">
|
||||
<div class="form-group" show-errors>
|
||||
<label for="uri">URI</label>
|
||||
<div class="input-group">
|
||||
<input type="text" id="uri" name="Login.Uri" ng-model="cipher.login.uri" class="form-control"
|
||||
placeholder="http://..." ng-readonly="readOnly" api-field />
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default btn-flat" type="button" uib-tooltip="Copy URI"
|
||||
tooltip-placement="left" ngclipboard ngclipboard-error="clipboardError(e)"
|
||||
data-clipboard-target="#uri">
|
||||
<i class="fa fa-clipboard"></i>
|
||||
</button>
|
||||
<a href="{{cipher.login.uri}}" target="_blank" class="btn btn-default btn-flat"
|
||||
uib-tooltip="Go To Website" tooltip-placement="left">
|
||||
<i class="fa fa-share"></i>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<div class="form-group" show-errors>
|
||||
@@ -79,7 +61,8 @@
|
||||
<label for="password">Password</label>
|
||||
<div class="input-group">
|
||||
<input type="password" id="password" name="Login.Password" ng-model="cipher.login.password"
|
||||
class="form-control monospaced" ng-readonly="readOnly" api-field />
|
||||
class="form-control monospaced" ng-readonly="readOnly" api-field
|
||||
autocomplete="new-password" />
|
||||
<span class="input-group-btn" uib-tooltip="Copy Password" tooltip-placement="left">
|
||||
<button class="btn btn-default btn-flat" type="button" ngclipboard
|
||||
ngclipboard-success="clipboardSuccess(e)" ngclipboard-error="clipboardError(e, true)"
|
||||
@@ -111,6 +94,60 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-repeat="u in cipher.login.uris" ng-if="cipher.login.uris && cipher.login.uris.length">
|
||||
<div class="row">
|
||||
<div class="col-sm-7">
|
||||
<div class="form-group" show-errors>
|
||||
<label for="uri{{$index}}">URI {{$index + 1}}</label>
|
||||
<div class="input-group">
|
||||
<input type="text" id="uri{{$index}}" name="Login.Uris[{{$index}}].Uri"
|
||||
ng-model="u.uri" class="form-control"
|
||||
placeholder="http://..." ng-readonly="readOnly" api-field />
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default btn-flat" type="button" uib-tooltip="Copy URI"
|
||||
tooltip-placement="left" ngclipboard ngclipboard-error="clipboardError(e)"
|
||||
data-clipboard-target="#uri{{$index}}">
|
||||
<i class="fa fa-clipboard"></i>
|
||||
</button>
|
||||
<a href="{{u.uri}}" target="_blank" class="btn btn-default btn-flat"
|
||||
uib-tooltip="Go To Website" tooltip-placement="left">
|
||||
<i class="fa fa-share"></i>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="form-group">
|
||||
<label for="uri_match_{{$index}}">Auto-fill Detection</label>
|
||||
<select id="uri_match_{{$index}}" name="Login.Uris[{{$index}}].Match" ng-disabled="readOnly"
|
||||
class="form-control" ng-model="u.matchValue" ng-change="uriMatchChanged(u)">
|
||||
<option value="">Default</option>
|
||||
<option value="0">Base domain</option>
|
||||
<option value="1">Host</option>
|
||||
<option value="2">Starts with</option>
|
||||
<option value="4">Regular Expression</option>
|
||||
<option value="3">Exact</option>
|
||||
<option value="5">Never</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-1" ng-if="!readOnly">
|
||||
<br class="hidden-xs" />
|
||||
<a href="#" ng-click="removeUri(u)" stop-click>
|
||||
<i class="fa fa-window-close-o fa-lg"></i>
|
||||
<span class="visible-xs-inline">Remove URI</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="visible-xs-block" />
|
||||
</div>
|
||||
<div ng-if="!readOnly">
|
||||
<a href="#" ng-click="addUri()" stop-click>
|
||||
<i class="fa fa-plus-circle"></i> New URI
|
||||
</a>
|
||||
<br /><br />
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="cipher.type === constants.cipherType.card">
|
||||
<div class="row">
|
||||
@@ -551,9 +588,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-1">
|
||||
<div class="col-sm-1" ng-if="!readOnly">
|
||||
<br class="hidden-xs" />
|
||||
<a href="#" ng-click="removeField(field)" stop-click ng-if="!readOnly">
|
||||
<a href="#" ng-click="removeField(field)" stop-click>
|
||||
<i class="fa fa-window-close-o fa-lg"></i>
|
||||
<span class="visible-xs-inline">Remove Custom Field</span>
|
||||
</a>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<p ng-show="loading">Loading...</p>
|
||||
<div ng-show="!loading && !organizations.length" class="callout callout-default">
|
||||
<h4><i class="fa fa-info-circle"></i> No Organizations</h4>
|
||||
<p>You do not belong to any organizations. Organizations allow you to share items with other bitwarden users.</p>
|
||||
<p>You do not belong to any organizations. Organizations allow you to share items with other Bitwarden users.</p>
|
||||
<a ng-click="createOrg()" class="btn btn-default btn-flat">
|
||||
Create an Organization
|
||||
</a>
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
<section class="content-header">
|
||||
<h1>
|
||||
Apps
|
||||
<small>for all of your devices</small>
|
||||
</h1>
|
||||
</section>
|
||||
<section class="content">
|
||||
<div class="box box-default box-apps">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Desktop/Browser</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<ul class="fa-ul">
|
||||
<li>
|
||||
<a href="https://chrome.google.com/webstore/detail/bitwarden-free-password-m/nngceckbapebfimnlniiiahkandclblb" target="_blank">
|
||||
<i class="fa fa-chrome fa-lg fa-fw fa-li"></i> Google Chrome
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://addons.mozilla.org/firefox/addon/bitwarden-password-manager/" target="_blank">
|
||||
<i class="fa fa-firefox fa-lg fa-fw fa-li"></i> Mozilla Firefox
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://addons.opera.com/extensions/details/bitwarden-free-password-manager/" target="_blank">
|
||||
<i class="fa fa-opera fa-lg fa-fw fa-li"></i> Opera
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://www.microsoft.com/store/p/bitwarden-free-password-manager/9p6kxl0svnnl" target="_blank">
|
||||
<i class="fa fa-edge fa-lg fa-fw fa-li"></i> Microsoft Edge
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
Others:
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://chrome.google.com/webstore/detail/bitwarden-free-password-m/nngceckbapebfimnlniiiahkandclblb" target="_blank">
|
||||
Vivaldi
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://brave.com/" target="_blank">
|
||||
Brave
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://addons.mozilla.org/firefox/addon/bitwarden-password-manager/" target="_blank">
|
||||
Tor Browser
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box box-default box-apps">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Mobile</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<ul class="fa-ul">
|
||||
<li>
|
||||
<a href="https://itunes.apple.com/app/bitwarden-free-password-manager/id1137397744?mt=8" target="_blank">
|
||||
<i class="fa fa-apple fa-lg fa-fw fa-li"></i> iOS
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://play.google.com/store/apps/details?id=com.x8bit.bitwarden" target="_blank">
|
||||
<i class="fa fa-android fa-lg fa-fw fa-li"></i> Android
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<ul class="fa-ul">
|
||||
<li>
|
||||
<a href="#" stop-click>
|
||||
<i class="fa fa-windows fa-lg fa-fw fa-li"></i> Windows
|
||||
<small class="text-muted">(coming soon)</small>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box box-default box-apps">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">Other</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<ul class="fa-ul">
|
||||
<li>
|
||||
<a href="#" stop-click>
|
||||
<i class="fa fa-windows fa-lg fa-fw fa-li"></i> Desktop Windows
|
||||
<small class="text-muted">(coming soon)</small>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" stop-click>
|
||||
<i class="fa fa-apple fa-lg fa-fw fa-li"></i> Desktop macOS
|
||||
<small class="text-muted">(coming soon)</small>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<ul class="fa-ul">
|
||||
<li>
|
||||
<a href="#" stop-click>
|
||||
<i class="fa fa-linux fa-lg fa-fw fa-li"></i> Desktop Linux
|
||||
<small class="text-muted">(coming soon)</small>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" stop-click>
|
||||
<i class="fa fa-terminal fa-lg fa-fw fa-li"></i> CLI
|
||||
<small class="text-muted">(coming soon)</small>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -104,7 +104,7 @@
|
||||
</ul>
|
||||
</li>
|
||||
<li ng-class="{active: $state.is('backend.user.apps')}">
|
||||
<a ui-sref="backend.user.apps">
|
||||
<a href="https://bitwarden.com/#download" target="_blank">
|
||||
<small class="label pull-right bg-green">FREE</small>
|
||||
<i class="fa fa-download fa-fw"></i> <span>Get the Apps</span>
|
||||
</a>
|
||||
|
||||
@@ -26,47 +26,6 @@
|
||||
</head>
|
||||
<body>
|
||||
<script src="js/duo.js"></script>
|
||||
<script>
|
||||
!(function () {
|
||||
var frameElement = document.createElement('iframe');
|
||||
frameElement.setAttribute('id', 'duo_iframe');
|
||||
setFrameHeight();
|
||||
document.body.appendChild(frameElement);
|
||||
|
||||
var hostParam = getQsParam('host');
|
||||
var requestParam = getQsParam('request');
|
||||
Duo.init({
|
||||
host: hostParam,
|
||||
sig_request: requestParam,
|
||||
submit_callback: function (form) {
|
||||
invokeCSCode(form.elements.sig_response.value);
|
||||
}
|
||||
});
|
||||
|
||||
window.onresize = setFrameHeight;
|
||||
function setFrameHeight() {
|
||||
frameElement.style.height = window.innerHeight + 'px';
|
||||
}
|
||||
})();
|
||||
|
||||
function getQsParam(name) {
|
||||
var url = window.location.href;
|
||||
name = name.replace(/[\[\]]/g, '\\$&');
|
||||
var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
|
||||
results = regex.exec(url);
|
||||
if (!results) return null;
|
||||
if (!results[2]) return '';
|
||||
return decodeURIComponent(results[2].replace(/\+/g, ' '));
|
||||
}
|
||||
|
||||
function invokeCSCode(data) {
|
||||
try {
|
||||
invokeCSharpAction(data);
|
||||
}
|
||||
catch (err) {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script src="js/duo-connector.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<meta name="theme-color" content="#3c8dbc">
|
||||
<base href="/" />
|
||||
|
||||
<title page-title>bitwarden Web Vault</title>
|
||||
<title page-title>Bitwarden Web Vault</title>
|
||||
|
||||
<!-- @if !selfHosted -->
|
||||
<script src="https://js.stripe.com/v2/"></script>
|
||||
@@ -67,12 +67,12 @@
|
||||
<div ui-view></div>
|
||||
|
||||
<!-- @if !selfHosted !>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"
|
||||
integrity="sha384-rY/jv8mMhqDabXSo+UCggqKtdmBfd3qC2/KvyTDNQ6PcUJXaxK1tMepoQda4g5vB" crossorigin="anonymous"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"
|
||||
integrity="sha384-xBuQ/xzmlsLoJpyjoggmTEz8OWUFM0/RC5BsqQBDX2v5cMvDHcMakNTNrHIW2I5f" crossorigin="anonymous"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"
|
||||
integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.3/angular.min.js"
|
||||
integrity="sha384-AH/e+s4V4kUifvnNED2x1XZqArO5qTFU4YKRzUXbz4IgPG1H0Xmz6fP1XUmO4vT/" crossorigin="anonymous"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.7/angular.min.js"
|
||||
integrity="sha384-R6kAKgTgRiD5889XyzYD/aMryNA4Yr9EBnt6rIXuukLgVONifQDnHNaadrSNakQl" crossorigin="anonymous"></script>
|
||||
<!-- @endif -->
|
||||
<!-- @if true !>
|
||||
<script src="js/fallback-scripts.min.js?v=<!-- @echo cacheTag !>"></script>
|
||||
|
||||
40
src/js/duo-connector.js
Normal file
40
src/js/duo-connector.js
Normal file
@@ -0,0 +1,40 @@
|
||||
!(function () {
|
||||
var frameElement = document.createElement('iframe');
|
||||
frameElement.setAttribute('id', 'duo_iframe');
|
||||
setFrameHeight();
|
||||
document.body.appendChild(frameElement);
|
||||
|
||||
var hostParam = getQsParam('host');
|
||||
var requestParam = getQsParam('request');
|
||||
Duo.init({
|
||||
host: hostParam,
|
||||
sig_request: requestParam,
|
||||
submit_callback: function (form) {
|
||||
invokeCSCode(form.elements.sig_response.value);
|
||||
}
|
||||
});
|
||||
|
||||
window.onresize = setFrameHeight;
|
||||
function setFrameHeight() {
|
||||
frameElement.style.height = window.innerHeight + 'px';
|
||||
}
|
||||
})();
|
||||
|
||||
function getQsParam(name) {
|
||||
var url = window.location.href;
|
||||
name = name.replace(/[\[\]]/g, '\\$&');
|
||||
var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
|
||||
results = regex.exec(url);
|
||||
if (!results) return null;
|
||||
if (!results[2]) return '';
|
||||
return decodeURIComponent(results[2].replace(/\+/g, ' '));
|
||||
}
|
||||
|
||||
function invokeCSCode(data) {
|
||||
try {
|
||||
invokeCSharpAction(data);
|
||||
}
|
||||
catch (err) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -735,7 +735,7 @@ h1, h2, h3, h4, h5, h6 {
|
||||
.totp-col {
|
||||
margin: -10px 0 10px 0;
|
||||
|
||||
@media (min-width: @screen-md) {
|
||||
@media (min-width: @screen-sm) {
|
||||
padding-top: 26px;
|
||||
margin: 0;
|
||||
}
|
||||
@@ -815,9 +815,9 @@ h1, h2, h3, h4, h5, h6 {
|
||||
textarea {
|
||||
&#notes {
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
&.big-textarea {
|
||||
height: 200px !important;
|
||||
&.big-textarea {
|
||||
height: 200px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user