mirror of
https://github.com/bitwarden/browser
synced 2026-02-10 13:40:06 +00:00
130 lines
4.6 KiB
TypeScript
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;
|
|
}
|
|
}
|