1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-16 16:23:44 +00:00
Files
browser/src/app/services/cipherService.js
2017-07-12 14:17:21 -04:00

368 lines
15 KiB
JavaScript

angular
.module('bit.services')
.factory('cipherService', function (cryptoService, apiService, $q, $window) {
var _service = {};
_service.decryptLogins = function (encryptedLogins) {
if (!encryptedLogins) throw "encryptedLogins is undefined or null";
var unencryptedLogins = [];
for (var i = 0; i < encryptedLogins.length; i++) {
unencryptedLogins.push(_service.decryptLogin(encryptedLogins[i]));
}
return unencryptedLogins;
};
_service.decryptLogin = function (encryptedLogin, isCipher) {
if (!encryptedLogin) throw "encryptedLogin is undefined or null";
var key = null;
if (encryptedLogin.OrganizationId) {
key = cryptoService.getOrgKey(encryptedLogin.OrganizationId);
}
var login = {
id: encryptedLogin.Id,
organizationId: encryptedLogin.OrganizationId,
collectionIds: encryptedLogin.CollectionIds || [],
'type': 1,
folderId: encryptedLogin.FolderId,
favorite: encryptedLogin.Favorite,
edit: encryptedLogin.Edit,
organizationUseTotp: encryptedLogin.OrganizationUseTotp,
attachments: null
};
var loginData = encryptedLogin.Data || encryptedLogin;
if (loginData) {
login.name = cryptoService.decrypt(loginData.Name, key);
login.uri = loginData.Uri && loginData.Uri !== '' ? cryptoService.decrypt(loginData.Uri, key) : null;
login.username = loginData.Username && loginData.Username !== '' ? cryptoService.decrypt(loginData.Username, key) : null;
login.password = loginData.Password && loginData.Password !== '' ? cryptoService.decrypt(loginData.Password, key) : null;
login.notes = loginData.Notes && loginData.Notes !== '' ? cryptoService.decrypt(loginData.Notes, key) : null;
login.totp = loginData.Totp && loginData.Totp !== '' ? cryptoService.decrypt(loginData.Totp, key) : null;
}
if (!encryptedLogin.Attachments) {
return login;
}
login.attachments = [];
for (var i = 0; i < encryptedLogin.Attachments.length; i++) {
login.attachments.push(_service.decryptAttachment(key, encryptedLogin.Attachments[i]));
}
return login;
};
_service.decryptLoginPreview = function (encryptedCipher) {
if (!encryptedCipher) throw "encryptedCipher is undefined or null";
var key = null;
if (encryptedCipher.OrganizationId) {
key = cryptoService.getOrgKey(encryptedCipher.OrganizationId);
}
var login = {
id: encryptedCipher.Id,
organizationId: encryptedCipher.OrganizationId,
collectionIds: encryptedCipher.CollectionIds || [],
folderId: encryptedCipher.FolderId,
favorite: encryptedCipher.Favorite,
edit: encryptedCipher.Edit,
organizationUseTotp: encryptedCipher.OrganizationUseTotp,
hasAttachments: !!encryptedCipher.Attachments && encryptedCipher.Attachments.length > 0
};
var loginData = encryptedCipher.Data || encryptedCipher;
if (loginData) {
login.name = cryptoService.decrypt(loginData.Name, key);
login.username = loginData.Username && loginData.Username !== '' ? cryptoService.decrypt(loginData.Username, key) : null;
login.password = loginData.Password && loginData.Password !== '' ? cryptoService.decrypt(loginData.Password, key) : null;
}
return login;
};
_service.decryptAttachment = function (key, encryptedAttachment) {
if (!encryptedAttachment) throw "encryptedAttachment is undefined or null";
return {
id: encryptedAttachment.Id,
url: encryptedAttachment.Url,
fileName: cryptoService.decrypt(encryptedAttachment.FileName, key),
size: encryptedAttachment.SizeName
};
};
_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";
var unencryptedFolders = [];
for (var i = 0; i < encryptedFolders.length; i++) {
unencryptedFolders.push(_service.decryptFolder(encryptedFolders[i]));
}
return unencryptedFolders;
};
_service.decryptFolder = function (encryptedFolder) {
if (!encryptedFolder) throw "encryptedFolder is undefined or null";
return {
id: encryptedFolder.Id,
name: cryptoService.decrypt(encryptedFolder.Name)
};
};
_service.decryptFolderPreview = function (encryptedFolder) {
if (!encryptedFolder) throw "encryptedFolder is undefined or null";
return {
id: encryptedFolder.Id,
name: _service.decryptProperty(encryptedFolder.Name, null, false)
};
};
_service.decryptCollections = function (encryptedCollections, orgId, catchError) {
if (!encryptedCollections) throw "encryptedCollections is undefined or null";
var unencryptedCollections = [];
for (var i = 0; i < encryptedCollections.length; i++) {
unencryptedCollections.push(_service.decryptCollection(encryptedCollections[i], orgId, catchError));
}
return unencryptedCollections;
};
_service.decryptCollection = function (encryptedCollection, orgId, catchError) {
if (!encryptedCollection) throw "encryptedCollection is undefined or null";
catchError = catchError === true ? true : false;
orgId = orgId || encryptedCollection.OrganizationId;
var key = cryptoService.getOrgKey(orgId);
return {
id: encryptedCollection.Id,
name: catchError ? _service.decryptProperty(encryptedCollection.Name, key, false) :
cryptoService.decrypt(encryptedCollection.Name, key)
};
};
_service.decryptProperty = function (property, key, checkEmpty) {
if (checkEmpty && (!property || property === '')) {
return null;
}
try {
property = cryptoService.decrypt(property, key);
}
catch (err) {
property = null;
}
return property || '[error: cannot decrypt]';
};
_service.encryptLogins = function (unencryptedLogins, key) {
if (!unencryptedLogins) throw "unencryptedLogins is undefined or null";
var encryptedLogins = [];
for (var i = 0; i < unencryptedLogins.length; i++) {
encryptedLogins.push(_service.encryptLogin(unencryptedLogins[i], key));
}
return encryptedLogins;
};
_service.encryptLogin = function (unencryptedLogin, key, attachments) {
if (!unencryptedLogin) throw "unencryptedLogin is undefined or null";
if (unencryptedLogin.organizationId) {
key = key || cryptoService.getOrgKey(unencryptedLogin.organizationId);
}
var login = {
id: unencryptedLogin.id,
'type': 1,
organizationId: unencryptedLogin.organizationId || null,
folderId: unencryptedLogin.folderId === '' ? null : unencryptedLogin.folderId,
favorite: unencryptedLogin.favorite !== null ? unencryptedLogin.favorite : false,
uri: !unencryptedLogin.uri || unencryptedLogin.uri === '' ? null : cryptoService.encrypt(unencryptedLogin.uri, key),
name: cryptoService.encrypt(unencryptedLogin.name, key),
username: !unencryptedLogin.username || unencryptedLogin.username === '' ? null : cryptoService.encrypt(unencryptedLogin.username, key),
password: !unencryptedLogin.password || unencryptedLogin.password === '' ? null : cryptoService.encrypt(unencryptedLogin.password, key),
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) {
if (!unencryptedFolders) throw "unencryptedFolders is undefined or null";
var encryptedFolders = [];
for (var i = 0; i < unencryptedFolders.length; i++) {
encryptedFolders.push(_service.encryptFolder(unencryptedFolders[i], key));
}
return encryptedFolders;
};
_service.encryptFolder = function (unencryptedFolder, key) {
if (!unencryptedFolder) throw "unencryptedFolder is undefined or null";
return {
id: unencryptedFolder.id,
name: cryptoService.encrypt(unencryptedFolder.name, key)
};
};
_service.encryptCollections = function (unencryptedCollections, orgId) {
if (!unencryptedCollections) throw "unencryptedCollections is undefined or null";
var encryptedCollections = [];
for (var i = 0; i < unencryptedCollections.length; i++) {
encryptedCollections.push(_service.encryptCollection(unencryptedCollections[i], orgId));
}
return encryptedCollections;
};
_service.encryptCollection = function (unencryptedCollection, orgId) {
if (!unencryptedCollection) throw "unencryptedCollection is undefined or null";
return {
id: unencryptedCollection.id,
name: cryptoService.encrypt(unencryptedCollection.name, cryptoService.getOrgKey(orgId))
};
};
_service.updateKey = function (masterPasswordHash, success, error) {
var madeEncKey = cryptoService.makeEncKey(null);
encKey = madeEncKey.encKey;
var encKeyEnc = madeEncKey.encKeyEnc;
var reencryptedLogins = [];
var loginsPromise = apiService.logins.list({}, function (encryptedLogins) {
var filteredEncryptedLogins = [];
for (var i = 0; i < encryptedLogins.Data.length; i++) {
if (encryptedLogins.Data[i].OrganizationId) {
continue;
}
filteredEncryptedLogins.push(encryptedLogins.Data[i]);
}
var unencryptedLogins = _service.decryptLogins(filteredEncryptedLogins);
reencryptedLogins = _service.encryptLogins(unencryptedLogins, encKey);
}).$promise;
var reencryptedFolders = [];
var foldersPromise = apiService.folders.list({}, function (encryptedFolders) {
var unencryptedFolders = _service.decryptFolders(encryptedFolders.Data);
reencryptedFolders = _service.encryptFolders(unencryptedFolders, encKey);
}).$promise;
var privateKey = cryptoService.getPrivateKey('raw'),
reencryptedPrivateKey = null;
if (privateKey) {
reencryptedPrivateKey = cryptoService.encrypt(privateKey, encKey, 'raw');
}
return $q.all([loginsPromise, foldersPromise]).then(function () {
var request = {
masterPasswordHash: masterPasswordHash,
ciphers: reencryptedLogins,
folders: reencryptedFolders,
privateKey: reencryptedPrivateKey,
key: encKeyEnc
};
return apiService.accounts.putKey(request).$promise;
}, error).then(function () {
cryptoService.setEncKey(encKey, null, true);
return success();
}, function () {
cryptoService.clearEncKey();
error();
});
};
return _service;
});