1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-16 16:23:44 +00:00

support for new attachment keys

This commit is contained in:
Kyle Spearrin
2018-11-13 20:43:45 -05:00
parent c297728967
commit 17e7ee4838
10 changed files with 73 additions and 10 deletions

View File

@@ -143,7 +143,8 @@ export class AttachmentsComponent implements OnInit {
try { try {
const buf = await response.arrayBuffer(); const buf = await response.arrayBuffer();
const key = await this.cryptoService.getOrgKey(this.cipher.organizationId); const key = attachment.key != null ? attachment.key :
await this.cryptoService.getOrgKey(this.cipher.organizationId);
const decBuf = await this.cryptoService.decryptFromBytes(buf, key); const decBuf = await this.cryptoService.decryptFromBytes(buf, key);
this.platformUtilsService.saveFile(this.win, decBuf, null, attachment.fileName); this.platformUtilsService.saveFile(this.win, decBuf, null, attachment.fileName);
} catch (e) { } catch (e) {

View File

@@ -171,7 +171,8 @@ export class ViewComponent implements OnDestroy, OnInit {
try { try {
const buf = await response.arrayBuffer(); const buf = await response.arrayBuffer();
const key = await this.cryptoService.getOrgKey(this.cipher.organizationId); const key = attachment.key != null ? attachment.key :
await this.cryptoService.getOrgKey(this.cipher.organizationId);
const decBuf = await this.cryptoService.decryptFromBytes(buf, key); const decBuf = await this.cryptoService.decryptFromBytes(buf, key);
this.platformUtilsService.saveFile(this.win, decBuf, null, attachment.fileName); this.platformUtilsService.saveFile(this.win, decBuf, null, attachment.fileName);
} catch (e) { } catch (e) {

View File

@@ -4,6 +4,7 @@ export class AttachmentData {
id: string; id: string;
url: string; url: string;
fileName: string; fileName: string;
key: string;
size: number; size: number;
sizeName: string; sizeName: string;
@@ -14,6 +15,7 @@ export class AttachmentData {
this.id = response.id; this.id = response.id;
this.url = response.url; this.url = response.url;
this.fileName = response.fileName; this.fileName = response.fileName;
this.key = response.key;
this.size = response.size; this.size = response.size;
this.sizeName = response.sizeName; this.sizeName = response.sizeName;
} }

View File

@@ -1,15 +1,21 @@
import { AttachmentData } from '../data/attachmentData'; import { AttachmentData } from '../data/attachmentData';
import { AttachmentView } from '../view/attachmentView';
import { CipherString } from './cipherString'; import { CipherString } from './cipherString';
import Domain from './domainBase'; import Domain from './domainBase';
import { SymmetricCryptoKey } from './symmetricCryptoKey';
import { AttachmentView } from '../view/attachmentView'; import { CryptoService } from '../../abstractions/crypto.service';
import { Utils } from '../../misc/utils';
export class Attachment extends Domain { export class Attachment extends Domain {
id: string; id: string;
url: string; url: string;
size: number; size: number;
sizeName: string; sizeName: string;
key: CipherString;
fileName: CipherString; fileName: CipherString;
constructor(obj?: AttachmentData, alreadyEncrypted: boolean = false) { constructor(obj?: AttachmentData, alreadyEncrypted: boolean = false) {
@@ -24,13 +30,34 @@ export class Attachment extends Domain {
url: null, url: null,
sizeName: null, sizeName: null,
fileName: null, fileName: null,
key: null,
}, alreadyEncrypted, ['id', 'url', 'sizeName']); }, alreadyEncrypted, ['id', 'url', 'sizeName']);
} }
decrypt(orgId: string): Promise<AttachmentView> { async decrypt(orgId: string): Promise<AttachmentView> {
return this.decryptObj(new AttachmentView(this), { const view = await this.decryptObj(new AttachmentView(this), {
fileName: null, fileName: null,
}, orgId); }, orgId);
if (this.key != null) {
let cryptoService: CryptoService;
const containerService = (Utils.global as any).bitwardenContainerService;
if (containerService) {
cryptoService = containerService.getCryptoService();
} else {
throw new Error('global bitwardenContainerService not initialized.');
}
try {
const orgKey = await cryptoService.getOrgKey(orgId);
const decValue = await cryptoService.decryptToBytes(this.key, orgKey);
view.key = new SymmetricCryptoKey(decValue);
} catch (e) {
// TODO: error?
}
}
return view;
} }
toAttachmentData(): AttachmentData { toAttachmentData(): AttachmentData {
@@ -40,6 +67,7 @@ export class Attachment extends Domain {
url: null, url: null,
sizeName: null, sizeName: null,
fileName: null, fileName: null,
key: null,
}, ['id', 'url', 'sizeName']); }, ['id', 'url', 'sizeName']);
return a; return a;
} }

View File

@@ -0,0 +1,4 @@
export class AttachmentRequest {
fileName: string;
key: string;
}

View File

@@ -8,6 +8,7 @@ import { IdentityApi } from '../api/identityApi';
import { LoginApi } from '../api/loginApi'; import { LoginApi } from '../api/loginApi';
import { SecureNoteApi } from '../api/secureNoteApi'; import { SecureNoteApi } from '../api/secureNoteApi';
import { AttachmentRequest } from './attachmentRequest';
import { PasswordHistoryRequest } from './passwordHistoryRequest'; import { PasswordHistoryRequest } from './passwordHistoryRequest';
export class CipherRequest { export class CipherRequest {
@@ -23,7 +24,9 @@ export class CipherRequest {
identity: IdentityApi; identity: IdentityApi;
fields: FieldApi[]; fields: FieldApi[];
passwordHistory: PasswordHistoryRequest[]; passwordHistory: PasswordHistoryRequest[];
// Deprecated, remove at some point and rename attachments2 to attachments
attachments: { [id: string]: string; }; attachments: { [id: string]: string; };
attachments2: { [id: string]: AttachmentRequest; };
constructor(cipher: Cipher) { constructor(cipher: Cipher) {
this.type = cipher.type; this.type = cipher.type;
@@ -119,8 +122,16 @@ export class CipherRequest {
if (cipher.attachments) { if (cipher.attachments) {
this.attachments = {}; this.attachments = {};
this.attachments2 = {};
cipher.attachments.forEach((attachment) => { cipher.attachments.forEach((attachment) => {
this.attachments[attachment.id] = attachment.fileName ? attachment.fileName.encryptedString : null; const fileName = attachment.fileName ? attachment.fileName.encryptedString : null;
this.attachments[attachment.id] = fileName;
const attachmentRequest = new AttachmentRequest();
attachmentRequest.fileName = fileName;
if (attachment.key != null) {
attachmentRequest.key = attachment.key.encryptedString;
}
this.attachments2[attachment.id] = attachmentRequest;
}); });
} }
} }

View File

@@ -2,6 +2,7 @@ export class AttachmentResponse {
id: string; id: string;
url: string; url: string;
fileName: string; fileName: string;
key: string;
size: number; size: number;
sizeName: string; sizeName: string;
@@ -9,6 +10,7 @@ export class AttachmentResponse {
this.id = response.Id; this.id = response.Id;
this.url = response.Url; this.url = response.Url;
this.fileName = response.FileName; this.fileName = response.FileName;
this.key = response.Key;
this.size = response.Size; this.size = response.Size;
this.sizeName = response.SizeName; this.sizeName = response.SizeName;
} }

View File

@@ -1,6 +1,7 @@
import { View } from './view'; import { View } from './view';
import { Attachment } from '../domain/attachment'; import { Attachment } from '../domain/attachment';
import { SymmetricCryptoKey } from '../domain/symmetricCryptoKey';
export class AttachmentView implements View { export class AttachmentView implements View {
id: string; id: string;
@@ -8,6 +9,7 @@ export class AttachmentView implements View {
size: number; size: number;
sizeName: string; sizeName: string;
fileName: string; fileName: string;
key: SymmetricCryptoKey;
constructor(a?: Attachment) { constructor(a?: Attachment) {
if (!a) { if (!a) {

View File

@@ -173,7 +173,10 @@ export class CipherService implements CipherServiceAbstraction {
attachment.url = model.url; attachment.url = model.url;
const promise = this.encryptObjProperty(model, attachment, { const promise = this.encryptObjProperty(model, attachment, {
fileName: null, fileName: null,
}, key).then(() => { }, key).then(async () => {
if (model.key != null) {
attachment.key = await this.cryptoService.encrypt(model.key.key, key);
}
encAttachments.push(attachment); encAttachments.push(attachment);
}); });
promises.push(promise); promises.push(promise);
@@ -519,14 +522,18 @@ export class CipherService implements CipherServiceAbstraction {
data: ArrayBuffer, admin = false): Promise<Cipher> { data: ArrayBuffer, admin = false): Promise<Cipher> {
const key = await this.cryptoService.getOrgKey(cipher.organizationId); const key = await this.cryptoService.getOrgKey(cipher.organizationId);
const encFileName = await this.cryptoService.encrypt(filename, key); const encFileName = await this.cryptoService.encrypt(filename, key);
const encData = await this.cryptoService.encryptToBytes(data, key);
const dataEncKey = await this.cryptoService.makeEncKey(key);
const encData = await this.cryptoService.encryptToBytes(data, dataEncKey[0]);
const fd = new FormData(); const fd = new FormData();
try { try {
fd.append('key', dataEncKey[1].encryptedString);
const blob = new Blob([encData], { type: 'application/octet-stream' }); const blob = new Blob([encData], { type: 'application/octet-stream' });
fd.append('data', blob, encFileName.encryptedString); fd.append('data', blob, encFileName.encryptedString);
} catch (e) { } catch (e) {
if (Utils.isNode && !Utils.isBrowser) { if (Utils.isNode && !Utils.isBrowser) {
fd.append('key', dataEncKey[1].encryptedString);
fd.append('data', Buffer.from(encData) as any, { fd.append('data', Buffer.from(encData) as any, {
filepath: encFileName.encryptedString, filepath: encFileName.encryptedString,
contentType: 'application/octet-stream', contentType: 'application/octet-stream',
@@ -753,15 +760,19 @@ export class CipherService implements CipherServiceAbstraction {
const buf = await attachmentResponse.arrayBuffer(); const buf = await attachmentResponse.arrayBuffer();
const decBuf = await this.cryptoService.decryptFromBytes(buf, null); const decBuf = await this.cryptoService.decryptFromBytes(buf, null);
const key = await this.cryptoService.getOrgKey(organizationId); const key = await this.cryptoService.getOrgKey(organizationId);
const encData = await this.cryptoService.encryptToBytes(decBuf, key);
const encFileName = await this.cryptoService.encrypt(attachmentView.fileName, key); const encFileName = await this.cryptoService.encrypt(attachmentView.fileName, key);
const dataEncKey = await this.cryptoService.makeEncKey(key);
const encData = await this.cryptoService.encryptToBytes(decBuf, dataEncKey[0]);
const fd = new FormData(); const fd = new FormData();
try { try {
fd.append('key', dataEncKey[1].encryptedString);
const blob = new Blob([encData], { type: 'application/octet-stream' }); const blob = new Blob([encData], { type: 'application/octet-stream' });
fd.append('data', blob, encFileName.encryptedString); fd.append('data', blob, encFileName.encryptedString);
} catch (e) { } catch (e) {
if (Utils.isNode && !Utils.isBrowser) { if (Utils.isNode && !Utils.isBrowser) {
fd.append('key', dataEncKey[1].encryptedString);
fd.append('data', Buffer.from(encData) as any, { fd.append('data', Buffer.from(encData) as any, {
filepath: encFileName.encryptedString, filepath: encFileName.encryptedString,
contentType: 'application/octet-stream', contentType: 'application/octet-stream',

View File

@@ -333,8 +333,9 @@ export class CryptoService implements CryptoServiceAbstraction {
} }
async makeEncKey(key: SymmetricCryptoKey): Promise<[SymmetricCryptoKey, CipherString]> { async makeEncKey(key: SymmetricCryptoKey): Promise<[SymmetricCryptoKey, CipherString]> {
const theKey = await this.getKeyForEncryption(key);
const encKey = await this.cryptoFunctionService.randomBytes(64); const encKey = await this.cryptoFunctionService.randomBytes(64);
return this.buildEncKey(key, encKey); return this.buildEncKey(theKey, encKey);
} }
async remakeEncKey(key: SymmetricCryptoKey): Promise<[SymmetricCryptoKey, CipherString]> { async remakeEncKey(key: SymmetricCryptoKey): Promise<[SymmetricCryptoKey, CipherString]> {