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

Apply Prettier (#426)

This commit is contained in:
Oscar Hinton
2021-12-20 18:04:00 +01:00
committed by GitHub
parent ec53a16c00
commit 910b4a24e6
59 changed files with 4630 additions and 4117 deletions

View File

@@ -1,114 +1,129 @@
import * as program from 'commander';
import * as fs from 'fs';
import * as path from 'path';
import * as program from "commander";
import * as fs from "fs";
import * as path from "path";
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
import { SendService } from 'jslib-common/abstractions/send.service';
import { UserService } from 'jslib-common/abstractions/user.service';
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
import { SendService } from "jslib-common/abstractions/send.service";
import { UserService } from "jslib-common/abstractions/user.service";
import { SendType } from 'jslib-common/enums/sendType';
import { SendType } from "jslib-common/enums/sendType";
import { NodeUtils } from 'jslib-common/misc/nodeUtils';
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 { 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';
import { SendResponse } from "../../models/response/sendResponse";
import { SendTextResponse } from "../../models/response/sendTextResponse";
import { CliUtils } from '../../utils';
import { CliUtils } from "../../utils";
export class SendCreateCommand {
constructor(private sendService: SendService, private userService: UserService,
private environmentService: EnvironmentService) { }
constructor(
private sendService: SendService,
private userService: UserService,
private environmentService: EnvironmentService
) {}
async run(requestJson: string, options: program.OptionValues) {
let req: any = null;
if (requestJson == null || requestJson === '') {
requestJson = await CliUtils.readStdin();
}
if (requestJson == null || requestJson === '') {
return Response.badRequest('`requestJson` was not provided.');
}
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);
}
return this.createSend(req, options);
async run(requestJson: string, options: program.OptionValues) {
let req: any = null;
if (requestJson == null || requestJson === "") {
requestJson = await CliUtils.readStdin();
}
private async createSend(req: SendResponse, options: program.OptionValues) {
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 (!(await this.userService.canAccessPremium())) {
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');
}
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 encoded 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.sendService.saveWithServer([encSend, fileData]);
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));
} catch (e) {
return Response.error(e);
}
if (requestJson == null || requestJson === "") {
return Response.badRequest("`requestJson` was not provided.");
}
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);
}
return this.createSend(req, options);
}
private async createSend(req: SendResponse, options: program.OptionValues) {
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 (!(await this.userService.canAccessPremium())) {
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"
);
}
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 encoded 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.sendService.saveWithServer([encSend, fileData]);
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)
);
} catch (e) {
return Response.error(e);
}
}
}

View File

@@ -1,22 +1,22 @@
import { SendService } from 'jslib-common/abstractions/send.service';
import { SendService } from "jslib-common/abstractions/send.service";
import { Response } from 'jslib-node/cli/models/response';
import { Response } from "jslib-node/cli/models/response";
export class SendDeleteCommand {
constructor(private sendService: SendService) { }
constructor(private sendService: SendService) {}
async run(id: string) {
const send = await this.sendService.get(id);
async run(id: string) {
const send = await this.sendService.get(id);
if (send == null) {
return Response.notFound();
}
try {
this.sendService.deleteWithServer(id);
return Response.success();
} catch (e) {
return Response.error(e);
}
if (send == null) {
return Response.notFound();
}
try {
this.sendService.deleteWithServer(id);
return Response.success();
} catch (e) {
return Response.error(e);
}
}
}

View File

@@ -1,76 +1,79 @@
import * as program from 'commander';
import * as program from "commander";
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
import { SendService } from 'jslib-common/abstractions/send.service';
import { UserService } from 'jslib-common/abstractions/user.service';
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
import { SendService } from "jslib-common/abstractions/send.service";
import { UserService } from "jslib-common/abstractions/user.service";
import { SendType } from 'jslib-common/enums/sendType';
import { Response } from 'jslib-node/cli/models/response';
import { SendType } from "jslib-common/enums/sendType";
import { Response } from "jslib-node/cli/models/response";
import { SendResponse } from '../../models/response/sendResponse';
import { SendResponse } from "../../models/response/sendResponse";
import { CliUtils } from '../../utils';
import { SendGetCommand } from './get.command';
import { CliUtils } from "../../utils";
import { SendGetCommand } from "./get.command";
export class SendEditCommand {
constructor(private sendService: SendService, private userService: UserService,
private getCommand: SendGetCommand) { }
constructor(
private sendService: SendService,
private userService: UserService,
private getCommand: SendGetCommand
) {}
async run(encodedJson: string, options: program.OptionValues): Promise<Response> {
if (encodedJson == null || encodedJson === '') {
encodedJson = await CliUtils.readStdin();
}
if (encodedJson == null || encodedJson === '') {
return Response.badRequest('`encodedJson` 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.');
}
req.id = options.itemid || req.id;
if (req.id != null) {
req.id = req.id.toLowerCase();
}
const send = await this.sendService.get(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.userService.canAccessPremium())) {
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.sendService.saveWithServer([encSend, encFileData]);
} catch (e) {
return Response.error(e);
}
return await this.getCommand.run(send.id, {});
async run(encodedJson: string, options: program.OptionValues): Promise<Response> {
if (encodedJson == null || encodedJson === "") {
encodedJson = await CliUtils.readStdin();
}
if (encodedJson == null || encodedJson === "") {
return Response.badRequest("`encodedJson` 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.");
}
req.id = options.itemid || req.id;
if (req.id != null) {
req.id = req.id.toLowerCase();
}
const send = await this.sendService.get(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.userService.canAccessPremium())) {
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.sendService.saveWithServer([encSend, encFileData]);
} catch (e) {
return Response.error(e);
}
return await this.getCommand.run(send.id, {});
}
}

