1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-12-28 17:27:50 +01:00

share login with attachments

This commit is contained in:
Kyle Spearrin 2017-07-10 14:30:33 -04:00
parent 204ee72926
commit 47cb20f01e
5 changed files with 174 additions and 147 deletions

View File

@ -22,77 +22,39 @@
return;
}
var file = files[0];
if (file.size > 104857600) { // 100 MB
validationService.addError(form, 'file', 'Maximum file size is 100 MB.', true);
return;
}
var reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = function (evt) {
$timeout(function () {
form.$loading = true;
});
var key = cryptoService.getOrgKey($scope.login.organizationId);
var encFilename = cryptoService.encrypt(file.name, key);
$scope.savePromise = cryptoService.encryptToBytes(evt.target.result, key).then(function (encData) {
var fd = new FormData();
var blob = new Blob([encData], { type: 'application/octet-stream' });
fd.append('data', blob, encFilename);
return apiService.ciphers.postAttachment({ id: loginId }, fd).$promise;
}).then(function (response) {
$analytics.eventTrack('Added Organization Attachment');
toastr.success('The attachment has been added.');
closing = true;
$uibModalInstance.close(true);
});
};
reader.onerror = function (evt) {
validationService.addError(form, 'file', 'Error reading file.', true);
};
var key = cryptoService.getOrgKey($scope.login.organizationId);
$scope.savePromise = cipherService.encryptAttachmentFile(key, files[0]).then(function (encValue) {
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: loginId }, fd).$promise;
}).then(function (response) {
$analytics.eventTrack('Added Attachment');
toastr.success('The attachment has been added.');
closing = true;
$uibModalInstance.close(true);
}, function (err) {
if (err) {
validationService.addError(form, 'file', err, true);
}
else {
validationService.addError(form, 'file', 'Something went wrong.', true);
}
});
}
$scope.download = function (attachment) {
attachment.loading = true;
var req = new XMLHttpRequest();
req.open('GET', attachment.url, true);
req.responseType = 'arraybuffer';
req.onload = function (evt) {
if (!req.response) {
$timeout(function () {
attachment.loading = false;
});
// error
return;
}
var key = cryptoService.getOrgKey($scope.login.organizationId);
cryptoService.decryptFromBytes(req.response, key).then(function (decBuf) {
var blob = new Blob([decBuf]);
// IE hack. ref http://msdn.microsoft.com/en-us/library/ie/hh779016.aspx
if (window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveBlob(blob, attachment.fileName);
}
else {
var a = window.document.createElement('a');
a.href = window.URL.createObjectURL(blob);
a.download = attachment.fileName;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
$timeout(function () {
attachment.loading = false;
});
var key = cryptoService.getOrgKey($scope.login.organizationId);
cipherService.downloadAndDecryptAttachment(key, attachment, true).then(function (res) {
$timeout(function () {
attachment.loading = false;
});
};
req.send(null);
}, function () {
$timeout(function () {
attachment.loading = false;
});
});
};
$scope.remove = function (attachment) {

View File

@ -47,6 +47,12 @@
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' } }
});

View File

@ -1,7 +1,7 @@
angular
.module('bit.services')
.factory('cipherService', function (cryptoService, apiService, $q) {
.factory('cipherService', function (cryptoService, apiService, $q, $window) {
var _service = {};
_service.decryptLogins = function (encryptedLogins) {
@ -89,6 +89,43 @@ angular
};
};
_service.downloadAndDecryptAttachment = function (key, decryptedAttachment, openDownload) {
var deferred = $q.defer();
var req = new XMLHttpRequest();
req.open('GET', decryptedAttachment.url, true);
req.responseType = 'arraybuffer';
req.onload = function (evt) {
if (!req.response) {
deferred.reject('No response');
// error
return;
}
cryptoService.decryptFromBytes(req.response, key).then(function (decBuf) {
if (openDownload) {
var blob = new Blob([decBuf]);
// IE hack. ref http://msdn.microsoft.com/en-us/library/ie/hh779016.aspx
if ($window.navigator.msSaveOrOpenBlob) {
$window.navigator.msSaveBlob(blob, decryptedAttachment.fileName);
}
else {
var a = $window.document.createElement('a');
a.href = $window.URL.createObjectURL(blob);
a.download = decryptedAttachment.fileName;
$window.document.body.appendChild(a);
a.click();
$window.document.body.removeChild(a);
}
}
deferred.resolve(new Uint8Array(decBuf));
});
};
req.send(null);
return deferred.promise;
};
_service.decryptFolders = function (encryptedFolders) {
if (!encryptedFolders) throw "encryptedFolders is undefined or null";
@ -169,14 +206,14 @@ angular
return encryptedLogins;
};
_service.encryptLogin = function (unencryptedLogin, key) {
_service.encryptLogin = function (unencryptedLogin, key, attachments) {
if (!unencryptedLogin) throw "unencryptedLogin is undefined or null";
if (unencryptedLogin.organizationId) {
key = key || cryptoService.getOrgKey(unencryptedLogin.organizationId);
}
return {
var login = {
id: unencryptedLogin.id,
'type': 1,
organizationId: unencryptedLogin.organizationId || null,
@ -189,6 +226,42 @@ angular
notes: !unencryptedLogin.notes || unencryptedLogin.notes === '' ? null : cryptoService.encrypt(unencryptedLogin.notes, key),
totp: !unencryptedLogin.totp || unencryptedLogin.totp === '' ? null : cryptoService.encrypt(unencryptedLogin.totp, key)
};
if (unencryptedLogin.attachments && attachments) {
login.attachments = {};
for (var i = 0; i < unencryptedLogin.attachments.length; i++) {
login.attachments[unencryptedLogin.attachments[i].id] =
cryptoService.encrypt(unencryptedLogin.attachments[i].fileName, key);
}
}
return login;
};
_service.encryptAttachmentFile = function (key, unencryptedFile) {
var deferred = $q.defer();
if (unencryptedFile.size > 104857600) { // 100 MB
deferred.reject('Maximum file size is 100 MB.');
return;
}
var reader = new FileReader();
reader.readAsArrayBuffer(unencryptedFile);
reader.onload = function (evt) {
cryptoService.encryptToBytes(evt.target.result, key).then(function (encData) {
deferred.resolve({
fileName: cryptoService.encrypt(unencryptedFile.name, key),
data: new Uint8Array(encData),
size: unencryptedFile.size
});
});
};
reader.onerror = function (evt) {
deferred.reject('Error reading file.');
};
return deferred.promise;
};
_service.encryptFolders = function (unencryptedFolders, key) {

View File

@ -24,78 +24,37 @@
return;
}
var file = files[0];
if (file.size > 104857600) { // 100 MB
validationService.addError(form, 'file', 'Maximum file size is 100 MB.', true);
return;
}
var reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = function (evt) {
$timeout(function () {
form.$loading = true;
});
var key = getKeyForLogin();
var encFilename = cryptoService.encrypt(file.name, key);
$scope.savePromise = cryptoService.encryptToBytes(evt.target.result, key).then(function (encData) {
var fd = new FormData();
var blob = new Blob([encData], { type: 'application/octet-stream' });
fd.append('data', blob, encFilename);
return apiService.ciphers.postAttachment({ id: loginId }, fd).$promise;
}).then(function (response) {
$analytics.eventTrack('Added Attachment');
toastr.success('The attachment has been added.');
closing = true;
$uibModalInstance.close(true);
});
};
reader.onerror = function (evt) {
validationService.addError(form, 'file', 'Error reading file.', true);
};
$scope.savePromise = cipherService.encryptAttachmentFile(getKeyForLogin(), files[0]).then(function (encValue) {
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: loginId }, fd).$promise;
}).then(function (response) {
$analytics.eventTrack('Added Attachment');
toastr.success('The attachment has been added.');
closing = true;
$uibModalInstance.close(true);
}, function (err) {
if (err) {
validationService.addError(form, 'file', err, true);
}
else {
validationService.addError(form, 'file', 'Something went wrong.', true);
}
});
}
$scope.download = function (attachment) {
attachment.loading = true;
var key = getKeyForLogin();
var req = new XMLHttpRequest();
req.open('GET', attachment.url, true);
req.responseType = 'arraybuffer';
req.onload = function (evt) {
if (!req.response) {
$timeout(function () {
attachment.loading = false;
});
// error
return;
}
cryptoService.decryptFromBytes(req.response, key).then(function (decBuf) {
var blob = new Blob([decBuf]);
// IE hack. ref http://msdn.microsoft.com/en-us/library/ie/hh779016.aspx
if (window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveBlob(blob, attachment.fileName);
}
else {
var a = window.document.createElement('a');
a.href = window.URL.createObjectURL(blob);
a.download = attachment.fileName;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
$timeout(function () {
attachment.loading = false;
});
cipherService.downloadAndDecryptAttachment(getKeyForLogin(), attachment, true).then(function (res) {
$timeout(function () {
attachment.loading = false;
});
};
req.send(null);
}, function () {
$timeout(function () {
attachment.loading = false;
});
});
};
function getKeyForLogin() {

View File

@ -2,7 +2,7 @@
.module('bit.vault')
.controller('vaultShareLoginController', function ($scope, apiService, $uibModalInstance, authService, cipherService,
loginId, $analytics, $state) {
loginId, $analytics, $state, cryptoService, $q) {
$analytics.eventTrack('vaultShareLoginController', { category: 'Modal' });
$scope.model = {};
$scope.login = {};
@ -111,23 +111,50 @@
$scope.submitPromise = null;
$scope.submit = function (model) {
$scope.login.organizationId = model.organizationId;
var orgKey = cryptoService.getOrgKey(model.organizationId);
var request = {
collectionIds: [],
cipher: cipherService.encryptLogin($scope.login)
};
var attachmentSharePromises = [];
if ($scope.login.attachments) {
for (var i = 0; i < $scope.login.attachments.length; i++) {
var attachment = $scope.login.attachments[i];
var promise = cipherService.downloadAndDecryptAttachment(null, attachment, false)
.then(function (decData) {
return cryptoService.encryptToBytes(decData.buffer, orgKey);
}).then(function (encData) {
var fd = new FormData();
var blob = new Blob([encData], { type: 'application/octet-stream' });
var encFilename = cryptoService.encrypt(attachment.fileName, orgKey);
fd.append('data', blob, encFilename);
for (var id in $scope.selectedCollections) {
if ($scope.selectedCollections.hasOwnProperty(id)) {
request.collectionIds.push(id);
return apiService.ciphers.postShareAttachment({
id: loginId,
attachmentId: attachment.id,
orgId: model.organizationId
}, fd).$promise;
});
attachmentSharePromises.push(promise);
}
}
$scope.submitPromise = apiService.ciphers.putShare({ id: loginId }, request, function (response) {
$scope.submitPromise = $q.all(attachmentSharePromises).then(function () {
$scope.login.organizationId = model.organizationId;
var request = {
collectionIds: [],
cipher: cipherService.encryptLogin($scope.login, null, true)
};
for (var id in $scope.selectedCollections) {
if ($scope.selectedCollections.hasOwnProperty(id)) {
request.collectionIds.push(id);
}
}
return apiService.ciphers.putShare({ id: loginId }, request).$promise;
}).then(function (response) {
$analytics.eventTrack('Shared Login');
$uibModalInstance.close(model.organizationId);
}).$promise;
});
};
$scope.close = function () {