mirror of
https://github.com/bitwarden/browser
synced 2026-02-09 21:20:27 +00:00
PM-919 created service send-download
This commit is contained in:
@@ -164,6 +164,7 @@ export class OssServeConfigurator {
|
||||
this.serviceContainer.searchService,
|
||||
this.serviceContainer.encryptService,
|
||||
this.serviceContainer.apiService,
|
||||
this.serviceContainer.sendDownloadService,
|
||||
);
|
||||
this.sendEditCommand = new SendEditCommand(
|
||||
this.serviceContainer.sendService,
|
||||
|
||||
@@ -185,6 +185,7 @@ import { I18nService } from "../platform/services/i18n.service";
|
||||
import { LowdbStorageService } from "../platform/services/lowdb-storage.service";
|
||||
import { NodeApiService } from "../platform/services/node-api.service";
|
||||
import { NodeEnvSecureStorageService } from "../platform/services/node-env-secure-storage.service";
|
||||
import { SendDownloadService } from "../tools/send/services/send-download.service";
|
||||
|
||||
// Polyfills
|
||||
global.DOMParser = new jsdom.JSDOM().window.DOMParser;
|
||||
@@ -283,6 +284,7 @@ export class ServiceContainer {
|
||||
cipherAuthorizationService: CipherAuthorizationService;
|
||||
ssoUrlService: SsoUrlService;
|
||||
masterPasswordApiService: MasterPasswordApiServiceAbstraction;
|
||||
sendDownloadService: SendDownloadService;
|
||||
|
||||
constructor() {
|
||||
let p = null;
|
||||
@@ -849,6 +851,16 @@ export class ServiceContainer {
|
||||
);
|
||||
|
||||
this.masterPasswordApiService = new MasterPasswordApiService(this.apiService, this.logService);
|
||||
|
||||
this.sendDownloadService = new SendDownloadService(
|
||||
this.environmentService,
|
||||
this.encryptService,
|
||||
this.apiService,
|
||||
this.platformUtilsService,
|
||||
this.keyService,
|
||||
this.cryptoFunctionService,
|
||||
this.sendApiService,
|
||||
);
|
||||
}
|
||||
|
||||
async logout() {
|
||||
|
||||
@@ -14,6 +14,7 @@ import { SendService } from "@bitwarden/common/tools/send/services/send.service.
|
||||
import { DownloadCommand } from "../../../commands/download.command";
|
||||
import { Response } from "../../../models/response";
|
||||
import { SendResponse } from "../models/send.response";
|
||||
import { SendDownloadService } from "../services/send-download.service";
|
||||
|
||||
export class SendGetCommand extends DownloadCommand {
|
||||
constructor(
|
||||
@@ -22,6 +23,7 @@ export class SendGetCommand extends DownloadCommand {
|
||||
private searchService: SearchService,
|
||||
encryptService: EncryptService,
|
||||
apiService: ApiService,
|
||||
private sendDownloadService: SendDownloadService,
|
||||
) {
|
||||
super(encryptService, apiService);
|
||||
}
|
||||
@@ -67,6 +69,10 @@ export class SendGetCommand extends DownloadCommand {
|
||||
}
|
||||
}
|
||||
|
||||
if (options?.file || options?.output || options?.raw) {
|
||||
return this.sendDownloadService.download(sends, options);
|
||||
}
|
||||
|
||||
return selector(sends);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ import {
|
||||
SendReceiveCommand,
|
||||
SendRemovePasswordCommand,
|
||||
} from "./commands";
|
||||
import { SendDownloadCommand } from "./commands/send-download.command";
|
||||
import { SendFileResponse } from "./models/send-file.response";
|
||||
import { SendTextResponse } from "./models/send-text.response";
|
||||
import { SendResponse } from "./models/send.response";
|
||||
@@ -68,7 +67,6 @@ export class SendProgram extends BaseProgram {
|
||||
.addCommand(this.editCommand())
|
||||
.addCommand(this.removePasswordCommand())
|
||||
.addCommand(this.deleteCommand())
|
||||
.addCommand(this.downloadCommand())
|
||||
.action(async (data: string, options: OptionValues) => {
|
||||
const encodedJson = this.makeSendJson(data, options);
|
||||
|
||||
@@ -161,64 +159,19 @@ export class SendProgram extends BaseProgram {
|
||||
});
|
||||
}
|
||||
|
||||
private downloadCommand(): Command {
|
||||
return (
|
||||
new Command("download")
|
||||
.arguments("<id>")
|
||||
.description("Downloads file attached to the send owned by you.")
|
||||
.option("--file", "Specifies to return the file content of a Send", true)
|
||||
.option("--password <password>", "Password needed to access the Send.")
|
||||
.option(
|
||||
"--passwordfile <passwordfile>",
|
||||
"Path to a file containing the Sends password as its first line",
|
||||
)
|
||||
// .option("--obj", "Return the Send's json object rather than the Send's content")
|
||||
.option("--output <location>", "Specify a file path to save a File-type Send to")
|
||||
.option("--raw", "Return the raw content of a Send", true)
|
||||
.on("--help", () => {
|
||||
writeLn("");
|
||||
writeLn(" Id:");
|
||||
writeLn("");
|
||||
writeLn(" Search term or Send's globally unique `id`.");
|
||||
writeLn("");
|
||||
writeLn(
|
||||
" If raw output is specified and no output filename or directory is given for",
|
||||
);
|
||||
writeLn(" an attachment query, the attachment content is written to stdout.");
|
||||
writeLn("");
|
||||
writeLn(" Examples:");
|
||||
writeLn("");
|
||||
writeLn(" bw send download searchText");
|
||||
writeLn(" bw send download id");
|
||||
writeLn(" bw send download id --file");
|
||||
writeLn(" bw send download id --file --output ../Photos/photo.jpg");
|
||||
writeLn(" bw send download id --file --raw");
|
||||
writeLn("", true);
|
||||
})
|
||||
.action(async (id: string, options: OptionValues) => {
|
||||
await this.exitIfLocked();
|
||||
const cmd = new SendDownloadCommand(
|
||||
this.serviceContainer.sendService,
|
||||
this.serviceContainer.environmentService,
|
||||
this.serviceContainer.searchService,
|
||||
this.serviceContainer.encryptService,
|
||||
this.serviceContainer.apiService,
|
||||
this.serviceContainer.platformUtilsService,
|
||||
this.serviceContainer.keyService,
|
||||
this.serviceContainer.cryptoFunctionService,
|
||||
this.serviceContainer.sendApiService,
|
||||
);
|
||||
const response = await cmd.run(id, options);
|
||||
this.processResponse(response);
|
||||
})
|
||||
);
|
||||
}
|
||||
private getCommand(): Command {
|
||||
return new Command("get")
|
||||
.arguments("<id>")
|
||||
.description("Get Sends owned by you.")
|
||||
.option("--output <output>", "Output directory or filename for attachment.")
|
||||
.option("--text", "Specifies to return the text content of a Send")
|
||||
.option("--file", "Specifies to return the file content of a Send", true)
|
||||
.option("--password <password>", "Password needed to access the Send.")
|
||||
.option(
|
||||
"--passwordfile <passwordfile>",
|
||||
"Path to a file containing the Sends password as its first line",
|
||||
)
|
||||
.option("--raw", "Return the raw content of a Send", true)
|
||||
.option("--output <output>", "Output directory or filename for attachment.")
|
||||
.on("--help", () => {
|
||||
writeLn("");
|
||||
writeLn(" Id:");
|
||||
@@ -233,6 +186,9 @@ export class SendProgram extends BaseProgram {
|
||||
writeLn(" bw send get searchText");
|
||||
writeLn(" bw send get id");
|
||||
writeLn(" bw send get searchText --text");
|
||||
writeLn(" bw send download id --file");
|
||||
writeLn(" bw send download id --output ../Photos/photo.jpg");
|
||||
writeLn(" bw send download id --file --raw");
|
||||
writeLn("", true);
|
||||
})
|
||||
.action(async (id: string, options: OptionValues) => {
|
||||
@@ -243,6 +199,7 @@ export class SendProgram extends BaseProgram {
|
||||
this.serviceContainer.searchService,
|
||||
this.serviceContainer.encryptService,
|
||||
this.serviceContainer.apiService,
|
||||
this.serviceContainer.sendDownloadService,
|
||||
);
|
||||
const response = await cmd.run(id, options);
|
||||
this.processResponse(response);
|
||||
@@ -303,6 +260,7 @@ export class SendProgram extends BaseProgram {
|
||||
this.serviceContainer.searchService,
|
||||
this.serviceContainer.encryptService,
|
||||
this.serviceContainer.apiService,
|
||||
this.serviceContainer.sendDownloadService,
|
||||
);
|
||||
const cmd = new SendEditCommand(
|
||||
this.serviceContainer.sendService,
|
||||
|
||||
@@ -5,7 +5,6 @@ import * as inquirer from "inquirer";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
||||
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||
@@ -19,7 +18,6 @@ import { SendAccessRequest } from "@bitwarden/common/tools/send/models/request/s
|
||||
import { SendAccessView } from "@bitwarden/common/tools/send/models/view/send-access.view";
|
||||
import { SendView } from "@bitwarden/common/tools/send/models/view/send.view";
|
||||
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
|
||||
import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction";
|
||||
import { KeyService } from "@bitwarden/key-management";
|
||||
import { NodeUtils } from "@bitwarden/node/node-utils";
|
||||
|
||||
@@ -28,13 +26,12 @@ import { Response } from "../../../models/response";
|
||||
import { SendAccessResponse } from "../models/send-access.response";
|
||||
import { SendResponse } from "../models/send.response";
|
||||
|
||||
export class SendDownloadCommand extends DownloadCommand {
|
||||
// Note: DownloadCommand is actually an abstract class
|
||||
export class SendDownloadService extends DownloadCommand {
|
||||
private decKey: SymmetricCryptoKey;
|
||||
|
||||
constructor(
|
||||
private sendService: SendService,
|
||||
protected environmentService: EnvironmentService,
|
||||
private searchService: SearchService,
|
||||
encryptService: EncryptService,
|
||||
apiService: ApiService,
|
||||
protected platformUtilsService: PlatformUtilsService,
|
||||
@@ -45,38 +42,14 @@ export class SendDownloadCommand extends DownloadCommand {
|
||||
super(encryptService, apiService);
|
||||
}
|
||||
|
||||
async run(id: string, options: OptionValues) {
|
||||
const serveCommand = process.env.BW_SERVE === "true";
|
||||
if (serveCommand && !Utils.isGuid(id)) {
|
||||
return Response.badRequest("`" + id + "` is not a GUID.");
|
||||
}
|
||||
|
||||
let sends = await this.getSendView(id);
|
||||
if (sends == null) {
|
||||
return Response.notFound();
|
||||
}
|
||||
|
||||
async download(sends: SendView, options: OptionValues) {
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
const webVaultUrl = env.getWebVaultUrl();
|
||||
|
||||
const selector = async (s: SendView): Promise<Response> =>
|
||||
Response.success(new SendResponse(s, webVaultUrl));
|
||||
|
||||
// we have multiple results. Attempt to narrow down the results
|
||||
if (Array.isArray(sends)) {
|
||||
// if we have multiple results, return the ids
|
||||
if (sends.length > 1) {
|
||||
return Response.multipleResults(sends.map((s) => s.id));
|
||||
}
|
||||
|
||||
// if we greater than zero results pick the first one
|
||||
if (sends.length > 0) {
|
||||
sends = sends[0];
|
||||
} else {
|
||||
return Response.notFound();
|
||||
}
|
||||
}
|
||||
|
||||
// only attempt to download if requested
|
||||
if (options?.file || options?.output || options?.raw) {
|
||||
// generate the send url
|
||||
const sendWithUrl = new SendResponse(sends, webVaultUrl);
|
||||
@@ -142,6 +115,7 @@ export class SendDownloadCommand extends DownloadCommand {
|
||||
|
||||
return selector(sends);
|
||||
}
|
||||
|
||||
private createUrlObject(url: string): URL | null {
|
||||
try {
|
||||
return new URL(url);
|
||||
@@ -160,23 +134,6 @@ export class SendDownloadCommand extends DownloadCommand {
|
||||
return Utils.fromBufferToB64(passwordHash);
|
||||
}
|
||||
|
||||
private async getSendView(id: string): Promise<SendView | SendView[]> {
|
||||
if (Utils.isGuid(id)) {
|
||||
const send = await this.sendService.getFromState(id);
|
||||
if (send != null) {
|
||||
return await send.decrypt();
|
||||
}
|
||||
} else if (id.trim() !== "") {
|
||||
let sends = await this.sendService.getAllDecryptedFromState();
|
||||
sends = this.searchService.searchSends(sends, id);
|
||||
if (sends.length > 1) {
|
||||
return sends;
|
||||
} else if (sends.length > 0) {
|
||||
return sends[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async sendRequest(
|
||||
url: string,
|
||||
id: string,
|
||||
Reference in New Issue
Block a user