1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-06-27 10:46:02 +02:00

[SG 623] Send Service Refactor (#4327)

* Split out api methods into sendApiService

* Move SendService and abstraction

* Libs updates

* Web updates

* CLI updates

* Desktop updates

* libs send service fixes

* browser factory additions

* Browser updates

* Fix service injection for CLI SendReceiveCommand

* Deprecate directly calling send state service methods

* SendService observables updates

* Update components to use new observables

* Modify CLI to use state service instead of observables

* Remove unnecessary await on get()

* Move delete() to InternalSendService

* SendService unit tests

* Split fileUploadService by send and cipher

* send and cipher service factory updates

* Add file upload methods to get around circular dependency issues

* Move api methods from sendService to sendApiService

* Update cipherService to use fileApi methods

* libs service injection and component changes

* browser service injection and component changes

* Desktop component changes

* Web component changes

* cipher service test fix

* Fix file capitalization

* CLI service import and command updates

* Remove extra abstract fileUploadService

* WIP: Condense callbacks for file upload

Co-authored-by: Robyn MacCallum <robyntmaccallum@gmail.com>

* Send callbacks for file upload

* Fix circular service dependencies

* Fix response return on upload

* Fix function definitions

* Service injection fixes and bug fixes

* Fix folder casing

* Service injection cleanup

* Remove deleted file from capital letters whitelist

* Create new SendApiService for popup

* Move cipherFileUploadService to vault

* Move SendFileUploadService methods into SendApiService

* Rename methods to remove 'WithServer'

* Properly subscribe to sendViews

* Fix Send serialization

* Implement fromJSON on sendFile and sendText

* [PM-1347] Fix send key serialization (#4989)

* Properly serialize key on send fromJSON

* Remove call that nulled out decrypted sends

* Fix null checks in fromJSON methods for models

* lint fixes

---------

Co-authored-by: Matt Gibson <mgibson@bitwarden.com>
This commit is contained in:
Robyn MacCallum 2023-03-28 12:37:40 -04:00 committed by GitHub
parent c2bfb2497b
commit d799529428
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
58 changed files with 1333 additions and 663 deletions

View File

@ -76,7 +76,6 @@
./libs/common/src/abstractions/formValidationErrors.service.ts ./libs/common/src/abstractions/formValidationErrors.service.ts
./libs/common/src/abstractions/vaultTimeout/vaultTimeoutSettings.service.ts ./libs/common/src/abstractions/vaultTimeout/vaultTimeoutSettings.service.ts
./libs/common/src/abstractions/vaultTimeout/vaultTimeout.service.ts ./libs/common/src/abstractions/vaultTimeout/vaultTimeout.service.ts
./libs/common/src/abstractions/fileUpload.service.ts
./libs/common/src/abstractions/cryptoFunction.service.ts ./libs/common/src/abstractions/cryptoFunction.service.ts
./libs/common/src/abstractions/anonymousHub.service.ts ./libs/common/src/abstractions/anonymousHub.service.ts
./libs/common/src/abstractions/appId.service.ts ./libs/common/src/abstractions/appId.service.ts
@ -86,7 +85,6 @@
./libs/common/src/services/formValidationErrors.service.ts ./libs/common/src/services/formValidationErrors.service.ts
./libs/common/src/services/vaultTimeout/vaultTimeoutSettings.service.ts ./libs/common/src/services/vaultTimeout/vaultTimeoutSettings.service.ts
./libs/common/src/services/vaultTimeout/vaultTimeout.service.ts ./libs/common/src/services/vaultTimeout/vaultTimeout.service.ts
./libs/common/src/services/fileUpload.service.ts
./libs/common/src/services/anonymousHub.service.ts ./libs/common/src/services/anonymousHub.service.ts
./libs/common/src/services/appId.service.ts ./libs/common/src/services/appId.service.ts
./libs/common/src/services/noopMessaging.service.ts ./libs/common/src/services/noopMessaging.service.ts

View File

@ -8,14 +8,15 @@ import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service";
import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service"; import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service";
import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/common/abstractions/event/event-upload.service"; import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/common/abstractions/event/event-upload.service";
import { ExportService as ExportServiceAbstraction } from "@bitwarden/common/abstractions/export.service"; import { ExportService as ExportServiceAbstraction } from "@bitwarden/common/abstractions/export.service";
import { FileUploadService as FileUploadServiceAbstraction } from "@bitwarden/common/abstractions/fileUpload.service"; import { FileUploadService as FileUploadServiceAbstraction } from "@bitwarden/common/abstractions/file-upload/file-upload.service";
import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/abstractions/i18n.service"; import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/abstractions/i18n.service";
import { LogService as LogServiceAbstraction } from "@bitwarden/common/abstractions/log.service"; import { LogService as LogServiceAbstraction } from "@bitwarden/common/abstractions/log.service";
import { MessagingService as MessagingServiceAbstraction } from "@bitwarden/common/abstractions/messaging.service"; import { MessagingService as MessagingServiceAbstraction } from "@bitwarden/common/abstractions/messaging.service";
import { NotificationsService as NotificationsServiceAbstraction } from "@bitwarden/common/abstractions/notifications.service"; import { NotificationsService as NotificationsServiceAbstraction } from "@bitwarden/common/abstractions/notifications.service";
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/abstractions/platformUtils.service"; import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/abstractions/platformUtils.service";
import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/abstractions/search.service"; import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/abstractions/search.service";
import { SendService as SendServiceAbstraction } from "@bitwarden/common/abstractions/send.service"; import { SendApiService as SendApiServiceAbstraction } from "@bitwarden/common/abstractions/send/send-api.service.abstraction";
import { InternalSendService as InternalSendServiceAbstraction } from "@bitwarden/common/abstractions/send/send.service.abstraction";
import { SettingsService as SettingsServiceAbstraction } from "@bitwarden/common/abstractions/settings.service"; import { SettingsService as SettingsServiceAbstraction } from "@bitwarden/common/abstractions/settings.service";
import { import {
AbstractMemoryStorageService, AbstractMemoryStorageService,
@ -58,11 +59,11 @@ import { MultithreadEncryptServiceImplementation } from "@bitwarden/common/servi
import { EventCollectionService } from "@bitwarden/common/services/event/event-collection.service"; import { EventCollectionService } from "@bitwarden/common/services/event/event-collection.service";
import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service"; import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service";
import { ExportService } from "@bitwarden/common/services/export.service"; import { ExportService } from "@bitwarden/common/services/export.service";
import { FileUploadService } from "@bitwarden/common/services/fileUpload.service"; import { FileUploadService } from "@bitwarden/common/services/file-upload/file-upload.service";
import { MemoryStorageService } from "@bitwarden/common/services/memoryStorage.service"; import { MemoryStorageService } from "@bitwarden/common/services/memoryStorage.service";
import { NotificationsService } from "@bitwarden/common/services/notifications.service"; import { NotificationsService } from "@bitwarden/common/services/notifications.service";
import { SearchService } from "@bitwarden/common/services/search.service"; import { SearchService } from "@bitwarden/common/services/search.service";
import { SendService } from "@bitwarden/common/services/send.service"; import { SendApiService } from "@bitwarden/common/services/send/send-api.service";
import { StateMigrationService } from "@bitwarden/common/services/stateMigration.service"; import { StateMigrationService } from "@bitwarden/common/services/stateMigration.service";
import { SystemService } from "@bitwarden/common/services/system.service"; import { SystemService } from "@bitwarden/common/services/system.service";
import { TotpService } from "@bitwarden/common/services/totp.service"; import { TotpService } from "@bitwarden/common/services/totp.service";
@ -77,12 +78,14 @@ import {
UsernameGenerationServiceAbstraction, UsernameGenerationServiceAbstraction,
} from "@bitwarden/common/tools/generator/username"; } from "@bitwarden/common/tools/generator/username";
import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/vault/abstractions/cipher.service";
import { CipherFileUploadService as CipherFileUploadServiceAbstraction } from "@bitwarden/common/vault/abstractions/file-upload/cipher-file-upload.service";
import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction"; import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction";
import { InternalFolderService as InternalFolderServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; import { InternalFolderService as InternalFolderServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
import { SyncNotifierService as SyncNotifierServiceAbstraction } from "@bitwarden/common/vault/abstractions/sync/sync-notifier.service.abstraction"; import { SyncNotifierService as SyncNotifierServiceAbstraction } from "@bitwarden/common/vault/abstractions/sync/sync-notifier.service.abstraction";
import { SyncService as SyncServiceAbstraction } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { SyncService as SyncServiceAbstraction } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { CipherService } from "@bitwarden/common/vault/services/cipher.service"; import { CipherService } from "@bitwarden/common/vault/services/cipher.service";
import { CipherFileUploadService } from "@bitwarden/common/vault/services/file-upload/cipher-file-upload.service";
import { FolderApiService } from "@bitwarden/common/vault/services/folder/folder-api.service"; import { FolderApiService } from "@bitwarden/common/vault/services/folder/folder-api.service";
import { SyncNotifierService } from "@bitwarden/common/vault/services/sync/sync-notifier.service"; import { SyncNotifierService } from "@bitwarden/common/vault/services/sync/sync-notifier.service";
import { SyncService } from "@bitwarden/common/vault/services/sync/sync.service"; import { SyncService } from "@bitwarden/common/vault/services/sync/sync.service";
@ -105,6 +108,7 @@ import { Account } from "../models/account";
import { BrowserStateService as StateServiceAbstraction } from "../services/abstractions/browser-state.service"; import { BrowserStateService as StateServiceAbstraction } from "../services/abstractions/browser-state.service";
import { BrowserEnvironmentService } from "../services/browser-environment.service"; import { BrowserEnvironmentService } from "../services/browser-environment.service";
import { BrowserI18nService } from "../services/browser-i18n.service"; import { BrowserI18nService } from "../services/browser-i18n.service";
import { BrowserSendService } from "../services/browser-send.service";
import { BrowserSettingsService } from "../services/browser-settings.service"; import { BrowserSettingsService } from "../services/browser-settings.service";
import { BrowserStateService } from "../services/browser-state.service"; import { BrowserStateService } from "../services/browser-state.service";
import { BrowserCryptoService } from "../services/browserCrypto.service"; import { BrowserCryptoService } from "../services/browserCrypto.service";
@ -160,8 +164,9 @@ export default class MainBackground {
eventCollectionService: EventCollectionServiceAbstraction; eventCollectionService: EventCollectionServiceAbstraction;
eventUploadService: EventUploadServiceAbstraction; eventUploadService: EventUploadServiceAbstraction;
policyService: InternalPolicyServiceAbstraction; policyService: InternalPolicyServiceAbstraction;
sendService: SendServiceAbstraction; sendService: InternalSendServiceAbstraction;
fileUploadService: FileUploadServiceAbstraction; fileUploadService: FileUploadServiceAbstraction;
cipherFileUploadService: CipherFileUploadServiceAbstraction;
organizationService: InternalOrganizationServiceAbstraction; organizationService: InternalOrganizationServiceAbstraction;
providerService: ProviderServiceAbstraction; providerService: ProviderServiceAbstraction;
keyConnectorService: KeyConnectorServiceAbstraction; keyConnectorService: KeyConnectorServiceAbstraction;
@ -172,6 +177,7 @@ export default class MainBackground {
encryptService: EncryptService; encryptService: EncryptService;
folderApiService: FolderApiServiceAbstraction; folderApiService: FolderApiServiceAbstraction;
policyApiService: PolicyApiServiceAbstraction; policyApiService: PolicyApiServiceAbstraction;
sendApiService: SendApiServiceAbstraction;
userVerificationApiService: UserVerificationApiServiceAbstraction; userVerificationApiService: UserVerificationApiServiceAbstraction;
syncNotifierService: SyncNotifierServiceAbstraction; syncNotifierService: SyncNotifierServiceAbstraction;
avatarUpdateService: AvatarUpdateServiceAbstraction; avatarUpdateService: AvatarUpdateServiceAbstraction;
@ -292,17 +298,21 @@ export default class MainBackground {
(expired: boolean) => this.logout(expired) (expired: boolean) => this.logout(expired)
); );
this.settingsService = new BrowserSettingsService(this.stateService); this.settingsService = new BrowserSettingsService(this.stateService);
this.fileUploadService = new FileUploadService(this.logService, this.apiService); this.fileUploadService = new FileUploadService(this.logService);
this.cipherFileUploadService = new CipherFileUploadService(
this.apiService,
this.fileUploadService
);
this.cipherService = new CipherService( this.cipherService = new CipherService(
this.cryptoService, this.cryptoService,
this.settingsService, this.settingsService,
this.apiService, this.apiService,
this.fileUploadService,
this.i18nService, this.i18nService,
() => this.searchService, () => this.searchService,
this.logService, this.logService,
this.stateService, this.stateService,
this.encryptService this.encryptService,
this.cipherFileUploadService
); );
this.folderService = new BrowserFolderService( this.folderService = new BrowserFolderService(
this.cryptoService, this.cryptoService,
@ -317,14 +327,6 @@ export default class MainBackground {
this.stateService this.stateService
); );
this.searchService = new SearchService(this.cipherService, this.logService, this.i18nService); this.searchService = new SearchService(this.cipherService, this.logService, this.i18nService);
this.sendService = new SendService(
this.cryptoService,
this.apiService,
this.fileUploadService,
this.i18nService,
this.cryptoFunctionService,
this.stateService
);
this.syncNotifierService = new SyncNotifierService(); this.syncNotifierService = new SyncNotifierService();
this.organizationService = new BrowserOrganizationService(this.stateService); this.organizationService = new BrowserOrganizationService(this.stateService);
this.policyService = new BrowserPolicyService(this.stateService, this.organizationService); this.policyService = new BrowserPolicyService(this.stateService, this.organizationService);
@ -401,7 +403,18 @@ export default class MainBackground {
lockedCallback, lockedCallback,
logoutCallback logoutCallback
); );
this.containerService = new ContainerService(this.cryptoService, this.encryptService);
this.sendService = new BrowserSendService(
this.cryptoService,
this.i18nService,
this.cryptoFunctionService,
this.stateService
);
this.sendApiService = new SendApiService(
this.apiService,
this.fileUploadService,
this.sendService
);
this.providerService = new ProviderService(this.stateService); this.providerService = new ProviderService(this.stateService);
this.syncService = new SyncService( this.syncService = new SyncService(
this.apiService, this.apiService,
@ -419,6 +432,7 @@ export default class MainBackground {
this.providerService, this.providerService,
this.folderApiService, this.folderApiService,
this.organizationService, this.organizationService,
this.sendApiService,
logoutCallback logoutCallback
); );
this.eventUploadService = new EventUploadService( this.eventUploadService = new EventUploadService(
@ -446,7 +460,6 @@ export default class MainBackground {
this.logService, this.logService,
this.settingsService this.settingsService
); );
this.containerService = new ContainerService(this.cryptoService, this.encryptService);
this.auditService = new AuditService(this.cryptoFunctionService, this.apiService); this.auditService = new AuditService(this.cryptoFunctionService, this.apiService);
this.exportService = new ExportService( this.exportService = new ExportService(
this.folderService, this.folderService,

View File

@ -0,0 +1,31 @@
import { CipherFileUploadService as CipherFileUploadServiceAbstraction } from "@bitwarden/common/vault/abstractions/file-upload/cipher-file-upload.service";
import { CipherFileUploadService } from "@bitwarden/common/vault/services/file-upload/cipher-file-upload.service";
import { apiServiceFactory, ApiServiceInitOptions } from "./api-service.factory";
import { FactoryOptions, CachedServices, factory } from "./factory-options";
import {
fileUploadServiceFactory,
FileUploadServiceInitOptions,
} from "./file-upload-service.factory";
type CipherFileUploadServiceFactoyOptions = FactoryOptions;
export type CipherFileUploadServiceInitOptions = CipherFileUploadServiceFactoyOptions &
ApiServiceInitOptions &
FileUploadServiceInitOptions;
export function cipherFileUploadServiceFactory(
cache: { cipherFileUploadService?: CipherFileUploadServiceAbstraction } & CachedServices,
opts: CipherFileUploadServiceInitOptions
): Promise<CipherFileUploadServiceAbstraction> {
return factory(
cache,
"cipherFileUploadService",
opts,
async () =>
new CipherFileUploadService(
await apiServiceFactory(cache, opts),
await fileUploadServiceFactory(cache, opts)
)
);
}

View File

@ -0,0 +1,31 @@
import { CipherFileUploadService as CipherFileUploadServiceAbstraction } from "@bitwarden/common/vault/abstractions/file-upload/cipher-file-upload.service";
import { CipherFileUploadService } from "@bitwarden/common/vault/services/file-upload/cipher-file-upload.service";
import { apiServiceFactory, ApiServiceInitOptions } from "./api-service.factory";
import { FactoryOptions, CachedServices, factory } from "./factory-options";
import {
fileUploadServiceFactory,
FileUploadServiceInitOptions,
} from "./file-upload-service.factory";
type CipherFileUploadServiceFactoyOptions = FactoryOptions;
export type CipherFileUploadServiceInitOptions = CipherFileUploadServiceFactoyOptions &
ApiServiceInitOptions &
FileUploadServiceInitOptions;
export function cipherFileUploadServiceFactory(
cache: { cipherFileUploadService?: CipherFileUploadServiceAbstraction } & CachedServices,
opts: CipherFileUploadServiceInitOptions
): Promise<CipherFileUploadServiceAbstraction> {
return factory(
cache,
"cipherFileUploadService",
opts,
async () =>
new CipherFileUploadService(
await apiServiceFactory(cache, opts),
await fileUploadServiceFactory(cache, opts)
)
);
}

View File

@ -1,28 +1,21 @@
import { FileUploadService as AbstractFileUploadService } from "@bitwarden/common/abstractions/fileUpload.service"; import { FileUploadService as FileUploadServiceAbstraction } from "@bitwarden/common/abstractions/file-upload/file-upload.service";
import { FileUploadService } from "@bitwarden/common/services/fileUpload.service"; import { FileUploadService } from "@bitwarden/common/services/file-upload/file-upload.service";
import { apiServiceFactory, ApiServiceInitOptions } from "./api-service.factory"; import { CachedServices, factory, FactoryOptions } from "./factory-options";
import { FactoryOptions, CachedServices, factory } from "./factory-options";
import { logServiceFactory, LogServiceInitOptions } from "./log-service.factory"; import { logServiceFactory, LogServiceInitOptions } from "./log-service.factory";
type FileUploadServiceFactoyOptions = FactoryOptions; type FileUploadServiceFactoryOptions = FactoryOptions;
export type FileUploadServiceInitOptions = FileUploadServiceFactoyOptions & export type FileUploadServiceInitOptions = FileUploadServiceFactoryOptions & LogServiceInitOptions;
LogServiceInitOptions &
ApiServiceInitOptions;
export function fileUploadServiceFactory( export function fileUploadServiceFactory(
cache: { fileUploadService?: AbstractFileUploadService } & CachedServices, cache: { fileUploadService?: FileUploadServiceAbstraction } & CachedServices,
opts: FileUploadServiceInitOptions opts: FileUploadServiceInitOptions
): Promise<AbstractFileUploadService> { ): Promise<FileUploadServiceAbstraction> {
return factory( return factory(
cache, cache,
"fileUploadService", "fileUploadService",
opts, opts,
async () => async () => new FileUploadService(await logServiceFactory(cache, opts))
new FileUploadService(
await logServiceFactory(cache, opts),
await apiServiceFactory(cache, opts)
)
); );
} }

View File

@ -0,0 +1,34 @@
import { InternalSendService } from "@bitwarden/common/abstractions/send/send.service.abstraction";
import { BrowserSendService } from "../../services/browser-send.service";
import { cryptoFunctionServiceFactory } from "./crypto-function-service.factory";
import { cryptoServiceFactory, CryptoServiceInitOptions } from "./crypto-service.factory";
import { FactoryOptions, CachedServices, factory } from "./factory-options";
import { i18nServiceFactory, I18nServiceInitOptions } from "./i18n-service.factory";
import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory";
type SendServiceFactoryOptions = FactoryOptions;
export type SendServiceInitOptions = SendServiceFactoryOptions &
CryptoServiceInitOptions &
I18nServiceInitOptions &
StateServiceInitOptions;
export function sendServiceFactory(
cache: { sendService?: InternalSendService } & CachedServices,
opts: SendServiceInitOptions
): Promise<InternalSendService> {
return factory(
cache,
"sendService",
opts,
async () =>
new BrowserSendService(
await cryptoServiceFactory(cache, opts),
await i18nServiceFactory(cache, opts),
await cryptoFunctionServiceFactory(cache, opts),
await stateServiceFactory(cache, opts)
)
);
}

View File

@ -9,7 +9,8 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service"; import { LogService } from "@bitwarden/common/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { SendService } from "@bitwarden/common/abstractions/send.service"; import { SendApiService } from "@bitwarden/common/abstractions/send/send-api.service.abstraction";
import { SendService } from "@bitwarden/common/abstractions/send/send.service.abstraction";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { BrowserStateService } from "../../services/abstractions/browser-state.service"; import { BrowserStateService } from "../../services/abstractions/browser-state.service";
@ -43,7 +44,8 @@ export class SendAddEditComponent extends BaseAddEditComponent {
private router: Router, private router: Router,
private location: Location, private location: Location,
private popupUtilsService: PopupUtilsService, private popupUtilsService: PopupUtilsService,
logService: LogService logService: LogService,
sendApiService: SendApiService
) { ) {
super( super(
i18nService, i18nService,
@ -54,7 +56,8 @@ export class SendAddEditComponent extends BaseAddEditComponent {
messagingService, messagingService,
policyService, policyService,
logService, logService,
stateService stateService,
sendApiService
); );
} }

View File

@ -8,7 +8,8 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service"; import { LogService } from "@bitwarden/common/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service";
import { SendService } from "@bitwarden/common/abstractions/send.service"; import { SendApiService } from "@bitwarden/common/abstractions/send/send-api.service.abstraction";
import { SendService } from "@bitwarden/common/abstractions/send/send.service.abstraction";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { SendType } from "@bitwarden/common/enums/sendType"; import { SendType } from "@bitwarden/common/enums/sendType";
import { SendView } from "@bitwarden/common/models/view/send.view"; import { SendView } from "@bitwarden/common/models/view/send.view";
@ -47,7 +48,8 @@ export class SendGroupingsComponent extends BaseSendComponent {
private syncService: SyncService, private syncService: SyncService,
private changeDetectorRef: ChangeDetectorRef, private changeDetectorRef: ChangeDetectorRef,
private broadcasterService: BroadcasterService, private broadcasterService: BroadcasterService,
logService: LogService logService: LogService,
sendApiService: SendApiService
) { ) {
super( super(
sendService, sendService,
@ -57,7 +59,8 @@ export class SendGroupingsComponent extends BaseSendComponent {
ngZone, ngZone,
searchService, searchService,
policyService, policyService,
logService logService,
sendApiService
); );
super.onSuccessfulLoad = async () => { super.onSuccessfulLoad = async () => {
this.calculateTypeCounts(); this.calculateTypeCounts();

View File

@ -10,7 +10,8 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service"; import { LogService } from "@bitwarden/common/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service";
import { SendService } from "@bitwarden/common/abstractions/send.service"; import { SendApiService } from "@bitwarden/common/abstractions/send/send-api.service.abstraction";
import { SendService } from "@bitwarden/common/abstractions/send/send.service.abstraction";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { SendType } from "@bitwarden/common/enums/sendType"; import { SendType } from "@bitwarden/common/enums/sendType";
import { SendView } from "@bitwarden/common/models/view/send.view"; import { SendView } from "@bitwarden/common/models/view/send.view";
@ -47,7 +48,8 @@ export class SendTypeComponent extends BaseSendComponent {
private changeDetectorRef: ChangeDetectorRef, private changeDetectorRef: ChangeDetectorRef,
private broadcasterService: BroadcasterService, private broadcasterService: BroadcasterService,
private router: Router, private router: Router,
logService: LogService logService: LogService,
sendApiService: SendApiService
) { ) {
super( super(
sendService, sendService,
@ -57,7 +59,8 @@ export class SendTypeComponent extends BaseSendComponent {
ngZone, ngZone,
searchService, searchService,
policyService, policyService,
logService logService,
sendApiService
); );
super.onSuccessfulLoad = async () => { super.onSuccessfulLoad = async () => {
this.selectType(this.type); this.selectType(this.type);

View File

@ -18,15 +18,19 @@ import { EnvironmentService } from "@bitwarden/common/abstractions/environment.s
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
import { EventUploadService } from "@bitwarden/common/abstractions/event/event-upload.service"; import { EventUploadService } from "@bitwarden/common/abstractions/event/event-upload.service";
import { ExportService } from "@bitwarden/common/abstractions/export.service"; import { ExportService } from "@bitwarden/common/abstractions/export.service";
import { FileUploadService } from "@bitwarden/common/abstractions/file-upload/file-upload.service";
import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service"; import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service";
import { FileUploadService } from "@bitwarden/common/abstractions/fileUpload.service";
import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/abstractions/i18n.service"; import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/abstractions/i18n.service";
import { LogService as LogServiceAbstraction } from "@bitwarden/common/abstractions/log.service"; import { LogService as LogServiceAbstraction } from "@bitwarden/common/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service"; import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/abstractions/search.service"; import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/abstractions/search.service";
import { SendService } from "@bitwarden/common/abstractions/send.service"; import { SendApiService as SendApiServiceAbstraction } from "@bitwarden/common/abstractions/send/send-api.service.abstraction";
import {
InternalSendService as InternalSendServiceAbstraction,
SendService,
} from "@bitwarden/common/abstractions/send/send.service.abstraction";
import { SettingsService } from "@bitwarden/common/abstractions/settings.service"; import { SettingsService } from "@bitwarden/common/abstractions/settings.service";
import { import {
StateService as BaseStateServiceAbstraction, StateService as BaseStateServiceAbstraction,
@ -62,9 +66,11 @@ import { GlobalState } from "@bitwarden/common/models/domain/global-state";
import { ConsoleLogService } from "@bitwarden/common/services/consoleLog.service"; import { ConsoleLogService } from "@bitwarden/common/services/consoleLog.service";
import { ContainerService } from "@bitwarden/common/services/container.service"; import { ContainerService } from "@bitwarden/common/services/container.service";
import { SearchService } from "@bitwarden/common/services/search.service"; import { SearchService } from "@bitwarden/common/services/search.service";
import { SendApiService } from "@bitwarden/common/services/send/send-api.service";
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
import { UsernameGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/username"; import { UsernameGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/username";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { CipherFileUploadService } from "@bitwarden/common/vault/abstractions/file-upload/cipher-file-upload.service";
import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction"; import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction";
import { import {
FolderService, FolderService,
@ -85,6 +91,7 @@ import { BrowserStateService as StateServiceAbstraction } from "../../services/a
import { BrowserConfigService } from "../../services/browser-config.service"; import { BrowserConfigService } from "../../services/browser-config.service";
import { BrowserEnvironmentService } from "../../services/browser-environment.service"; import { BrowserEnvironmentService } from "../../services/browser-environment.service";
import { BrowserI18nService } from "../../services/browser-i18n.service"; import { BrowserI18nService } from "../../services/browser-i18n.service";
import { BrowserSendService } from "../../services/browser-send.service";
import { BrowserSettingsService } from "../../services/browser-settings.service"; import { BrowserSettingsService } from "../../services/browser-settings.service";
import { BrowserStateService } from "../../services/browser-state.service"; import { BrowserStateService } from "../../services/browser-state.service";
import { BrowserFileDownloadService } from "../../services/browserFileDownloadService"; import { BrowserFileDownloadService } from "../../services/browserFileDownloadService";
@ -173,8 +180,8 @@ function getBgService<T>(service: keyof MainBackground) {
}, },
{ provide: AuditService, useFactory: getBgService<AuditService>("auditService"), deps: [] }, { provide: AuditService, useFactory: getBgService<AuditService>("auditService"), deps: [] },
{ {
provide: FileUploadService, provide: CipherFileUploadService,
useFactory: getBgService<FileUploadService>("fileUploadService"), useFactory: getBgService<CipherFileUploadService>("cipherFileUploadService"),
deps: [], deps: [],
}, },
{ provide: CipherService, useFactory: getBgService<CipherService>("cipherService"), deps: [] }, { provide: CipherService, useFactory: getBgService<CipherService>("cipherService"), deps: [] },
@ -183,6 +190,10 @@ function getBgService<T>(service: keyof MainBackground) {
useFactory: getBgService<CryptoFunctionService>("cryptoFunctionService"), useFactory: getBgService<CryptoFunctionService>("cryptoFunctionService"),
deps: [], deps: [],
}, },
{
provide: FileUploadService,
useFactory: getBgService<FileUploadService>("fileUploadService"),
},
{ {
provide: FolderService, provide: FolderService,
useFactory: ( useFactory: (
@ -285,6 +296,38 @@ function getBgService<T>(service: keyof MainBackground) {
deps: [], deps: [],
}, },
{ provide: ApiService, useFactory: getBgService<ApiService>("apiService"), deps: [] }, { provide: ApiService, useFactory: getBgService<ApiService>("apiService"), deps: [] },
{
provide: SendService,
useFactory: (
cryptoService: CryptoService,
i18nService: I18nServiceAbstraction,
cryptoFunctionService: CryptoFunctionService,
stateServiceAbstraction: StateServiceAbstraction
) => {
return new BrowserSendService(
cryptoService,
i18nService,
cryptoFunctionService,
stateServiceAbstraction
);
},
deps: [CryptoService, I18nServiceAbstraction, CryptoFunctionService, StateServiceAbstraction],
},
{
provide: InternalSendServiceAbstraction,
useExisting: SendService,
},
{
provide: SendApiServiceAbstraction,
useFactory: (
apiService: ApiService,
fileUploadService: FileUploadService,
sendService: InternalSendServiceAbstraction
) => {
return new SendApiService(apiService, fileUploadService, sendService);
},
deps: [ApiService, FileUploadService, InternalSendServiceAbstraction],
},
{ provide: SyncService, useFactory: getBgService<SyncService>("syncService"), deps: [] }, { provide: SyncService, useFactory: getBgService<SyncService>("syncService"), deps: [] },
{ {
provide: SettingsService, provide: SettingsService,
@ -305,7 +348,6 @@ function getBgService<T>(service: keyof MainBackground) {
deps: [], deps: [],
}, },
{ provide: ExportService, useFactory: getBgService<ExportService>("exportService"), deps: [] }, { provide: ExportService, useFactory: getBgService<ExportService>("exportService"), deps: [] },
{ provide: SendService, useFactory: getBgService<SendService>("sendService"), deps: [] },
{ {
provide: KeyConnectorService, provide: KeyConnectorService,
useFactory: getBgService<KeyConnectorService>("keyConnectorService"), useFactory: getBgService<KeyConnectorService>("keyConnectorService"),

View File

@ -0,0 +1,15 @@
import { BehaviorSubject } from "rxjs";
import { Send } from "@bitwarden/common/models/domain/send";
import { SendView } from "@bitwarden/common/models/view/send.view";
import { SendService } from "@bitwarden/common/services/send/send.service";
import { browserSession, sessionSync } from "../decorators/session-sync-observable";
@browserSession
export class BrowserSendService extends SendService {
@sessionSync({ initializer: Send.fromJSON, initializeAs: "array" })
protected _sends: BehaviorSubject<Send[]>;
@sessionSync({ initializer: SendView.fromJSON, initializeAs: "array" })
protected _sendViews: BehaviorSubject<SendView[]>;
}

View File

@ -6,6 +6,10 @@ import {
apiServiceFactory, apiServiceFactory,
ApiServiceInitOptions, ApiServiceInitOptions,
} from "../../../background/service_factories/api-service.factory"; } from "../../../background/service_factories/api-service.factory";
import {
CipherFileUploadServiceInitOptions,
cipherFileUploadServiceFactory,
} from "../../../background/service_factories/cipher-file-upload-service.factory";
import { import {
cryptoServiceFactory, cryptoServiceFactory,
CryptoServiceInitOptions, CryptoServiceInitOptions,
@ -19,10 +23,6 @@ import {
factory, factory,
FactoryOptions, FactoryOptions,
} from "../../../background/service_factories/factory-options"; } from "../../../background/service_factories/factory-options";
import {
FileUploadServiceInitOptions,
fileUploadServiceFactory,
} from "../../../background/service_factories/file-upload-service.factory";
import { import {
i18nServiceFactory, i18nServiceFactory,
I18nServiceInitOptions, I18nServiceInitOptions,
@ -50,7 +50,7 @@ export type CipherServiceInitOptions = CipherServiceFactoryOptions &
CryptoServiceInitOptions & CryptoServiceInitOptions &
SettingsServiceInitOptions & SettingsServiceInitOptions &
ApiServiceInitOptions & ApiServiceInitOptions &
FileUploadServiceInitOptions & CipherFileUploadServiceInitOptions &
I18nServiceInitOptions & I18nServiceInitOptions &
LogServiceInitOptions & LogServiceInitOptions &
StateServiceInitOptions & StateServiceInitOptions &
@ -69,14 +69,14 @@ export function cipherServiceFactory(
await cryptoServiceFactory(cache, opts), await cryptoServiceFactory(cache, opts),
await settingsServiceFactory(cache, opts), await settingsServiceFactory(cache, opts),
await apiServiceFactory(cache, opts), await apiServiceFactory(cache, opts),
await fileUploadServiceFactory(cache, opts),
await i18nServiceFactory(cache, opts), await i18nServiceFactory(cache, opts),
opts.cipherServiceOptions?.searchServiceFactory === undefined opts.cipherServiceOptions?.searchServiceFactory === undefined
? () => cache.searchService as SearchService ? () => cache.searchService as SearchService
: opts.cipherServiceOptions.searchServiceFactory, : opts.cipherServiceOptions.searchServiceFactory,
await logServiceFactory(cache, opts), await logServiceFactory(cache, opts),
await stateServiceFactory(cache, opts), await stateServiceFactory(cache, opts),
await encryptServiceFactory(cache, opts) await encryptServiceFactory(cache, opts),
await cipherFileUploadServiceFactory(cache, opts)
) )
); );
} }

View File

@ -10,6 +10,7 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service"; import { LogService } from "@bitwarden/common/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { SendApiService } from "@bitwarden/common/abstractions/send/send-api.service.abstraction";
import { StateService } from "@bitwarden/common/abstractions/state.service"; import { StateService } from "@bitwarden/common/abstractions/state.service";
import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
@ -51,7 +52,8 @@ export class AddEditComponent extends BaseAddEditComponent {
private popupUtilsService: PopupUtilsService, private popupUtilsService: PopupUtilsService,
organizationService: OrganizationService, organizationService: OrganizationService,
passwordRepromptService: PasswordRepromptService, passwordRepromptService: PasswordRepromptService,
logService: LogService logService: LogService,
sendApiService: SendApiService
) { ) {
super( super(
cipherService, cipherService,
@ -66,7 +68,8 @@ export class AddEditComponent extends BaseAddEditComponent {
policyService, policyService,
logService, logService,
passwordRepromptService, passwordRepromptService,
organizationService organizationService,
sendApiService
); );
} }

View File

@ -31,12 +31,13 @@ import { CryptoService } from "@bitwarden/common/services/crypto.service";
import { EncryptServiceImplementation } from "@bitwarden/common/services/cryptography/encrypt.service.implementation"; import { EncryptServiceImplementation } from "@bitwarden/common/services/cryptography/encrypt.service.implementation";
import { EnvironmentService } from "@bitwarden/common/services/environment.service"; import { EnvironmentService } from "@bitwarden/common/services/environment.service";
import { ExportService } from "@bitwarden/common/services/export.service"; import { ExportService } from "@bitwarden/common/services/export.service";
import { FileUploadService } from "@bitwarden/common/services/fileUpload.service"; import { FileUploadService } from "@bitwarden/common/services/file-upload/file-upload.service";
import { MemoryStorageService } from "@bitwarden/common/services/memoryStorage.service"; import { MemoryStorageService } from "@bitwarden/common/services/memoryStorage.service";
import { NoopMessagingService } from "@bitwarden/common/services/noopMessaging.service"; import { NoopMessagingService } from "@bitwarden/common/services/noopMessaging.service";
import { OrganizationUserServiceImplementation } from "@bitwarden/common/services/organization-user/organization-user.service.implementation"; import { OrganizationUserServiceImplementation } from "@bitwarden/common/services/organization-user/organization-user.service.implementation";
import { SearchService } from "@bitwarden/common/services/search.service"; import { SearchService } from "@bitwarden/common/services/search.service";
import { SendService } from "@bitwarden/common/services/send.service"; import { SendApiService } from "@bitwarden/common/services/send/send-api.service";
import { SendService } from "@bitwarden/common/services/send/send.service";
import { SettingsService } from "@bitwarden/common/services/settings.service"; import { SettingsService } from "@bitwarden/common/services/settings.service";
import { StateService } from "@bitwarden/common/services/state.service"; import { StateService } from "@bitwarden/common/services/state.service";
import { StateMigrationService } from "@bitwarden/common/services/stateMigration.service"; import { StateMigrationService } from "@bitwarden/common/services/stateMigration.service";
@ -49,6 +50,7 @@ import {
} from "@bitwarden/common/tools/generator/password"; } from "@bitwarden/common/tools/generator/password";
import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
import { CipherService } from "@bitwarden/common/vault/services/cipher.service"; import { CipherService } from "@bitwarden/common/vault/services/cipher.service";
import { CipherFileUploadService } from "@bitwarden/common/vault/services/file-upload/cipher-file-upload.service";
import { FolderApiService } from "@bitwarden/common/vault/services/folder/folder-api.service"; import { FolderApiService } from "@bitwarden/common/vault/services/folder/folder-api.service";
import { FolderService } from "@bitwarden/common/vault/services/folder/folder.service"; import { FolderService } from "@bitwarden/common/vault/services/folder/folder.service";
import { SyncNotifierService } from "@bitwarden/common/vault/services/sync/sync-notifier.service"; import { SyncNotifierService } from "@bitwarden/common/vault/services/sync/sync-notifier.service";
@ -115,6 +117,7 @@ export class Main {
logService: ConsoleLogService; logService: ConsoleLogService;
sendService: SendService; sendService: SendService;
fileUploadService: FileUploadService; fileUploadService: FileUploadService;
cipherFileUploadService: CipherFileUploadService;
keyConnectorService: KeyConnectorService; keyConnectorService: KeyConnectorService;
userVerificationService: UserVerificationService; userVerificationService: UserVerificationService;
stateService: StateService; stateService: StateService;
@ -127,6 +130,7 @@ export class Main {
userVerificationApiService: UserVerificationApiService; userVerificationApiService: UserVerificationApiService;
organizationApiService: OrganizationApiServiceAbstraction; organizationApiService: OrganizationApiServiceAbstraction;
syncNotifierService: SyncNotifierService; syncNotifierService: SyncNotifierService;
sendApiService: SendApiService;
constructor() { constructor() {
let p = null; let p = null;
@ -217,18 +221,36 @@ export class Main {
this.settingsService = new SettingsService(this.stateService); this.settingsService = new SettingsService(this.stateService);
this.fileUploadService = new FileUploadService(this.logService, this.apiService); this.fileUploadService = new FileUploadService(this.logService);
this.sendService = new SendService(
this.cryptoService,
this.i18nService,
this.cryptoFunctionService,
this.stateService
);
this.cipherFileUploadService = new CipherFileUploadService(
this.apiService,
this.fileUploadService
);
this.sendApiService = this.sendApiService = new SendApiService(
this.apiService,
this.fileUploadService,
this.sendService
);
this.cipherService = new CipherService( this.cipherService = new CipherService(
this.cryptoService, this.cryptoService,
this.settingsService, this.settingsService,
this.apiService, this.apiService,
this.fileUploadService,
this.i18nService, this.i18nService,
null, null,
this.logService, this.logService,
this.stateService, this.stateService,
this.encryptService this.encryptService,
this.cipherFileUploadService
); );
this.broadcasterService = new BroadcasterService(); this.broadcasterService = new BroadcasterService();
@ -258,15 +280,6 @@ export class Main {
this.policyService = new PolicyService(this.stateService, this.organizationService); this.policyService = new PolicyService(this.stateService, this.organizationService);
this.sendService = new SendService(
this.cryptoService,
this.apiService,
this.fileUploadService,
this.i18nService,
this.cryptoFunctionService,
this.stateService
);
this.keyConnectorService = new KeyConnectorService( this.keyConnectorService = new KeyConnectorService(
this.stateService, this.stateService,
this.cryptoService, this.cryptoService,
@ -338,6 +351,7 @@ export class Main {
this.providerService, this.providerService,
this.folderApiService, this.folderApiService,
this.organizationService, this.organizationService,
this.sendApiService,
async (expired: boolean) => await this.logout() async (expired: boolean) => await this.logout()
); );

View File

@ -2,7 +2,8 @@ import * as fs from "fs";
import * as path from "path"; import * as path from "path";
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service"; import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
import { SendService } from "@bitwarden/common/abstractions/send.service"; import { SendApiService } from "@bitwarden/common/abstractions/send/send-api.service.abstraction";
import { SendService } from "@bitwarden/common/abstractions/send/send.service.abstraction";
import { StateService } from "@bitwarden/common/abstractions/state.service"; import { StateService } from "@bitwarden/common/abstractions/state.service";
import { SendType } from "@bitwarden/common/enums/sendType"; import { SendType } from "@bitwarden/common/enums/sendType";
import { NodeUtils } from "@bitwarden/common/misc/nodeUtils"; import { NodeUtils } from "@bitwarden/common/misc/nodeUtils";
@ -16,7 +17,8 @@ export class SendCreateCommand {
constructor( constructor(
private sendService: SendService, private sendService: SendService,
private stateService: StateService, private stateService: StateService,
private environmentService: EnvironmentService private environmentService: EnvironmentService,
private sendApiService: SendApiService
) {} ) {}
async run(requestJson: any, cmdOptions: Record<string, any>) { async run(requestJson: any, cmdOptions: Record<string, any>) {
@ -120,8 +122,8 @@ export class SendCreateCommand {
encSend.deletionDate = sendView.deletionDate; encSend.deletionDate = sendView.deletionDate;
encSend.expirationDate = sendView.expirationDate; encSend.expirationDate = sendView.expirationDate;
await this.sendService.saveWithServer([encSend, fileData]); await this.sendApiService.save([encSend, fileData]);
const newSend = await this.sendService.get(encSend.id); const newSend = await this.sendService.getFromState(encSend.id);
const decSend = await newSend.decrypt(); const decSend = await newSend.decrypt();
const res = new SendResponse(decSend, this.environmentService.getWebVaultUrl()); const res = new SendResponse(decSend, this.environmentService.getWebVaultUrl());
return Response.success(res); return Response.success(res);

View File

@ -1,19 +1,20 @@
import { SendService } from "@bitwarden/common/abstractions/send.service"; import { SendApiService } from "@bitwarden/common/abstractions/send/send-api.service.abstraction";
import { SendService } from "@bitwarden/common/abstractions/send/send.service.abstraction";
import { Response } from "../../models/response"; import { Response } from "../../models/response";
export class SendDeleteCommand { export class SendDeleteCommand {
constructor(private sendService: SendService) {} constructor(private sendService: SendService, private sendApiService: SendApiService) {}
async run(id: string) { async run(id: string) {
const send = await this.sendService.get(id); const send = await this.sendService.getFromState(id);
if (send == null) { if (send == null) {
return Response.notFound(); return Response.notFound();
} }
try { try {
await this.sendService.deleteWithServer(id); await this.sendApiService.delete(id);
return Response.success(); return Response.success();
} catch (e) { } catch (e) {
return Response.error(e); return Response.error(e);

View File

@ -1,4 +1,5 @@
import { SendService } from "@bitwarden/common/abstractions/send.service"; import { SendApiService } from "@bitwarden/common/abstractions/send/send-api.service.abstraction";
import { SendService } from "@bitwarden/common/abstractions/send/send.service.abstraction";
import { StateService } from "@bitwarden/common/abstractions/state.service"; import { StateService } from "@bitwarden/common/abstractions/state.service";
import { SendType } from "@bitwarden/common/enums/sendType"; import { SendType } from "@bitwarden/common/enums/sendType";
@ -12,7 +13,8 @@ export class SendEditCommand {
constructor( constructor(
private sendService: SendService, private sendService: SendService,
private stateService: StateService, private stateService: StateService,
private getCommand: SendGetCommand private getCommand: SendGetCommand,
private sendApiService: SendApiService
) {} ) {}
async run(requestJson: string, cmdOptions: Record<string, any>): Promise<Response> { async run(requestJson: string, cmdOptions: Record<string, any>): Promise<Response> {
@ -45,7 +47,7 @@ export class SendEditCommand {
req.id = req.id.toLowerCase(); req.id = req.id.toLowerCase();
} }
const send = await this.sendService.get(req.id); const send = await this.sendService.getFromState(req.id);
if (send == null) { if (send == null) {
return Response.notFound(); return Response.notFound();
@ -72,7 +74,7 @@ export class SendEditCommand {
encSend.deletionDate = sendView.deletionDate; encSend.deletionDate = sendView.deletionDate;
encSend.expirationDate = sendView.expirationDate; encSend.expirationDate = sendView.expirationDate;
await this.sendService.saveWithServer([encSend, encFileData]); await this.sendApiService.save([encSend, encFileData]);
} catch (e) { } catch (e) {
return Response.error(e); return Response.error(e);
} }

View File

@ -3,7 +3,7 @@ import * as program from "commander";
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service"; import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service";
import { SendService } from "@bitwarden/common/abstractions/send.service"; import { SendService } from "@bitwarden/common/abstractions/send/send.service.abstraction";
import { Utils } from "@bitwarden/common/misc/utils"; import { Utils } from "@bitwarden/common/misc/utils";
import { SendView } from "@bitwarden/common/models/view/send.view"; import { SendView } from "@bitwarden/common/models/view/send.view";
@ -66,12 +66,12 @@ export class SendGetCommand extends DownloadCommand {
private async getSendView(id: string): Promise<SendView | SendView[]> { private async getSendView(id: string): Promise<SendView | SendView[]> {
if (Utils.isGuid(id)) { if (Utils.isGuid(id)) {
const send = await this.sendService.get(id); const send = await this.sendService.getFromState(id);
if (send != null) { if (send != null) {
return await send.decrypt(); return await send.decrypt();
} }
} else if (id.trim() !== "") { } else if (id.trim() !== "") {
let sends = await this.sendService.getAllDecrypted(); let sends = await this.sendService.getAllDecryptedFromState();
sends = this.searchService.searchSends(sends, id); sends = this.searchService.searchSends(sends, id);
if (sends.length > 1) { if (sends.length > 1) {
return sends; return sends;

View File

@ -1,6 +1,6 @@
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service"; import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service";
import { SendService } from "@bitwarden/common/abstractions/send.service"; import { SendService } from "@bitwarden/common/abstractions/send/send.service.abstraction";
import { Response } from "../../models/response"; import { Response } from "../../models/response";
import { ListResponse } from "../../models/response/list.response"; import { ListResponse } from "../../models/response/list.response";
@ -14,7 +14,7 @@ export class SendListCommand {
) {} ) {}
async run(cmdOptions: Record<string, any>): Promise<Response> { async run(cmdOptions: Record<string, any>): Promise<Response> {
let sends = await this.sendService.getAllDecrypted(); let sends = await this.sendService.getAllDecryptedFromState();
const normalizedOptions = new Options(cmdOptions); const normalizedOptions = new Options(cmdOptions);
if (normalizedOptions.search != null && normalizedOptions.search.trim() !== "") { if (normalizedOptions.search != null && normalizedOptions.search.trim() !== "") {

View File

@ -6,6 +6,7 @@ import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { CryptoFunctionService } from "@bitwarden/common/abstractions/cryptoFunction.service"; import { CryptoFunctionService } from "@bitwarden/common/abstractions/cryptoFunction.service";
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service"; import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { SendApiService } from "@bitwarden/common/abstractions/send/send-api.service.abstraction";
import { SendType } from "@bitwarden/common/enums/sendType"; import { SendType } from "@bitwarden/common/enums/sendType";
import { NodeUtils } from "@bitwarden/common/misc/nodeUtils"; import { NodeUtils } from "@bitwarden/common/misc/nodeUtils";
import { Utils } from "@bitwarden/common/misc/utils"; import { Utils } from "@bitwarden/common/misc/utils";
@ -29,7 +30,8 @@ export class SendReceiveCommand extends DownloadCommand {
cryptoService: CryptoService, cryptoService: CryptoService,
private cryptoFunctionService: CryptoFunctionService, private cryptoFunctionService: CryptoFunctionService,
private platformUtilsService: PlatformUtilsService, private platformUtilsService: PlatformUtilsService,
private environmentService: EnvironmentService private environmentService: EnvironmentService,
private sendApiService: SendApiService
) { ) {
super(cryptoService); super(cryptoService);
} }
@ -84,7 +86,7 @@ export class SendReceiveCommand extends DownloadCommand {
process.stdout.write(response?.text?.text); process.stdout.write(response?.text?.text);
return Response.success(); return Response.success();
case SendType.File: { case SendType.File: {
const downloadData = await this.apiService.getSendFileDownloadData( const downloadData = await this.sendApiService.getSendFileDownloadData(
response, response,
this.sendAccessRequest, this.sendAccessRequest,
apiUrl apiUrl
@ -135,7 +137,11 @@ export class SendReceiveCommand extends DownloadCommand {
key: ArrayBuffer key: ArrayBuffer
): Promise<Response | SendAccessView> { ): Promise<Response | SendAccessView> {
try { try {
const sendResponse = await this.apiService.postSendAccess(id, this.sendAccessRequest, url); const sendResponse = await this.sendApiService.postSendAccess(
id,
this.sendAccessRequest,
url
);
const sendAccess = new SendAccess(sendResponse); const sendAccess = new SendAccess(sendResponse);
this.decKey = await this.cryptoService.makeSendKey(key); this.decKey = await this.cryptoService.makeSendKey(key);

View File

@ -1,14 +1,15 @@
import { SendService } from "@bitwarden/common/abstractions/send.service"; import { SendApiService } from "@bitwarden/common/abstractions/send/send-api.service.abstraction";
import { SendService } from "@bitwarden/common/abstractions/send/send.service.abstraction";
import { Response } from "../../models/response"; import { Response } from "../../models/response";
import { SendResponse } from "../../models/response/send.response"; import { SendResponse } from "../../models/response/send.response";
export class SendRemovePasswordCommand { export class SendRemovePasswordCommand {
constructor(private sendService: SendService) {} constructor(private sendService: SendService, private sendApiService: SendApiService) {}
async run(id: string) { async run(id: string) {
try { try {
await this.sendService.removePasswordWithServer(id); await this.sendApiService.removePassword(id);
const updatedSend = await this.sendService.get(id); const updatedSend = await this.sendService.get(id);
const decSend = await updatedSend.decrypt(); const decSend = await updatedSend.decrypt();

View File

@ -133,9 +133,10 @@ export class ServeCommand {
this.sendCreateCommand = new SendCreateCommand( this.sendCreateCommand = new SendCreateCommand(
this.main.sendService, this.main.sendService,
this.main.stateService, this.main.stateService,
this.main.environmentService this.main.environmentService,
this.main.sendApiService
); );
this.sendDeleteCommand = new SendDeleteCommand(this.main.sendService); this.sendDeleteCommand = new SendDeleteCommand(this.main.sendService, this.main.sendApiService);
this.sendGetCommand = new SendGetCommand( this.sendGetCommand = new SendGetCommand(
this.main.sendService, this.main.sendService,
this.main.environmentService, this.main.environmentService,
@ -145,14 +146,18 @@ export class ServeCommand {
this.sendEditCommand = new SendEditCommand( this.sendEditCommand = new SendEditCommand(
this.main.sendService, this.main.sendService,
this.main.stateService, this.main.stateService,
this.sendGetCommand this.sendGetCommand,
this.main.sendApiService
); );
this.sendListCommand = new SendListCommand( this.sendListCommand = new SendListCommand(
this.main.sendService, this.main.sendService,
this.main.environmentService, this.main.environmentService,
this.main.searchService this.main.searchService
); );
this.sendRemovePasswordCommand = new SendRemovePasswordCommand(this.main.sendService); this.sendRemovePasswordCommand = new SendRemovePasswordCommand(
this.main.sendService,
this.main.sendApiService
);
} }
async run(options: program.OptionValues) { async run(options: program.OptionValues) {

View File

@ -109,7 +109,8 @@ export class SendProgram extends Program {
this.main.cryptoService, this.main.cryptoService,
this.main.cryptoFunctionService, this.main.cryptoFunctionService,
this.main.platformUtilsService, this.main.platformUtilsService,
this.main.environmentService this.main.environmentService,
this.main.sendApiService
); );
const response = await cmd.run(url, options); const response = await cmd.run(url, options);
this.processResponse(response); this.processResponse(response);
@ -259,7 +260,12 @@ export class SendProgram extends Program {
this.main.searchService, this.main.searchService,
this.main.cryptoService this.main.cryptoService
); );
const cmd = new SendEditCommand(this.main.sendService, this.main.stateService, getCmd); const cmd = new SendEditCommand(
this.main.sendService,
this.main.stateService,
getCmd,
this.main.sendApiService
);
const response = await cmd.run(encodedJson, options); const response = await cmd.run(encodedJson, options);
this.processResponse(response); this.processResponse(response);
}); });
@ -273,7 +279,7 @@ export class SendProgram extends Program {
}) })
.action(async (id: string) => { .action(async (id: string) => {
await this.exitIfLocked(); await this.exitIfLocked();
const cmd = new SendDeleteCommand(this.main.sendService); const cmd = new SendDeleteCommand(this.main.sendService, this.main.sendApiService);
const response = await cmd.run(id); const response = await cmd.run(id);
this.processResponse(response); this.processResponse(response);
}); });
@ -287,7 +293,7 @@ export class SendProgram extends Program {
}) })
.action(async (id: string) => { .action(async (id: string) => {
await this.exitIfLocked(); await this.exitIfLocked();
const cmd = new SendRemovePasswordCommand(this.main.sendService); const cmd = new SendRemovePasswordCommand(this.main.sendService, this.main.sendApiService);
const response = await cmd.run(id); const response = await cmd.run(id);
this.processResponse(response); this.processResponse(response);
}); });
@ -327,7 +333,8 @@ export class SendProgram extends Program {
const cmd = new SendCreateCommand( const cmd = new SendCreateCommand(
this.main.sendService, this.main.sendService,
this.main.stateService, this.main.stateService,
this.main.environmentService this.main.environmentService,
this.main.sendApiService
); );
return await cmd.run(encodedJson, options); return await cmd.run(encodedJson, options);
} }

View File

@ -7,7 +7,8 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service"; import { LogService } from "@bitwarden/common/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { SendService } from "@bitwarden/common/abstractions/send.service"; import { SendApiService } from "@bitwarden/common/abstractions/send/send-api.service.abstraction";
import { SendService } from "@bitwarden/common/abstractions/send/send.service.abstraction";
import { StateService } from "@bitwarden/common/abstractions/state.service"; import { StateService } from "@bitwarden/common/abstractions/state.service";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
@ -25,7 +26,8 @@ export class AddEditComponent extends BaseAddEditComponent {
stateService: StateService, stateService: StateService,
messagingService: MessagingService, messagingService: MessagingService,
policyService: PolicyService, policyService: PolicyService,
logService: LogService logService: LogService,
sendApiService: SendApiService
) { ) {
super( super(
i18nService, i18nService,
@ -36,7 +38,8 @@ export class AddEditComponent extends BaseAddEditComponent {
messagingService, messagingService,
policyService, policyService,
logService, logService,
stateService stateService,
sendApiService
); );
} }

View File

@ -7,7 +7,8 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service"; import { LogService } from "@bitwarden/common/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service";
import { SendService } from "@bitwarden/common/abstractions/send.service"; import { SendApiService } from "@bitwarden/common/abstractions/send/send-api.service.abstraction";
import { SendService } from "@bitwarden/common/abstractions/send/send.service.abstraction";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { SendView } from "@bitwarden/common/models/view/send.view"; import { SendView } from "@bitwarden/common/models/view/send.view";
@ -44,7 +45,8 @@ export class SendComponent extends BaseSendComponent implements OnInit, OnDestro
searchService: SearchService, searchService: SearchService,
policyService: PolicyService, policyService: PolicyService,
private searchBarService: SearchBarService, private searchBarService: SearchBarService,
logService: LogService logService: LogService,
sendApiService: SendApiService
) { ) {
super( super(
sendService, sendService,
@ -54,7 +56,8 @@ export class SendComponent extends BaseSendComponent implements OnInit, OnDestro
ngZone, ngZone,
searchService, searchService,
policyService, policyService,
logService logService,
sendApiService
); );
// eslint-disable-next-line rxjs-angular/prefer-takeuntil // eslint-disable-next-line rxjs-angular/prefer-takeuntil
this.searchBarService.searchText$.subscribe((searchText) => { this.searchBarService.searchText$.subscribe((searchText) => {

View File

@ -9,6 +9,7 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service"; import { LogService } from "@bitwarden/common/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { SendApiService } from "@bitwarden/common/abstractions/send/send-api.service.abstraction";
import { StateService } from "@bitwarden/common/abstractions/state.service"; import { StateService } from "@bitwarden/common/abstractions/state.service";
import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
@ -41,7 +42,8 @@ export class AddEditComponent extends BaseAddEditComponent implements OnChanges,
private broadcasterService: BroadcasterService, private broadcasterService: BroadcasterService,
private ngZone: NgZone, private ngZone: NgZone,
logService: LogService, logService: LogService,
organizationService: OrganizationService organizationService: OrganizationService,
sendApiService: SendApiService
) { ) {
super( super(
cipherService, cipherService,
@ -56,7 +58,8 @@ export class AddEditComponent extends BaseAddEditComponent implements OnChanges,
policyService, policyService,
logService, logService,
passwordRepromptService, passwordRepromptService,
organizationService organizationService,
sendApiService
); );
} }

View File

@ -7,6 +7,7 @@ import { CryptoFunctionService } from "@bitwarden/common/abstractions/cryptoFunc
import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service"; import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { SendApiService } from "@bitwarden/common/abstractions/send/send-api.service.abstraction";
import { SEND_KDF_ITERATIONS } from "@bitwarden/common/enums/kdfType"; import { SEND_KDF_ITERATIONS } from "@bitwarden/common/enums/kdfType";
import { SendType } from "@bitwarden/common/enums/sendType"; import { SendType } from "@bitwarden/common/enums/sendType";
import { Utils } from "@bitwarden/common/misc/utils"; import { Utils } from "@bitwarden/common/misc/utils";
@ -48,7 +49,8 @@ export class AccessComponent implements OnInit {
private platformUtilsService: PlatformUtilsService, private platformUtilsService: PlatformUtilsService,
private route: ActivatedRoute, private route: ActivatedRoute,
private cryptoService: CryptoService, private cryptoService: CryptoService,
private fileDownloadService: FileDownloadService private fileDownloadService: FileDownloadService,
private sendApiService: SendApiService
) {} ) {}
get sendText() { get sendText() {
@ -93,7 +95,7 @@ export class AccessComponent implements OnInit {
return; return;
} }
const downloadData = await this.apiService.getSendFileDownloadData( const downloadData = await this.sendApiService.getSendFileDownloadData(
this.send, this.send,
this.accessRequest this.accessRequest
); );
@ -157,9 +159,9 @@ export class AccessComponent implements OnInit {
try { try {
let sendResponse: SendAccessResponse = null; let sendResponse: SendAccessResponse = null;
if (this.loading) { if (this.loading) {
sendResponse = await this.apiService.postSendAccess(this.id, this.accessRequest); sendResponse = await this.sendApiService.postSendAccess(this.id, this.accessRequest);
} else { } else {
this.formPromise = this.apiService.postSendAccess(this.id, this.accessRequest); this.formPromise = this.sendApiService.postSendAccess(this.id, this.accessRequest);
sendResponse = await this.formPromise; sendResponse = await this.formPromise;
} }
this.passwordRequired = false; this.passwordRequired = false;

View File

@ -7,7 +7,8 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service"; import { LogService } from "@bitwarden/common/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { SendService } from "@bitwarden/common/abstractions/send.service"; import { SendApiService } from "@bitwarden/common/abstractions/send/send-api.service.abstraction";
import { SendService } from "@bitwarden/common/abstractions/send/send.service.abstraction";
import { StateService } from "@bitwarden/common/abstractions/state.service"; import { StateService } from "@bitwarden/common/abstractions/state.service";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
@ -27,7 +28,8 @@ export class AddEditComponent extends BaseAddEditComponent {
stateService: StateService, stateService: StateService,
messagingService: MessagingService, messagingService: MessagingService,
policyService: PolicyService, policyService: PolicyService,
logService: LogService logService: LogService,
sendApiService: SendApiService
) { ) {
super( super(
i18nService, i18nService,
@ -38,7 +40,8 @@ export class AddEditComponent extends BaseAddEditComponent {
messagingService, messagingService,
policyService, policyService,
logService, logService,
stateService stateService,
sendApiService
); );
} }

View File

@ -8,7 +8,8 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service"; import { LogService } from "@bitwarden/common/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service";
import { SendService } from "@bitwarden/common/abstractions/send.service"; import { SendApiService } from "@bitwarden/common/abstractions/send/send-api.service.abstraction";
import { SendService } from "@bitwarden/common/abstractions/send/send.service.abstraction";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { SendView } from "@bitwarden/common/models/view/send.view"; import { SendView } from "@bitwarden/common/models/view/send.view";
import { Icons } from "@bitwarden/components"; import { Icons } from "@bitwarden/components";
@ -36,7 +37,8 @@ export class SendComponent extends BaseSendComponent {
policyService: PolicyService, policyService: PolicyService,
private modalService: ModalService, private modalService: ModalService,
private broadcasterService: BroadcasterService, private broadcasterService: BroadcasterService,
logService: LogService logService: LogService,
sendApiService: SendApiService
) { ) {
super( super(
sendService, sendService,
@ -46,7 +48,8 @@ export class SendComponent extends BaseSendComponent {
ngZone, ngZone,
searchService, searchService,
policyService, policyService,
logService logService,
sendApiService
); );
} }

View File

@ -11,7 +11,7 @@ import { MessagingService } from "@bitwarden/common/abstractions/messaging.servi
import { OrganizationUserService } from "@bitwarden/common/abstractions/organization-user/organization-user.service"; import { OrganizationUserService } from "@bitwarden/common/abstractions/organization-user/organization-user.service";
import { OrganizationUserResetPasswordEnrollmentRequest } from "@bitwarden/common/abstractions/organization-user/requests"; import { OrganizationUserResetPasswordEnrollmentRequest } from "@bitwarden/common/abstractions/organization-user/requests";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { SendService } from "@bitwarden/common/abstractions/send.service"; import { SendService } from "@bitwarden/common/abstractions/send/send.service.abstraction";
import { StateService } from "@bitwarden/common/abstractions/state.service"; import { StateService } from "@bitwarden/common/abstractions/state.service";
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
@ -240,7 +240,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
request.ciphers.push(new CipherWithIdRequest(cipher)); request.ciphers.push(new CipherWithIdRequest(cipher));
} }
const sends = await this.sendService.getAll(); const sends = await firstValueFrom(this.sendService.sends$);
await Promise.all( await Promise.all(
sends.map(async (send) => { sends.map(async (send) => {
const cryptoKey = await this.cryptoService.decryptToBytes(send.key, null); const cryptoKey = await this.cryptoService.decryptToBytes(send.key, null);

View File

@ -7,6 +7,7 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service"; import { LogService } from "@bitwarden/common/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { SendApiService } from "@bitwarden/common/abstractions/send/send-api.service.abstraction";
import { StateService } from "@bitwarden/common/abstractions/state.service"; import { StateService } from "@bitwarden/common/abstractions/state.service";
import { TotpService } from "@bitwarden/common/abstractions/totp.service"; import { TotpService } from "@bitwarden/common/abstractions/totp.service";
import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service";
@ -56,7 +57,8 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit, On
protected policyService: PolicyService, protected policyService: PolicyService,
organizationService: OrganizationService, organizationService: OrganizationService,
logService: LogService, logService: LogService,
passwordRepromptService: PasswordRepromptService passwordRepromptService: PasswordRepromptService,
sendApiService: SendApiService
) { ) {
super( super(
cipherService, cipherService,
@ -71,7 +73,8 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit, On
policyService, policyService,
logService, logService,
passwordRepromptService, passwordRepromptService,
organizationService organizationService,
sendApiService
); );
} }

View File

@ -7,6 +7,7 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service"; import { LogService } from "@bitwarden/common/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { SendApiService } from "@bitwarden/common/abstractions/send/send-api.service.abstraction";
import { StateService } from "@bitwarden/common/abstractions/state.service"; import { StateService } from "@bitwarden/common/abstractions/state.service";
import { TotpService } from "@bitwarden/common/abstractions/totp.service"; import { TotpService } from "@bitwarden/common/abstractions/totp.service";
import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service";
@ -47,7 +48,8 @@ export class AddEditComponent extends BaseAddEditComponent {
policyService: PolicyService, policyService: PolicyService,
logService: LogService, logService: LogService,
passwordRepromptService: PasswordRepromptService, passwordRepromptService: PasswordRepromptService,
organizationService: OrganizationService organizationService: OrganizationService,
sendApiService: SendApiService
) { ) {
super( super(
cipherService, cipherService,
@ -64,7 +66,8 @@ export class AddEditComponent extends BaseAddEditComponent {
policyService, policyService,
organizationService, organizationService,
logService, logService,
passwordRepromptService passwordRepromptService,
sendApiService
); );
} }

View File

@ -6,6 +6,7 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service"; import { LogService } from "@bitwarden/common/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { SendApiService } from "@bitwarden/common/abstractions/send/send-api.service.abstraction";
import { StateService } from "@bitwarden/common/abstractions/state.service"; import { StateService } from "@bitwarden/common/abstractions/state.service";
import { TotpService } from "@bitwarden/common/abstractions/totp.service"; import { TotpService } from "@bitwarden/common/abstractions/totp.service";
import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service";
@ -43,7 +44,8 @@ export class EmergencyAddEditComponent extends BaseAddEditComponent {
policyService: PolicyService, policyService: PolicyService,
passwordRepromptService: PasswordRepromptService, passwordRepromptService: PasswordRepromptService,
organizationService: OrganizationService, organizationService: OrganizationService,
logService: LogService logService: LogService,
sendApiService: SendApiService
) { ) {
super( super(
cipherService, cipherService,
@ -60,7 +62,8 @@ export class EmergencyAddEditComponent extends BaseAddEditComponent {
policyService, policyService,
organizationService, organizationService,
logService, logService,
passwordRepromptService passwordRepromptService,
sendApiService
); );
} }

View File

@ -7,7 +7,8 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service"; import { LogService } from "@bitwarden/common/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { SendService } from "@bitwarden/common/abstractions/send.service"; import { SendApiService } from "@bitwarden/common/abstractions/send/send-api.service.abstraction";
import { SendService } from "@bitwarden/common/abstractions/send/send.service.abstraction";
import { StateService } from "@bitwarden/common/abstractions/state.service"; import { StateService } from "@bitwarden/common/abstractions/state.service";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { PolicyType } from "@bitwarden/common/admin-console/enums/policy-type"; import { PolicyType } from "@bitwarden/common/admin-console/enums/policy-type";
@ -58,7 +59,8 @@ export class AddEditComponent implements OnInit, OnDestroy {
protected messagingService: MessagingService, protected messagingService: MessagingService,
protected policyService: PolicyService, protected policyService: PolicyService,
private logService: LogService, private logService: LogService,
protected stateService: StateService protected stateService: StateService,
protected sendApiService: SendApiService
) { ) {
this.typeOptions = [ this.typeOptions = [
{ name: i18nService.t("sendTypeFile"), value: SendType.File }, { name: i18nService.t("sendTypeFile"), value: SendType.File },
@ -127,7 +129,7 @@ export class AddEditComponent implements OnInit, OnDestroy {
if (this.send == null) { if (this.send == null) {
if (this.editMode) { if (this.editMode) {
const send = await this.loadSend(); const send = this.loadSend();
this.send = await send.decrypt(); this.send = await send.decrypt();
} else { } else {
this.send = new SendView(); this.send = new SendView();
@ -191,7 +193,7 @@ export class AddEditComponent implements OnInit, OnDestroy {
} }
this.formPromise = this.encryptSend(file).then(async (encSend) => { this.formPromise = this.encryptSend(file).then(async (encSend) => {
const uploadPromise = this.sendService.saveWithServer(encSend); const uploadPromise = this.sendApiService.save(encSend);
await uploadPromise; await uploadPromise;
if (this.send.id == null) { if (this.send.id == null) {
this.send.id = encSend[0].id; this.send.id = encSend[0].id;
@ -241,7 +243,7 @@ export class AddEditComponent implements OnInit, OnDestroy {
} }
try { try {
this.deletePromise = this.sendService.deleteWithServer(this.send.id); this.deletePromise = this.sendApiService.delete(this.send.id);
await this.deletePromise; await this.deletePromise;
this.platformUtilsService.showToast("success", null, this.i18nService.t("deletedSend")); this.platformUtilsService.showToast("success", null, this.i18nService.t("deletedSend"));
await this.load(); await this.load();
@ -270,7 +272,7 @@ export class AddEditComponent implements OnInit, OnDestroy {
this.showOptions = !this.showOptions; this.showOptions = !this.showOptions;
} }
protected async loadSend(): Promise<Send> { protected loadSend(): Send {
return this.sendService.get(this.sendId); return this.sendService.get(this.sendId);
} }

View File

@ -6,7 +6,8 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service"; import { LogService } from "@bitwarden/common/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service";
import { SendService } from "@bitwarden/common/abstractions/send.service"; import { SendApiService } from "@bitwarden/common/abstractions/send/send-api.service.abstraction";
import { SendService } from "@bitwarden/common/abstractions/send/send.service.abstraction";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { PolicyType } from "@bitwarden/common/admin-console/enums/policy-type"; import { PolicyType } from "@bitwarden/common/admin-console/enums/policy-type";
import { SendType } from "@bitwarden/common/enums/sendType"; import { SendType } from "@bitwarden/common/enums/sendType";
@ -47,7 +48,8 @@ export class SendComponent implements OnInit, OnDestroy {
protected ngZone: NgZone, protected ngZone: NgZone,
protected searchService: SearchService, protected searchService: SearchService,
protected policyService: PolicyService, protected policyService: PolicyService,
private logService: LogService private logService: LogService,
protected sendApiService: SendApiService
) {} ) {}
async ngOnInit() { async ngOnInit() {
@ -66,8 +68,9 @@ export class SendComponent implements OnInit, OnDestroy {
async load(filter: (send: SendView) => boolean = null) { async load(filter: (send: SendView) => boolean = null) {
this.loading = true; this.loading = true;
const sends = await this.sendService.getAllDecrypted(); this.sendService.sendViews$.pipe(takeUntil(this.destroy$)).subscribe((sends) => {
this.sends = sends; this.sends = sends;
});
if (this.onSuccessfulLoad != null) { if (this.onSuccessfulLoad != null) {
await this.onSuccessfulLoad(); await this.onSuccessfulLoad();
} else { } else {
@ -134,7 +137,7 @@ export class SendComponent implements OnInit, OnDestroy {
} }
try { try {
this.actionPromise = this.sendService.removePasswordWithServer(s.id); this.actionPromise = this.sendApiService.removePassword(s.id);
await this.actionPromise; await this.actionPromise;
if (this.onSuccessfulRemovePassword != null) { if (this.onSuccessfulRemovePassword != null) {
this.onSuccessfulRemovePassword(); this.onSuccessfulRemovePassword();
@ -165,7 +168,7 @@ export class SendComponent implements OnInit, OnDestroy {
} }
try { try {
this.actionPromise = this.sendService.deleteWithServer(s.id); this.actionPromise = this.sendApiService.delete(s.id);
await this.actionPromise; await this.actionPromise;
if (this.onSuccessfulDelete != null) { if (this.onSuccessfulDelete != null) {

View File

@ -15,7 +15,7 @@ import { EnvironmentService as EnvironmentServiceAbstraction } from "@bitwarden/
import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service"; import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service";
import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/common/abstractions/event/event-upload.service"; import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/common/abstractions/event/event-upload.service";
import { ExportService as ExportServiceAbstraction } from "@bitwarden/common/abstractions/export.service"; import { ExportService as ExportServiceAbstraction } from "@bitwarden/common/abstractions/export.service";
import { FileUploadService as FileUploadServiceAbstraction } from "@bitwarden/common/abstractions/fileUpload.service"; import { FileUploadService as FileUploadServiceAbstraction } from "@bitwarden/common/abstractions/file-upload/file-upload.service";
import { FormValidationErrorsService as FormValidationErrorsServiceAbstraction } from "@bitwarden/common/abstractions/formValidationErrors.service"; import { FormValidationErrorsService as FormValidationErrorsServiceAbstraction } from "@bitwarden/common/abstractions/formValidationErrors.service";
import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/abstractions/i18n.service"; import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service"; import { LogService } from "@bitwarden/common/abstractions/log.service";
@ -29,7 +29,8 @@ import {
import { OrganizationUserService } from "@bitwarden/common/abstractions/organization-user/organization-user.service"; import { OrganizationUserService } from "@bitwarden/common/abstractions/organization-user/organization-user.service";
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/abstractions/platformUtils.service"; import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/abstractions/platformUtils.service";
import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/abstractions/search.service"; import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/abstractions/search.service";
import { SendService as SendServiceAbstraction } from "@bitwarden/common/abstractions/send.service"; import { SendApiService as SendApiServiceAbstraction } from "@bitwarden/common/abstractions/send/send-api.service.abstraction";
import { SendService as SendServiceAbstraction } from "@bitwarden/common/abstractions/send/send.service.abstraction";
import { SettingsService as SettingsServiceAbstraction } from "@bitwarden/common/abstractions/settings.service"; import { SettingsService as SettingsServiceAbstraction } from "@bitwarden/common/abstractions/settings.service";
import { StateService as StateServiceAbstraction } from "@bitwarden/common/abstractions/state.service"; import { StateService as StateServiceAbstraction } from "@bitwarden/common/abstractions/state.service";
import { StateMigrationService as StateMigrationServiceAbstraction } from "@bitwarden/common/abstractions/stateMigration.service"; import { StateMigrationService as StateMigrationServiceAbstraction } from "@bitwarden/common/abstractions/stateMigration.service";
@ -96,14 +97,15 @@ import { EnvironmentService } from "@bitwarden/common/services/environment.servi
import { EventCollectionService } from "@bitwarden/common/services/event/event-collection.service"; import { EventCollectionService } from "@bitwarden/common/services/event/event-collection.service";
import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service"; import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service";
import { ExportService } from "@bitwarden/common/services/export.service"; import { ExportService } from "@bitwarden/common/services/export.service";
import { FileUploadService } from "@bitwarden/common/services/fileUpload.service"; import { FileUploadService } from "@bitwarden/common/services/file-upload/file-upload.service";
import { FormValidationErrorsService } from "@bitwarden/common/services/formValidationErrors.service"; import { FormValidationErrorsService } from "@bitwarden/common/services/formValidationErrors.service";
import { NotificationsService } from "@bitwarden/common/services/notifications.service"; import { NotificationsService } from "@bitwarden/common/services/notifications.service";
import { OrgDomainApiService } from "@bitwarden/common/services/organization-domain/org-domain-api.service"; import { OrgDomainApiService } from "@bitwarden/common/services/organization-domain/org-domain-api.service";
import { OrgDomainService } from "@bitwarden/common/services/organization-domain/org-domain.service"; import { OrgDomainService } from "@bitwarden/common/services/organization-domain/org-domain.service";
import { OrganizationUserServiceImplementation } from "@bitwarden/common/services/organization-user/organization-user.service.implementation"; import { OrganizationUserServiceImplementation } from "@bitwarden/common/services/organization-user/organization-user.service.implementation";
import { SearchService } from "@bitwarden/common/services/search.service"; import { SearchService } from "@bitwarden/common/services/search.service";
import { SendService } from "@bitwarden/common/services/send.service"; import { SendApiService } from "@bitwarden/common/services/send/send-api.service";
import { SendService } from "@bitwarden/common/services/send/send.service";
import { SettingsService } from "@bitwarden/common/services/settings.service"; import { SettingsService } from "@bitwarden/common/services/settings.service";
import { StateService } from "@bitwarden/common/services/state.service"; import { StateService } from "@bitwarden/common/services/state.service";
import { StateMigrationService } from "@bitwarden/common/services/stateMigration.service"; import { StateMigrationService } from "@bitwarden/common/services/stateMigration.service";
@ -121,6 +123,7 @@ import {
UsernameGenerationServiceAbstraction, UsernameGenerationServiceAbstraction,
} from "@bitwarden/common/tools/generator/username"; } from "@bitwarden/common/tools/generator/username";
import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/vault/abstractions/cipher.service";
import { CipherFileUploadService as CipherFileUploadServiceAbstraction } from "@bitwarden/common/vault/abstractions/file-upload/cipher-file-upload.service";
import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction"; import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction";
import { import {
FolderService as FolderServiceAbstraction, FolderService as FolderServiceAbstraction,
@ -130,6 +133,7 @@ import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "@
import { SyncNotifierService as SyncNotifierServiceAbstraction } from "@bitwarden/common/vault/abstractions/sync/sync-notifier.service.abstraction"; import { SyncNotifierService as SyncNotifierServiceAbstraction } from "@bitwarden/common/vault/abstractions/sync/sync-notifier.service.abstraction";
import { SyncService as SyncServiceAbstraction } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { SyncService as SyncServiceAbstraction } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
import { CipherService } from "@bitwarden/common/vault/services/cipher.service"; import { CipherService } from "@bitwarden/common/vault/services/cipher.service";
import { CipherFileUploadService } from "@bitwarden/common/vault/services/file-upload/cipher-file-upload.service";
import { FolderApiService } from "@bitwarden/common/vault/services/folder/folder-api.service"; import { FolderApiService } from "@bitwarden/common/vault/services/folder/folder-api.service";
import { FolderService } from "@bitwarden/common/vault/services/folder/folder.service"; import { FolderService } from "@bitwarden/common/vault/services/folder/folder.service";
import { SyncNotifierService } from "@bitwarden/common/vault/services/sync/sync-notifier.service"; import { SyncNotifierService } from "@bitwarden/common/vault/services/sync/sync-notifier.service";
@ -230,40 +234,50 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction";
I18nServiceAbstraction, I18nServiceAbstraction,
], ],
}, },
{
provide: FileUploadServiceAbstraction,
useClass: FileUploadService,
deps: [LoginServiceAbstraction],
},
{
provide: CipherFileUploadServiceAbstraction,
useClass: CipherFileUploadService,
deps: [ApiServiceAbstraction, FileUploadServiceAbstraction],
},
{ {
provide: CipherServiceAbstraction, provide: CipherServiceAbstraction,
useFactory: ( useFactory: (
cryptoService: CryptoServiceAbstraction, cryptoService: CryptoServiceAbstraction,
settingsService: SettingsServiceAbstraction, settingsService: SettingsServiceAbstraction,
apiService: ApiServiceAbstraction, apiService: ApiServiceAbstraction,
fileUploadService: FileUploadServiceAbstraction,
i18nService: I18nServiceAbstraction, i18nService: I18nServiceAbstraction,
injector: Injector, injector: Injector,
logService: LogService, logService: LogService,
stateService: StateServiceAbstraction, stateService: StateServiceAbstraction,
encryptService: EncryptService encryptService: EncryptService,
fileUploadService: CipherFileUploadServiceAbstraction
) => ) =>
new CipherService( new CipherService(
cryptoService, cryptoService,
settingsService, settingsService,
apiService, apiService,
fileUploadService,
i18nService, i18nService,
() => injector.get(SearchServiceAbstraction), () => injector.get(SearchServiceAbstraction),
logService, logService,
stateService, stateService,
encryptService encryptService,
fileUploadService
), ),
deps: [ deps: [
CryptoServiceAbstraction, CryptoServiceAbstraction,
SettingsServiceAbstraction, SettingsServiceAbstraction,
ApiServiceAbstraction, ApiServiceAbstraction,
FileUploadServiceAbstraction,
I18nServiceAbstraction, I18nServiceAbstraction,
Injector, // TODO: Get rid of this circular dependency! Injector, // TODO: Get rid of this circular dependency!
LogService, LogService,
StateServiceAbstraction, StateServiceAbstraction,
EncryptService, EncryptService,
CipherFileUploadServiceAbstraction,
], ],
}, },
{ {
@ -359,9 +373,19 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction";
], ],
}, },
{ {
provide: FileUploadServiceAbstraction, provide: SendServiceAbstraction,
useClass: FileUploadService, useClass: SendService,
deps: [LogService, ApiServiceAbstraction], deps: [
CryptoServiceAbstraction,
I18nServiceAbstraction,
CryptoFunctionServiceAbstraction,
StateServiceAbstraction,
],
},
{
provide: SendApiServiceAbstraction,
useClass: SendApiService,
deps: [ApiServiceAbstraction, FileUploadServiceAbstraction, SendServiceAbstraction],
}, },
{ {
provide: SyncServiceAbstraction, provide: SyncServiceAbstraction,
@ -382,6 +406,7 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction";
ProviderServiceAbstraction, ProviderServiceAbstraction,
FolderApiServiceAbstraction, FolderApiServiceAbstraction,
OrganizationServiceAbstraction, OrganizationServiceAbstraction,
SendApiServiceAbstraction,
LOGOUT_CALLBACK, LOGOUT_CALLBACK,
], ],
}, },
@ -508,18 +533,6 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction";
useClass: PolicyApiService, useClass: PolicyApiService,
deps: [PolicyServiceAbstraction, ApiServiceAbstraction, StateServiceAbstraction], deps: [PolicyServiceAbstraction, ApiServiceAbstraction, StateServiceAbstraction],
}, },
{
provide: SendServiceAbstraction,
useClass: SendService,
deps: [
CryptoServiceAbstraction,
ApiServiceAbstraction,
FileUploadServiceAbstraction,
I18nServiceAbstraction,
CryptoFunctionServiceAbstraction,
StateServiceAbstraction,
],
},
{ {
provide: KeyConnectorServiceAbstraction, provide: KeyConnectorServiceAbstraction,
useClass: KeyConnectorService, useClass: KeyConnectorService,

View File

@ -7,6 +7,7 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service"; import { LogService } from "@bitwarden/common/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
import { SendApiService } from "@bitwarden/common/abstractions/send/send-api.service.abstraction";
import { StateService } from "@bitwarden/common/abstractions/state.service"; import { StateService } from "@bitwarden/common/abstractions/state.service";
import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service";
import { import {
@ -99,7 +100,8 @@ export class AddEditComponent implements OnInit, OnDestroy {
protected policyService: PolicyService, protected policyService: PolicyService,
private logService: LogService, private logService: LogService,
protected passwordRepromptService: PasswordRepromptService, protected passwordRepromptService: PasswordRepromptService,
private organizationService: OrganizationService private organizationService: OrganizationService,
protected sendApiService: SendApiService
) { ) {
this.typeOptions = [ this.typeOptions = [
{ name: i18nService.t("typeLogin"), value: CipherType.Login }, { name: i18nService.t("typeLogin"), value: CipherType.Login },

View File

@ -0,0 +1,178 @@
import { any, mock, MockProxy } from "jest-mock-extended";
import { BehaviorSubject, firstValueFrom } from "rxjs";
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { CryptoFunctionService } from "@bitwarden/common/abstractions/cryptoFunction.service";
import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { StateService } from "@bitwarden/common/abstractions/state.service";
import { SendData } from "@bitwarden/common/models/data/send.data";
import { EncString } from "@bitwarden/common/models/domain/enc-string";
import { Send } from "@bitwarden/common/models/domain/send";
import { SendView } from "@bitwarden/common/models/view/send.view";
import { ContainerService } from "@bitwarden/common/services/container.service";
import { SendService } from "@bitwarden/common/services/send/send.service";
describe("SendService", () => {
const cryptoService = mock<CryptoService>();
const i18nService = mock<I18nService>();
const cryptoFunctionService = mock<CryptoFunctionService>();
const encryptService = mock<EncryptService>();
let sendService: SendService;
let stateService: MockProxy<StateService>;
let activeAccount: BehaviorSubject<string>;
let activeAccountUnlocked: BehaviorSubject<boolean>;
beforeEach(() => {
activeAccount = new BehaviorSubject("123");
activeAccountUnlocked = new BehaviorSubject(true);
stateService = mock<StateService>();
stateService.activeAccount$ = activeAccount;
stateService.activeAccountUnlocked$ = activeAccountUnlocked;
(window as any).bitwardenContainerService = new ContainerService(cryptoService, encryptService);
stateService.getEncryptedSends.calledWith(any()).mockResolvedValue({
"1": sendData("1", "Test Send"),
});
stateService.getDecryptedSends
.calledWith(any())
.mockResolvedValue([sendView("1", "Test Send")]);
sendService = new SendService(cryptoService, i18nService, cryptoFunctionService, stateService);
});
afterEach(() => {
activeAccount.complete();
activeAccountUnlocked.complete();
});
describe("get", () => {
it("exists", async () => {
const result = sendService.get("1");
expect(result).toEqual(send("1", "Test Send"));
});
it("does not exist", async () => {
const result = sendService.get("2");
expect(result).toBe(undefined);
});
});
it("getAll", async () => {
const sends = await sendService.getAll();
const send1 = sends[0];
expect(sends).toHaveLength(1);
expect(send1).toEqual(send("1", "Test Send"));
});
describe("getFromState", () => {
it("exists", async () => {
const result = await sendService.getFromState("1");
expect(result).toEqual(send("1", "Test Send"));
});
it("does not exist", async () => {
const result = await sendService.getFromState("2");
expect(result).toBe(null);
});
});
it("getAllDecryptedFromState", async () => {
await sendService.getAllDecryptedFromState();
expect(stateService.getDecryptedSends).toHaveBeenCalledTimes(1);
});
// InternalSendService
it("upsert", async () => {
await sendService.upsert(sendData("2", "Test 2"));
expect(await firstValueFrom(sendService.sends$)).toEqual([
send("1", "Test Send"),
send("2", "Test 2"),
]);
});
it("replace", async () => {
await sendService.replace({ "2": sendData("2", "test 2") });
expect(await firstValueFrom(sendService.sends$)).toEqual([send("2", "test 2")]);
});
it("clear", async () => {
await sendService.clear();
expect(await firstValueFrom(sendService.sends$)).toEqual([]);
});
describe("delete", () => {
it("exists", async () => {
await sendService.delete("1");
expect(stateService.getEncryptedSends).toHaveBeenCalledTimes(2);
expect(stateService.setEncryptedSends).toHaveBeenCalledTimes(1);
});
it("does not exist", async () => {
sendService.delete("1");
expect(stateService.getEncryptedSends).toHaveBeenCalledTimes(2);
});
});
// Send object helper functions
function sendData(id: string, name: string) {
const data = new SendData({} as any);
data.id = id;
data.name = name;
data.disabled = false;
data.accessCount = 2;
data.accessId = "1";
data.revisionDate = null;
data.expirationDate = null;
data.deletionDate = null;
data.notes = "Notes!!";
data.key = null;
return data;
}
function sendView(id: string, name: string) {
const data = new SendView({} as any);
data.id = id;
data.name = name;
data.disabled = false;
data.accessCount = 2;
data.accessId = "1";
data.revisionDate = null;
data.expirationDate = null;
data.deletionDate = null;
data.notes = "Notes!!";
data.key = null;
return data;
}
function send(id: string, name: string) {
const data = new Send({} as any);
data.id = id;
data.name = new EncString(name);
data.disabled = false;
data.accessCount = 2;
data.accessId = "1";
data.revisionDate = null;
data.expirationDate = null;
data.deletionDate = null;
data.notes = new EncString("Notes!!");
data.key = null;
return data;
}
});

View File

@ -112,8 +112,6 @@ import { KeysRequest } from "../models/request/keys.request";
import { OrganizationImportRequest } from "../models/request/organization-import.request"; import { OrganizationImportRequest } from "../models/request/organization-import.request";
import { PreloginRequest } from "../models/request/prelogin.request"; import { PreloginRequest } from "../models/request/prelogin.request";
import { RegisterRequest } from "../models/request/register.request"; import { RegisterRequest } from "../models/request/register.request";
import { SendAccessRequest } from "../models/request/send-access.request";
import { SendRequest } from "../models/request/send.request";
import { StorageRequest } from "../models/request/storage.request"; import { StorageRequest } from "../models/request/storage.request";
import { UpdateAvatarRequest } from "../models/request/update-avatar.request"; import { UpdateAvatarRequest } from "../models/request/update-avatar.request";
import { UpdateDomainsRequest } from "../models/request/update-domains.request"; import { UpdateDomainsRequest } from "../models/request/update-domains.request";
@ -125,12 +123,7 @@ import { DomainsResponse } from "../models/response/domains.response";
import { EventResponse } from "../models/response/event.response"; import { EventResponse } from "../models/response/event.response";
import { ListResponse } from "../models/response/list.response"; import { ListResponse } from "../models/response/list.response";
import { ProfileResponse } from "../models/response/profile.response"; import { ProfileResponse } from "../models/response/profile.response";
import { SendAccessResponse } from "../models/response/send-access.response";
import { SendFileDownloadDataResponse } from "../models/response/send-file-download-data.response";
import { SendFileUploadDataResponse } from "../models/response/send-file-upload-data.response";
import { SendResponse } from "../models/response/send.response";
import { UserKeyResponse } from "../models/response/user-key.response"; import { UserKeyResponse } from "../models/response/user-key.response";
import { SendAccessView } from "../models/view/send-access.view";
import { AttachmentRequest } from "../vault/models/request/attachment.request"; import { AttachmentRequest } from "../vault/models/request/attachment.request";
import { CipherBulkDeleteRequest } from "../vault/models/request/cipher-bulk-delete.request"; import { CipherBulkDeleteRequest } from "../vault/models/request/cipher-bulk-delete.request";
import { CipherBulkMoveRequest } from "../vault/models/request/cipher-bulk-move.request"; import { CipherBulkMoveRequest } from "../vault/models/request/cipher-bulk-move.request";
@ -213,31 +206,6 @@ export abstract class ApiService {
getUserBillingHistory: () => Promise<BillingHistoryResponse>; getUserBillingHistory: () => Promise<BillingHistoryResponse>;
getUserBillingPayment: () => Promise<BillingPaymentResponse>; getUserBillingPayment: () => Promise<BillingPaymentResponse>;
getSend: (id: string) => Promise<SendResponse>;
postSendAccess: (
id: string,
request: SendAccessRequest,
apiUrl?: string
) => Promise<SendAccessResponse>;
getSends: () => Promise<ListResponse<SendResponse>>;
postSend: (request: SendRequest) => Promise<SendResponse>;
postFileTypeSend: (request: SendRequest) => Promise<SendFileUploadDataResponse>;
postSendFile: (sendId: string, fileId: string, data: FormData) => Promise<any>;
/**
* @deprecated Mar 25 2021: This method has been deprecated in favor of direct uploads.
* This method still exists for backward compatibility with old server versions.
*/
postSendFileLegacy: (data: FormData) => Promise<SendResponse>;
putSend: (id: string, request: SendRequest) => Promise<SendResponse>;
putSendRemovePassword: (id: string) => Promise<SendResponse>;
deleteSend: (id: string) => Promise<any>;
getSendFileDownloadData: (
send: SendAccessView,
request: SendAccessRequest,
apiUrl?: string
) => Promise<SendFileDownloadDataResponse>;
renewSendFileUploadUrl: (sendId: string, fileId: string) => Promise<SendFileUploadDataResponse>;
getCipher: (id: string) => Promise<CipherResponse>; getCipher: (id: string) => Promise<CipherResponse>;
getFullCipherDetails: (id: string) => Promise<CipherResponse>; getFullCipherDetails: (id: string) => Promise<CipherResponse>;
getCipherAdmin: (id: string) => Promise<CipherResponse>; getCipherAdmin: (id: string) => Promise<CipherResponse>;

View File

@ -0,0 +1,18 @@
import { FileUploadType } from "../../enums/fileUploadType";
import { EncArrayBuffer } from "../../models/domain/enc-array-buffer";
import { EncString } from "../../models/domain/enc-string";
export abstract class FileUploadService {
upload: (
uploadData: { url: string; fileUploadType: FileUploadType },
fileName: EncString,
encryptedFileData: EncArrayBuffer,
fileUploadMethods: FileUploadApiMethods
) => Promise<void>;
}
export type FileUploadApiMethods = {
postDirect: (fileData: FormData) => Promise<void>;
renewFileUploadUrl: () => Promise<string>;
rollback: () => Promise<void>;
};

View File

@ -1,18 +0,0 @@
import { EncArrayBuffer } from "../models/domain/enc-array-buffer";
import { EncString } from "../models/domain/enc-string";
import { SendFileUploadDataResponse } from "../models/response/send-file-upload-data.response";
import { AttachmentUploadDataResponse } from "../vault/models/response/attachment-upload-data.response";
export abstract class FileUploadService {
uploadSendFile: (
uploadData: SendFileUploadDataResponse,
fileName: EncString,
encryptedFileData: EncArrayBuffer
) => Promise<any>;
uploadCipherAttachment: (
admin: boolean,
uploadData: AttachmentUploadDataResponse,
fileName: EncString,
encryptedFileData: EncArrayBuffer
) => Promise<any>;
}

View File

@ -1,25 +0,0 @@
import { SendData } from "../models/data/send.data";
import { EncArrayBuffer } from "../models/domain/enc-array-buffer";
import { Send } from "../models/domain/send";
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
import { SendView } from "../models/view/send.view";
export abstract class SendService {
clearCache: () => Promise<void>;
encrypt: (
model: SendView,
file: File | ArrayBuffer,
password: string,
key?: SymmetricCryptoKey
) => Promise<[Send, EncArrayBuffer]>;
get: (id: string) => Promise<Send>;
getAll: () => Promise<Send[]>;
getAllDecrypted: () => Promise<SendView[]>;
saveWithServer: (sendData: [Send, EncArrayBuffer]) => Promise<any>;
upsert: (send: SendData | SendData[]) => Promise<any>;
replace: (sends: { [id: string]: SendData }) => Promise<any>;
clear: (userId: string) => Promise<any>;
delete: (id: string | string[]) => Promise<any>;
deleteWithServer: (id: string) => Promise<any>;
removePasswordWithServer: (id: string) => Promise<any>;
}

View File

@ -0,0 +1,40 @@
import { EncArrayBuffer } from "../../models/domain/enc-array-buffer";
import { Send } from "../../models/domain/send";
import { SendAccessRequest } from "../../models/request/send-access.request";
import { SendRequest } from "../../models/request/send.request";
import { ListResponse } from "../../models/response/list.response";
import { SendAccessResponse } from "../../models/response/send-access.response";
import { SendFileDownloadDataResponse } from "../../models/response/send-file-download-data.response";
import { SendFileUploadDataResponse } from "../../models/response/send-file-upload-data.response";
import { SendResponse } from "../../models/response/send.response";
import { SendAccessView } from "../../models/view/send-access.view";
export abstract class SendApiService {
getSend: (id: string) => Promise<SendResponse>;
postSendAccess: (
id: string,
request: SendAccessRequest,
apiUrl?: string
) => Promise<SendAccessResponse>;
getSends: () => Promise<ListResponse<SendResponse>>;
postSend: (request: SendRequest) => Promise<SendResponse>;
postFileTypeSend: (request: SendRequest) => Promise<SendFileUploadDataResponse>;
postSendFile: (sendId: string, fileId: string, data: FormData) => Promise<any>;
/**
* @deprecated Mar 25 2021: This method has been deprecated in favor of direct uploads.
* This method still exists for backward compatibility with old server versions.
*/
postSendFileLegacy: (data: FormData) => Promise<SendResponse>;
putSend: (id: string, request: SendRequest) => Promise<SendResponse>;
putSendRemovePassword: (id: string) => Promise<SendResponse>;
deleteSend: (id: string) => Promise<any>;
getSendFileDownloadData: (
send: SendAccessView,
request: SendAccessRequest,
apiUrl?: string
) => Promise<SendFileDownloadDataResponse>;
renewSendFileUploadUrl: (sendId: string, fileId: string) => Promise<SendFileUploadDataResponse>;
removePassword: (id: string) => Promise<any>;
delete: (id: string) => Promise<any>;
save: (sendData: [Send, EncArrayBuffer]) => Promise<any>;
}

View File

@ -0,0 +1,39 @@
import { Observable } from "rxjs";
import { SendData } from "../../models/data/send.data";
import { EncArrayBuffer } from "../../models/domain/enc-array-buffer";
import { Send } from "../../models/domain/send";
import { SymmetricCryptoKey } from "../../models/domain/symmetric-crypto-key";
import { SendView } from "../../models/view/send.view";
export abstract class SendService {
sends$: Observable<Send[]>;
sendViews$: Observable<SendView[]>;
encrypt: (
model: SendView,
file: File | ArrayBuffer,
password: string,
key?: SymmetricCryptoKey
) => Promise<[Send, EncArrayBuffer]>;
get: (id: string) => Send;
/**
* @deprecated Do not call this, use the sends$ observable collection
*/
getAll: () => Promise<Send[]>;
/**
* @deprecated Only use in CLI
*/
getFromState: (id: string) => Promise<Send>;
/**
* @deprecated Only use in CLI
*/
getAllDecryptedFromState: () => Promise<SendView[]>;
}
export abstract class InternalSendService extends SendService {
upsert: (send: SendData | SendData[]) => Promise<any>;
replace: (sends: { [id: string]: SendData }) => Promise<void>;
clear: (userId: string) => Promise<any>;
delete: (id: string | string[]) => Promise<any>;
}

View File

@ -120,7 +120,13 @@ export abstract class StateService<T extends Account = Account> {
value: Map<string, SymmetricCryptoKey>, value: Map<string, SymmetricCryptoKey>,
options?: StorageOptions options?: StorageOptions
) => Promise<void>; ) => Promise<void>;
/**
* @deprecated Do not call this directly, use SendService
*/
getDecryptedSends: (options?: StorageOptions) => Promise<SendView[]>; getDecryptedSends: (options?: StorageOptions) => Promise<SendView[]>;
/**
* @deprecated Do not call this directly, use SendService
*/
setDecryptedSends: (value: SendView[], options?: StorageOptions) => Promise<void>; setDecryptedSends: (value: SendView[], options?: StorageOptions) => Promise<void>;
getDefaultUriMatch: (options?: StorageOptions) => Promise<UriMatchType>; getDefaultUriMatch: (options?: StorageOptions) => Promise<UriMatchType>;
setDefaultUriMatch: (value: UriMatchType, options?: StorageOptions) => Promise<void>; setDefaultUriMatch: (value: UriMatchType, options?: StorageOptions) => Promise<void>;
@ -237,7 +243,13 @@ export abstract class StateService<T extends Account = Account> {
setEncryptedPrivateKey: (value: string, options?: StorageOptions) => Promise<void>; setEncryptedPrivateKey: (value: string, options?: StorageOptions) => Promise<void>;
getEncryptedProviderKeys: (options?: StorageOptions) => Promise<any>; getEncryptedProviderKeys: (options?: StorageOptions) => Promise<any>;
setEncryptedProviderKeys: (value: any, options?: StorageOptions) => Promise<void>; setEncryptedProviderKeys: (value: any, options?: StorageOptions) => Promise<void>;
/**
* @deprecated Do not call this directly, use SendService
*/
getEncryptedSends: (options?: StorageOptions) => Promise<{ [id: string]: SendData }>; getEncryptedSends: (options?: StorageOptions) => Promise<{ [id: string]: SendData }>;
/**
* @deprecated Do not call this directly, use SendService
*/
setEncryptedSends: (value: { [id: string]: SendData }, options?: StorageOptions) => Promise<void>; setEncryptedSends: (value: { [id: string]: SendData }, options?: StorageOptions) => Promise<void>;
getEntityId: (options?: StorageOptions) => Promise<string>; getEntityId: (options?: StorageOptions) => Promise<string>;
setEntityId: (value: string, options?: StorageOptions) => Promise<void>; setEntityId: (value: string, options?: StorageOptions) => Promise<void>;

View File

@ -1,3 +1,5 @@
import { Jsonify } from "type-fest";
import { SendFileData } from "../data/send-file.data"; import { SendFileData } from "../data/send-file.data";
import { SendFileView } from "../view/send-file.view"; import { SendFileView } from "../view/send-file.view";
@ -41,4 +43,14 @@ export class SendFile extends Domain {
); );
return view; return view;
} }
static fromJSON(obj: Jsonify<SendFile>) {
if (obj == null) {
return null;
}
return Object.assign(new SendFile(), obj, {
fileName: EncString.fromJSON(obj.fileName),
});
}
} }

View File

@ -1,3 +1,5 @@
import { Jsonify } from "type-fest";
import { SendTextData } from "../data/send-text.data"; import { SendTextData } from "../data/send-text.data";
import { SendTextView } from "../view/send-text.view"; import { SendTextView } from "../view/send-text.view";
@ -36,4 +38,14 @@ export class SendText extends Domain {
key key
); );
} }
static fromJSON(obj: Jsonify<SendText>) {
if (obj == null) {
return null;
}
return Object.assign(new SendText(), obj, {
text: EncString.fromJSON(obj.text),
});
}
} }

View File

@ -1,3 +1,5 @@
import { Jsonify } from "type-fest";
import { SendType } from "../../enums/sendType"; import { SendType } from "../../enums/sendType";
import { Utils } from "../../misc/utils"; import { Utils } from "../../misc/utils";
import { SendData } from "../data/send.data"; import { SendData } from "../data/send.data";
@ -102,4 +104,25 @@ export class Send extends Domain {
return model; return model;
} }
static fromJSON(obj: Jsonify<Send>) {
if (obj == null) {
return null;
}
const revisionDate = obj.revisionDate == null ? null : new Date(obj.revisionDate);
const expirationDate = obj.expirationDate == null ? null : new Date(obj.expirationDate);
const deletionDate = obj.deletionDate == null ? null : new Date(obj.deletionDate);
return Object.assign(new Send(), obj, {
key: EncString.fromJSON(obj.key),
name: EncString.fromJSON(obj.name),
notes: EncString.fromJSON(obj.notes),
text: SendText.fromJSON(obj.text),
file: SendFile.fromJSON(obj.file),
revisionDate,
expirationDate,
deletionDate,
});
}
} }

View File

@ -121,8 +121,6 @@ import { KeysRequest } from "../models/request/keys.request";
import { OrganizationImportRequest } from "../models/request/organization-import.request"; import { OrganizationImportRequest } from "../models/request/organization-import.request";
import { PreloginRequest } from "../models/request/prelogin.request"; import { PreloginRequest } from "../models/request/prelogin.request";
import { RegisterRequest } from "../models/request/register.request"; import { RegisterRequest } from "../models/request/register.request";
import { SendAccessRequest } from "../models/request/send-access.request";
import { SendRequest } from "../models/request/send.request";
import { StorageRequest } from "../models/request/storage.request"; import { StorageRequest } from "../models/request/storage.request";
import { UpdateAvatarRequest } from "../models/request/update-avatar.request"; import { UpdateAvatarRequest } from "../models/request/update-avatar.request";
import { UpdateDomainsRequest } from "../models/request/update-domains.request"; import { UpdateDomainsRequest } from "../models/request/update-domains.request";
@ -135,12 +133,7 @@ import { ErrorResponse } from "../models/response/error.response";
import { EventResponse } from "../models/response/event.response"; import { EventResponse } from "../models/response/event.response";
import { ListResponse } from "../models/response/list.response"; import { ListResponse } from "../models/response/list.response";
import { ProfileResponse } from "../models/response/profile.response"; import { ProfileResponse } from "../models/response/profile.response";
import { SendAccessResponse } from "../models/response/send-access.response";
import { SendFileDownloadDataResponse } from "../models/response/send-file-download-data.response";
import { SendFileUploadDataResponse } from "../models/response/send-file-upload-data.response";
import { SendResponse } from "../models/response/send.response";
import { UserKeyResponse } from "../models/response/user-key.response"; import { UserKeyResponse } from "../models/response/user-key.response";
import { SendAccessView } from "../models/view/send-access.view";
import { AttachmentRequest } from "../vault/models/request/attachment.request"; import { AttachmentRequest } from "../vault/models/request/attachment.request";
import { CipherBulkDeleteRequest } from "../vault/models/request/cipher-bulk-delete.request"; import { CipherBulkDeleteRequest } from "../vault/models/request/cipher-bulk-delete.request";
import { CipherBulkMoveRequest } from "../vault/models/request/cipher-bulk-move.request"; import { CipherBulkMoveRequest } from "../vault/models/request/cipher-bulk-move.request";
@ -485,103 +478,6 @@ export class ApiService implements ApiServiceAbstraction {
return new BillingPaymentResponse(r); return new BillingPaymentResponse(r);
} }
// Send APIs
async getSend(id: string): Promise<SendResponse> {
const r = await this.send("GET", "/sends/" + id, null, true, true);
return new SendResponse(r);
}
async postSendAccess(
id: string,
request: SendAccessRequest,
apiUrl?: string
): Promise<SendAccessResponse> {
const addSendIdHeader = (headers: Headers) => {
headers.set("Send-Id", id);
};
const r = await this.send(
"POST",
"/sends/access/" + id,
request,
false,
true,
apiUrl,
addSendIdHeader
);
return new SendAccessResponse(r);
}
async getSendFileDownloadData(
send: SendAccessView,
request: SendAccessRequest,
apiUrl?: string
): Promise<SendFileDownloadDataResponse> {
const addSendIdHeader = (headers: Headers) => {
headers.set("Send-Id", send.id);
};
const r = await this.send(
"POST",
"/sends/" + send.id + "/access/file/" + send.file.id,
request,
false,
true,
apiUrl,
addSendIdHeader
);
return new SendFileDownloadDataResponse(r);
}
async getSends(): Promise<ListResponse<SendResponse>> {
const r = await this.send("GET", "/sends", null, true, true);
return new ListResponse(r, SendResponse);
}
async postSend(request: SendRequest): Promise<SendResponse> {
const r = await this.send("POST", "/sends", request, true, true);
return new SendResponse(r);
}
async postFileTypeSend(request: SendRequest): Promise<SendFileUploadDataResponse> {
const r = await this.send("POST", "/sends/file/v2", request, true, true);
return new SendFileUploadDataResponse(r);
}
async renewSendFileUploadUrl(
sendId: string,
fileId: string
): Promise<SendFileUploadDataResponse> {
const r = await this.send("GET", "/sends/" + sendId + "/file/" + fileId, null, true, true);
return new SendFileUploadDataResponse(r);
}
postSendFile(sendId: string, fileId: string, data: FormData): Promise<any> {
return this.send("POST", "/sends/" + sendId + "/file/" + fileId, data, true, false);
}
/**
* @deprecated Mar 25 2021: This method has been deprecated in favor of direct uploads.
* This method still exists for backward compatibility with old server versions.
*/
async postSendFileLegacy(data: FormData): Promise<SendResponse> {
const r = await this.send("POST", "/sends/file", data, true, true);
return new SendResponse(r);
}
async putSend(id: string, request: SendRequest): Promise<SendResponse> {
const r = await this.send("PUT", "/sends/" + id, request, true, true);
return new SendResponse(r);
}
async putSendRemovePassword(id: string): Promise<SendResponse> {
const r = await this.send("PUT", "/sends/" + id + "/remove-password", null, true, true);
return new SendResponse(r);
}
deleteSend(id: string): Promise<any> {
return this.send("DELETE", "/sends/" + id, null, true, false);
}
// Cipher APIs // Cipher APIs
async getCipher(id: string): Promise<CipherResponse> { async getCipher(id: string): Promise<CipherResponse> {

View File

@ -0,0 +1,52 @@
import {
FileUploadApiMethods,
FileUploadService as FileUploadServiceAbstraction,
} from "../../abstractions/file-upload/file-upload.service";
import { LogService } from "../../abstractions/log.service";
import { FileUploadType } from "../../enums/fileUploadType";
import { EncArrayBuffer } from "../../models/domain/enc-array-buffer";
import { EncString } from "../../models/domain/enc-string";
import { AzureFileUploadService } from "../azureFileUpload.service";
import { BitwardenFileUploadService } from "../bitwardenFileUpload.service";
export class FileUploadService implements FileUploadServiceAbstraction {
private azureFileUploadService: AzureFileUploadService;
private bitwardenFileUploadService: BitwardenFileUploadService;
constructor(protected logService: LogService) {
this.azureFileUploadService = new AzureFileUploadService(logService);
this.bitwardenFileUploadService = new BitwardenFileUploadService();
}
async upload(
uploadData: { url: string; fileUploadType: FileUploadType },
fileName: EncString,
encryptedFileData: EncArrayBuffer,
fileUploadMethods: FileUploadApiMethods
) {
try {
switch (uploadData.fileUploadType) {
case FileUploadType.Direct:
await this.bitwardenFileUploadService.upload(
fileName.encryptedString,
encryptedFileData,
(fd) => fileUploadMethods.postDirect(fd)
);
break;
case FileUploadType.Azure: {
await this.azureFileUploadService.upload(
uploadData.url,
encryptedFileData,
fileUploadMethods.renewFileUploadUrl
);
break;
}
default:
throw new Error("Unknown file upload type");
}
} catch (e) {
await fileUploadMethods.rollback();
throw e;
}
}
}

View File

@ -1,108 +0,0 @@
import { ApiService } from "../abstractions/api.service";
import { FileUploadService as FileUploadServiceAbstraction } from "../abstractions/fileUpload.service";
import { LogService } from "../abstractions/log.service";
import { FileUploadType } from "../enums/fileUploadType";
import { EncArrayBuffer } from "../models/domain/enc-array-buffer";
import { EncString } from "../models/domain/enc-string";
import { SendFileUploadDataResponse } from "../models/response/send-file-upload-data.response";
import { AttachmentUploadDataResponse } from "../vault/models/response/attachment-upload-data.response";
import { AzureFileUploadService } from "./azureFileUpload.service";
import { BitwardenFileUploadService } from "./bitwardenFileUpload.service";
export class FileUploadService implements FileUploadServiceAbstraction {
private azureFileUploadService: AzureFileUploadService;
private bitwardenFileUploadService: BitwardenFileUploadService;
constructor(private logService: LogService, private apiService: ApiService) {
this.azureFileUploadService = new AzureFileUploadService(logService);
this.bitwardenFileUploadService = new BitwardenFileUploadService();
}
async uploadSendFile(
uploadData: SendFileUploadDataResponse,
fileName: EncString,
encryptedFileData: EncArrayBuffer
) {
try {
switch (uploadData.fileUploadType) {
case FileUploadType.Direct:
await this.bitwardenFileUploadService.upload(
fileName.encryptedString,
encryptedFileData,
(fd) =>
this.apiService.postSendFile(
uploadData.sendResponse.id,
uploadData.sendResponse.file.id,
fd
)
);
break;
case FileUploadType.Azure: {
const renewalCallback = async () => {
const renewalResponse = await this.apiService.renewSendFileUploadUrl(
uploadData.sendResponse.id,
uploadData.sendResponse.file.id
);
return renewalResponse.url;
};
await this.azureFileUploadService.upload(
uploadData.url,
encryptedFileData,
renewalCallback
);
break;
}
default:
throw new Error("Unknown file upload type");
}
} catch (e) {
await this.apiService.deleteSend(uploadData.sendResponse.id);
throw e;
}
}
async uploadCipherAttachment(
admin: boolean,
uploadData: AttachmentUploadDataResponse,
encryptedFileName: EncString,
encryptedFileData: EncArrayBuffer
) {
const response = admin ? uploadData.cipherMiniResponse : uploadData.cipherResponse;
try {
switch (uploadData.fileUploadType) {
case FileUploadType.Direct:
await this.bitwardenFileUploadService.upload(
encryptedFileName.encryptedString,
encryptedFileData,
(fd) => this.apiService.postAttachmentFile(response.id, uploadData.attachmentId, fd)
);
break;
case FileUploadType.Azure: {
const renewalCallback = async () => {
const renewalResponse = await this.apiService.renewAttachmentUploadUrl(
response.id,
uploadData.attachmentId
);
return renewalResponse.url;
};
await this.azureFileUploadService.upload(
uploadData.url,
encryptedFileData,
renewalCallback
);
break;
}
default:
throw new Error("Unknown file upload type.");
}
} catch (e) {
if (admin) {
await this.apiService.deleteCipherAttachmentAdmin(response.id, uploadData.attachmentId);
} else {
await this.apiService.deleteCipherAttachment(response.id, uploadData.attachmentId);
}
throw e;
}
}
}

View File

@ -0,0 +1,251 @@
import { SendType } from "../../../../common/src/enums/sendType";
import { Utils } from "../../../../common/src/misc/utils";
import { ErrorResponse } from "../../../../common/src/models/response/error.response";
import { ApiService } from "../../abstractions/api.service";
import {
FileUploadApiMethods,
FileUploadService,
} from "../../abstractions/file-upload/file-upload.service";
import { SendApiService as SendApiServiceAbstraction } from "../../abstractions/send/send-api.service.abstraction";
import { InternalSendService } from "../../abstractions/send/send.service.abstraction";
import { SendData } from "../../models/data/send.data";
import { EncArrayBuffer } from "../../models/domain/enc-array-buffer";
import { Send } from "../../models/domain/send";
import { SendAccessRequest } from "../../models/request/send-access.request";
import { SendRequest } from "../../models/request/send.request";
import { ListResponse } from "../../models/response/list.response";
import { SendAccessResponse } from "../../models/response/send-access.response";
import { SendFileDownloadDataResponse } from "../../models/response/send-file-download-data.response";
import { SendFileUploadDataResponse } from "../../models/response/send-file-upload-data.response";
import { SendResponse } from "../../models/response/send.response";
import { SendAccessView } from "../../models/view/send-access.view";
export class SendApiService implements SendApiServiceAbstraction {
constructor(
private apiService: ApiService,
private fileUploadService: FileUploadService,
private sendService: InternalSendService
) {}
async getSend(id: string): Promise<SendResponse> {
const r = await this.apiService.send("GET", "/sends/" + id, null, true, true);
return new SendResponse(r);
}
async postSendAccess(
id: string,
request: SendAccessRequest,
apiUrl?: string
): Promise<SendAccessResponse> {
const addSendIdHeader = (headers: Headers) => {
headers.set("Send-Id", id);
};
const r = await this.apiService.send(
"POST",
"/sends/access/" + id,
request,
false,
true,
apiUrl,
addSendIdHeader
);
return new SendAccessResponse(r);
}
async getSendFileDownloadData(
send: SendAccessView,
request: SendAccessRequest,
apiUrl?: string
): Promise<SendFileDownloadDataResponse> {
const addSendIdHeader = (headers: Headers) => {
headers.set("Send-Id", send.id);
};
const r = await this.apiService.send(
"POST",
"/sends/" + send.id + "/access/file/" + send.file.id,
request,
false,
true,
apiUrl,
addSendIdHeader
);
return new SendFileDownloadDataResponse(r);
}
async getSends(): Promise<ListResponse<SendResponse>> {
const r = await this.apiService.send("GET", "/sends", null, true, true);
return new ListResponse(r, SendResponse);
}
async postSend(request: SendRequest): Promise<SendResponse> {
const r = await this.apiService.send("POST", "/sends", request, true, true);
return new SendResponse(r);
}
async postFileTypeSend(request: SendRequest): Promise<SendFileUploadDataResponse> {
const r = await this.apiService.send("POST", "/sends/file/v2", request, true, true);
return new SendFileUploadDataResponse(r);
}
async renewSendFileUploadUrl(
sendId: string,
fileId: string
): Promise<SendFileUploadDataResponse> {
const r = await this.apiService.send(
"GET",
"/sends/" + sendId + "/file/" + fileId,
null,
true,
true
);
return new SendFileUploadDataResponse(r);
}
postSendFile(sendId: string, fileId: string, data: FormData): Promise<any> {
return this.apiService.send("POST", "/sends/" + sendId + "/file/" + fileId, data, true, false);
}
/**
* @deprecated Mar 25 2021: This method has been deprecated in favor of direct uploads.
* This method still exists for backward compatibility with old server versions.
*/
async postSendFileLegacy(data: FormData): Promise<SendResponse> {
const r = await this.apiService.send("POST", "/sends/file", data, true, true);
return new SendResponse(r);
}
async putSend(id: string, request: SendRequest): Promise<SendResponse> {
const r = await this.apiService.send("PUT", "/sends/" + id, request, true, true);
return new SendResponse(r);
}
async putSendRemovePassword(id: string): Promise<SendResponse> {
const r = await this.apiService.send(
"PUT",
"/sends/" + id + "/remove-password",
null,
true,
true
);
return new SendResponse(r);
}
deleteSend(id: string): Promise<any> {
return this.apiService.send("DELETE", "/sends/" + id, null, true, false);
}
async save(sendData: [Send, EncArrayBuffer]): Promise<any> {
const response = await this.upload(sendData);
const data = new SendData(response);
await this.sendService.upsert(data);
}
async delete(id: string): Promise<any> {
await this.deleteSend(id);
await this.sendService.delete(id);
}
async removePassword(id: string): Promise<any> {
const response = await this.putSendRemovePassword(id);
const data = new SendData(response);
await this.sendService.upsert(data);
}
// Send File Upload methoids
private async upload(sendData: [Send, EncArrayBuffer]): Promise<SendResponse> {
const request = new SendRequest(sendData[0], sendData[1]?.buffer.byteLength);
let response: SendResponse;
if (sendData[0].id == null) {
if (sendData[0].type === SendType.Text) {
response = await this.postSend(request);
} else {
try {
const uploadDataResponse = await this.postFileTypeSend(request);
response = uploadDataResponse.sendResponse;
await this.fileUploadService.upload(
uploadDataResponse,
sendData[0].file.fileName,
sendData[1],
this.generateMethods(uploadDataResponse, response)
);
} catch (e) {
if (e instanceof ErrorResponse && (e as ErrorResponse).statusCode === 404) {
response = await this.legacyServerSendFileUpload(sendData, request);
} else if (e instanceof ErrorResponse) {
throw new Error((e as ErrorResponse).getSingleMessage());
} else {
throw e;
}
}
}
sendData[0].id = response.id;
sendData[0].accessId = response.accessId;
} else {
response = await this.putSend(sendData[0].id, request);
}
return response;
}
private generateMethods(
uploadData: SendFileUploadDataResponse,
response: SendResponse
): FileUploadApiMethods {
return {
postDirect: this.generatePostDirectCallback(response),
renewFileUploadUrl: this.generateRenewFileUploadUrlCallback(response.id, response.file.id),
rollback: this.generateRollbackCallback(response.id),
};
}
private generatePostDirectCallback(sendResponse: SendResponse) {
return (data: FormData) => {
return this.postSendFile(sendResponse.id, sendResponse.file.id, data);
};
}
private generateRenewFileUploadUrlCallback(sendId: string, fileId: string) {
return async () => {
const renewResponse = await this.renewSendFileUploadUrl(sendId, fileId);
return renewResponse?.url;
};
}
private generateRollbackCallback(sendId: string) {
return () => {
return this.deleteSend(sendId);
};
}
/**
* @deprecated Mar 25 2021: This method has been deprecated in favor of direct uploads.
* This method still exists for backward compatibility with old server versions.
*/
async legacyServerSendFileUpload(
sendData: [Send, EncArrayBuffer],
request: SendRequest
): Promise<SendResponse> {
const fd = new FormData();
try {
const blob = new Blob([sendData[1].buffer], { 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].buffer) as any,
{
filepath: sendData[0].file.fileName.encryptedString,
contentType: "application/octet-stream",
} as any
);
} else {
throw e;
}
}
return await this.postSendFileLegacy(fd);
}
}

View File

@ -1,37 +1,58 @@
import { ApiService } from "../abstractions/api.service"; import { BehaviorSubject, concatMap } from "rxjs";
import { CryptoService } from "../abstractions/crypto.service";
import { CryptoFunctionService } from "../abstractions/cryptoFunction.service"; import { CryptoService } from "../../abstractions/crypto.service";
import { FileUploadService } from "../abstractions/fileUpload.service"; import { CryptoFunctionService } from "../../abstractions/cryptoFunction.service";
import { I18nService } from "../abstractions/i18n.service"; import { I18nService } from "../../abstractions/i18n.service";
import { SendService as SendServiceAbstraction } from "../abstractions/send.service"; import { InternalSendService as InternalSendServiceAbstraction } from "../../abstractions/send/send.service.abstraction";
import { StateService } from "../abstractions/state.service"; import { StateService } from "../../abstractions/state.service";
import { SEND_KDF_ITERATIONS } from "../enums/kdfType"; import { SEND_KDF_ITERATIONS } from "../../enums/kdfType";
import { SendType } from "../enums/sendType"; import { SendType } from "../../enums/sendType";
import { Utils } from "../misc/utils"; import { Utils } from "../../misc/utils";
import { SendData } from "../models/data/send.data"; import { SendData } from "../../models/data/send.data";
import { EncArrayBuffer } from "../models/domain/enc-array-buffer"; import { EncArrayBuffer } from "../../models/domain/enc-array-buffer";
import { EncString } from "../models/domain/enc-string"; import { EncString } from "../../models/domain/enc-string";
import { Send } from "../models/domain/send"; import { Send } from "../../models/domain/send";
import { SendFile } from "../models/domain/send-file"; import { SendFile } from "../../models/domain/send-file";
import { SendText } from "../models/domain/send-text"; import { SendText } from "../../models/domain/send-text";
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key"; import { SymmetricCryptoKey } from "../../models/domain/symmetric-crypto-key";
import { SendRequest } from "../models/request/send.request"; import { SendView } from "../../models/view/send.view";
import { ErrorResponse } from "../models/response/error.response";
import { SendResponse } from "../models/response/send.response"; export class SendService implements InternalSendServiceAbstraction {
import { SendView } from "../models/view/send.view"; protected _sends: BehaviorSubject<Send[]> = new BehaviorSubject([]);
protected _sendViews: BehaviorSubject<SendView[]> = new BehaviorSubject([]);
sends$ = this._sends.asObservable();
sendViews$ = this._sendViews.asObservable();
export class SendService implements SendServiceAbstraction {
constructor( constructor(
private cryptoService: CryptoService, private cryptoService: CryptoService,
private apiService: ApiService,
private fileUploadService: FileUploadService,
private i18nService: I18nService, private i18nService: I18nService,
private cryptoFunctionService: CryptoFunctionService, private cryptoFunctionService: CryptoFunctionService,
private stateService: StateService private stateService: StateService
) {} ) {
this.stateService.activeAccountUnlocked$
.pipe(
concatMap(async (unlocked) => {
if (Utils.global.bitwardenContainerService == null) {
return;
}
if (!unlocked) {
this._sends.next([]);
this._sendViews.next([]);
return;
}
const data = await this.stateService.getEncryptedSends();
await this.updateObservables(data);
})
)
.subscribe();
}
async clearCache(): Promise<void> { async clearCache(): Promise<void> {
await this.stateService.setDecryptedSends(null); await this._sendViews.next([]);
} }
async encrypt( async encrypt(
@ -87,7 +108,12 @@ export class SendService implements SendServiceAbstraction {
return [send, fileData]; return [send, fileData];
} }
async get(id: string): Promise<Send> { get(id: string): Send {
const sends = this._sends.getValue();
return sends.find((send) => send.id === id);
}
async getFromState(id: string): Promise<Send> {
const sends = await this.stateService.getEncryptedSends(); const sends = await this.stateService.getEncryptedSends();
// eslint-disable-next-line // eslint-disable-next-line
if (sends == null || !sends.hasOwnProperty(id)) { if (sends == null || !sends.hasOwnProperty(id)) {
@ -109,7 +135,7 @@ export class SendService implements SendServiceAbstraction {
return response; return response;
} }
async getAllDecrypted(): Promise<SendView[]> { async getAllDecryptedFromState(): Promise<SendView[]> {
let decSends = await this.stateService.getDecryptedSends(); let decSends = await this.stateService.getDecryptedSends();
if (decSends != null) { if (decSends != null) {
return decSends; return decSends;
@ -134,79 +160,11 @@ export class SendService implements SendServiceAbstraction {
return decSends; return decSends;
} }
async saveWithServer(sendData: [Send, EncArrayBuffer]): Promise<any> {
const request = new SendRequest(sendData[0], sendData[1]?.buffer.byteLength);
let response: SendResponse;
if (sendData[0].id == null) {
if (sendData[0].type === SendType.Text) {
response = await this.apiService.postSend(request);
} else {
try {
const uploadDataResponse = await this.apiService.postFileTypeSend(request);
response = uploadDataResponse.sendResponse;
await this.fileUploadService.uploadSendFile(
uploadDataResponse,
sendData[0].file.fileName,
sendData[1]
);
} catch (e) {
if (e instanceof ErrorResponse && (e as ErrorResponse).statusCode === 404) {
response = await this.legacyServerSendFileUpload(sendData, request);
} else if (e instanceof ErrorResponse) {
throw new Error((e as ErrorResponse).getSingleMessage());
} else {
throw e;
}
}
}
sendData[0].id = response.id;
sendData[0].accessId = response.accessId;
} else {
response = await this.apiService.putSend(sendData[0].id, request);
}
const data = new SendData(response);
await this.upsert(data);
}
/**
* @deprecated Mar 25 2021: This method has been deprecated in favor of direct uploads.
* This method still exists for backward compatibility with old server versions.
*/
async legacyServerSendFileUpload(
sendData: [Send, EncArrayBuffer],
request: SendRequest
): Promise<SendResponse> {
const fd = new FormData();
try {
const blob = new Blob([sendData[1].buffer], { 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].buffer) as any,
{
filepath: sendData[0].file.fileName.encryptedString,
contentType: "application/octet-stream",
} as any
);
} else {
throw e;
}
}
return await this.apiService.postSendFileLegacy(fd);
}
async upsert(send: SendData | SendData[]): Promise<any> { async upsert(send: SendData | SendData[]): Promise<any> {
let sends = await this.stateService.getEncryptedSends(); let sends = await this.stateService.getEncryptedSends();
if (sends == null) { if (sends == null) {
sends = {}; sends = {};
} }
if (send instanceof SendData) { if (send instanceof SendData) {
const s = send as SendData; const s = send as SendData;
sends[s.id] = s; sends[s.id] = s;
@ -219,14 +177,13 @@ export class SendService implements SendServiceAbstraction {
await this.replace(sends); await this.replace(sends);
} }
async replace(sends: { [id: string]: SendData }): Promise<any> { async clear(userId?: string): Promise<any> {
await this.stateService.setDecryptedSends(null); if (userId == null || userId == (await this.stateService.getUserId())) {
await this.stateService.setEncryptedSends(sends); this._sends.next([]);
} this._sendViews.next([]);
}
async clear(): Promise<any> { await this.stateService.setDecryptedSends(null, { userId: userId });
await this.stateService.setDecryptedSends(null); await this.stateService.setEncryptedSends(null, { userId: userId });
await this.stateService.setEncryptedSends(null);
} }
async delete(id: string | string[]): Promise<any> { async delete(id: string | string[]): Promise<any> {
@ -249,15 +206,9 @@ export class SendService implements SendServiceAbstraction {
await this.replace(sends); await this.replace(sends);
} }
async deleteWithServer(id: string): Promise<any> { async replace(sends: { [id: string]: SendData }): Promise<any> {
await this.apiService.deleteSend(id); await this.updateObservables(sends);
await this.delete(id); await this.stateService.setEncryptedSends(sends);
}
async removePasswordWithServer(id: string): Promise<any> {
const response = await this.apiService.putSendRemovePassword(id);
const data = new SendData(response);
await this.upsert(data);
} }
private parseFile(send: Send, file: File, key: SymmetricCryptoKey): Promise<EncArrayBuffer> { private parseFile(send: Send, file: File, key: SymmetricCryptoKey): Promise<EncArrayBuffer> {
@ -292,4 +243,21 @@ export class SendService implements SendServiceAbstraction {
const encFileData = await this.cryptoService.encryptToBytes(data, key); const encFileData = await this.cryptoService.encryptToBytes(data, key);
return [encFileName, encFileData]; return [encFileName, encFileData];
} }
private async updateObservables(sendsMap: { [id: string]: SendData }) {
const sends = Object.values(sendsMap || {}).map((f) => new Send(f));
this._sends.next(sends);
if (await this.cryptoService.hasKey()) {
this._sendViews.next(await this.decryptSends(sends));
}
}
private async decryptSends(sends: Send[]) {
const decryptSendPromises = sends.map((s) => s.decrypt());
const decryptedSends = await Promise.all(decryptSendPromises);
decryptedSends.sort(Utils.getSortFunction(this.i18nService, "name"));
return decryptedSends;
}
} }

View File

@ -0,0 +1,15 @@
import { EncArrayBuffer } from "../../../models/domain/enc-array-buffer";
import { EncString } from "../../../models/domain/enc-string";
import { SymmetricCryptoKey } from "../../../models/domain/symmetric-crypto-key";
import { Cipher } from "../../models/domain/cipher";
import { CipherResponse } from "../../models/response/cipher.response";
export abstract class CipherFileUploadService {
upload: (
cipher: Cipher,
encFileName: EncString,
encData: EncArrayBuffer,
admin: boolean,
dataEncKey: [SymmetricCryptoKey, EncString]
) => Promise<CipherResponse>;
}

View File

@ -4,7 +4,6 @@ import { Arg, Substitute, SubstituteOf } from "@fluffy-spoon/substitute";
import { ApiService } from "../../abstractions/api.service"; import { ApiService } from "../../abstractions/api.service";
import { CryptoService } from "../../abstractions/crypto.service"; import { CryptoService } from "../../abstractions/crypto.service";
import { EncryptService } from "../../abstractions/encrypt.service"; import { EncryptService } from "../../abstractions/encrypt.service";
import { FileUploadService } from "../../abstractions/fileUpload.service";
import { I18nService } from "../../abstractions/i18n.service"; import { I18nService } from "../../abstractions/i18n.service";
import { LogService } from "../../abstractions/log.service"; import { LogService } from "../../abstractions/log.service";
import { SearchService } from "../../abstractions/search.service"; import { SearchService } from "../../abstractions/search.service";
@ -13,6 +12,7 @@ import { StateService } from "../../abstractions/state.service";
import { EncArrayBuffer } from "../../models/domain/enc-array-buffer"; import { EncArrayBuffer } from "../../models/domain/enc-array-buffer";
import { EncString } from "../../models/domain/enc-string"; import { EncString } from "../../models/domain/enc-string";
import { SymmetricCryptoKey } from "../../models/domain/symmetric-crypto-key"; import { SymmetricCryptoKey } from "../../models/domain/symmetric-crypto-key";
import { CipherFileUploadService } from "../abstractions/file-upload/cipher-file-upload.service";
import { Cipher } from "../models/domain/cipher"; import { Cipher } from "../models/domain/cipher";
import { CipherService } from "./cipher.service"; import { CipherService } from "./cipher.service";
@ -25,7 +25,7 @@ describe("Cipher Service", () => {
let stateService: SubstituteOf<StateService>; let stateService: SubstituteOf<StateService>;
let settingsService: SubstituteOf<SettingsService>; let settingsService: SubstituteOf<SettingsService>;
let apiService: SubstituteOf<ApiService>; let apiService: SubstituteOf<ApiService>;
let fileUploadService: SubstituteOf<FileUploadService>; let cipherFileUploadService: SubstituteOf<CipherFileUploadService>;
let i18nService: SubstituteOf<I18nService>; let i18nService: SubstituteOf<I18nService>;
let searchService: SubstituteOf<SearchService>; let searchService: SubstituteOf<SearchService>;
let logService: SubstituteOf<LogService>; let logService: SubstituteOf<LogService>;
@ -38,7 +38,7 @@ describe("Cipher Service", () => {
stateService = Substitute.for<StateService>(); stateService = Substitute.for<StateService>();
settingsService = Substitute.for<SettingsService>(); settingsService = Substitute.for<SettingsService>();
apiService = Substitute.for<ApiService>(); apiService = Substitute.for<ApiService>();
fileUploadService = Substitute.for<FileUploadService>(); cipherFileUploadService = Substitute.for<CipherFileUploadService>();
i18nService = Substitute.for<I18nService>(); i18nService = Substitute.for<I18nService>();
searchService = Substitute.for<SearchService>(); searchService = Substitute.for<SearchService>();
logService = Substitute.for<LogService>(); logService = Substitute.for<LogService>();
@ -51,12 +51,12 @@ describe("Cipher Service", () => {
cryptoService, cryptoService,
settingsService, settingsService,
apiService, apiService,
fileUploadService,
i18nService, i18nService,
() => searchService, () => searchService,
logService, logService,
stateService, stateService,
encryptService encryptService,
cipherFileUploadService
); );
}); });
@ -67,8 +67,8 @@ describe("Cipher Service", () => {
await cipherService.saveAttachmentRawWithServer(new Cipher(), fileName, fileData); await cipherService.saveAttachmentRawWithServer(new Cipher(), fileName, fileData);
fileUploadService cipherFileUploadService
.received(1) .received(1)
.uploadCipherAttachment(Arg.any(), Arg.any(), new EncString(ENCRYPTED_TEXT), ENCRYPTED_BYTES); .upload(Arg.any(), Arg.any(), ENCRYPTED_BYTES, Arg.any(), Arg.any());
}); });
}); });

View File

@ -3,7 +3,6 @@ import { firstValueFrom } from "rxjs";
import { ApiService } from "../../abstractions/api.service"; import { ApiService } from "../../abstractions/api.service";
import { CryptoService } from "../../abstractions/crypto.service"; import { CryptoService } from "../../abstractions/crypto.service";
import { EncryptService } from "../../abstractions/encrypt.service"; import { EncryptService } from "../../abstractions/encrypt.service";
import { FileUploadService } from "../../abstractions/fileUpload.service";
import { I18nService } from "../../abstractions/i18n.service"; import { I18nService } from "../../abstractions/i18n.service";
import { LogService } from "../../abstractions/log.service"; import { LogService } from "../../abstractions/log.service";
import { SearchService } from "../../abstractions/search.service"; import { SearchService } from "../../abstractions/search.service";
@ -21,6 +20,7 @@ import { SymmetricCryptoKey } from "../../models/domain/symmetric-crypto-key";
import { ErrorResponse } from "../../models/response/error.response"; import { ErrorResponse } from "../../models/response/error.response";
import { View } from "../../models/view/view"; import { View } from "../../models/view/view";
import { CipherService as CipherServiceAbstraction } from "../abstractions/cipher.service"; import { CipherService as CipherServiceAbstraction } from "../abstractions/cipher.service";
import { CipherFileUploadService } from "../abstractions/file-upload/cipher-file-upload.service";
import { CipherType } from "../enums/cipher-type"; import { CipherType } from "../enums/cipher-type";
import { CipherData } from "../models/data/cipher.data"; import { CipherData } from "../models/data/cipher.data";
import { Attachment } from "../models/domain/attachment"; import { Attachment } from "../models/domain/attachment";
@ -33,7 +33,6 @@ import { LoginUri } from "../models/domain/login-uri";
import { Password } from "../models/domain/password"; import { Password } from "../models/domain/password";
import { SecureNote } from "../models/domain/secure-note"; import { SecureNote } from "../models/domain/secure-note";
import { SortedCiphersCache } from "../models/domain/sorted-ciphers-cache"; import { SortedCiphersCache } from "../models/domain/sorted-ciphers-cache";
import { AttachmentRequest } from "../models/request/attachment.request";
import { CipherBulkDeleteRequest } from "../models/request/cipher-bulk-delete.request"; import { CipherBulkDeleteRequest } from "../models/request/cipher-bulk-delete.request";
import { CipherBulkMoveRequest } from "../models/request/cipher-bulk-move.request"; import { CipherBulkMoveRequest } from "../models/request/cipher-bulk-move.request";
import { CipherBulkRestoreRequest } from "../models/request/cipher-bulk-restore.request"; import { CipherBulkRestoreRequest } from "../models/request/cipher-bulk-restore.request";
@ -58,12 +57,12 @@ export class CipherService implements CipherServiceAbstraction {
private cryptoService: CryptoService, private cryptoService: CryptoService,
private settingsService: SettingsService, private settingsService: SettingsService,
private apiService: ApiService, private apiService: ApiService,
private fileUploadService: FileUploadService,
private i18nService: I18nService, private i18nService: I18nService,
private searchService: () => SearchService, private searchService: () => SearchService,
private logService: LogService, private logService: LogService,
private stateService: StateService, private stateService: StateService,
private encryptService: EncryptService private encryptService: EncryptService,
private cipherFileUploadService: CipherFileUploadService
) {} ) {}
async getDecryptedCipherCache(): Promise<CipherView[]> { async getDecryptedCipherCache(): Promise<CipherView[]> {
@ -725,41 +724,13 @@ export class CipherService implements CipherServiceAbstraction {
const dataEncKey = await this.cryptoService.makeEncKey(key); const dataEncKey = await this.cryptoService.makeEncKey(key);
const encData = await this.cryptoService.encryptToBytes(data, dataEncKey[0]); const encData = await this.cryptoService.encryptToBytes(data, dataEncKey[0]);
const request: AttachmentRequest = { const response = await this.cipherFileUploadService.upload(
key: dataEncKey[1].encryptedString, cipher,
fileName: encFileName.encryptedString, encFileName,
fileSize: encData.buffer.byteLength, encData,
adminRequest: admin, admin,
}; dataEncKey
);
let response: CipherResponse;
try {
const uploadDataResponse = await this.apiService.postCipherAttachment(cipher.id, request);
response = admin ? uploadDataResponse.cipherMiniResponse : uploadDataResponse.cipherResponse;
await this.fileUploadService.uploadCipherAttachment(
admin,
uploadDataResponse,
encFileName,
encData
);
} catch (e) {
if (
(e instanceof ErrorResponse && (e as ErrorResponse).statusCode === 404) ||
(e as ErrorResponse).statusCode === 405
) {
response = await this.legacyServerAttachmentFileUpload(
admin,
cipher.id,
encFileName,
encData,
dataEncKey[1]
);
} else if (e instanceof ErrorResponse) {
throw new Error((e as ErrorResponse).getSingleMessage());
} else {
throw e;
}
}
const cData = new CipherData(response, cipher.collectionIds); const cData = new CipherData(response, cipher.collectionIds);
if (!admin) { if (!admin) {
@ -768,52 +739,6 @@ export class CipherService implements CipherServiceAbstraction {
return new Cipher(cData); return new Cipher(cData);
} }
/**
* @deprecated Mar 25 2021: This method has been deprecated in favor of direct uploads.
* This method still exists for backward compatibility with old server versions.
*/
async legacyServerAttachmentFileUpload(
admin: boolean,
cipherId: string,
encFileName: EncString,
encData: EncArrayBuffer,
key: EncString
) {
const fd = new FormData();
try {
const blob = new Blob([encData.buffer], { type: "application/octet-stream" });
fd.append("key", key.encryptedString);
fd.append("data", blob, encFileName.encryptedString);
} catch (e) {
if (Utils.isNode && !Utils.isBrowser) {
fd.append("key", key.encryptedString);
fd.append(
"data",
Buffer.from(encData.buffer) as any,
{
filepath: encFileName.encryptedString,
contentType: "application/octet-stream",
} as any
);
} else {
throw e;
}
}
let response: CipherResponse;
try {
if (admin) {
response = await this.apiService.postCipherAttachmentAdminLegacy(cipherId, fd);
} else {
response = await this.apiService.postCipherAttachmentLegacy(cipherId, fd);
}
} catch (e) {
throw new Error((e as ErrorResponse).getSingleMessage());
}
return response;
}
async saveCollectionsWithServer(cipher: Cipher): Promise<any> { async saveCollectionsWithServer(cipher: Cipher): Promise<any> {
const request = new CipherCollectionsRequest(cipher.collectionIds); const request = new CipherCollectionsRequest(cipher.collectionIds);
await this.apiService.putCipherCollections(cipher.id, request); await this.apiService.putCipherCollections(cipher.id, request);

View File

@ -0,0 +1,157 @@
import { ApiService } from "../../../abstractions/api.service";
import {
FileUploadApiMethods,
FileUploadService,
} from "../../../abstractions/file-upload/file-upload.service";
import { Utils } from "../../../misc/utils";
import { EncArrayBuffer } from "../../../models/domain/enc-array-buffer";
import { EncString } from "../../../models/domain/enc-string";
import { SymmetricCryptoKey } from "../../../models/domain/symmetric-crypto-key";
import { ErrorResponse } from "../../../models/response/error.response";
import { CipherFileUploadService as CipherFileUploadServiceAbstraction } from "../../abstractions/file-upload/cipher-file-upload.service";
import { Cipher } from "../../models/domain/cipher";
import { AttachmentRequest } from "../../models/request/attachment.request";
import { AttachmentUploadDataResponse } from "../../models/response/attachment-upload-data.response";
import { CipherResponse } from "../../models/response/cipher.response";
export class CipherFileUploadService implements CipherFileUploadServiceAbstraction {
constructor(private apiService: ApiService, private fileUploadService: FileUploadService) {}
async upload(
cipher: Cipher,
encFileName: EncString,
encData: EncArrayBuffer,
admin: boolean,
dataEncKey: [SymmetricCryptoKey, EncString]
): Promise<CipherResponse> {
const request: AttachmentRequest = {
key: dataEncKey[1].encryptedString,
fileName: encFileName.encryptedString,
fileSize: encData.buffer.byteLength,
adminRequest: admin,
};
let response: CipherResponse;
try {
const uploadDataResponse = await this.apiService.postCipherAttachment(cipher.id, request);
response = admin ? uploadDataResponse.cipherMiniResponse : uploadDataResponse.cipherResponse;
await this.fileUploadService.upload(
uploadDataResponse,
encFileName,
encData,
this.generateMethods(uploadDataResponse, response, request.adminRequest)
);
} catch (e) {
if (
(e instanceof ErrorResponse && (e as ErrorResponse).statusCode === 404) ||
(e as ErrorResponse).statusCode === 405
) {
response = await this.legacyServerAttachmentFileUpload(
request.adminRequest,
cipher.id,
encFileName,
encData,
dataEncKey[1]
);
} else if (e instanceof ErrorResponse) {
throw new Error((e as ErrorResponse).getSingleMessage());
} else {
throw e;
}
}
return response;
}
private generateMethods(
uploadData: AttachmentUploadDataResponse,
response: CipherResponse,
isAdmin: boolean
): FileUploadApiMethods {
return {
postDirect: this.generatePostDirectCallback(uploadData, isAdmin),
renewFileUploadUrl: this.generateRenewFileUploadUrlCallback(uploadData, response, isAdmin),
rollback: this.generateRollbackCallback(response, uploadData, isAdmin),
};
}
private generatePostDirectCallback(uploadData: AttachmentUploadDataResponse, isAdmin: boolean) {
return (data: FormData) => {
const response = isAdmin ? uploadData.cipherMiniResponse : uploadData.cipherResponse;
return this.apiService.postAttachmentFile(response.id, uploadData.attachmentId, data);
};
}
private generateRenewFileUploadUrlCallback(
uploadData: AttachmentUploadDataResponse,
response: CipherResponse,
isAdmin: boolean
) {
return async () => {
const renewResponse = await this.apiService.renewAttachmentUploadUrl(
response.id,
uploadData.attachmentId
);
return renewResponse?.url;
};
}
private generateRollbackCallback(
response: CipherResponse,
uploadData: AttachmentUploadDataResponse,
isAdmin: boolean
) {
return () => {
if (isAdmin) {
return this.apiService.deleteCipherAttachmentAdmin(response.id, uploadData.attachmentId);
} else {
return this.apiService.deleteCipherAttachment(response.id, uploadData.attachmentId);
}
};
}
/**
* @deprecated Mar 25 2021: This method has been deprecated in favor of direct uploads.
* This method still exists for backward compatibility with old server versions.
*/
async legacyServerAttachmentFileUpload(
admin: boolean,
cipherId: string,
encFileName: EncString,
encData: EncArrayBuffer,
key: EncString
) {
const fd = new FormData();
try {
const blob = new Blob([encData.buffer], { type: "application/octet-stream" });
fd.append("key", key.encryptedString);
fd.append("data", blob, encFileName.encryptedString);
} catch (e) {
if (Utils.isNode && !Utils.isBrowser) {
fd.append("key", key.encryptedString);
fd.append(
"data",
Buffer.from(encData.buffer) as any,
{
filepath: encFileName.encryptedString,
contentType: "application/octet-stream",
} as any
);
} else {
throw e;
}
}
let response: CipherResponse;
try {
if (admin) {
response = await this.apiService.postCipherAttachmentAdminLegacy(cipherId, fd);
} else {
response = await this.apiService.postCipherAttachmentLegacy(cipherId, fd);
}
} catch (e) {
throw new Error((e as ErrorResponse).getSingleMessage());
}
return response;
}
}

View File

@ -2,7 +2,8 @@ import { ApiService } from "../../../abstractions/api.service";
import { CryptoService } from "../../../abstractions/crypto.service"; import { CryptoService } from "../../../abstractions/crypto.service";
import { LogService } from "../../../abstractions/log.service"; import { LogService } from "../../../abstractions/log.service";
import { MessagingService } from "../../../abstractions/messaging.service"; import { MessagingService } from "../../../abstractions/messaging.service";
import { SendService } from "../../../abstractions/send.service"; import { SendApiService } from "../../../abstractions/send/send-api.service.abstraction";
import { InternalSendService } from "../../../abstractions/send/send.service.abstraction";
import { SettingsService } from "../../../abstractions/settings.service"; import { SettingsService } from "../../../abstractions/settings.service";
import { StateService } from "../../../abstractions/state.service"; import { StateService } from "../../../abstractions/state.service";
import { CollectionService } from "../../../admin-console/abstractions/collection.service"; import { CollectionService } from "../../../admin-console/abstractions/collection.service";
@ -47,13 +48,14 @@ export class SyncService implements SyncServiceAbstraction {
private collectionService: CollectionService, private collectionService: CollectionService,
private messagingService: MessagingService, private messagingService: MessagingService,
private policyService: InternalPolicyService, private policyService: InternalPolicyService,
private sendService: SendService, private sendService: InternalSendService,
private logService: LogService, private logService: LogService,
private keyConnectorService: KeyConnectorService, private keyConnectorService: KeyConnectorService,
private stateService: StateService, private stateService: StateService,
private providerService: ProviderService, private providerService: ProviderService,
private folderApiService: FolderApiServiceAbstraction, private folderApiService: FolderApiServiceAbstraction,
private organizationService: InternalOrganizationService, private organizationService: InternalOrganizationService,
private sendApiService: SendApiService,
private logoutCallback: (expired: boolean) => Promise<void> private logoutCallback: (expired: boolean) => Promise<void>
) {} ) {}
@ -230,12 +232,12 @@ export class SyncService implements SyncServiceAbstraction {
this.syncStarted(); this.syncStarted();
if (await this.stateService.getIsAuthenticated()) { if (await this.stateService.getIsAuthenticated()) {
try { try {
const localSend = await this.sendService.get(notification.id); const localSend = this.sendService.get(notification.id);
if ( if (
(!isEdit && localSend == null) || (!isEdit && localSend == null) ||
(isEdit && localSend != null && localSend.revisionDate < notification.revisionDate) (isEdit && localSend != null && localSend.revisionDate < notification.revisionDate)
) { ) {
const remoteSend = await this.apiService.getSend(notification.id); const remoteSend = await this.sendApiService.getSend(notification.id);
if (remoteSend != null) { if (remoteSend != null) {
await this.sendService.upsert(new SendData(remoteSend)); await this.sendService.upsert(new SendData(remoteSend));
this.messagingService.send("syncedUpsertedSend", { sendId: notification.id }); this.messagingService.send("syncedUpsertedSend", { sendId: notification.id });