1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-16 08:13:42 +00:00

serve command (#451)

This commit is contained in:
Kyle Spearrin
2022-01-19 10:45:14 -05:00
committed by GitHub
parent 84a0bfb07c
commit 922cd1dc54
26 changed files with 2091 additions and 332 deletions

View File

@@ -1,4 +1,3 @@
import * as program from "commander";
import * as fs from "fs";
import * as path from "path";
@@ -11,7 +10,6 @@ import { SendType } from "jslib-common/enums/sendType";
import { NodeUtils } from "jslib-common/misc/nodeUtils";
import { Response } from "jslib-node/cli/models/response";
import { StringResponse } from "jslib-node/cli/models/response/stringResponse";
import { SendResponse } from "../../models/response/sendResponse";
import { SendTextResponse } from "../../models/response/sendTextResponse";
@@ -25,9 +23,9 @@ export class SendCreateCommand {
private environmentService: EnvironmentService
) {}
async run(requestJson: string, options: program.OptionValues) {
async run(requestJson: any, cmdOptions: Record<string, any>) {
let req: any = null;
if (requestJson == null || requestJson === "") {
if (process.env.BW_SERVE !== "true" && (requestJson == null || requestJson === "")) {
requestJson = await CliUtils.readStdin();
}
@@ -35,15 +33,19 @@ export class SendCreateCommand {
return Response.badRequest("`requestJson` was not provided.");
}
try {
const reqJson = Buffer.from(requestJson, "base64").toString();
req = SendResponse.fromJson(reqJson);
if (typeof requestJson !== "string") {
req = requestJson;
} else {
try {
const reqJson = Buffer.from(requestJson, "base64").toString();
req = SendResponse.fromJson(reqJson);
if (req == null) {
throw new Error("Null request");
if (req == null) {
throw new Error("Null request");
}
} catch (e) {
return Response.badRequest("Error parsing the encoded request data.");
}
} catch (e) {
return Response.badRequest("Error parsing the encoded request data.");
}
if (
@@ -58,10 +60,11 @@ export class SendCreateCommand {
return Response.badRequest("Unable to parse expirationDate: " + req.expirationDate);
}
return this.createSend(req, options);
const normalizedOptions = new Options(cmdOptions);
return this.createSend(req, normalizedOptions);
}
private async createSend(req: SendResponse, options: program.OptionValues) {
private async createSend(req: SendResponse, options: Options) {
const filePath = req.file?.fileName ?? options.file;
const text = req.text?.text ?? options.text;
const hidden = req.text?.hidden ?? options.hidden;
@@ -73,13 +76,19 @@ export class SendCreateCommand {
switch (req.type) {
case SendType.File:
if (process.env.BW_SERVE === "true") {
return Response.error(
"Creating a file-based Send is unsupported through the `serve` command at this time."
);
}
if (!(await this.stateService.getCanAccessPremium())) {
return Response.error("Premium status is required to use this feature.");
}
if (filePath == null) {
return Response.badRequest(
"Must specify a file to Send either with the --file option or in the encoded json"
"Must specify a file to Send either with the --file option or in the request JSON."
);
}
@@ -88,7 +97,7 @@ export class SendCreateCommand {
case SendType.Text:
if (text == null) {
return Response.badRequest(
"Must specify text content to Send either with the --text option or in the encoded json"
"Must specify text content to Send either with the --text option or in the request JSON."
);
}
req.text = new SendTextResponse();
@@ -97,7 +106,7 @@ export class SendCreateCommand {
break;
default:
return Response.badRequest(
"Unknown Send type " + SendType[req.type] + "valid types are: file, text"
"Unknown Send type " + SendType[req.type] + ". Valid types are: file, text"
);
}
@@ -117,13 +126,26 @@ export class SendCreateCommand {
const newSend = await this.sendService.get(encSend.id);
const decSend = await newSend.decrypt();
const res = new SendResponse(decSend, this.environmentService.getWebVaultUrl());
return Response.success(
options.fullObject
? res
: new StringResponse("Send created! It can be accessed at:\n" + res.accessUrl)
);
return Response.success(res);
} catch (e) {
return Response.error(e);
}
}
}
class Options {
file: string;
text: string;
maxAccessCount: number;
password: string;
hidden: boolean;
constructor(passedOptions: Record<string, any>) {
this.file = passedOptions.file;
this.text = passedOptions.text;
this.password = passedOptions.password;
this.hidden = CliUtils.convertBooleanOption(passedOptions.hidden);
this.maxAccessCount =
passedOptions.maxAccessCount != null ? parseInt(passedOptions.maxAccessCount, null) : null;
}
}

View File

@@ -1,5 +1,3 @@
import * as program from "commander";
import { SendService } from "jslib-common/abstractions/send.service";
import { StateService } from "jslib-common/abstractions/state.service";
@@ -18,24 +16,29 @@ export class SendEditCommand {
private getCommand: SendGetCommand
) {}
async run(encodedJson: string, options: program.OptionValues): Promise<Response> {
if (encodedJson == null || encodedJson === "") {
encodedJson = await CliUtils.readStdin();
async run(requestJson: string, cmdOptions: Record<string, any>): Promise<Response> {
if (process.env.BW_SERVE !== "true" && (requestJson == null || requestJson === "")) {
requestJson = await CliUtils.readStdin();
}
if (encodedJson == null || encodedJson === "") {
return Response.badRequest("`encodedJson` was not provided.");
if (requestJson == null || requestJson === "") {
return Response.badRequest("`requestJson` was not provided.");
}
let req: SendResponse = null;
try {
const reqJson = Buffer.from(encodedJson, "base64").toString();
req = SendResponse.fromJson(reqJson);
} catch (e) {
return Response.badRequest("Error parsing the encoded request data.");
if (typeof requestJson !== "string") {
req = requestJson;
} else {
try {
const reqJson = Buffer.from(requestJson, "base64").toString();
req = SendResponse.fromJson(reqJson);
} catch (e) {
return Response.badRequest("Error parsing the encoded request data.");
}
}
req.id = options.itemid || req.id;
const normalizedOptions = new Options(cmdOptions);
req.id = normalizedOptions.itemId || req.id;
if (req.id != null) {
req.id = req.id.toLowerCase();
@@ -76,3 +79,11 @@ export class SendEditCommand {
return await this.getCommand.run(send.id, {});
}
}
class Options {
itemId: string;
constructor(passedOptions: Record<string, any>) {
this.itemId = passedOptions.itemId || passedOptions.itemid;
}
}

View File

@@ -1,6 +1,5 @@
import * as program from "commander";
import { ApiService } from "jslib-common/abstractions/api.service";
import { CryptoService } from "jslib-common/abstractions/crypto.service";
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
import { SearchService } from "jslib-common/abstractions/search.service";
@@ -27,6 +26,11 @@ export class SendGetCommand extends DownloadCommand {
}
async run(id: string, options: program.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();
@@ -36,7 +40,7 @@ export class SendGetCommand extends DownloadCommand {
let filter = (s: SendView) => true;
let selector = async (s: SendView): Promise<Response> =>
Response.success(new SendResponse(s, webVaultUrl));
if (options.text != null) {
if (!serveCommand && options?.text != null) {
filter = (s) => {
return filter(s) && s.text != null;
};

View File

@@ -1,5 +1,3 @@
import * as program from "commander";
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
import { SearchService } from "jslib-common/abstractions/search.service";
import { SendService } from "jslib-common/abstractions/send.service";
@@ -16,11 +14,12 @@ export class SendListCommand {
private searchService: SearchService
) {}
async run(options: program.OptionValues): Promise<Response> {
async run(cmdOptions: Record<string, any>): Promise<Response> {
let sends = await this.sendService.getAllDecrypted();
if (options.search != null && options.search.trim() !== "") {
sends = this.searchService.searchSends(sends, options.search);
const normalizedOptions = new Options(cmdOptions);
if (normalizedOptions.search != null && normalizedOptions.search.trim() !== "") {
sends = this.searchService.searchSends(sends, normalizedOptions.search);
}
const webVaultUrl = this.environmentService.getWebVaultUrl();
@@ -28,3 +27,11 @@ export class SendListCommand {
return Response.success(res);
}
}
class Options {
search: string;
constructor(passedOptions: Record<string, any>) {
this.search = passedOptions.search;
}
}