1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-10 13:40:06 +00:00
Files
browser/apps/cli/src/tools/send/commands/edit.command.ts
2026-01-16 10:53:43 -07:00

130 lines
4.6 KiB
TypeScript

// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { firstValueFrom } from "rxjs";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction";
import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction";
import { AuthType } from "@bitwarden/common/tools/send/types/auth-type";
import { SendType } from "@bitwarden/common/tools/send/types/send-type";
import { Response } from "../../../models/response";
import { CliUtils } from "../../../utils";
import { SendResponse } from "../models/send.response";
import { SendGetCommand } from "./get.command";
export class SendEditCommand {
constructor(
private sendService: SendService,
private getCommand: SendGetCommand,
private sendApiService: SendApiService,
private accountProfileService: BillingAccountProfileStateService,
private accountService: AccountService,
) {}
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);
// FIXME: Remove when updating file. Eslint update
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (e) {
return Response.badRequest("Error parsing the encoded request data.");
}
}
const normalizedOptions = new Options(cmdOptions);
req.id = normalizedOptions.itemId || req.id;
if (normalizedOptions.emails) {
req.emails = normalizedOptions.emails;
}
if (normalizedOptions.password) {
req.password = normalizedOptions.password;
}
if (req.password && (typeof req.password !== "string" || req.password === "")) {
req.password = undefined;
}
// Infer authType based on emails/password (mutually exclusive)
const hasEmails = req.emails != null && req.emails.length > 0;
const hasPassword = req.password != null && req.password.trim() !== "";
if (hasEmails && hasPassword) {
return Response.badRequest("--password and --emails are mutually exclusive.");
}
if (hasEmails) {
req.authType = AuthType.Email;
} else if (hasPassword) {
req.authType = AuthType.Password;
} else {
req.authType = AuthType.None;
}
if (!req.id) {
return Response.error("`itemid` was not provided.");
}
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");
}
const account = await firstValueFrom(this.accountService.activeAccount$);
const canAccessPremium = await firstValueFrom(
this.accountProfileService.hasPremiumFromAnySource$(account.id),
);
if (send.type === SendType.File && !canAccessPremium) {
return Response.error("Premium status is required to use this feature.");
}
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
let sendView = await send.decrypt(activeUserId);
sendView = SendResponse.toView(req, sendView);
try {
const [encSend, encFileData] = await this.sendService.encrypt(sendView, null, req.password);
await this.sendApiService.save([encSend, encFileData]);
} catch (e) {
return Response.error(e);
}
return await this.getCommand.run(send.id, {});
}
}
class Options {
itemId: string;
password: string;
emails: string[];
constructor(passedOptions: Record<string, any>) {
this.itemId = passedOptions?.itemId || passedOptions?.itemid;
this.password = passedOptions.password;
this.emails = passedOptions.email;
}
}