mirror of
https://github.com/bitwarden/browser.git
synced 2024-12-29 17:38:04 +01:00
share login with attachments
This commit is contained in:
parent
204ee72926
commit
47cb20f01e
@ -22,78 +22,40 @@
|
||||
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) {
|
||||
$scope.savePromise = cipherService.encryptAttachmentFile(key, files[0]).then(function (encValue) {
|
||||
var fd = new FormData();
|
||||
var blob = new Blob([encData], { type: 'application/octet-stream' });
|
||||
fd.append('data', blob, encFilename);
|
||||
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 Organization Attachment');
|
||||
$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);
|
||||
}
|
||||
});
|
||||
};
|
||||
reader.onerror = function (evt) {
|
||||
validationService.addError(form, 'file', 'Error reading file.', 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);
|
||||
}
|
||||
|
||||
cipherService.downloadAndDecryptAttachment(key, attachment, true).then(function (res) {
|
||||
$timeout(function () {
|
||||
attachment.loading = false;
|
||||
});
|
||||
}, function () {
|
||||
$timeout(function () {
|
||||
attachment.loading = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
req.send(null);
|
||||
};
|
||||
|
||||
$scope.remove = function (attachment) {
|
||||
if (!confirm('Are you sure you want to delete this attachment (' + attachment.fileName + ')?')) {
|
||||
|
@ -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' } }
|
||||
});
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -24,79 +24,38 @@
|
||||
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) {
|
||||
$scope.savePromise = cipherService.encryptAttachmentFile(getKeyForLogin(), files[0]).then(function (encValue) {
|
||||
var fd = new FormData();
|
||||
var blob = new Blob([encData], { type: 'application/octet-stream' });
|
||||
fd.append('data', blob, encFilename);
|
||||
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);
|
||||
}
|
||||
});
|
||||
};
|
||||
reader.onerror = function (evt) {
|
||||
validationService.addError(form, 'file', 'Error reading file.', 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) {
|
||||
cipherService.downloadAndDecryptAttachment(getKeyForLogin(), attachment, true).then(function (res) {
|
||||
$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);
|
||||
}
|
||||
|
||||
}, function () {
|
||||
$timeout(function () {
|
||||
attachment.loading = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
req.send(null);
|
||||
};
|
||||
|
||||
function getKeyForLogin() {
|
||||
if ($scope.login.organizationId) {
|
||||
|
@ -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,11 +111,37 @@
|
||||
|
||||
$scope.submitPromise = null;
|
||||
$scope.submit = function (model) {
|
||||
var orgKey = cryptoService.getOrgKey(model.organizationId);
|
||||
|
||||
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);
|
||||
|
||||
return apiService.ciphers.postShareAttachment({
|
||||
id: loginId,
|
||||
attachmentId: attachment.id,
|
||||
orgId: model.organizationId
|
||||
}, fd).$promise;
|
||||
});
|
||||
attachmentSharePromises.push(promise);
|
||||
}
|
||||
}
|
||||
|
||||
$scope.submitPromise = $q.all(attachmentSharePromises).then(function () {
|
||||
$scope.login.organizationId = model.organizationId;
|
||||
|
||||
var request = {
|
||||
collectionIds: [],
|
||||
cipher: cipherService.encryptLogin($scope.login)
|
||||
cipher: cipherService.encryptLogin($scope.login, null, true)
|
||||
};
|
||||
|
||||
for (var id in $scope.selectedCollections) {
|
||||
@ -124,10 +150,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
$scope.submitPromise = apiService.ciphers.putShare({ id: loginId }, request, function (response) {
|
||||
return apiService.ciphers.putShare({ id: loginId }, request).$promise;
|
||||
}).then(function (response) {
|
||||
$analytics.eventTrack('Shared Login');
|
||||
$uibModalInstance.close(model.organizationId);
|
||||
}).$promise;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.close = function () {
|
||||
|
Loading…
Reference in New Issue
Block a user