mirror of
https://github.com/bitwarden/web
synced 2025-12-10 21:33:16 +00:00
send service implementation (#708)
* send service implementation * update jslib
This commit is contained in:
2
jslib
2
jslib
Submodule jslib updated: 79b856cb6e...6563dccf3b
@@ -11,26 +11,19 @@ import { Component } from '@angular/core';
|
|||||||
import { SendType } from 'jslib/enums/sendType';
|
import { SendType } from 'jslib/enums/sendType';
|
||||||
|
|
||||||
import { ApiService } from 'jslib/abstractions/api.service';
|
import { ApiService } from 'jslib/abstractions/api.service';
|
||||||
import { CryptoService } from 'jslib/abstractions/crypto.service';
|
|
||||||
import { CryptoFunctionService } from 'jslib/abstractions/cryptoFunction.service';
|
|
||||||
import { EnvironmentService } from 'jslib/abstractions/environment.service';
|
import { EnvironmentService } from 'jslib/abstractions/environment.service';
|
||||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||||
|
import { SendService } from 'jslib/abstractions/send.service';
|
||||||
|
|
||||||
import { SendView } from 'jslib/models/view/sendView';
|
import { SendView } from 'jslib/models/view/sendView';
|
||||||
import { SendFileView } from 'jslib/models/view/sendFileView';
|
import { SendFileView } from 'jslib/models/view/sendFileView';
|
||||||
import { SendTextView } from 'jslib/models/view/sendTextView';
|
import { SendTextView } from 'jslib/models/view/sendTextView';
|
||||||
|
|
||||||
import { Send } from 'jslib/models/domain/send';
|
import { Send } from 'jslib/models/domain/send';
|
||||||
import { SendFile } from 'jslib/models/domain/sendFile';
|
|
||||||
import { SendText } from 'jslib/models/domain/sendText';
|
|
||||||
|
|
||||||
import { SendData } from 'jslib/models/data/sendData';
|
import { SendData } from 'jslib/models/data/sendData';
|
||||||
|
|
||||||
import { SendRequest } from 'jslib/models/request/sendRequest';
|
|
||||||
|
|
||||||
import { Utils } from 'jslib/misc/utils';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-send-add-edit',
|
selector: 'app-send-add-edit',
|
||||||
templateUrl: 'add-edit.component.html',
|
templateUrl: 'add-edit.component.html',
|
||||||
@@ -57,9 +50,8 @@ export class AddEditComponent {
|
|||||||
typeOptions: any[];
|
typeOptions: any[];
|
||||||
|
|
||||||
constructor(private i18nService: I18nService, private platformUtilsService: PlatformUtilsService,
|
constructor(private i18nService: I18nService, private platformUtilsService: PlatformUtilsService,
|
||||||
private apiService: ApiService, private cryptoService: CryptoService,
|
private apiService: ApiService, private environmentService: EnvironmentService,
|
||||||
private cryptoFunctionService: CryptoFunctionService, private environmentService: EnvironmentService,
|
private datePipe: DatePipe, private sendService: SendService) {
|
||||||
private datePipe: DatePipe) {
|
|
||||||
this.typeOptions = [
|
this.typeOptions = [
|
||||||
{ name: i18nService.t('sendTypeFile'), value: SendType.File },
|
{ name: i18nService.t('sendTypeFile'), value: SendType.File },
|
||||||
{ name: i18nService.t('sendTypeText'), value: SendType.Text },
|
{ name: i18nService.t('sendTypeText'), value: SendType.Text },
|
||||||
@@ -137,7 +129,7 @@ export class AddEditComponent {
|
|||||||
|
|
||||||
const encSend = await this.encryptSend(file);
|
const encSend = await this.encryptSend(file);
|
||||||
try {
|
try {
|
||||||
this.formPromise = this.saveSend(encSend);
|
this.formPromise = this.sendService.saveWithServer(encSend);
|
||||||
await this.formPromise;
|
await this.formPromise;
|
||||||
this.send.id = encSend[0].id;
|
this.send.id = encSend[0].id;
|
||||||
this.platformUtilsService.showToast('success', null,
|
this.platformUtilsService.showToast('success', null,
|
||||||
@@ -181,96 +173,20 @@ export class AddEditComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected async encryptSend(file: File): Promise<[Send, ArrayBuffer]> {
|
protected async encryptSend(file: File): Promise<[Send, ArrayBuffer]> {
|
||||||
let fileData: ArrayBuffer = null;
|
const sendData = await this.sendService.encrypt(this.send, file, this.password, null);
|
||||||
const send = new Send();
|
|
||||||
send.id = this.send.id;
|
|
||||||
send.type = this.send.type;
|
|
||||||
send.disabled = this.send.disabled;
|
|
||||||
send.maxAccessCount = this.send.maxAccessCount;
|
|
||||||
if (this.send.key == null) {
|
|
||||||
this.send.key = await this.cryptoFunctionService.randomBytes(16);
|
|
||||||
this.send.cryptoKey = await this.cryptoService.makeSendKey(this.send.key);
|
|
||||||
}
|
|
||||||
if (this.password != null) {
|
|
||||||
const passwordHash = await this.cryptoFunctionService.pbkdf2(this.password,
|
|
||||||
this.send.key, 'sha256', 100000);
|
|
||||||
send.password = Utils.fromBufferToB64(passwordHash);
|
|
||||||
}
|
|
||||||
send.key = await this.cryptoService.encrypt(this.send.key, null);
|
|
||||||
send.name = await this.cryptoService.encrypt(this.send.name, this.send.cryptoKey);
|
|
||||||
send.notes = await this.cryptoService.encrypt(this.send.notes, this.send.cryptoKey);
|
|
||||||
if (send.type === SendType.Text) {
|
|
||||||
send.text = new SendText();
|
|
||||||
send.text.text = await this.cryptoService.encrypt(this.send.text.text, this.send.cryptoKey);
|
|
||||||
send.text.hidden = this.send.text.hidden;
|
|
||||||
} else if (send.type === SendType.File) {
|
|
||||||
send.file = new SendFile();
|
|
||||||
if (file != null) {
|
|
||||||
fileData = await this.parseFile(send, file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse dates
|
// Parse dates
|
||||||
try {
|
try {
|
||||||
send.deletionDate = this.deletionDate == null ? null : new Date(this.deletionDate);
|
sendData[0].deletionDate = this.deletionDate == null ? null : new Date(this.deletionDate);
|
||||||
} catch {
|
} catch {
|
||||||
send.deletionDate = null;
|
sendData[0].deletionDate = null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
send.expirationDate = this.expirationDate == null ? null : new Date(this.expirationDate);
|
sendData[0].expirationDate = this.expirationDate == null ? null : new Date(this.expirationDate);
|
||||||
} catch {
|
} catch {
|
||||||
send.expirationDate = null;
|
sendData[0].expirationDate = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return [send, fileData];
|
return sendData;
|
||||||
}
|
|
||||||
|
|
||||||
protected async saveSend(sendData: [Send, ArrayBuffer]) {
|
|
||||||
const request = new SendRequest(sendData[0]);
|
|
||||||
if (sendData[0].id == null) {
|
|
||||||
if (sendData[0].type === SendType.Text) {
|
|
||||||
await this.apiService.postSend(request);
|
|
||||||
} else {
|
|
||||||
const fd = new FormData();
|
|
||||||
try {
|
|
||||||
const blob = new Blob([sendData[1]], { type: 'application/octet-stream' });
|
|
||||||
fd.append('model', JSON.stringify(request));
|
|
||||||
fd.append('data', blob, sendData[0].file.fileName.encryptedString);
|
|
||||||
} catch (e) {
|
|
||||||
if (Utils.isNode && !Utils.isBrowser) {
|
|
||||||
fd.append('model', JSON.stringify(request));
|
|
||||||
fd.append('data', Buffer.from(sendData[1]) as any, {
|
|
||||||
filepath: sendData[0].file.fileName.encryptedString,
|
|
||||||
contentType: 'application/octet-stream',
|
|
||||||
} as any);
|
|
||||||
} else {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await this.apiService.postSendFile(fd);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
await this.apiService.putSend(sendData[0].id, request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private parseFile(send: Send, file: File): Promise<ArrayBuffer> {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.readAsArrayBuffer(file);
|
|
||||||
reader.onload = async (evt) => {
|
|
||||||
try {
|
|
||||||
send.file.fileName = await this.cryptoService.encrypt(file.name, this.send.cryptoKey);
|
|
||||||
const fileData = await this.cryptoService.encryptToBytes(evt.target.result as ArrayBuffer,
|
|
||||||
this.send.cryptoKey);
|
|
||||||
resolve(fileData);
|
|
||||||
} catch (e) {
|
|
||||||
reject(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
reader.onerror = (evt) => {
|
|
||||||
reject('Error reading file.');
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,11 +18,7 @@ import { ApiService } from 'jslib/abstractions/api.service';
|
|||||||
import { EnvironmentService } from 'jslib/abstractions/environment.service';
|
import { EnvironmentService } from 'jslib/abstractions/environment.service';
|
||||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||||
import { UserService } from 'jslib/abstractions/user.service';
|
import { SendService } from 'jslib/abstractions/send.service';
|
||||||
|
|
||||||
import { SendData } from 'jslib/models/data/sendData';
|
|
||||||
|
|
||||||
import { Send } from 'jslib/models/domain/send';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-send',
|
selector: 'app-send',
|
||||||
@@ -51,7 +47,7 @@ export class SendComponent implements OnInit {
|
|||||||
|
|
||||||
private searchTimeout: any;
|
private searchTimeout: any;
|
||||||
|
|
||||||
constructor(private apiService: ApiService, private userService: UserService,
|
constructor(private apiService: ApiService, private sendService: SendService,
|
||||||
private i18nService: I18nService, private componentFactoryResolver: ComponentFactoryResolver,
|
private i18nService: I18nService, private componentFactoryResolver: ComponentFactoryResolver,
|
||||||
private platformUtilsService: PlatformUtilsService, private environmentService: EnvironmentService) { }
|
private platformUtilsService: PlatformUtilsService, private environmentService: EnvironmentService) { }
|
||||||
|
|
||||||
@@ -60,18 +56,8 @@ export class SendComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
async load(filter: (send: SendView) => boolean = null) {
|
async load(filter: (send: SendView) => boolean = null) {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
const userId = await this.userService.getUserId();
|
const sends = await this.sendService.getAllDecrypted();
|
||||||
const sends = await this.apiService.getSends();
|
this.sends = sends;
|
||||||
const sendsArr: SendView[] = [];
|
|
||||||
if (sends != null && sends.data != null) {
|
|
||||||
for (const res of sends.data) {
|
|
||||||
const data = new SendData(res, userId);
|
|
||||||
const send = new Send(data);
|
|
||||||
const view = await send.decrypt();
|
|
||||||
sendsArr.push(view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.sends = sendsArr;
|
|
||||||
this.selectAll();
|
this.selectAll();
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
this.loaded = true;
|
this.loaded = true;
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ import { NotificationsService } from 'jslib/services/notifications.service';
|
|||||||
import { PasswordGenerationService } from 'jslib/services/passwordGeneration.service';
|
import { PasswordGenerationService } from 'jslib/services/passwordGeneration.service';
|
||||||
import { PolicyService } from 'jslib/services/policy.service';
|
import { PolicyService } from 'jslib/services/policy.service';
|
||||||
import { SearchService } from 'jslib/services/search.service';
|
import { SearchService } from 'jslib/services/search.service';
|
||||||
|
import { SendService } from 'jslib/services/send.service';
|
||||||
import { SettingsService } from 'jslib/services/settings.service';
|
import { SettingsService } from 'jslib/services/settings.service';
|
||||||
import { StateService } from 'jslib/services/state.service';
|
import { StateService } from 'jslib/services/state.service';
|
||||||
import { SyncService } from 'jslib/services/sync.service';
|
import { SyncService } from 'jslib/services/sync.service';
|
||||||
@@ -74,6 +75,7 @@ import {
|
|||||||
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from 'jslib/abstractions/platformUtils.service';
|
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from 'jslib/abstractions/platformUtils.service';
|
||||||
import { PolicyService as PolicyServiceAbstraction } from 'jslib/abstractions/policy.service';
|
import { PolicyService as PolicyServiceAbstraction } from 'jslib/abstractions/policy.service';
|
||||||
import { SearchService as SearchServiceAbstraction } from 'jslib/abstractions/search.service';
|
import { SearchService as SearchServiceAbstraction } from 'jslib/abstractions/search.service';
|
||||||
|
import { SendService as SendServiceAbstraction } from 'jslib/abstractions/send.service';
|
||||||
import { SettingsService as SettingsServiceAbstraction } from 'jslib/abstractions/settings.service';
|
import { SettingsService as SettingsServiceAbstraction } from 'jslib/abstractions/settings.service';
|
||||||
import { StateService as StateServiceAbstraction } from 'jslib/abstractions/state.service';
|
import { StateService as StateServiceAbstraction } from 'jslib/abstractions/state.service';
|
||||||
import { StorageService as StorageServiceAbstraction } from 'jslib/abstractions/storage.service';
|
import { StorageService as StorageServiceAbstraction } from 'jslib/abstractions/storage.service';
|
||||||
@@ -108,12 +110,14 @@ const folderService = new FolderService(cryptoService, userService, apiService,
|
|||||||
const collectionService = new CollectionService(cryptoService, userService, storageService, i18nService);
|
const collectionService = new CollectionService(cryptoService, userService, storageService, i18nService);
|
||||||
searchService = new SearchService(cipherService);
|
searchService = new SearchService(cipherService);
|
||||||
const policyService = new PolicyService(userService, storageService);
|
const policyService = new PolicyService(userService, storageService);
|
||||||
|
const sendService = new SendService(cryptoService, userService, apiService, storageService,
|
||||||
|
i18nService, cryptoFunctionService);
|
||||||
const vaultTimeoutService = new VaultTimeoutService(cipherService, folderService, collectionService,
|
const vaultTimeoutService = new VaultTimeoutService(cipherService, folderService, collectionService,
|
||||||
cryptoService, platformUtilsService, storageService, messagingService, searchService, userService, tokenService,
|
cryptoService, platformUtilsService, storageService, messagingService, searchService, userService, tokenService,
|
||||||
null, async () => messagingService.send('logout', { expired: false }));
|
null, async () => messagingService.send('logout', { expired: false }));
|
||||||
const syncService = new SyncService(userService, apiService, settingsService,
|
const syncService = new SyncService(userService, apiService, settingsService,
|
||||||
folderService, cipherService, cryptoService, collectionService, storageService, messagingService, policyService,
|
folderService, cipherService, cryptoService, collectionService, storageService, messagingService, policyService,
|
||||||
async (expired: boolean) => messagingService.send('logout', { expired: expired }));
|
sendService, async (expired: boolean) => messagingService.send('logout', { expired: expired }));
|
||||||
const passwordGenerationService = new PasswordGenerationService(cryptoService, storageService, policyService);
|
const passwordGenerationService = new PasswordGenerationService(cryptoService, storageService, policyService);
|
||||||
const totpService = new TotpService(storageService, cryptoFunctionService);
|
const totpService = new TotpService(storageService, cryptoFunctionService);
|
||||||
const containerService = new ContainerService(cryptoService);
|
const containerService = new ContainerService(cryptoService);
|
||||||
@@ -218,6 +222,7 @@ export function initFactory(): Function {
|
|||||||
{ provide: CryptoFunctionServiceAbstraction, useValue: cryptoFunctionService },
|
{ provide: CryptoFunctionServiceAbstraction, useValue: cryptoFunctionService },
|
||||||
{ provide: EventLoggingServiceAbstraction, useValue: eventLoggingService },
|
{ provide: EventLoggingServiceAbstraction, useValue: eventLoggingService },
|
||||||
{ provide: PolicyServiceAbstraction, useValue: policyService },
|
{ provide: PolicyServiceAbstraction, useValue: policyService },
|
||||||
|
{ provide: SendServiceAbstraction, useValue: sendService },
|
||||||
{
|
{
|
||||||
provide: APP_INITIALIZER,
|
provide: APP_INITIALIZER,
|
||||||
useFactory: initFactory,
|
useFactory: initFactory,
|
||||||
|
|||||||
Reference in New Issue
Block a user