mirror of
https://github.com/bitwarden/browser
synced 2025-12-17 00:33:44 +00:00
[PM-328] Move Send to Tools (#5104)
* Move send in libs/common * Move send in libs/angular * Move send in browser * Move send in cli * Move send in desktop * Move send in web
This commit is contained in:
committed by
GitHub
parent
e645688f8a
commit
e238ea20a9
@@ -8,7 +8,6 @@ import { CollectionService } from "@bitwarden/common/admin-console/abstractions/
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view";
|
||||
import { SendType } from "@bitwarden/common/enums/sendType";
|
||||
import { Utils } from "@bitwarden/common/misc/utils";
|
||||
import { EncString } from "@bitwarden/common/models/domain/enc-string";
|
||||
import { CardExport } from "@bitwarden/common/models/export/card.export";
|
||||
@@ -21,6 +20,7 @@ import { LoginUriExport } from "@bitwarden/common/models/export/login-uri.export
|
||||
import { LoginExport } from "@bitwarden/common/models/export/login.export";
|
||||
import { SecureNoteExport } from "@bitwarden/common/models/export/secure-note.export";
|
||||
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||
import { SendType } from "@bitwarden/common/tools/send/enums/send-type";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums/cipher-type";
|
||||
@@ -33,9 +33,9 @@ import { OrganizationCollectionResponse } from "../admin-console/models/response
|
||||
import { OrganizationResponse } from "../admin-console/models/response/organization.response";
|
||||
import { SelectionReadOnly } from "../admin-console/models/selection-read-only";
|
||||
import { Response } from "../models/response";
|
||||
import { SendResponse } from "../models/response/send.response";
|
||||
import { StringResponse } from "../models/response/string.response";
|
||||
import { TemplateResponse } from "../models/response/template.response";
|
||||
import { SendResponse } from "../tools/send/models/send.response";
|
||||
import { CliUtils } from "../utils";
|
||||
import { CipherResponse } from "../vault/models/cipher.response";
|
||||
import { FolderResponse } from "../vault/models/folder.response";
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.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 { SendType } from "@bitwarden/common/enums/sendType";
|
||||
import { NodeUtils } from "@bitwarden/common/misc/nodeUtils";
|
||||
|
||||
import { Response } from "../../models/response";
|
||||
import { SendTextResponse } from "../../models/response/send-text.response";
|
||||
import { SendResponse } from "../../models/response/send.response";
|
||||
import { CliUtils } from "../../utils";
|
||||
|
||||
export class SendCreateCommand {
|
||||
constructor(
|
||||
private sendService: SendService,
|
||||
private stateService: StateService,
|
||||
private environmentService: EnvironmentService,
|
||||
private sendApiService: SendApiService
|
||||
) {}
|
||||
|
||||
async run(requestJson: any, cmdOptions: Record<string, any>) {
|
||||
let req: any = null;
|
||||
if (process.env.BW_SERVE !== "true" && (requestJson == null || requestJson === "")) {
|
||||
requestJson = await CliUtils.readStdin();
|
||||
}
|
||||
|
||||
if (requestJson == null || requestJson === "") {
|
||||
return Response.badRequest("`requestJson` was not provided.");
|
||||
}
|
||||
|
||||
if (typeof requestJson !== "string") {
|
||||
req = requestJson;
|
||||
req.deletionDate = req.deletionDate == null ? null : new Date(req.deletionDate);
|
||||
req.expirationDate = req.expirationDate == null ? null : new Date(req.expirationDate);
|
||||
} else {
|
||||
try {
|
||||
const reqJson = Buffer.from(requestJson, "base64").toString();
|
||||
req = SendResponse.fromJson(reqJson);
|
||||
|
||||
if (req == null) {
|
||||
throw new Error("Null request");
|
||||
}
|
||||
} catch (e) {
|
||||
return Response.badRequest("Error parsing the encoded request data.");
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
req.deletionDate == null ||
|
||||
isNaN(new Date(req.deletionDate).getTime()) ||
|
||||
new Date(req.deletionDate) <= new Date()
|
||||
) {
|
||||
return Response.badRequest("Must specify a valid deletion date after the current time");
|
||||
}
|
||||
|
||||
if (req.expirationDate != null && isNaN(new Date(req.expirationDate).getTime())) {
|
||||
return Response.badRequest("Unable to parse expirationDate: " + req.expirationDate);
|
||||
}
|
||||
|
||||
const normalizedOptions = new Options(cmdOptions);
|
||||
return this.createSend(req, normalizedOptions);
|
||||
}
|
||||
|
||||
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;
|
||||
const password = req.password ?? options.password;
|
||||
const maxAccessCount = req.maxAccessCount ?? options.maxAccessCount;
|
||||
|
||||
req.key = null;
|
||||
req.maxAccessCount = maxAccessCount;
|
||||
|
||||
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 request JSON."
|
||||
);
|
||||
}
|
||||
|
||||
req.file.fileName = path.basename(filePath);
|
||||
break;
|
||||
case SendType.Text:
|
||||
if (text == null) {
|
||||
return Response.badRequest(
|
||||
"Must specify text content to Send either with the --text option or in the request JSON."
|
||||
);
|
||||
}
|
||||
req.text = new SendTextResponse();
|
||||
req.text.text = text;
|
||||
req.text.hidden = hidden;
|
||||
break;
|
||||
default:
|
||||
return Response.badRequest(
|
||||
"Unknown Send type " + SendType[req.type] + ". Valid types are: file, text"
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
let fileBuffer: ArrayBuffer = null;
|
||||
if (req.type === SendType.File) {
|
||||
fileBuffer = NodeUtils.bufferToArrayBuffer(fs.readFileSync(filePath));
|
||||
}
|
||||
|
||||
const sendView = SendResponse.toView(req);
|
||||
const [encSend, fileData] = await this.sendService.encrypt(sendView, fileBuffer, password);
|
||||
// Add dates from template
|
||||
encSend.deletionDate = sendView.deletionDate;
|
||||
encSend.expirationDate = sendView.expirationDate;
|
||||
|
||||
await this.sendApiService.save([encSend, fileData]);
|
||||
const newSend = await this.sendService.getFromState(encSend.id);
|
||||
const decSend = await newSend.decrypt();
|
||||
const res = new SendResponse(decSend, this.environmentService.getWebVaultUrl());
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
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";
|
||||
|
||||
export class SendDeleteCommand {
|
||||
constructor(private sendService: SendService, private sendApiService: SendApiService) {}
|
||||
|
||||
async run(id: string) {
|
||||
const send = await this.sendService.getFromState(id);
|
||||
|
||||
if (send == null) {
|
||||
return Response.notFound();
|
||||
}
|
||||
|
||||
try {
|
||||
await this.sendApiService.delete(id);
|
||||
return Response.success();
|
||||
} catch (e) {
|
||||
return Response.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
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 { SendType } from "@bitwarden/common/enums/sendType";
|
||||
|
||||
import { Response } from "../../models/response";
|
||||
import { SendResponse } from "../../models/response/send.response";
|
||||
import { CliUtils } from "../../utils";
|
||||
|
||||
import { SendGetCommand } from "./get.command";
|
||||
|
||||
export class SendEditCommand {
|
||||
constructor(
|
||||
private sendService: SendService,
|
||||
private stateService: StateService,
|
||||
private getCommand: SendGetCommand,
|
||||
private sendApiService: SendApiService
|
||||
) {}
|
||||
|
||||
async run(requestJson: string, cmdOptions: Record<string, any>): Promise<Response> {
|
||||
if (process.env.BW_SERVE !== "true" && (requestJson == null || requestJson === "")) {
|
||||
requestJson = await CliUtils.readStdin();
|
||||
}
|
||||
|
||||
if (requestJson == null || requestJson === "") {
|
||||
return Response.badRequest("`requestJson` was not provided.");
|
||||
}
|
||||
|
||||
let req: SendResponse = null;
|
||||
if (typeof requestJson !== "string") {
|
||||
req = requestJson;
|
||||
req.deletionDate = req.deletionDate == null ? null : new Date(req.deletionDate);
|
||||
req.expirationDate = req.expirationDate == null ? null : new Date(req.expirationDate);
|
||||
} else {
|
||||
try {
|
||||
const reqJson = Buffer.from(requestJson, "base64").toString();
|
||||
req = SendResponse.fromJson(reqJson);
|
||||
} catch (e) {
|
||||
return Response.badRequest("Error parsing the encoded request data.");
|
||||
}
|
||||
}
|
||||
|
||||
const normalizedOptions = new Options(cmdOptions);
|
||||
req.id = normalizedOptions.itemId || req.id;
|
||||
|
||||
if (req.id != null) {
|
||||
req.id = req.id.toLowerCase();
|
||||
}
|
||||
|
||||
const send = await this.sendService.getFromState(req.id);
|
||||
|
||||
if (send == null) {
|
||||
return Response.notFound();
|
||||
}
|
||||
|
||||
if (send.type !== req.type) {
|
||||
return Response.badRequest("Cannot change a Send's type");
|
||||
}
|
||||
|
||||
if (send.type === SendType.File && !(await this.stateService.getCanAccessPremium())) {
|
||||
return Response.error("Premium status is required to use this feature.");
|
||||
}
|
||||
|
||||
let sendView = await send.decrypt();
|
||||
sendView = SendResponse.toView(req, sendView);
|
||||
|
||||
if (typeof req.password !== "string" || req.password === "") {
|
||||
req.password = null;
|
||||
}
|
||||
|
||||
try {
|
||||
const [encSend, encFileData] = await this.sendService.encrypt(sendView, null, req.password);
|
||||
// Add dates from template
|
||||
encSend.deletionDate = sendView.deletionDate;
|
||||
encSend.expirationDate = sendView.expirationDate;
|
||||
|
||||
await this.sendApiService.save([encSend, encFileData]);
|
||||
} catch (e) {
|
||||
return Response.error(e);
|
||||
}
|
||||
|
||||
return await this.getCommand.run(send.id, {});
|
||||
}
|
||||
}
|
||||
|
||||
class Options {
|
||||
itemId: string;
|
||||
|
||||
constructor(passedOptions: Record<string, any>) {
|
||||
this.itemId = passedOptions?.itemId || passedOptions?.itemid;
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
import * as program from "commander";
|
||||
|
||||
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
|
||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||
import { SendService } from "@bitwarden/common/abstractions/send/send.service.abstraction";
|
||||
import { Utils } from "@bitwarden/common/misc/utils";
|
||||
import { SendView } from "@bitwarden/common/models/view/send.view";
|
||||
|
||||
import { Response } from "../../models/response";
|
||||
import { SendResponse } from "../../models/response/send.response";
|
||||
import { DownloadCommand } from "../download.command";
|
||||
|
||||
export class SendGetCommand extends DownloadCommand {
|
||||
constructor(
|
||||
private sendService: SendService,
|
||||
private environmentService: EnvironmentService,
|
||||
private searchService: SearchService,
|
||||
cryptoService: CryptoService
|
||||
) {
|
||||
super(cryptoService);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
const webVaultUrl = this.environmentService.getWebVaultUrl();
|
||||
let filter = (s: SendView) => true;
|
||||
let selector = async (s: SendView): Promise<Response> =>
|
||||
Response.success(new SendResponse(s, webVaultUrl));
|
||||
if (!serveCommand && options?.text != null) {
|
||||
filter = (s) => {
|
||||
return filter(s) && s.text != null;
|
||||
};
|
||||
selector = async (s) => {
|
||||
// Write to stdout and response success so we get the text string only to stdout
|
||||
process.stdout.write(s.text.text);
|
||||
return Response.success();
|
||||
};
|
||||
}
|
||||
|
||||
if (Array.isArray(sends)) {
|
||||
if (filter != null) {
|
||||
sends = sends.filter(filter);
|
||||
}
|
||||
if (sends.length > 1) {
|
||||
return Response.multipleResults(sends.map((s) => s.id));
|
||||
}
|
||||
if (sends.length > 0) {
|
||||
return selector(sends[0]);
|
||||
} else {
|
||||
return Response.notFound();
|
||||
}
|
||||
}
|
||||
|
||||
return selector(sends);
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
|
||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||
import { SendService } from "@bitwarden/common/abstractions/send/send.service.abstraction";
|
||||
|
||||
import { Response } from "../../models/response";
|
||||
import { ListResponse } from "../../models/response/list.response";
|
||||
import { SendResponse } from "../../models/response/send.response";
|
||||
|
||||
export class SendListCommand {
|
||||
constructor(
|
||||
private sendService: SendService,
|
||||
private environmentService: EnvironmentService,
|
||||
private searchService: SearchService
|
||||
) {}
|
||||
|
||||
async run(cmdOptions: Record<string, any>): Promise<Response> {
|
||||
let sends = await this.sendService.getAllDecryptedFromState();
|
||||
|
||||
const normalizedOptions = new Options(cmdOptions);
|
||||
if (normalizedOptions.search != null && normalizedOptions.search.trim() !== "") {
|
||||
sends = this.searchService.searchSends(sends, normalizedOptions.search);
|
||||
}
|
||||
|
||||
const webVaultUrl = this.environmentService.getWebVaultUrl();
|
||||
const res = new ListResponse(sends.map((s) => new SendResponse(s, webVaultUrl)));
|
||||
return Response.success(res);
|
||||
}
|
||||
}
|
||||
|
||||
class Options {
|
||||
search: string;
|
||||
|
||||
constructor(passedOptions: Record<string, any>) {
|
||||
this.search = passedOptions?.search;
|
||||
}
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
import * as program from "commander";
|
||||
import * as inquirer from "inquirer";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
|
||||
import { CryptoFunctionService } from "@bitwarden/common/abstractions/cryptoFunction.service";
|
||||
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.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 { NodeUtils } from "@bitwarden/common/misc/nodeUtils";
|
||||
import { Utils } from "@bitwarden/common/misc/utils";
|
||||
import { SendAccess } from "@bitwarden/common/models/domain/send-access";
|
||||
import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetric-crypto-key";
|
||||
import { SendAccessRequest } from "@bitwarden/common/models/request/send-access.request";
|
||||
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||
import { SendAccessView } from "@bitwarden/common/models/view/send-access.view";
|
||||
|
||||
import { Response } from "../../models/response";
|
||||
import { SendAccessResponse } from "../../models/response/send-access.response";
|
||||
import { DownloadCommand } from "../download.command";
|
||||
|
||||
export class SendReceiveCommand extends DownloadCommand {
|
||||
private canInteract: boolean;
|
||||
private decKey: SymmetricCryptoKey;
|
||||
private sendAccessRequest: SendAccessRequest;
|
||||
|
||||
constructor(
|
||||
private apiService: ApiService,
|
||||
cryptoService: CryptoService,
|
||||
private cryptoFunctionService: CryptoFunctionService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private environmentService: EnvironmentService,
|
||||
private sendApiService: SendApiService
|
||||
) {
|
||||
super(cryptoService);
|
||||
}
|
||||
|
||||
async run(url: string, options: program.OptionValues): Promise<Response> {
|
||||
this.canInteract = process.env.BW_NOINTERACTION !== "true";
|
||||
|
||||
let urlObject: URL;
|
||||
try {
|
||||
urlObject = new URL(url);
|
||||
} catch (e) {
|
||||
return Response.badRequest("Failed to parse the provided Send url");
|
||||
}
|
||||
|
||||
const apiUrl = this.getApiUrl(urlObject);
|
||||
const [id, key] = this.getIdAndKey(urlObject);
|
||||
|
||||
if (Utils.isNullOrWhitespace(id) || Utils.isNullOrWhitespace(key)) {
|
||||
return Response.badRequest("Failed to parse url, the url provided is not a valid Send url");
|
||||
}
|
||||
|
||||
const keyArray = Utils.fromUrlB64ToArray(key);
|
||||
this.sendAccessRequest = new SendAccessRequest();
|
||||
|
||||
let password = options.password;
|
||||
if (password == null || password === "") {
|
||||
if (options.passwordfile) {
|
||||
password = await NodeUtils.readFirstLine(options.passwordfile);
|
||||
} else if (options.passwordenv && process.env[options.passwordenv]) {
|
||||
password = process.env[options.passwordenv];
|
||||
}
|
||||
}
|
||||
|
||||
if (password != null && password !== "") {
|
||||
this.sendAccessRequest.password = await this.getUnlockedPassword(password, keyArray);
|
||||
}
|
||||
|
||||
const response = await this.sendRequest(apiUrl, id, keyArray);
|
||||
|
||||
if (response instanceof Response) {
|
||||
// Error scenario
|
||||
return response;
|
||||
}
|
||||
|
||||
if (options.obj != null) {
|
||||
return Response.success(new SendAccessResponse(response));
|
||||
}
|
||||
|
||||
switch (response.type) {
|
||||
case SendType.Text:
|
||||
// Write to stdout and response success so we get the text string only to stdout
|
||||
process.stdout.write(response?.text?.text);
|
||||
return Response.success();
|
||||
case SendType.File: {
|
||||
const downloadData = await this.sendApiService.getSendFileDownloadData(
|
||||
response,
|
||||
this.sendAccessRequest,
|
||||
apiUrl
|
||||
);
|
||||
return await this.saveAttachmentToFile(
|
||||
downloadData.url,
|
||||
this.decKey,
|
||||
response?.file?.fileName,
|
||||
options.output
|
||||
);
|
||||
}
|
||||
default:
|
||||
return Response.success(new SendAccessResponse(response));
|
||||
}
|
||||
}
|
||||
|
||||
private getIdAndKey(url: URL): [string, string] {
|
||||
const result = url.hash.slice(1).split("/").slice(-2);
|
||||
return [result[0], result[1]];
|
||||
}
|
||||
|
||||
private getApiUrl(url: URL) {
|
||||
const urls = this.environmentService.getUrls();
|
||||
if (url.origin === "https://send.bitwarden.com") {
|
||||
return "https://vault.bitwarden.com/api";
|
||||
} else if (url.origin === urls.api) {
|
||||
return url.origin;
|
||||
} else if (this.platformUtilsService.isDev() && url.origin === urls.webVault) {
|
||||
return urls.api;
|
||||
} else {
|
||||
return url.origin + "/api";
|
||||
}
|
||||
}
|
||||
|
||||
private async getUnlockedPassword(password: string, keyArray: ArrayBuffer) {
|
||||
const passwordHash = await this.cryptoFunctionService.pbkdf2(
|
||||
password,
|
||||
keyArray,
|
||||
"sha256",
|
||||
100000
|
||||
);
|
||||
return Utils.fromBufferToB64(passwordHash);
|
||||
}
|
||||
|
||||
private async sendRequest(
|
||||
url: string,
|
||||
id: string,
|
||||
key: ArrayBuffer
|
||||
): Promise<Response | SendAccessView> {
|
||||
try {
|
||||
const sendResponse = await this.sendApiService.postSendAccess(
|
||||
id,
|
||||
this.sendAccessRequest,
|
||||
url
|
||||
);
|
||||
|
||||
const sendAccess = new SendAccess(sendResponse);
|
||||
this.decKey = await this.cryptoService.makeSendKey(key);
|
||||
return await sendAccess.decrypt(this.decKey);
|
||||
} catch (e) {
|
||||
if (e instanceof ErrorResponse) {
|
||||
if (e.statusCode === 401) {
|
||||
if (this.canInteract) {
|
||||
const answer: inquirer.Answers = await inquirer.createPromptModule({
|
||||
output: process.stderr,
|
||||
})({
|
||||
type: "password",
|
||||
name: "password",
|
||||
message: "Send password:",
|
||||
});
|
||||
|
||||
// reattempt with new password
|
||||
this.sendAccessRequest.password = await this.getUnlockedPassword(answer.password, key);
|
||||
return await this.sendRequest(url, id, key);
|
||||
}
|
||||
|
||||
return Response.badRequest("Incorrect or missing password");
|
||||
} else if (e.statusCode === 405) {
|
||||
return Response.badRequest("Bad Request");
|
||||
} else if (e.statusCode === 404) {
|
||||
return Response.notFound();
|
||||
}
|
||||
}
|
||||
return Response.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
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 { SendResponse } from "../../models/response/send.response";
|
||||
|
||||
export class SendRemovePasswordCommand {
|
||||
constructor(private sendService: SendService, private sendApiService: SendApiService) {}
|
||||
|
||||
async run(id: string) {
|
||||
try {
|
||||
await this.sendApiService.removePassword(id);
|
||||
|
||||
const updatedSend = await this.sendService.get(id);
|
||||
const decSend = await updatedSend.decrypt();
|
||||
const res = new SendResponse(decSend);
|
||||
return Response.success(res);
|
||||
} catch (e) {
|
||||
return Response.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,14 @@ import { Main } from "../bw";
|
||||
import { Response } from "../models/response";
|
||||
import { FileResponse } from "../models/response/file.response";
|
||||
import { GenerateCommand } from "../tools/generate.command";
|
||||
import {
|
||||
SendEditCommand,
|
||||
SendCreateCommand,
|
||||
SendDeleteCommand,
|
||||
SendGetCommand,
|
||||
SendListCommand,
|
||||
SendRemovePasswordCommand,
|
||||
} from "../tools/send";
|
||||
import { CreateCommand } from "../vault/create.command";
|
||||
import { DeleteCommand } from "../vault/delete.command";
|
||||
import { SyncCommand } from "../vault/sync.command";
|
||||
@@ -24,12 +32,6 @@ import { EditCommand } from "./edit.command";
|
||||
import { GetCommand } from "./get.command";
|
||||
import { ListCommand } from "./list.command";
|
||||
import { RestoreCommand } from "./restore.command";
|
||||
import { SendCreateCommand } from "./send/create.command";
|
||||
import { SendDeleteCommand } from "./send/delete.command";
|
||||
import { SendEditCommand } from "./send/edit.command";
|
||||
import { SendGetCommand } from "./send/get.command";
|
||||
import { SendListCommand } from "./send/list.command";
|
||||
import { SendRemovePasswordCommand } from "./send/remove-password.command";
|
||||
import { StatusCommand } from "./status.command";
|
||||
|
||||
export class ServeCommand {
|
||||
|
||||
Reference in New Issue
Block a user