1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-11-08 09:43:42 +01:00

raw attachment saves with node form data

This commit is contained in:
Kyle Spearrin 2018-05-17 15:35:02 -04:00
parent ed89dfaba7
commit a421f6e64a
5 changed files with 56 additions and 33 deletions

21
package-lock.json generated
View File

@ -84,6 +84,15 @@
"tslib": "1.9.0" "tslib": "1.9.0"
} }
}, },
"@types/form-data": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-2.2.1.tgz",
"integrity": "sha512-JAMFhOaHIciYVh8fb5/83nmuO/AHwmto+Hq7a9y8FzLDcC1KCU344XDOMEmahnrTFlHjgh4L0WJFczNIX2GxnQ==",
"dev": true,
"requires": {
"@types/node": "8.0.19"
}
},
"@types/jasmine": { "@types/jasmine": {
"version": "2.8.6", "version": "2.8.6",
"resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.8.6.tgz", "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.8.6.tgz",
@ -383,8 +392,7 @@
"asynckit": { "asynckit": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
"dev": true
}, },
"atob": { "atob": {
"version": "2.1.0", "version": "2.1.0",
@ -1249,7 +1257,6 @@
"version": "1.0.6", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
"integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
"dev": true,
"requires": { "requires": {
"delayed-stream": "1.0.0" "delayed-stream": "1.0.0"
} }
@ -1759,8 +1766,7 @@
"delayed-stream": { "delayed-stream": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
"dev": true
}, },
"depd": { "depd": {
"version": "1.1.2", "version": "1.1.2",
@ -2575,7 +2581,6 @@
"version": "2.3.2", "version": "2.3.2",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz",
"integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=",
"dev": true,
"requires": { "requires": {
"asynckit": "0.4.0", "asynckit": "0.4.0",
"combined-stream": "1.0.6", "combined-stream": "1.0.6",
@ -5642,14 +5647,12 @@
"mime-db": { "mime-db": {
"version": "1.33.0", "version": "1.33.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz",
"integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ=="
"dev": true
}, },
"mime-types": { "mime-types": {
"version": "2.1.18", "version": "2.1.18",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz",
"integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==",
"dev": true,
"requires": { "requires": {
"mime-db": "1.33.0" "mime-db": "1.33.0"
} }

View File

@ -24,6 +24,7 @@
"test:node:watch": "concurrently -k -n TSC,Node -c yellow,cyan \"npm run build:watch\" \"nodemon -w ./dist --delay 500ms --exec jasmine\"" "test:node:watch": "concurrently -k -n TSC,Node -c yellow,cyan \"npm run build:watch\" \"nodemon -w ./dist --delay 500ms --exec jasmine\""
}, },
"devDependencies": { "devDependencies": {
"@types/form-data": "^2.2.1",
"@types/jasmine": "^2.8.2", "@types/jasmine": "^2.8.2",
"@types/keytar": "^4.0.1", "@types/keytar": "^4.0.1",
"@types/lunr": "2.1.5", "@types/lunr": "2.1.5",
@ -72,6 +73,7 @@
"electron-log": "2.2.14", "electron-log": "2.2.14",
"electron-store": "1.3.0", "electron-store": "1.3.0",
"electron-updater": "2.21.4", "electron-updater": "2.21.4",
"form-data": "2.3.2",
"keytar": "4.1.0", "keytar": "4.1.0",
"lunr": "2.1.6", "lunr": "2.1.6",
"node-fetch": "2.1.2", "node-fetch": "2.1.2",

View File

@ -25,7 +25,8 @@ export abstract class CipherService {
updateLastUsedDate: (id: string) => Promise<void>; updateLastUsedDate: (id: string) => Promise<void>;
saveNeverDomain: (domain: string) => Promise<void>; saveNeverDomain: (domain: string) => Promise<void>;
saveWithServer: (cipher: Cipher) => Promise<any>; saveWithServer: (cipher: Cipher) => Promise<any>;
saveAttachmentWithServer: (cipher: Cipher, unencryptedFile: any) => Promise<any>; saveAttachmentWithServer: (cipher: Cipher, unencryptedFile: any) => Promise<Cipher>;
saveAttachmentRawWithServer: (cipher: Cipher, filename: string, data: ArrayBuffer) => Promise<Cipher>;
upsert: (cipher: CipherData | CipherData[]) => Promise<any>; upsert: (cipher: CipherData | CipherData[]) => Promise<any>;
replace: (ciphers: { [id: string]: CipherData; }) => Promise<any>; replace: (ciphers: { [id: string]: CipherData; }) => Promise<any>;
clear: (userId: string) => Promise<any>; clear: (userId: string) => Promise<any>;

View File

@ -322,43 +322,58 @@ export class CipherService implements CipherServiceAbstraction {
await this.upsert(data); await this.upsert(data);
} }
saveAttachmentWithServer(cipher: Cipher, unencryptedFile: any): Promise<any> { saveAttachmentWithServer(cipher: Cipher, unencryptedFile: any): Promise<Cipher> {
const self = this;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const reader = new FileReader(); const reader = new FileReader();
reader.readAsArrayBuffer(unencryptedFile); reader.readAsArrayBuffer(unencryptedFile);
reader.onload = async (evt: any) => { reader.onload = async (evt: any) => {
const key = await self.cryptoService.getOrgKey(cipher.organizationId);
const encFileName = await self.cryptoService.encrypt(unencryptedFile.name, key);
const encData = await self.cryptoService.encryptToBytes(evt.target.result, key);
const fd = new FormData();
const blob = new Blob([encData], { type: 'application/octet-stream' });
fd.append('data', blob, encFileName.encryptedString);
let response: CipherResponse;
try { try {
response = await self.apiService.postCipherAttachment(cipher.id, fd); const cData = await this.saveAttachmentRawWithServer(cipher,
unencryptedFile.name, evt.target.result);
resolve(cData);
} catch (e) { } catch (e) {
reject((e as ErrorResponse).getSingleMessage()); reject(e);
return;
} }
const userId = await self.userService.getUserId();
const data = new CipherData(response, userId, cipher.collectionIds);
this.upsert(data);
resolve(new Cipher(data));
}; };
reader.onerror = (evt) => { reader.onerror = (evt) => {
reject('Error reading file.'); reject('Error reading file.');
}; };
}); });
} }
async saveAttachmentRawWithServer(cipher: Cipher, filename: string, data: ArrayBuffer): Promise<Cipher> {
const key = await this.cryptoService.getOrgKey(cipher.organizationId);
const encFileName = await this.cryptoService.encrypt(filename, key);
const encData = await this.cryptoService.encryptToBytes(data, key);
const fd = new FormData();
try {
const blob = new Blob([encData], { type: 'application/octet-stream' });
fd.append('data', blob, encFileName.encryptedString);
} catch (e) {
if (Utils.isNode) {
fd.append('data', new Buffer(encData) as any, {
filename: encFileName.encryptedString,
contentType: 'application/octet-stream',
} as any);
} else {
throw e;
}
}
let response: CipherResponse;
try {
response = await this.apiService.postCipherAttachment(cipher.id, fd);
} catch (e) {
throw new Error((e as ErrorResponse).getSingleMessage());
}
const userId = await this.userService.getUserId();
const cData = new CipherData(response, userId, cipher.collectionIds);
this.upsert(cData);
return new Cipher(cData);
}
async upsert(cipher: CipherData | CipherData[]): Promise<any> { async upsert(cipher: CipherData | CipherData[]): Promise<any> {
const userId = await this.userService.getUserId(); const userId = await this.userService.getUserId();
let ciphers = await this.storageService.get<{ [id: string]: CipherData; }>( let ciphers = await this.storageService.get<{ [id: string]: CipherData; }>(

View File

@ -1,3 +1,4 @@
import * as FormData from 'form-data';
import * as fe from 'node-fetch'; import * as fe from 'node-fetch';
import { ApiService } from './api.service'; import { ApiService } from './api.service';
@ -9,6 +10,7 @@ import { TokenService } from '../abstractions/token.service';
(global as any).Request = fe.Request; (global as any).Request = fe.Request;
(global as any).Response = fe.Response; (global as any).Response = fe.Response;
(global as any).Headers = fe.Headers; (global as any).Headers = fe.Headers;
(global as any).FormData = FormData;
export class NodeApiService extends ApiService { export class NodeApiService extends ApiService {
constructor(tokenService: TokenService, platformUtilsService: PlatformUtilsService, constructor(tokenService: TokenService, platformUtilsService: PlatformUtilsService,