mirror of
https://github.com/bitwarden/browser.git
synced 2025-02-03 23:21:29 +01:00
serve command (#451)
This commit is contained in:
parent
84a0bfb07c
commit
922cd1dc54
1412
package-lock.json
generated
1412
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -51,10 +51,12 @@
|
||||
"assets": "./build/**/*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/inquirer": "^7.3.1",
|
||||
"@types/jsdom": "^16.2.10",
|
||||
"@types/lowdb": "^1.0.10",
|
||||
"@types/lunr": "^2.3.3",
|
||||
"@types/multer": "^1.4.7",
|
||||
"@types/node": "^16.11.12",
|
||||
"@types/node-fetch": "^2.5.10",
|
||||
"@types/node-forge": "^0.9.7",
|
||||
@ -83,12 +85,14 @@
|
||||
"browser-hrtime": "^1.1.8",
|
||||
"chalk": "^4.1.1",
|
||||
"commander": "7.2.0",
|
||||
"express": "^4.17.1",
|
||||
"form-data": "4.0.0",
|
||||
"https-proxy-agent": "5.0.0",
|
||||
"inquirer": "8.0.0",
|
||||
"jsdom": "^16.5.3",
|
||||
"lowdb": "1.0.0",
|
||||
"lunr": "^2.3.9",
|
||||
"multer": "^1.4.3",
|
||||
"node-fetch": "^2.6.1",
|
||||
"node-forge": "0.10.0",
|
||||
"open": "^8.0.8",
|
||||
|
@ -23,7 +23,7 @@ export class CompletionCommand {
|
||||
const shell: typeof validShells[number] = options.shell;
|
||||
|
||||
if (!shell) {
|
||||
return Response.badRequest("`shell` was not provided.");
|
||||
return Response.badRequest("`shell` option was not provided.");
|
||||
}
|
||||
|
||||
if (!validShells.includes(shell)) {
|
||||
|
@ -1,5 +1,3 @@
|
||||
import * as program from "commander";
|
||||
|
||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||
|
||||
@ -12,35 +10,36 @@ import { Utils } from "jslib-common/misc/utils";
|
||||
export class ConfirmCommand {
|
||||
constructor(private apiService: ApiService, private cryptoService: CryptoService) {}
|
||||
|
||||
async run(object: string, id: string, cmd: program.Command): Promise<Response> {
|
||||
async run(object: string, id: string, cmdOptions: Record<string, any>): Promise<Response> {
|
||||
if (id != null) {
|
||||
id = id.toLowerCase();
|
||||
}
|
||||
|
||||
const normalizedOptions = new Options(cmdOptions);
|
||||
switch (object.toLowerCase()) {
|
||||
case "org-member":
|
||||
return await this.confirmOrganizationMember(id, cmd);
|
||||
return await this.confirmOrganizationMember(id, normalizedOptions);
|
||||
default:
|
||||
return Response.badRequest("Unknown object.");
|
||||
}
|
||||
}
|
||||
|
||||
private async confirmOrganizationMember(id: string, options: program.OptionValues) {
|
||||
if (options.organizationid == null || options.organizationid === "") {
|
||||
private async confirmOrganizationMember(id: string, options: Options) {
|
||||
if (options.organizationId == null || options.organizationId === "") {
|
||||
return Response.badRequest("--organizationid <organizationid> required.");
|
||||
}
|
||||
if (!Utils.isGuid(id)) {
|
||||
return Response.error("`" + id + "` is not a GUID.");
|
||||
return Response.badRequest("`" + id + "` is not a GUID.");
|
||||
}
|
||||
if (!Utils.isGuid(options.organizationid)) {
|
||||
return Response.error("`" + options.organizationid + "` is not a GUID.");
|
||||
if (!Utils.isGuid(options.organizationId)) {
|
||||
return Response.badRequest("`" + options.organizationId + "` is not a GUID.");
|
||||
}
|
||||
try {
|
||||
const orgKey = await this.cryptoService.getOrgKey(options.organizationid);
|
||||
const orgKey = await this.cryptoService.getOrgKey(options.organizationId);
|
||||
if (orgKey == null) {
|
||||
throw new Error("No encryption key for this organization.");
|
||||
}
|
||||
const orgUser = await this.apiService.getOrganizationUser(options.organizationid, id);
|
||||
const orgUser = await this.apiService.getOrganizationUser(options.organizationId, id);
|
||||
if (orgUser == null) {
|
||||
throw new Error("Member id does not exist for this organization.");
|
||||
}
|
||||
@ -49,10 +48,18 @@ export class ConfirmCommand {
|
||||
const key = await this.cryptoService.rsaEncrypt(orgKey.key, publicKey.buffer);
|
||||
const req = new OrganizationUserConfirmRequest();
|
||||
req.key = key.encryptedString;
|
||||
await this.apiService.postOrganizationUserConfirm(options.organizationid, id, req);
|
||||
await this.apiService.postOrganizationUserConfirm(options.organizationId, id, req);
|
||||
return Response.success();
|
||||
} catch (e) {
|
||||
return Response.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Options {
|
||||
organizationId: string;
|
||||
|
||||
constructor(passedOptions: Record<string, any>) {
|
||||
this.organizationId = passedOptions.organizationid || passedOptions.organizationId;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import * as program from "commander";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
@ -36,10 +35,15 @@ export class CreateCommand {
|
||||
private apiService: ApiService
|
||||
) {}
|
||||
|
||||
async run(object: string, requestJson: string, cmd: program.Command): Promise<Response> {
|
||||
async run(
|
||||
object: string,
|
||||
requestJson: string,
|
||||
cmdOptions: Record<string, any>,
|
||||
additionalData: any = null
|
||||
): Promise<Response> {
|
||||
let req: any = null;
|
||||
if (object !== "attachment") {
|
||||
if (requestJson == null || requestJson === "") {
|
||||
if (process.env.BW_SERVE !== "true" && (requestJson == null || requestJson === "")) {
|
||||
requestJson = await CliUtils.readStdin();
|
||||
}
|
||||
|
||||
@ -47,23 +51,28 @@ export class CreateCommand {
|
||||
return Response.badRequest("`requestJson` was not provided.");
|
||||
}
|
||||
|
||||
try {
|
||||
const reqJson = Buffer.from(requestJson, "base64").toString();
|
||||
req = JSON.parse(reqJson);
|
||||
} catch (e) {
|
||||
return Response.badRequest("Error parsing the encoded request data.");
|
||||
if (typeof requestJson !== "string") {
|
||||
req = requestJson;
|
||||
} else {
|
||||
try {
|
||||
const reqJson = Buffer.from(requestJson, "base64").toString();
|
||||
req = JSON.parse(reqJson);
|
||||
} catch (e) {
|
||||
return Response.badRequest("Error parsing the encoded request data.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const normalizedOptions = new Options(cmdOptions);
|
||||
switch (object.toLowerCase()) {
|
||||
case "item":
|
||||
return await this.createCipher(req);
|
||||
case "attachment":
|
||||
return await this.createAttachment(cmd);
|
||||
return await this.createAttachment(normalizedOptions, additionalData);
|
||||
case "folder":
|
||||
return await this.createFolder(req);
|
||||
case "org-collection":
|
||||
return await this.createOrganizationCollection(req, cmd);
|
||||
return await this.createOrganizationCollection(req, normalizedOptions);
|
||||
default:
|
||||
return Response.badRequest("Unknown object.");
|
||||
}
|
||||
@ -82,19 +91,35 @@ export class CreateCommand {
|
||||
}
|
||||
}
|
||||
|
||||
private async createAttachment(options: program.OptionValues) {
|
||||
if (options.itemid == null || options.itemid === "") {
|
||||
return Response.badRequest("--itemid <itemid> required.");
|
||||
private async createAttachment(options: Options, additionalData: any) {
|
||||
if (options.itemId == null || options.itemId === "") {
|
||||
return Response.badRequest("`itemid` option is required.");
|
||||
}
|
||||
if (options.file == null || options.file === "") {
|
||||
return Response.badRequest("--file <file> required.");
|
||||
}
|
||||
const filePath = path.resolve(options.file);
|
||||
if (!fs.existsSync(options.file)) {
|
||||
return Response.badRequest("Cannot find file at " + filePath);
|
||||
let fileBuf: Buffer = null;
|
||||
let fileName: string = null;
|
||||
if (process.env.BW_SERVE === "true") {
|
||||
fileBuf = additionalData.fileBuffer;
|
||||
fileName = additionalData.fileName;
|
||||
} else {
|
||||
if (options.file == null || options.file === "") {
|
||||
return Response.badRequest("`file` option is required.");
|
||||
}
|
||||
const filePath = path.resolve(options.file);
|
||||
if (!fs.existsSync(options.file)) {
|
||||
return Response.badRequest("Cannot find file at " + filePath);
|
||||
}
|
||||
fileBuf = fs.readFileSync(filePath);
|
||||
fileName = path.basename(filePath);
|
||||
}
|
||||
|
||||
const itemId = options.itemid.toLowerCase();
|
||||
if (fileBuf == null) {
|
||||
return Response.badRequest("File not provided.");
|
||||
}
|
||||
if (fileName == null || fileName.trim() === "") {
|
||||
return Response.badRequest("File name not provided.");
|
||||
}
|
||||
|
||||
const itemId = options.itemId.toLowerCase();
|
||||
const cipher = await this.cipherService.get(itemId);
|
||||
if (cipher == null) {
|
||||
return Response.notFound();
|
||||
@ -113,16 +138,14 @@ export class CreateCommand {
|
||||
}
|
||||
|
||||
try {
|
||||
const fileBuf = fs.readFileSync(filePath);
|
||||
await this.cipherService.saveAttachmentRawWithServer(
|
||||
cipher,
|
||||
path.basename(filePath),
|
||||
fileName,
|
||||
new Uint8Array(fileBuf).buffer
|
||||
);
|
||||
const updatedCipher = await this.cipherService.get(cipher.id);
|
||||
const decCipher = await updatedCipher.decrypt();
|
||||
const res = new CipherResponse(decCipher);
|
||||
return Response.success(res);
|
||||
} catch (e) {
|
||||
return Response.error(e);
|
||||
}
|
||||
@ -141,18 +164,15 @@ export class CreateCommand {
|
||||
}
|
||||
}
|
||||
|
||||
private async createOrganizationCollection(
|
||||
req: OrganizationCollectionRequest,
|
||||
options: program.OptionValues
|
||||
) {
|
||||
if (options.organizationid == null || options.organizationid === "") {
|
||||
return Response.badRequest("--organizationid <organizationid> required.");
|
||||
private async createOrganizationCollection(req: OrganizationCollectionRequest, options: Options) {
|
||||
if (options.organizationId == null || options.organizationId === "") {
|
||||
return Response.badRequest("`organizationid` option is required.");
|
||||
}
|
||||
if (!Utils.isGuid(options.organizationid)) {
|
||||
return Response.error("`" + options.organizationid + "` is not a GUID.");
|
||||
if (!Utils.isGuid(options.organizationId)) {
|
||||
return Response.badRequest("`" + options.organizationId + "` is not a GUID.");
|
||||
}
|
||||
if (options.organizationid !== req.organizationId) {
|
||||
return Response.error("--organizationid <organizationid> does not match request object.");
|
||||
if (options.organizationId !== req.organizationId) {
|
||||
return Response.badRequest("`organizationid` option does not match request object.");
|
||||
}
|
||||
try {
|
||||
const orgKey = await this.cryptoService.getOrgKey(req.organizationId);
|
||||
@ -178,3 +198,15 @@ export class CreateCommand {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Options {
|
||||
itemId: string;
|
||||
organizationId: string;
|
||||
file: string;
|
||||
|
||||
constructor(passedOptions: Record<string, any>) {
|
||||
this.organizationId = passedOptions.organizationid || passedOptions.organizationId;
|
||||
this.itemId = passedOptions.itemid || passedOptions.itemId;
|
||||
this.file = passedOptions.file;
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import { StateService } from "jslib-common/abstractions/state.service";
|
||||
import { Response } from "jslib-node/cli/models/response";
|
||||
|
||||
import { Utils } from "jslib-common/misc/utils";
|
||||
import { CliUtils } from "src/utils";
|
||||
|
||||
export class DeleteCommand {
|
||||
constructor(
|
||||
@ -17,26 +18,27 @@ export class DeleteCommand {
|
||||
private apiService: ApiService
|
||||
) {}
|
||||
|
||||
async run(object: string, id: string, cmd: program.Command): Promise<Response> {
|
||||
async run(object: string, id: string, cmdOptions: Record<string, any>): Promise<Response> {
|
||||
if (id != null) {
|
||||
id = id.toLowerCase();
|
||||
}
|
||||
|
||||
const normalizedOptions = new Options(cmdOptions);
|
||||
switch (object.toLowerCase()) {
|
||||
case "item":
|
||||
return await this.deleteCipher(id, cmd);
|
||||
return await this.deleteCipher(id, normalizedOptions);
|
||||
case "attachment":
|
||||
return await this.deleteAttachment(id, cmd);
|
||||
return await this.deleteAttachment(id, normalizedOptions);
|
||||
case "folder":
|
||||
return await this.deleteFolder(id);
|
||||
case "org-collection":
|
||||
return await this.deleteOrganizationCollection(id, cmd);
|
||||
return await this.deleteOrganizationCollection(id, normalizedOptions);
|
||||
default:
|
||||
return Response.badRequest("Unknown object.");
|
||||
}
|
||||
}
|
||||
|
||||
private async deleteCipher(id: string, options: program.OptionValues) {
|
||||
private async deleteCipher(id: string, options: Options) {
|
||||
const cipher = await this.cipherService.get(id);
|
||||
if (cipher == null) {
|
||||
return Response.notFound();
|
||||
@ -54,12 +56,12 @@ export class DeleteCommand {
|
||||
}
|
||||
}
|
||||
|
||||
private async deleteAttachment(id: string, options: program.OptionValues) {
|
||||
if (options.itemid == null || options.itemid === "") {
|
||||
return Response.badRequest("--itemid <itemid> required.");
|
||||
private async deleteAttachment(id: string, options: Options) {
|
||||
if (options.itemId == null || options.itemId === "") {
|
||||
return Response.badRequest("`itemid` option is required.");
|
||||
}
|
||||
|
||||
const itemId = options.itemid.toLowerCase();
|
||||
const itemId = options.itemId.toLowerCase();
|
||||
const cipher = await this.cipherService.get(itemId);
|
||||
if (cipher == null) {
|
||||
return Response.notFound();
|
||||
@ -100,21 +102,33 @@ export class DeleteCommand {
|
||||
}
|
||||
}
|
||||
|
||||
private async deleteOrganizationCollection(id: string, options: program.OptionValues) {
|
||||
if (options.organizationid == null || options.organizationid === "") {
|
||||
return Response.badRequest("--organizationid <organizationid> required.");
|
||||
private async deleteOrganizationCollection(id: string, options: Options) {
|
||||
if (options.organizationId == null || options.organizationId === "") {
|
||||
return Response.badRequest("`organizationid` options is required.");
|
||||
}
|
||||
if (!Utils.isGuid(id)) {
|
||||
return Response.error("`" + id + "` is not a GUID.");
|
||||
return Response.badRequest("`" + id + "` is not a GUID.");
|
||||
}
|
||||
if (!Utils.isGuid(options.organizationid)) {
|
||||
return Response.error("`" + options.organizationid + "` is not a GUID.");
|
||||
if (!Utils.isGuid(options.organizationId)) {
|
||||
return Response.badRequest("`" + options.organizationId + "` is not a GUID.");
|
||||
}
|
||||
try {
|
||||
await this.apiService.deleteCollection(options.organizationid, id);
|
||||
await this.apiService.deleteCollection(options.organizationId, id);
|
||||
return Response.success();
|
||||
} catch (e) {
|
||||
return Response.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Options {
|
||||
itemId: string;
|
||||
organizationId: string;
|
||||
permanent: boolean;
|
||||
|
||||
constructor(passedOptions: Record<string, any>) {
|
||||
this.organizationId = passedOptions.organizationid || passedOptions.organizationId;
|
||||
this.itemId = passedOptions.itemid || passedOptions.itemId;
|
||||
this.permanent = CliUtils.convertBooleanOption(passedOptions.permanent);
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||
import { SymmetricCryptoKey } from "jslib-common/models/domain/symmetricCryptoKey";
|
||||
|
||||
import { Response } from "jslib-node/cli/models/response";
|
||||
import { FileResponse } from "jslib-node/cli/models/response/fileResponse";
|
||||
|
||||
import { CliUtils } from "../utils";
|
||||
|
||||
@ -27,7 +28,12 @@ export abstract class DownloadCommand {
|
||||
try {
|
||||
const buf = await response.arrayBuffer();
|
||||
const decBuf = await this.cryptoService.decryptFromBytes(buf, key);
|
||||
return await CliUtils.saveResultToFile(Buffer.from(decBuf), output, fileName);
|
||||
if (process.env.BW_SERVE === "true") {
|
||||
const res = new FileResponse(Buffer.from(decBuf), fileName);
|
||||
return Response.success(res);
|
||||
} else {
|
||||
return await CliUtils.saveResultToFile(Buffer.from(decBuf), output, fileName);
|
||||
}
|
||||
} catch (e) {
|
||||
if (typeof e === "string") {
|
||||
return Response.error(e);
|
||||
|
@ -35,10 +35,10 @@ export class EditCommand {
|
||||
async run(
|
||||
object: string,
|
||||
id: string,
|
||||
requestJson: string,
|
||||
cmd: program.Command
|
||||
requestJson: any,
|
||||
cmdOptions: Record<string, any>
|
||||
): Promise<Response> {
|
||||
if (requestJson == null || requestJson === "") {
|
||||
if (process.env.BW_SERVE !== "true" && (requestJson == null || requestJson === "")) {
|
||||
requestJson = await CliUtils.readStdin();
|
||||
}
|
||||
|
||||
@ -47,17 +47,22 @@ export class EditCommand {
|
||||
}
|
||||
|
||||
let req: any = null;
|
||||
try {
|
||||
const reqJson = Buffer.from(requestJson, "base64").toString();
|
||||
req = JSON.parse(reqJson);
|
||||
} catch (e) {
|
||||
return Response.badRequest("Error parsing the encoded request data.");
|
||||
if (typeof requestJson !== "string") {
|
||||
req = requestJson;
|
||||
} else {
|
||||
try {
|
||||
const reqJson = Buffer.from(requestJson, "base64").toString();
|
||||
req = JSON.parse(reqJson);
|
||||
} catch (e) {
|
||||
return Response.badRequest("Error parsing the encoded request data.");
|
||||
}
|
||||
}
|
||||
|
||||
if (id != null) {
|
||||
id = id.toLowerCase();
|
||||
}
|
||||
|
||||
const normalizedOptions = new Options(cmdOptions);
|
||||
switch (object.toLowerCase()) {
|
||||
case "item":
|
||||
return await this.editCipher(id, req);
|
||||
@ -66,7 +71,7 @@ export class EditCommand {
|
||||
case "folder":
|
||||
return await this.editFolder(id, req);
|
||||
case "org-collection":
|
||||
return await this.editOrganizationCollection(id, req, cmd);
|
||||
return await this.editOrganizationCollection(id, req, normalizedOptions);
|
||||
default:
|
||||
return Response.badRequest("Unknown object.");
|
||||
}
|
||||
@ -80,9 +85,7 @@ export class EditCommand {
|
||||
|
||||
let cipherView = await cipher.decrypt();
|
||||
if (cipherView.isDeleted) {
|
||||
return Response.badRequest(
|
||||
"You may not edit a deleted cipher. Use restore item <id> command first."
|
||||
);
|
||||
return Response.badRequest("You may not edit a deleted item. Use the restore command first.");
|
||||
}
|
||||
cipherView = Cipher.toView(req, cipherView);
|
||||
const encCipher = await this.cipherService.encrypt(cipherView);
|
||||
@ -104,7 +107,7 @@ export class EditCommand {
|
||||
}
|
||||
if (cipher.organizationId == null) {
|
||||
return Response.badRequest(
|
||||
"Item does not belong to an organization. Consider sharing it first."
|
||||
"Item does not belong to an organization. Consider moving it first."
|
||||
);
|
||||
}
|
||||
|
||||
@ -143,19 +146,19 @@ export class EditCommand {
|
||||
private async editOrganizationCollection(
|
||||
id: string,
|
||||
req: OrganizationCollectionRequest,
|
||||
options: program.OptionValues
|
||||
options: Options
|
||||
) {
|
||||
if (options.organizationid == null || options.organizationid === "") {
|
||||
return Response.badRequest("--organizationid <organizationid> required.");
|
||||
if (options.organizationId == null || options.organizationId === "") {
|
||||
return Response.badRequest("`organizationid` option is required.");
|
||||
}
|
||||
if (!Utils.isGuid(id)) {
|
||||
return Response.error("`" + id + "` is not a GUID.");
|
||||
return Response.badRequest("`" + id + "` is not a GUID.");
|
||||
}
|
||||
if (!Utils.isGuid(options.organizationid)) {
|
||||
return Response.error("`" + options.organizationid + "` is not a GUID.");
|
||||
if (!Utils.isGuid(options.organizationId)) {
|
||||
return Response.badRequest("`" + options.organizationId + "` is not a GUID.");
|
||||
}
|
||||
if (options.organizationid !== req.organizationId) {
|
||||
return Response.error("--organizationid <organizationid> does not match request object.");
|
||||
if (options.organizationId !== req.organizationId) {
|
||||
return Response.badRequest("`organizationid` option does not match request object.");
|
||||
}
|
||||
try {
|
||||
const orgKey = await this.cryptoService.getOrgKey(req.organizationId);
|
||||
@ -181,3 +184,11 @@ export class EditCommand {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Options {
|
||||
organizationId: string;
|
||||
|
||||
constructor(passedOptions: Record<string, any>) {
|
||||
this.organizationId = passedOptions.organizationid || passedOptions.organizationId;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,3 @@
|
||||
import * as program from "commander";
|
||||
|
||||
import { Response } from "jslib-node/cli/models/response";
|
||||
import { StringResponse } from "jslib-node/cli/models/response/stringResponse";
|
||||
|
||||
|
@ -1,42 +1,27 @@
|
||||
import * as program from "commander";
|
||||
|
||||
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
|
||||
|
||||
import { Response } from "jslib-node/cli/models/response";
|
||||
import { StringResponse } from "jslib-node/cli/models/response/stringResponse";
|
||||
|
||||
import { CliUtils } from "../utils";
|
||||
|
||||
export class GenerateCommand {
|
||||
constructor(private passwordGenerationService: PasswordGenerationService) {}
|
||||
|
||||
async run(cmdOptions: program.OptionValues): Promise<Response> {
|
||||
async run(cmdOptions: Record<string, any>): Promise<Response> {
|
||||
const normalizedOptions = new Options(cmdOptions);
|
||||
const options = {
|
||||
uppercase: cmdOptions.uppercase || false,
|
||||
lowercase: cmdOptions.lowercase || false,
|
||||
number: cmdOptions.number || false,
|
||||
special: cmdOptions.special || false,
|
||||
length: cmdOptions.length || 14,
|
||||
type: cmdOptions.passphrase ? "passphrase" : "password",
|
||||
wordSeparator: cmdOptions.separator == null ? "-" : cmdOptions.separator,
|
||||
numWords: cmdOptions.words || 3,
|
||||
capitalize: cmdOptions.capitalize || false,
|
||||
includeNumber: cmdOptions.includeNumber || false,
|
||||
uppercase: normalizedOptions.uppercase,
|
||||
lowercase: normalizedOptions.lowercase,
|
||||
number: normalizedOptions.number,
|
||||
special: normalizedOptions.special,
|
||||
length: normalizedOptions.length,
|
||||
type: normalizedOptions.type,
|
||||
wordSeparator: normalizedOptions.separator,
|
||||
numWords: normalizedOptions.words,
|
||||
capitalize: normalizedOptions.capitalize,
|
||||
includeNumber: normalizedOptions.includeNumber,
|
||||
};
|
||||
if (!options.uppercase && !options.lowercase && !options.special && !options.number) {
|
||||
options.lowercase = true;
|
||||
options.uppercase = true;
|
||||
options.number = true;
|
||||
}
|
||||
if (options.length < 5) {
|
||||
options.length = 5;
|
||||
}
|
||||
if (options.numWords < 3) {
|
||||
options.numWords = 3;
|
||||
}
|
||||
if (options.wordSeparator === "space") {
|
||||
options.wordSeparator = " ";
|
||||
} else if (options.wordSeparator != null && options.wordSeparator.length > 1) {
|
||||
options.wordSeparator = options.wordSeparator[0];
|
||||
}
|
||||
const enforcedOptions =
|
||||
await this.passwordGenerationService.enforcePasswordGeneratorPoliciesOnOptions(options);
|
||||
const password = await this.passwordGenerationService.generatePassword(enforcedOptions[0]);
|
||||
@ -44,3 +29,46 @@ export class GenerateCommand {
|
||||
return Response.success(res);
|
||||
}
|
||||
}
|
||||
|
||||
class Options {
|
||||
uppercase: boolean;
|
||||
lowercase: boolean;
|
||||
number: boolean;
|
||||
special: boolean;
|
||||
length: number;
|
||||
type: "passphrase" | "password";
|
||||
separator: string;
|
||||
words: number;
|
||||
capitalize: boolean;
|
||||
includeNumber: boolean;
|
||||
|
||||
constructor(passedOptions: Record<string, any>) {
|
||||
this.uppercase = CliUtils.convertBooleanOption(passedOptions.uppercase);
|
||||
this.lowercase = CliUtils.convertBooleanOption(passedOptions.lowercase);
|
||||
this.number = CliUtils.convertBooleanOption(passedOptions.number);
|
||||
this.special = CliUtils.convertBooleanOption(passedOptions.special);
|
||||
this.capitalize = CliUtils.convertBooleanOption(passedOptions.capitalize);
|
||||
this.includeNumber = CliUtils.convertBooleanOption(passedOptions.includeNumber);
|
||||
this.length = passedOptions.length != null ? parseInt(passedOptions.length, null) : 14;
|
||||
this.type = passedOptions.passphrase ? "passphrase" : "password";
|
||||
this.separator = passedOptions.separator == null ? "-" : passedOptions.separator + "";
|
||||
this.words = passedOptions.words != null ? parseInt(passedOptions.words, null) : 3;
|
||||
|
||||
if (!this.uppercase && !this.lowercase && !this.special && !this.number) {
|
||||
this.lowercase = true;
|
||||
this.uppercase = true;
|
||||
this.number = true;
|
||||
}
|
||||
if (this.length < 5) {
|
||||
this.length = 5;
|
||||
}
|
||||
if (this.words < 3) {
|
||||
this.words = 3;
|
||||
}
|
||||
if (this.separator === "space") {
|
||||
this.separator = " ";
|
||||
} else if (this.separator != null && this.separator.length > 1) {
|
||||
this.separator = this.separator[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,3 @@
|
||||
import * as program from "commander";
|
||||
|
||||
import { CipherType } from "jslib-common/enums/cipherType";
|
||||
|
||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||
@ -71,11 +69,12 @@ export class GetCommand extends DownloadCommand {
|
||||
super(cryptoService);
|
||||
}
|
||||
|
||||
async run(object: string, id: string, options: program.OptionValues): Promise<Response> {
|
||||
async run(object: string, id: string, cmdOptions: Record<string, any>): Promise<Response> {
|
||||
if (id != null) {
|
||||
id = id.toLowerCase();
|
||||
}
|
||||
|
||||
const normalizedOptions = new Options(cmdOptions);
|
||||
switch (object.toLowerCase()) {
|
||||
case "item":
|
||||
return await this.getCipher(id);
|
||||
@ -92,13 +91,13 @@ export class GetCommand extends DownloadCommand {
|
||||
case "exposed":
|
||||
return await this.getExposed(id);
|
||||
case "attachment":
|
||||
return await this.getAttachment(id, options);
|
||||
return await this.getAttachment(id, normalizedOptions);
|
||||
case "folder":
|
||||
return await this.getFolder(id);
|
||||
case "collection":
|
||||
return await this.getCollection(id);
|
||||
case "org-collection":
|
||||
return await this.getOrganizationCollection(id, options);
|
||||
return await this.getOrganizationCollection(id, normalizedOptions);
|
||||
case "organization":
|
||||
return await this.getOrganization(id);
|
||||
case "template":
|
||||
@ -292,12 +291,12 @@ export class GetCommand extends DownloadCommand {
|
||||
return Response.success(res);
|
||||
}
|
||||
|
||||
private async getAttachment(id: string, options: program.OptionValues) {
|
||||
if (options.itemid == null || options.itemid === "") {
|
||||
private async getAttachment(id: string, options: Options) {
|
||||
if (options.itemId == null || options.itemId === "") {
|
||||
return Response.badRequest("--itemid <itemid> required.");
|
||||
}
|
||||
|
||||
const itemId = options.itemid.toLowerCase();
|
||||
const itemId = options.itemId.toLowerCase();
|
||||
const cipherResponse = await this.getCipher(itemId);
|
||||
if (!cipherResponse.success) {
|
||||
return cipherResponse;
|
||||
@ -412,23 +411,23 @@ export class GetCommand extends DownloadCommand {
|
||||
return Response.success(res);
|
||||
}
|
||||
|
||||
private async getOrganizationCollection(id: string, options: program.OptionValues) {
|
||||
if (options.organizationid == null || options.organizationid === "") {
|
||||
return Response.badRequest("--organizationid <organizationid> required.");
|
||||
private async getOrganizationCollection(id: string, options: Options) {
|
||||
if (options.organizationId == null || options.organizationId === "") {
|
||||
return Response.badRequest("`organizationid` option is required.");
|
||||
}
|
||||
if (!Utils.isGuid(id)) {
|
||||
return Response.error("`" + id + "` is not a GUID.");
|
||||
return Response.badRequest("`" + id + "` is not a GUID.");
|
||||
}
|
||||
if (!Utils.isGuid(options.organizationid)) {
|
||||
return Response.error("`" + options.organizationid + "` is not a GUID.");
|
||||
if (!Utils.isGuid(options.organizationId)) {
|
||||
return Response.badRequest("`" + options.organizationId + "` is not a GUID.");
|
||||
}
|
||||
try {
|
||||
const orgKey = await this.cryptoService.getOrgKey(options.organizationid);
|
||||
const orgKey = await this.cryptoService.getOrgKey(options.organizationId);
|
||||
if (orgKey == null) {
|
||||
throw new Error("No encryption key for this organization.");
|
||||
}
|
||||
|
||||
const response = await this.apiService.getCollectionDetails(options.organizationid, id);
|
||||
const response = await this.apiService.getCollectionDetails(options.organizationId, id);
|
||||
const decCollection = new CollectionView(response);
|
||||
decCollection.name = await this.cryptoService.decryptToUtf8(
|
||||
new EncString(response.name),
|
||||
@ -536,3 +535,15 @@ export class GetCommand extends DownloadCommand {
|
||||
return Response.success(res);
|
||||
}
|
||||
}
|
||||
|
||||
class Options {
|
||||
itemId: string;
|
||||
organizationId: string;
|
||||
output: string;
|
||||
|
||||
constructor(passedOptions: Record<string, any>) {
|
||||
this.organizationId = passedOptions.organizationid || passedOptions.organizationId;
|
||||
this.itemId = passedOptions.itemid || passedOptions.itemId;
|
||||
this.output = passedOptions.output;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,3 @@
|
||||
import * as program from "commander";
|
||||
|
||||
import { CipherView } from "jslib-common/models/view/cipherView";
|
||||
|
||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||
@ -42,26 +40,27 @@ export class ListCommand {
|
||||
private apiService: ApiService
|
||||
) {}
|
||||
|
||||
async run(object: string, cmd: program.Command): Promise<Response> {
|
||||
async run(object: string, cmdOptions: Record<string, any>): Promise<Response> {
|
||||
const normalizedOptions = new Options(cmdOptions);
|
||||
switch (object.toLowerCase()) {
|
||||
case "items":
|
||||
return await this.listCiphers(cmd);
|
||||
return await this.listCiphers(normalizedOptions);
|
||||
case "folders":
|
||||
return await this.listFolders(cmd);
|
||||
return await this.listFolders(normalizedOptions);
|
||||
case "collections":
|
||||
return await this.listCollections(cmd);
|
||||
return await this.listCollections(normalizedOptions);
|
||||
case "org-collections":
|
||||
return await this.listOrganizationCollections(cmd);
|
||||
return await this.listOrganizationCollections(normalizedOptions);
|
||||
case "org-members":
|
||||
return await this.listOrganizationMembers(cmd);
|
||||
return await this.listOrganizationMembers(normalizedOptions);
|
||||
case "organizations":
|
||||
return await this.listOrganizations(cmd);
|
||||
return await this.listOrganizations(normalizedOptions);
|
||||
default:
|
||||
return Response.badRequest("Unknown object.");
|
||||
}
|
||||
}
|
||||
|
||||
private async listCiphers(options: program.OptionValues) {
|
||||
private async listCiphers(options: Options) {
|
||||
let ciphers: CipherView[];
|
||||
options.trash = options.trash || false;
|
||||
if (options.url != null && options.url.trim() !== "") {
|
||||
@ -71,43 +70,43 @@ export class ListCommand {
|
||||
}
|
||||
|
||||
if (
|
||||
options.folderid != null ||
|
||||
options.collectionid != null ||
|
||||
options.organizationid != null
|
||||
options.folderId != null ||
|
||||
options.collectionId != null ||
|
||||
options.organizationId != null
|
||||
) {
|
||||
ciphers = ciphers.filter((c) => {
|
||||
if (options.trash !== c.isDeleted) {
|
||||
return false;
|
||||
}
|
||||
if (options.folderid != null) {
|
||||
if (options.folderid === "notnull" && c.folderId != null) {
|
||||
if (options.folderId != null) {
|
||||
if (options.folderId === "notnull" && c.folderId != null) {
|
||||
return true;
|
||||
}
|
||||
const folderId = options.folderid === "null" ? null : options.folderid;
|
||||
const folderId = options.folderId === "null" ? null : options.folderId;
|
||||
if (folderId === c.folderId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.organizationid != null) {
|
||||
if (options.organizationid === "notnull" && c.organizationId != null) {
|
||||
if (options.organizationId != null) {
|
||||
if (options.organizationId === "notnull" && c.organizationId != null) {
|
||||
return true;
|
||||
}
|
||||
const organizationId = options.organizationid === "null" ? null : options.organizationid;
|
||||
const organizationId = options.organizationId === "null" ? null : options.organizationId;
|
||||
if (organizationId === c.organizationId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.collectionid != null) {
|
||||
if (options.collectionId != null) {
|
||||
if (
|
||||
options.collectionid === "notnull" &&
|
||||
options.collectionId === "notnull" &&
|
||||
c.collectionIds != null &&
|
||||
c.collectionIds.length > 0
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
const collectionId = options.collectionid === "null" ? null : options.collectionid;
|
||||
const collectionId = options.collectionId === "null" ? null : options.collectionId;
|
||||
if (collectionId == null && (c.collectionIds == null || c.collectionIds.length === 0)) {
|
||||
return true;
|
||||
}
|
||||
@ -133,7 +132,7 @@ export class ListCommand {
|
||||
return Response.success(res);
|
||||
}
|
||||
|
||||
private async listFolders(options: program.OptionValues) {
|
||||
private async listFolders(options: Options) {
|
||||
let folders = await this.folderService.getAllDecrypted();
|
||||
|
||||
if (options.search != null && options.search.trim() !== "") {
|
||||
@ -144,12 +143,12 @@ export class ListCommand {
|
||||
return Response.success(res);
|
||||
}
|
||||
|
||||
private async listCollections(options: program.OptionValues) {
|
||||
private async listCollections(options: Options) {
|
||||
let collections = await this.collectionService.getAllDecrypted();
|
||||
|
||||
if (options.organizationid != null) {
|
||||
if (options.organizationId != null) {
|
||||
collections = collections.filter((c) => {
|
||||
if (options.organizationid === c.organizationId) {
|
||||
if (options.organizationId === c.organizationId) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -164,14 +163,14 @@ export class ListCommand {
|
||||
return Response.success(res);
|
||||
}
|
||||
|
||||
private async listOrganizationCollections(options: program.OptionValues) {
|
||||
if (options.organizationid == null || options.organizationid === "") {
|
||||
return Response.badRequest("--organizationid <organizationid> required.");
|
||||
private async listOrganizationCollections(options: Options) {
|
||||
if (options.organizationId == null || options.organizationId === "") {
|
||||
return Response.badRequest("`organizationid` option is required.");
|
||||
}
|
||||
if (!Utils.isGuid(options.organizationid)) {
|
||||
return Response.error("`" + options.organizationid + "` is not a GUID.");
|
||||
if (!Utils.isGuid(options.organizationId)) {
|
||||
return Response.badRequest("`" + options.organizationId + "` is not a GUID.");
|
||||
}
|
||||
const organization = await this.organizationService.get(options.organizationid);
|
||||
const organization = await this.organizationService.get(options.organizationId);
|
||||
if (organization == null) {
|
||||
return Response.error("Organization not found.");
|
||||
}
|
||||
@ -179,12 +178,12 @@ export class ListCommand {
|
||||
try {
|
||||
let response: ApiListResponse<ApiCollectionResponse>;
|
||||
if (organization.canViewAllCollections) {
|
||||
response = await this.apiService.getCollections(options.organizationid);
|
||||
response = await this.apiService.getCollections(options.organizationId);
|
||||
} else {
|
||||
response = await this.apiService.getUserCollections();
|
||||
}
|
||||
const collections = response.data
|
||||
.filter((c) => c.organizationId === options.organizationid)
|
||||
.filter((c) => c.organizationId === options.organizationId)
|
||||
.map((r) => new Collection(new CollectionData(r as ApiCollectionDetailsResponse)));
|
||||
let decCollections = await this.collectionService.decryptMany(collections);
|
||||
if (options.search != null && options.search.trim() !== "") {
|
||||
@ -197,20 +196,20 @@ export class ListCommand {
|
||||
}
|
||||
}
|
||||
|
||||
private async listOrganizationMembers(options: program.OptionValues) {
|
||||
if (options.organizationid == null || options.organizationid === "") {
|
||||
return Response.badRequest("--organizationid <organizationid> required.");
|
||||
private async listOrganizationMembers(options: Options) {
|
||||
if (options.organizationId == null || options.organizationId === "") {
|
||||
return Response.badRequest("`organizationid` option is required.");
|
||||
}
|
||||
if (!Utils.isGuid(options.organizationid)) {
|
||||
return Response.error("`" + options.organizationid + "` is not a GUID.");
|
||||
if (!Utils.isGuid(options.organizationId)) {
|
||||
return Response.badRequest("`" + options.organizationId + "` is not a GUID.");
|
||||
}
|
||||
const organization = await this.organizationService.get(options.organizationid);
|
||||
const organization = await this.organizationService.get(options.organizationId);
|
||||
if (organization == null) {
|
||||
return Response.error("Organization not found.");
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await this.apiService.getOrganizationUsers(options.organizationid);
|
||||
const response = await this.apiService.getOrganizationUsers(options.organizationId);
|
||||
const res = new ListResponse(
|
||||
response.data.map((r) => {
|
||||
const u = new OrganizationUserResponse();
|
||||
@ -229,7 +228,7 @@ export class ListCommand {
|
||||
}
|
||||
}
|
||||
|
||||
private async listOrganizations(options: program.OptionValues) {
|
||||
private async listOrganizations(options: Options) {
|
||||
let organizations = await this.organizationService.getAll();
|
||||
|
||||
if (options.search != null && options.search.trim() !== "") {
|
||||
@ -240,3 +239,21 @@ export class ListCommand {
|
||||
return Response.success(res);
|
||||
}
|
||||
}
|
||||
|
||||
class Options {
|
||||
organizationId: string;
|
||||
collectionId: string;
|
||||
folderId: string;
|
||||
search: string;
|
||||
url: string;
|
||||
trash: boolean;
|
||||
|
||||
constructor(passedOptions: Record<string, any>) {
|
||||
this.organizationId = passedOptions.organizationid || passedOptions.organizationId;
|
||||
this.collectionId = passedOptions.collectionid || passedOptions.collectionId;
|
||||
this.folderId = passedOptions.folderid || passedOptions.folderId;
|
||||
this.search = passedOptions.search;
|
||||
this.url = passedOptions.url;
|
||||
this.trash = CliUtils.convertBooleanOption(passedOptions.trash);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,3 @@
|
||||
import * as program from "commander";
|
||||
|
||||
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
|
||||
|
||||
import { Response } from "jslib-node/cli/models/response";
|
||||
@ -8,7 +6,7 @@ import { MessageResponse } from "jslib-node/cli/models/response/messageResponse"
|
||||
export class LockCommand {
|
||||
constructor(private vaultTimeoutService: VaultTimeoutService) {}
|
||||
|
||||
async run(cmd: program.Command) {
|
||||
async run() {
|
||||
await this.vaultTimeoutService.lock();
|
||||
process.env.BW_SESSION = null;
|
||||
const res = new MessageResponse("Your vault is locked.", null);
|
||||
|
@ -1,5 +1,3 @@
|
||||
import * as program from "commander";
|
||||
|
||||
import { CipherService } from "jslib-common/abstractions/cipher.service";
|
||||
|
||||
import { Response } from "jslib-node/cli/models/response";
|
||||
@ -7,20 +5,20 @@ import { Response } from "jslib-node/cli/models/response";
|
||||
export class RestoreCommand {
|
||||
constructor(private cipherService: CipherService) {}
|
||||
|
||||
async run(object: string, id: string, cmd: program.Command): Promise<Response> {
|
||||
async run(object: string, id: string): Promise<Response> {
|
||||
if (id != null) {
|
||||
id = id.toLowerCase();
|
||||
}
|
||||
|
||||
switch (object.toLowerCase()) {
|
||||
case "item":
|
||||
return await this.restoreCipher(id, cmd);
|
||||
return await this.restoreCipher(id);
|
||||
default:
|
||||
return Response.badRequest("Unknown object.");
|
||||
}
|
||||
}
|
||||
|
||||
private async restoreCipher(id: string, cmd: program.Command) {
|
||||
private async restoreCipher(id: string) {
|
||||
const cipher = await this.cipherService.get(id);
|
||||
if (cipher == null) {
|
||||
return Response.notFound();
|
||||
|
@ -1,4 +1,3 @@
|
||||
import * as program from "commander";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
@ -11,7 +10,6 @@ import { SendType } from "jslib-common/enums/sendType";
|
||||
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 { SendResponse } from "../../models/response/sendResponse";
|
||||
import { SendTextResponse } from "../../models/response/sendTextResponse";
|
||||
@ -25,9 +23,9 @@ export class SendCreateCommand {
|
||||
private environmentService: EnvironmentService
|
||||
) {}
|
||||
|
||||
async run(requestJson: string, options: program.OptionValues) {
|
||||
async run(requestJson: any, cmdOptions: Record<string, any>) {
|
||||
let req: any = null;
|
||||
if (requestJson == null || requestJson === "") {
|
||||
if (process.env.BW_SERVE !== "true" && (requestJson == null || requestJson === "")) {
|
||||
requestJson = await CliUtils.readStdin();
|
||||
}
|
||||
|
||||
@ -35,15 +33,19 @@ export class SendCreateCommand {
|
||||
return Response.badRequest("`requestJson` was not provided.");
|
||||
}
|
||||
|
||||
try {
|
||||
const reqJson = Buffer.from(requestJson, "base64").toString();
|
||||
req = SendResponse.fromJson(reqJson);
|
||||
if (typeof requestJson !== "string") {
|
||||
req = requestJson;
|
||||
} else {
|
||||
try {
|
||||
const reqJson = Buffer.from(requestJson, "base64").toString();
|
||||
req = SendResponse.fromJson(reqJson);
|
||||
|
||||
if (req == null) {
|
||||
throw new Error("Null request");
|
||||
if (req == null) {
|
||||
throw new Error("Null request");
|
||||
}
|
||||
} catch (e) {
|
||||
return Response.badRequest("Error parsing the encoded request data.");
|
||||
}
|
||||
} catch (e) {
|
||||
return Response.badRequest("Error parsing the encoded request data.");
|
||||
}
|
||||
|
||||
if (
|
||||
@ -58,10 +60,11 @@ export class SendCreateCommand {
|
||||
return Response.badRequest("Unable to parse expirationDate: " + req.expirationDate);
|
||||
}
|
||||
|
||||
return this.createSend(req, options);
|
||||
const normalizedOptions = new Options(cmdOptions);
|
||||
return this.createSend(req, normalizedOptions);
|
||||
}
|
||||
|
||||
private async createSend(req: SendResponse, options: program.OptionValues) {
|
||||
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;
|
||||
@ -73,13 +76,19 @@ export class SendCreateCommand {
|
||||
|
||||
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 encoded json"
|
||||
"Must specify a file to Send either with the --file option or in the request JSON."
|
||||
);
|
||||
}
|
||||
|
||||
@ -88,7 +97,7 @@ export class SendCreateCommand {
|
||||
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"
|
||||
"Must specify text content to Send either with the --text option or in the request JSON."
|
||||
);
|
||||
}
|
||||
req.text = new SendTextResponse();
|
||||
@ -97,7 +106,7 @@ export class SendCreateCommand {
|
||||
break;
|
||||
default:
|
||||
return Response.badRequest(
|
||||
"Unknown Send type " + SendType[req.type] + "valid types are: file, text"
|
||||
"Unknown Send type " + SendType[req.type] + ". Valid types are: file, text"
|
||||
);
|
||||
}
|
||||
|
||||
@ -117,13 +126,26 @@ export class SendCreateCommand {
|
||||
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)
|
||||
);
|
||||
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,5 +1,3 @@
|
||||
import * as program from "commander";
|
||||
|
||||
import { SendService } from "jslib-common/abstractions/send.service";
|
||||
import { StateService } from "jslib-common/abstractions/state.service";
|
||||
|
||||
@ -18,24 +16,29 @@ export class SendEditCommand {
|
||||
private getCommand: SendGetCommand
|
||||
) {}
|
||||
|
||||
async run(encodedJson: string, options: program.OptionValues): Promise<Response> {
|
||||
if (encodedJson == null || encodedJson === "") {
|
||||
encodedJson = await CliUtils.readStdin();
|
||||
async run(requestJson: string, cmdOptions: Record<string, any>): Promise<Response> {
|
||||
if (process.env.BW_SERVE !== "true" && (requestJson == null || requestJson === "")) {
|
||||
requestJson = await CliUtils.readStdin();
|
||||
}
|
||||
|
||||
if (encodedJson == null || encodedJson === "") {
|
||||
return Response.badRequest("`encodedJson` was not provided.");
|
||||
if (requestJson == null || requestJson === "") {
|
||||
return Response.badRequest("`requestJson` 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.");
|
||||
if (typeof requestJson !== "string") {
|
||||
req = requestJson;
|
||||
} else {
|
||||
try {
|
||||
const reqJson = Buffer.from(requestJson, "base64").toString();
|
||||
req = SendResponse.fromJson(reqJson);
|
||||
} catch (e) {
|
||||
return Response.badRequest("Error parsing the encoded request data.");
|
||||
}
|
||||
}
|
||||
|
||||
req.id = options.itemid || req.id;
|
||||
const normalizedOptions = new Options(cmdOptions);
|
||||
req.id = normalizedOptions.itemId || req.id;
|
||||
|
||||
if (req.id != null) {
|
||||
req.id = req.id.toLowerCase();
|
||||
@ -76,3 +79,11 @@ export class SendEditCommand {
|
||||
return await this.getCommand.run(send.id, {});
|
||||
}
|
||||
}
|
||||
|
||||
class Options {
|
||||
itemId: string;
|
||||
|
||||
constructor(passedOptions: Record<string, any>) {
|
||||
this.itemId = passedOptions.itemId || passedOptions.itemid;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
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";
|
||||
@ -27,6 +26,11 @@ export class SendGetCommand extends DownloadCommand {
|
||||
}
|
||||
|
||||
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();
|
||||
@ -36,7 +40,7 @@ export class SendGetCommand extends DownloadCommand {
|
||||
let filter = (s: SendView) => true;
|
||||
let selector = async (s: SendView): Promise<Response> =>
|
||||
Response.success(new SendResponse(s, webVaultUrl));
|
||||
if (options.text != null) {
|
||||
if (!serveCommand && options?.text != null) {
|
||||
filter = (s) => {
|
||||
return filter(s) && s.text != null;
|
||||
};
|
||||
|
@ -1,5 +1,3 @@
|
||||
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";
|
||||
@ -16,11 +14,12 @@ export class SendListCommand {
|
||||
private searchService: SearchService
|
||||
) {}
|
||||
|
||||
async run(options: program.OptionValues): Promise<Response> {
|
||||
async run(cmdOptions: Record<string, any>): Promise<Response> {
|
||||
let sends = await this.sendService.getAllDecrypted();
|
||||
|
||||
if (options.search != null && options.search.trim() !== "") {
|
||||
sends = this.searchService.searchSends(sends, options.search);
|
||||
const normalizedOptions = new Options(cmdOptions);
|
||||
if (normalizedOptions.search != null && normalizedOptions.search.trim() !== "") {
|
||||
sends = this.searchService.searchSends(sends, normalizedOptions.search);
|
||||
}
|
||||
|
||||
const webVaultUrl = this.environmentService.getWebVaultUrl();
|
||||
@ -28,3 +27,11 @@ export class SendListCommand {
|
||||
return Response.success(res);
|
||||
}
|
||||
}
|
||||
|
||||
class Options {
|
||||
search: string;
|
||||
|
||||
constructor(passedOptions: Record<string, any>) {
|
||||
this.search = passedOptions.search;
|
||||
}
|
||||
}
|
||||
|
294
src/commands/serve.command.ts
Normal file
294
src/commands/serve.command.ts
Normal file
@ -0,0 +1,294 @@
|
||||
import * as program from "commander";
|
||||
import * as express from "express";
|
||||
import * as multer from "multer";
|
||||
|
||||
import { Main } from "../bw";
|
||||
|
||||
import { ConfirmCommand } from "./confirm.command";
|
||||
import { CreateCommand } from "./create.command";
|
||||
import { DeleteCommand } from "./delete.command";
|
||||
import { EditCommand } from "./edit.command";
|
||||
import { GenerateCommand } from "./generate.command";
|
||||
import { GetCommand } from "./get.command";
|
||||
import { ListCommand } from "./list.command";
|
||||
import { LockCommand } from "./lock.command";
|
||||
import { RestoreCommand } from "./restore.command";
|
||||
import { ShareCommand } from "./share.command";
|
||||
import { StatusCommand } from "./status.command";
|
||||
import { SyncCommand } from "./sync.command";
|
||||
import { UnlockCommand } from "./unlock.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/removePassword.command";
|
||||
|
||||
import { Response } from "jslib-node/cli/models/response";
|
||||
import { FileResponse } from "jslib-node/cli/models/response/fileResponse";
|
||||
|
||||
export class ServeCommand {
|
||||
private listCommand: ListCommand;
|
||||
private getCommand: GetCommand;
|
||||
private createCommand: CreateCommand;
|
||||
private editCommand: EditCommand;
|
||||
private generateCommand: GenerateCommand;
|
||||
private shareCommand: ShareCommand;
|
||||
private statusCommand: StatusCommand;
|
||||
private syncCommand: SyncCommand;
|
||||
private deleteCommand: DeleteCommand;
|
||||
private confirmCommand: ConfirmCommand;
|
||||
private restoreCommand: RestoreCommand;
|
||||
private lockCommand: LockCommand;
|
||||
private unlockCommand: UnlockCommand;
|
||||
|
||||
private sendCreateCommand: SendCreateCommand;
|
||||
private sendDeleteCommand: SendDeleteCommand;
|
||||
private sendEditCommand: SendEditCommand;
|
||||
private sendGetCommand: SendGetCommand;
|
||||
private sendListCommand: SendListCommand;
|
||||
private sendRemovePasswordCommand: SendRemovePasswordCommand;
|
||||
|
||||
constructor(protected main: Main) {
|
||||
this.getCommand = new GetCommand(
|
||||
this.main.cipherService,
|
||||
this.main.folderService,
|
||||
this.main.collectionService,
|
||||
this.main.totpService,
|
||||
this.main.auditService,
|
||||
this.main.cryptoService,
|
||||
this.main.stateService,
|
||||
this.main.searchService,
|
||||
this.main.apiService,
|
||||
this.main.organizationService
|
||||
);
|
||||
this.listCommand = new ListCommand(
|
||||
this.main.cipherService,
|
||||
this.main.folderService,
|
||||
this.main.collectionService,
|
||||
this.main.organizationService,
|
||||
this.main.searchService,
|
||||
this.main.apiService
|
||||
);
|
||||
this.createCommand = new CreateCommand(
|
||||
this.main.cipherService,
|
||||
this.main.folderService,
|
||||
this.main.stateService,
|
||||
this.main.cryptoService,
|
||||
this.main.apiService
|
||||
);
|
||||
this.editCommand = new EditCommand(
|
||||
this.main.cipherService,
|
||||
this.main.folderService,
|
||||
this.main.cryptoService,
|
||||
this.main.apiService
|
||||
);
|
||||
this.generateCommand = new GenerateCommand(this.main.passwordGenerationService);
|
||||
this.syncCommand = new SyncCommand(this.main.syncService);
|
||||
this.statusCommand = new StatusCommand(
|
||||
this.main.environmentService,
|
||||
this.main.syncService,
|
||||
this.main.stateService,
|
||||
this.main.vaultTimeoutService
|
||||
);
|
||||
this.deleteCommand = new DeleteCommand(
|
||||
this.main.cipherService,
|
||||
this.main.folderService,
|
||||
this.main.stateService,
|
||||
this.main.apiService
|
||||
);
|
||||
this.confirmCommand = new ConfirmCommand(this.main.apiService, this.main.cryptoService);
|
||||
this.restoreCommand = new RestoreCommand(this.main.cipherService);
|
||||
this.shareCommand = new ShareCommand(this.main.cipherService);
|
||||
this.lockCommand = new LockCommand(this.main.vaultTimeoutService);
|
||||
this.unlockCommand = new UnlockCommand(
|
||||
this.main.cryptoService,
|
||||
this.main.stateService,
|
||||
this.main.cryptoFunctionService,
|
||||
this.main.apiService,
|
||||
this.main.logService
|
||||
);
|
||||
|
||||
this.sendCreateCommand = new SendCreateCommand(
|
||||
this.main.sendService,
|
||||
this.main.stateService,
|
||||
this.main.environmentService
|
||||
);
|
||||
this.sendDeleteCommand = new SendDeleteCommand(this.main.sendService);
|
||||
this.sendGetCommand = new SendGetCommand(
|
||||
this.main.sendService,
|
||||
this.main.environmentService,
|
||||
this.main.searchService,
|
||||
this.main.cryptoService
|
||||
);
|
||||
this.sendEditCommand = new SendEditCommand(
|
||||
this.main.sendService,
|
||||
this.main.stateService,
|
||||
this.sendGetCommand
|
||||
);
|
||||
this.sendListCommand = new SendListCommand(
|
||||
this.main.sendService,
|
||||
this.main.environmentService,
|
||||
this.main.searchService
|
||||
);
|
||||
this.sendRemovePasswordCommand = new SendRemovePasswordCommand(this.main.sendService);
|
||||
}
|
||||
|
||||
async run(options: program.OptionValues) {
|
||||
const port = options.port || 8087;
|
||||
const server = express();
|
||||
process.env.BW_SERVE = "true";
|
||||
process.env.BW_NOINTERACTION = "true";
|
||||
|
||||
server.use(express.json());
|
||||
server.use((req, res, next) => {
|
||||
const sessionHeader = req.get("Session");
|
||||
if (sessionHeader != null && sessionHeader !== "") {
|
||||
process.env.BW_SESSION = sessionHeader;
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
server.get("/generate", async (req, res) => {
|
||||
const response = await this.generateCommand.run(req.query);
|
||||
this.processResponse(res, response);
|
||||
});
|
||||
|
||||
server.get("/status", async (req, res) => {
|
||||
const response = await this.statusCommand.run();
|
||||
this.processResponse(res, response);
|
||||
});
|
||||
|
||||
server.get("/list/:object", async (req, res) => {
|
||||
let response: Response = null;
|
||||
if (req.params.object === "send") {
|
||||
response = await this.sendListCommand.run(req.query);
|
||||
} else {
|
||||
response = await this.listCommand.run(req.params.object, req.query);
|
||||
}
|
||||
this.processResponse(res, response);
|
||||
});
|
||||
|
||||
server.get("/send/list", async (req, res) => {
|
||||
const response = await this.sendListCommand.run(req.query);
|
||||
this.processResponse(res, response);
|
||||
});
|
||||
|
||||
server.post("/sync", async (req, res) => {
|
||||
const response = await this.syncCommand.run(req.query);
|
||||
this.processResponse(res, response);
|
||||
});
|
||||
|
||||
server.post("/lock", async (req, res) => {
|
||||
const response = await this.lockCommand.run();
|
||||
this.processResponse(res, response);
|
||||
});
|
||||
|
||||
server.post("/unlock", async (req, res) => {
|
||||
const response = await this.unlockCommand.run(
|
||||
req.body == null ? null : (req.body.password as string),
|
||||
req.query
|
||||
);
|
||||
this.processResponse(res, response);
|
||||
});
|
||||
|
||||
server.post("/confirm/:object/:id", async (req, res) => {
|
||||
const response = await this.confirmCommand.run(req.params.object, req.params.id, req.query);
|
||||
this.processResponse(res, response);
|
||||
});
|
||||
|
||||
server.post("/restore/:object/:id", async (req, res) => {
|
||||
const response = await this.restoreCommand.run(req.params.object, req.params.id);
|
||||
this.processResponse(res, response);
|
||||
});
|
||||
|
||||
server.post("/move/:id/:organizationId", async (req, res) => {
|
||||
const response = await this.shareCommand.run(
|
||||
req.params.id,
|
||||
req.params.organizationId,
|
||||
req.body
|
||||
);
|
||||
this.processResponse(res, response);
|
||||
});
|
||||
|
||||
server.post("/attachment", multer().single("file"), async (req, res) => {
|
||||
const response = await this.createCommand.run("attachment", req.body, req.query, {
|
||||
fileBuffer: req.file.buffer,
|
||||
fileName: req.file.originalname,
|
||||
});
|
||||
this.processResponse(res, response);
|
||||
});
|
||||
|
||||
server.post("/send/:id/remove-password", async (req, res) => {
|
||||
const response = await this.sendRemovePasswordCommand.run(req.params.id);
|
||||
this.processResponse(res, response);
|
||||
});
|
||||
|
||||
server.post("/:object", async (req, res) => {
|
||||
let response: Response = null;
|
||||
if (req.params.object === "send") {
|
||||
response = await this.sendCreateCommand.run(req.body, req.query);
|
||||
} else {
|
||||
response = await this.createCommand.run(req.params.object, req.body, req.query);
|
||||
}
|
||||
this.processResponse(res, response);
|
||||
});
|
||||
|
||||
server.put("/:object/:id", async (req, res) => {
|
||||
let response: Response = null;
|
||||
if (req.params.object === "send") {
|
||||
req.body.id = req.params.id;
|
||||
response = await this.sendEditCommand.run(req.body, req.query);
|
||||
} else {
|
||||
response = await this.editCommand.run(
|
||||
req.params.object,
|
||||
req.params.id,
|
||||
req.body,
|
||||
req.query
|
||||
);
|
||||
}
|
||||
this.processResponse(res, response);
|
||||
});
|
||||
|
||||
server.get("/:object/:id", async (req, res) => {
|
||||
let response: Response = null;
|
||||
if (req.params.object === "send") {
|
||||
response = await this.sendGetCommand.run(req.params.id, null);
|
||||
} else {
|
||||
response = await this.getCommand.run(req.params.object, req.params.id, req.query);
|
||||
}
|
||||
this.processResponse(res, response);
|
||||
});
|
||||
|
||||
server.delete("/:object/:id", async (req, res) => {
|
||||
let response: Response = null;
|
||||
if (req.params.object === "send") {
|
||||
response = await this.sendDeleteCommand.run(req.params.id);
|
||||
} else {
|
||||
response = await this.deleteCommand.run(req.params.object, req.params.id, req.query);
|
||||
}
|
||||
this.processResponse(res, response);
|
||||
});
|
||||
|
||||
server.listen(port, () => {
|
||||
this.main.logService.info("Listening on port " + port);
|
||||
});
|
||||
}
|
||||
|
||||
private processResponse(res: any, commandResponse: Response) {
|
||||
if (!commandResponse.success) {
|
||||
res.statusCode = 400;
|
||||
}
|
||||
if (commandResponse.data instanceof FileResponse) {
|
||||
res.writeHead(200, {
|
||||
"Content-Type": "application/octet-stream",
|
||||
"Content-Disposition": "attachment;filename=" + commandResponse.data.fileName,
|
||||
"Content-Length": commandResponse.data.data.length,
|
||||
});
|
||||
res.end(commandResponse.data.data);
|
||||
} else {
|
||||
res.json(commandResponse);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,3 @@
|
||||
import * as program from "commander";
|
||||
|
||||
import { CipherService } from "jslib-common/abstractions/cipher.service";
|
||||
|
||||
import { Response } from "jslib-node/cli/models/response";
|
||||
@ -11,13 +9,8 @@ import { CliUtils } from "../utils";
|
||||
export class ShareCommand {
|
||||
constructor(private cipherService: CipherService) {}
|
||||
|
||||
async run(
|
||||
id: string,
|
||||
organizationId: string,
|
||||
requestJson: string,
|
||||
cmd: program.Command
|
||||
): Promise<Response> {
|
||||
if (requestJson == null || requestJson === "") {
|
||||
async run(id: string, organizationId: string, requestJson: string): Promise<Response> {
|
||||
if (process.env.BW_SERVE !== "true" && (requestJson == null || requestJson === "")) {
|
||||
requestJson = await CliUtils.readStdin();
|
||||
}
|
||||
|
||||
@ -26,14 +19,18 @@ export class ShareCommand {
|
||||
}
|
||||
|
||||
let req: string[] = [];
|
||||
try {
|
||||
const reqJson = Buffer.from(requestJson, "base64").toString();
|
||||
req = JSON.parse(reqJson);
|
||||
if (req == null || req.length === 0) {
|
||||
return Response.badRequest("You must provide at least one collection id for this item.");
|
||||
if (typeof requestJson !== "string") {
|
||||
req = requestJson;
|
||||
} else {
|
||||
try {
|
||||
const reqJson = Buffer.from(requestJson, "base64").toString();
|
||||
req = JSON.parse(reqJson);
|
||||
if (req == null || req.length === 0) {
|
||||
return Response.badRequest("You must provide at least one collection id for this item.");
|
||||
}
|
||||
} catch (e) {
|
||||
return Response.badRequest("Error parsing the encoded request data.");
|
||||
}
|
||||
} catch (e) {
|
||||
return Response.badRequest("Error parsing the encoded request data.");
|
||||
}
|
||||
|
||||
if (id != null) {
|
||||
|
@ -1,5 +1,3 @@
|
||||
import * as program from "commander";
|
||||
|
||||
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
||||
import { StateService } from "jslib-common/abstractions/state.service";
|
||||
import { SyncService } from "jslib-common/abstractions/sync.service";
|
||||
|
@ -1,21 +1,22 @@
|
||||
import * as program from "commander";
|
||||
|
||||
import { SyncService } from "jslib-common/abstractions/sync.service";
|
||||
|
||||
import { Response } from "jslib-node/cli/models/response";
|
||||
import { MessageResponse } from "jslib-node/cli/models/response/messageResponse";
|
||||
import { StringResponse } from "jslib-node/cli/models/response/stringResponse";
|
||||
|
||||
import { CliUtils } from "src/utils";
|
||||
|
||||
export class SyncCommand {
|
||||
constructor(private syncService: SyncService) {}
|
||||
|
||||
async run(options: program.OptionValues): Promise<Response> {
|
||||
if (options.last || false) {
|
||||
async run(cmdOptions: Record<string, any>): Promise<Response> {
|
||||
const normalizedOptions = new Options(cmdOptions);
|
||||
if (normalizedOptions.last) {
|
||||
return await this.getLastSync();
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await this.syncService.fullSync(options.force || false, true);
|
||||
const result = await this.syncService.fullSync(normalizedOptions.force, true);
|
||||
const res = new MessageResponse("Syncing complete.", null);
|
||||
return Response.success(res);
|
||||
} catch (e) {
|
||||
@ -29,3 +30,13 @@ export class SyncCommand {
|
||||
return Response.success(res);
|
||||
}
|
||||
}
|
||||
|
||||
class Options {
|
||||
last: boolean;
|
||||
force: boolean;
|
||||
|
||||
constructor(passedOptions: Record<string, any>) {
|
||||
this.last = CliUtils.convertBooleanOption(passedOptions.last);
|
||||
this.force = CliUtils.convertBooleanOption(passedOptions.force);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import * as program from "commander";
|
||||
import * as inquirer from "inquirer";
|
||||
|
||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||
@ -26,17 +25,18 @@ export class UnlockCommand {
|
||||
private logService: ConsoleLogService
|
||||
) {}
|
||||
|
||||
async run(password: string, options: program.OptionValues) {
|
||||
async run(password: string, cmdOptions: Record<string, any>) {
|
||||
const canInteract = process.env.BW_NOINTERACTION !== "true";
|
||||
const normalizedOptions = new Options(cmdOptions);
|
||||
if (password == null || password === "") {
|
||||
if (options?.passwordfile) {
|
||||
password = await NodeUtils.readFirstLine(options.passwordfile);
|
||||
} else if (options?.passwordenv) {
|
||||
if (process.env[options.passwordenv]) {
|
||||
password = process.env[options.passwordenv];
|
||||
if (normalizedOptions?.passwordFile) {
|
||||
password = await NodeUtils.readFirstLine(normalizedOptions.passwordFile);
|
||||
} else if (normalizedOptions?.passwordEnv) {
|
||||
if (process.env[normalizedOptions.passwordEnv]) {
|
||||
password = process.env[normalizedOptions.passwordEnv];
|
||||
} else {
|
||||
this.logService.warning(
|
||||
`Warning: Provided passwordenv ${options.passwordenv} is not set`
|
||||
`Warning: Provided passwordenv ${normalizedOptions.passwordEnv} is not set`
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -118,3 +118,13 @@ export class UnlockCommand {
|
||||
process.env.BW_SESSION = Utils.fromBufferToB64(key);
|
||||
}
|
||||
}
|
||||
|
||||
class Options {
|
||||
passwordEnv: string;
|
||||
passwordFile: string;
|
||||
|
||||
constructor(passedOptions: Record<string, any>) {
|
||||
this.passwordEnv = passedOptions.passwordenv || passedOptions.passwordEnv;
|
||||
this.passwordFile = passedOptions.passwordfile || passedOptions.passwordFile;
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import { EncodeCommand } from "./commands/encode.command";
|
||||
import { GenerateCommand } from "./commands/generate.command";
|
||||
import { LockCommand } from "./commands/lock.command";
|
||||
import { LoginCommand } from "./commands/login.command";
|
||||
import { ServeCommand } from "./commands/serve.command";
|
||||
import { StatusCommand } from "./commands/status.command";
|
||||
import { SyncCommand } from "./commands/sync.command";
|
||||
import { UnlockCommand } from "./commands/unlock.command";
|
||||
@ -214,7 +215,7 @@ export class Program extends BaseProgram {
|
||||
}
|
||||
|
||||
const command = new LockCommand(this.main.vaultTimeoutService);
|
||||
const response = await command.run(cmd);
|
||||
const response = await command.run();
|
||||
this.processResponse(response);
|
||||
});
|
||||
|
||||
@ -462,6 +463,22 @@ export class Program extends BaseProgram {
|
||||
const response = await command.run();
|
||||
this.processResponse(response);
|
||||
});
|
||||
|
||||
program
|
||||
.command("serve")
|
||||
.description("Start a RESTful API webserver.")
|
||||
.option("--port <port>", "The port to run your API webserver on. Default port is 8087.")
|
||||
.on("--help", () => {
|
||||
writeLn("\n Examples:");
|
||||
writeLn("");
|
||||
writeLn(" bw serve");
|
||||
writeLn(" bw serve --port 8080");
|
||||
writeLn("", true);
|
||||
})
|
||||
.action(async (cmd) => {
|
||||
const command = new ServeCommand(this.main);
|
||||
await command.run(cmd);
|
||||
});
|
||||
}
|
||||
|
||||
protected processResponse(response: Response, exitImmediately = false) {
|
||||
|
@ -170,4 +170,8 @@ export class CliUtils {
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
static convertBooleanOption(optionValue: any) {
|
||||
return optionValue || optionValue === "" ? true : false;
|
||||
}
|
||||
}
|
||||
|
@ -346,7 +346,7 @@ export class VaultProgram extends Program {
|
||||
|
||||
await this.exitIfLocked();
|
||||
const command = new RestoreCommand(this.main.cipherService);
|
||||
const response = await command.run(object, id, cmd);
|
||||
const response = await command.run(object, id);
|
||||
this.processResponse(response);
|
||||
});
|
||||
}
|
||||
@ -383,7 +383,7 @@ export class VaultProgram extends Program {
|
||||
.action(async (id, organizationId, encodedJson, cmd) => {
|
||||
await this.exitIfLocked();
|
||||
const command = new ShareCommand(this.main.cipherService);
|
||||
const response = await command.run(id, organizationId, encodedJson, cmd);
|
||||
const response = await command.run(id, organizationId, encodedJson);
|
||||
this.processResponse(response);
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user