View File

@@ -1,79 +1,83 @@
import * as program from 'commander';
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';
import { SendService } from 'jslib-common/abstractions/send.service';
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";
import { SendService } from "jslib-common/abstractions/send.service";
import { SendView } from 'jslib-common/models/view/sendView';
import { SendView } from "jslib-common/models/view/sendView";
import { Response } from 'jslib-node/cli/models/response';
import { Response } from "jslib-node/cli/models/response";
import { DownloadCommand } from '../download.command';
import { DownloadCommand } from "../download.command";
import { SendResponse } from '../../models/response/sendResponse';
import { SendResponse } from "../../models/response/sendResponse";
import { Utils } from 'jslib-common/misc/utils';
import { Utils } from "jslib-common/misc/utils";
export class SendGetCommand extends DownloadCommand {
constructor(private sendService: SendService, private environmentService: EnvironmentService,
private searchService: SearchService, cryptoService: CryptoService) {
super(cryptoService);
constructor(
private sendService: SendService,
private environmentService: EnvironmentService,
private searchService: SearchService,
cryptoService: CryptoService
) {
super(cryptoService);
}
async run(id: string, options: program.OptionValues) {
let sends = await this.getSendView(id);
if (sends == null) {
return Response.notFound();
}
async run(id: string, options: program.OptionValues) {
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 (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);
const webVaultUrl = this.environmentService.getWebVaultUrl();
let filter = (s: SendView) => true;
let selector = async (s: SendView): Promise<Response> =>
Response.success(new SendResponse(s, webVaultUrl));
if (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();
};
}
private async getSendView(id: string): Promise<SendView | SendView[]> {
if (Utils.isGuid(id)) {
const send = await this.sendService.get(id);
if (send != null) {
return await send.decrypt();
}
} else if (id.trim() !== '') {
let sends = await this.sendService.getAllDecrypted();
sends = this.searchService.searchSends(sends, id);
if (sends.length > 1) {
return sends;
} else if (sends.length > 0) {
return sends[0];
}
}
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.get(id);
if (send != null) {
return await send.decrypt();
}
} else if (id.trim() !== "") {
let sends = await this.sendService.getAllDecrypted();
sends = this.searchService.searchSends(sends, id);
if (sends.length > 1) {
return sends;
} else if (sends.length > 0) {
return sends[0];
}
}
}
}

View File

@@ -1,28 +1,30 @@
import * as program from 'commander';
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';
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
import { SearchService } from "jslib-common/abstractions/search.service";
import { SendService } from "jslib-common/abstractions/send.service";
import { Response } from 'jslib-node/cli/models/response';
import { ListResponse } from 'jslib-node/cli/models/response/listResponse';
import { Response } from "jslib-node/cli/models/response";
import { ListResponse } from "jslib-node/cli/models/response/listResponse";
import { SendResponse } from '../..//models/response/sendResponse';
import { SendResponse } from "../..//models/response/sendResponse";
export class SendListCommand {
constructor(
private sendService: SendService,
private environmentService: EnvironmentService,
private searchService: SearchService
) {}
constructor(private sendService: SendService, private environmentService: EnvironmentService,
private searchService: SearchService) { }
async run(options: program.OptionValues): Promise<Response> {
let sends = await this.sendService.getAllDecrypted();
async run(options: program.OptionValues): Promise<Response> {
let sends = await this.sendService.getAllDecrypted();
if (options.search != null && options.search.trim() !== '') {
sends = this.searchService.searchSends(sends, options.search);
}
const webVaultUrl = this.environmentService.getWebVaultUrl();
const res = new ListResponse(sends.map(s => new SendResponse(s, webVaultUrl)));
return Response.success(res);
if (options.search != null && options.search.trim() !== "") {
sends = this.searchService.searchSends(sends, options.search);
}
const webVaultUrl = this.environmentService.getWebVaultUrl();
const res = new ListResponse(sends.map((s) => new SendResponse(s, webVaultUrl)));
return Response.success(res);
}
}

View File

@@ -1,151 +1,175 @@
import * as program from 'commander';
import * as inquirer from 'inquirer';
import * as program from "commander";
import * as inquirer from "inquirer";
import { ApiService } from 'jslib-common/abstractions/api.service';
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
import { CryptoFunctionService } from 'jslib-common/abstractions/cryptoFunction.service';
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { ApiService } from "jslib-common/abstractions/api.service";
import { CryptoService } from "jslib-common/abstractions/crypto.service";
import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service";
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { SendAccessRequest } from 'jslib-common/models/request/sendAccessRequest';
import { ErrorResponse } from 'jslib-common/models/response/errorResponse';
import { SendAccessView } from 'jslib-common/models/view/sendAccessView';
import { SendAccessRequest } from "jslib-common/models/request/sendAccessRequest";
import { ErrorResponse } from "jslib-common/models/response/errorResponse";
import { SendAccessView } from "jslib-common/models/view/sendAccessView";
import { Response } from 'jslib-node/cli/models/response';
import { Response } from "jslib-node/cli/models/response";
import { SendAccess } from 'jslib-common/models/domain/sendAccess';
import { SymmetricCryptoKey } from 'jslib-common/models/domain/symmetricCryptoKey';
import { SendAccess } from "jslib-common/models/domain/sendAccess";
import { SymmetricCryptoKey } from "jslib-common/models/domain/symmetricCryptoKey";
import { SendType } from 'jslib-common/enums/sendType';
import { SendType } from "jslib-common/enums/sendType";
import { NodeUtils } from 'jslib-common/misc/nodeUtils';
import { Utils } from 'jslib-common/misc/utils';
import { NodeUtils } from "jslib-common/misc/nodeUtils";
import { Utils } from "jslib-common/misc/utils";
import { SendAccessResponse } from '../../models/response/sendAccessResponse';
import { SendAccessResponse } from "../../models/response/sendAccessResponse";
import { DownloadCommand } from '../download.command';
import { DownloadCommand } from "../download.command";
export class SendReceiveCommand extends DownloadCommand {
private canInteract: boolean;
private decKey: SymmetricCryptoKey;
private sendAccessRequest: SendAccessRequest;
private canInteract: boolean;
private decKey: SymmetricCryptoKey;
private sendAccessRequest: SendAccessRequest;
constructor(private apiService: ApiService, cryptoService: CryptoService,
private cryptoFunctionService: CryptoFunctionService, private platformUtilsService: PlatformUtilsService,
private environmentService: EnvironmentService) {
super(cryptoService);
constructor(
private apiService: ApiService,
cryptoService: CryptoService,
private cryptoFunctionService: CryptoFunctionService,
private platformUtilsService: PlatformUtilsService,
private environmentService: EnvironmentService
) {
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");
}
async run(url: string, options: program.OptionValues): Promise<Response> {
this.canInteract = process.env.BW_NOINTERACTION !== 'true';
const apiUrl = this.getApiUrl(urlObject);
const [id, key] = this.getIdAndKey(urlObject);
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.apiService.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));
}
if (Utils.isNullOrWhitespace(id) || Utils.isNullOrWhitespace(key)) {
return Response.badRequest("Failed to parse url, the url provided is not a valid Send url");
}
private getIdAndKey(url: URL): [string, string] {
const result = url.hash.slice(1).split('/').slice(-2);
return [result[0], result[1]];
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];
}
}
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.apiService.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);
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.apiService.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.apiService.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);
}
}
}

View File

@@ -1,22 +1,22 @@
import { SendService } from 'jslib-common/abstractions/send.service';
import { SendService } from "jslib-common/abstractions/send.service";
import { Response } from 'jslib-node/cli/models/response';
import { Response } from "jslib-node/cli/models/response";
import { SendResponse } from '../../models/response/sendResponse';
import { SendResponse } from "../../models/response/sendResponse";
export class SendRemovePasswordCommand {
constructor(private sendService: SendService) { }
constructor(private sendService: SendService) {}
async run(id: string) {
try {
await this.sendService.removePasswordWithServer(id);
async run(id: string) {
try {
await this.sendService.removePasswordWithServer(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);
}
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);
}
}
}