mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 08:13:42 +00:00
Apply Prettier (#426)
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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, {});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user