mirror of
https://github.com/bitwarden/cli
synced 2025-12-10 21:33:33 +00:00
serve command (#451)
This commit is contained in:
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/**/*"
|
"assets": "./build/**/*"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/express": "^4.17.13",
|
||||||
"@types/inquirer": "^7.3.1",
|
"@types/inquirer": "^7.3.1",
|
||||||
"@types/jsdom": "^16.2.10",
|
"@types/jsdom": "^16.2.10",
|
||||||
"@types/lowdb": "^1.0.10",
|
"@types/lowdb": "^1.0.10",
|
||||||
"@types/lunr": "^2.3.3",
|
"@types/lunr": "^2.3.3",
|
||||||
|
"@types/multer": "^1.4.7",
|
||||||
"@types/node": "^16.11.12",
|
"@types/node": "^16.11.12",
|
||||||
"@types/node-fetch": "^2.5.10",
|
"@types/node-fetch": "^2.5.10",
|
||||||
"@types/node-forge": "^0.9.7",
|
"@types/node-forge": "^0.9.7",
|
||||||
@@ -83,12 +85,14 @@
|
|||||||
"browser-hrtime": "^1.1.8",
|
"browser-hrtime": "^1.1.8",
|
||||||
"chalk": "^4.1.1",
|
"chalk": "^4.1.1",
|
||||||
"commander": "7.2.0",
|
"commander": "7.2.0",
|
||||||
|
"express": "^4.17.1",
|
||||||
"form-data": "4.0.0",
|
"form-data": "4.0.0",
|
||||||
"https-proxy-agent": "5.0.0",
|
"https-proxy-agent": "5.0.0",
|
||||||
"inquirer": "8.0.0",
|
"inquirer": "8.0.0",
|
||||||
"jsdom": "^16.5.3",
|
"jsdom": "^16.5.3",
|
||||||
"lowdb": "1.0.0",
|
"lowdb": "1.0.0",
|
||||||
"lunr": "^2.3.9",
|
"lunr": "^2.3.9",
|
||||||
|
"multer": "^1.4.3",
|
||||||
"node-fetch": "^2.6.1",
|
"node-fetch": "^2.6.1",
|
||||||
"node-forge": "0.10.0",
|
"node-forge": "0.10.0",
|
||||||
"open": "^8.0.8",
|
"open": "^8.0.8",
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export class CompletionCommand {
|
|||||||
const shell: typeof validShells[number] = options.shell;
|
const shell: typeof validShells[number] = options.shell;
|
||||||
|
|
||||||
if (!shell) {
|
if (!shell) {
|
||||||
return Response.badRequest("`shell` was not provided.");
|
return Response.badRequest("`shell` option was not provided.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!validShells.includes(shell)) {
|
if (!validShells.includes(shell)) {
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import * as program from "commander";
|
|
||||||
|
|
||||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||||
|
|
||||||
@@ -12,35 +10,36 @@ import { Utils } from "jslib-common/misc/utils";
|
|||||||
export class ConfirmCommand {
|
export class ConfirmCommand {
|
||||||
constructor(private apiService: ApiService, private cryptoService: CryptoService) {}
|
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) {
|
if (id != null) {
|
||||||
id = id.toLowerCase();
|
id = id.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const normalizedOptions = new Options(cmdOptions);
|
||||||
switch (object.toLowerCase()) {
|
switch (object.toLowerCase()) {
|
||||||
case "org-member":
|
case "org-member":
|
||||||
return await this.confirmOrganizationMember(id, cmd);
|
return await this.confirmOrganizationMember(id, normalizedOptions);
|
||||||
default:
|
default:
|
||||||
return Response.badRequest("Unknown object.");
|
return Response.badRequest("Unknown object.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async confirmOrganizationMember(id: string, options: program.OptionValues) {
|
private async confirmOrganizationMember(id: string, options: Options) {
|
||||||
if (options.organizationid == null || options.organizationid === "") {
|
if (options.organizationId == null || options.organizationId === "") {
|
||||||
return Response.badRequest("--organizationid <organizationid> required.");
|
return Response.badRequest("--organizationid <organizationid> required.");
|
||||||
}
|
}
|
||||||
if (!Utils.isGuid(id)) {
|
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)) {
|
if (!Utils.isGuid(options.organizationId)) {
|
||||||
return Response.error("`" + options.organizationid + "` is not a GUID.");
|
return Response.badRequest("`" + options.organizationId + "` is not a GUID.");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const orgKey = await this.cryptoService.getOrgKey(options.organizationid);
|
const orgKey = await this.cryptoService.getOrgKey(options.organizationId);
|
||||||
if (orgKey == null) {
|
if (orgKey == null) {
|
||||||
throw new Error("No encryption key for this organization.");
|
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) {
|
if (orgUser == null) {
|
||||||
throw new Error("Member id does not exist for this organization.");
|
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 key = await this.cryptoService.rsaEncrypt(orgKey.key, publicKey.buffer);
|
||||||
const req = new OrganizationUserConfirmRequest();
|
const req = new OrganizationUserConfirmRequest();
|
||||||
req.key = key.encryptedString;
|
req.key = key.encryptedString;
|
||||||
await this.apiService.postOrganizationUserConfirm(options.organizationid, id, req);
|
await this.apiService.postOrganizationUserConfirm(options.organizationId, id, req);
|
||||||
return Response.success();
|
return Response.success();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return Response.error(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 fs from "fs";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
|
|
||||||
@@ -36,10 +35,15 @@ export class CreateCommand {
|
|||||||
private apiService: ApiService
|
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;
|
let req: any = null;
|
||||||
if (object !== "attachment") {
|
if (object !== "attachment") {
|
||||||
if (requestJson == null || requestJson === "") {
|
if (process.env.BW_SERVE !== "true" && (requestJson == null || requestJson === "")) {
|
||||||
requestJson = await CliUtils.readStdin();
|
requestJson = await CliUtils.readStdin();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,23 +51,28 @@ export class CreateCommand {
|
|||||||
return Response.badRequest("`requestJson` was not provided.");
|
return Response.badRequest("`requestJson` was not provided.");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
if (typeof requestJson !== "string") {
|
||||||
const reqJson = Buffer.from(requestJson, "base64").toString();
|
req = requestJson;
|
||||||
req = JSON.parse(reqJson);
|
} else {
|
||||||
} catch (e) {
|
try {
|
||||||
return Response.badRequest("Error parsing the encoded request data.");
|
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()) {
|
switch (object.toLowerCase()) {
|
||||||
case "item":
|
case "item":
|
||||||
return await this.createCipher(req);
|
return await this.createCipher(req);
|
||||||
case "attachment":
|
case "attachment":
|
||||||
return await this.createAttachment(cmd);
|
return await this.createAttachment(normalizedOptions, additionalData);
|
||||||
case "folder":
|
case "folder":
|
||||||
return await this.createFolder(req);
|
return await this.createFolder(req);
|
||||||
case "org-collection":
|
case "org-collection":
|
||||||
return await this.createOrganizationCollection(req, cmd);
|
return await this.createOrganizationCollection(req, normalizedOptions);
|
||||||
default:
|
default:
|
||||||
return Response.badRequest("Unknown object.");
|
return Response.badRequest("Unknown object.");
|
||||||
}
|
}
|
||||||
@@ -82,19 +91,35 @@ export class CreateCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createAttachment(options: program.OptionValues) {
|
private async createAttachment(options: Options, additionalData: any) {
|
||||||
if (options.itemid == null || options.itemid === "") {
|
if (options.itemId == null || options.itemId === "") {
|
||||||
return Response.badRequest("--itemid <itemid> required.");
|
return Response.badRequest("`itemid` option is required.");
|
||||||
}
|
}
|
||||||
if (options.file == null || options.file === "") {
|
let fileBuf: Buffer = null;
|
||||||
return Response.badRequest("--file <file> required.");
|
let fileName: string = null;
|
||||||
}
|
if (process.env.BW_SERVE === "true") {
|
||||||
const filePath = path.resolve(options.file);
|
fileBuf = additionalData.fileBuffer;
|
||||||
if (!fs.existsSync(options.file)) {
|
fileName = additionalData.fileName;
|
||||||
return Response.badRequest("Cannot find file at " + filePath);
|
} 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);
|
const cipher = await this.cipherService.get(itemId);
|
||||||
if (cipher == null) {
|
if (cipher == null) {
|
||||||
return Response.notFound();
|
return Response.notFound();
|
||||||
@@ -113,16 +138,14 @@ export class CreateCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const fileBuf = fs.readFileSync(filePath);
|
|
||||||
await this.cipherService.saveAttachmentRawWithServer(
|
await this.cipherService.saveAttachmentRawWithServer(
|
||||||
cipher,
|
cipher,
|
||||||
path.basename(filePath),
|
fileName,
|
||||||
new Uint8Array(fileBuf).buffer
|
new Uint8Array(fileBuf).buffer
|
||||||
);
|
);
|
||||||
const updatedCipher = await this.cipherService.get(cipher.id);
|
const updatedCipher = await this.cipherService.get(cipher.id);
|
||||||
const decCipher = await updatedCipher.decrypt();
|
const decCipher = await updatedCipher.decrypt();
|
||||||
const res = new CipherResponse(decCipher);
|
const res = new CipherResponse(decCipher);
|
||||||
return Response.success(res);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return Response.error(e);
|
return Response.error(e);
|
||||||
}
|
}
|
||||||
@@ -141,18 +164,15 @@ export class CreateCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createOrganizationCollection(
|
private async createOrganizationCollection(req: OrganizationCollectionRequest, options: Options) {
|
||||||
req: OrganizationCollectionRequest,
|
if (options.organizationId == null || options.organizationId === "") {
|
||||||
options: program.OptionValues
|
return Response.badRequest("`organizationid` option is required.");
|
||||||
) {
|
|
||||||
if (options.organizationid == null || options.organizationid === "") {
|
|
||||||
return Response.badRequest("--organizationid <organizationid> required.");
|
|
||||||
}
|
}
|
||||||
if (!Utils.isGuid(options.organizationid)) {
|
if (!Utils.isGuid(options.organizationId)) {
|
||||||
return Response.error("`" + options.organizationid + "` is not a GUID.");
|
return Response.badRequest("`" + options.organizationId + "` is not a GUID.");
|
||||||
}
|
}
|
||||||
if (options.organizationid !== req.organizationId) {
|
if (options.organizationId !== req.organizationId) {
|
||||||
return Response.error("--organizationid <organizationid> does not match request object.");
|
return Response.badRequest("`organizationid` option does not match request object.");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const orgKey = await this.cryptoService.getOrgKey(req.organizationId);
|
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 { Response } from "jslib-node/cli/models/response";
|
||||||
|
|
||||||
import { Utils } from "jslib-common/misc/utils";
|
import { Utils } from "jslib-common/misc/utils";
|
||||||
|
import { CliUtils } from "src/utils";
|
||||||
|
|
||||||
export class DeleteCommand {
|
export class DeleteCommand {
|
||||||
constructor(
|
constructor(
|
||||||
@@ -17,26 +18,27 @@ export class DeleteCommand {
|
|||||||
private apiService: ApiService
|
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) {
|
if (id != null) {
|
||||||
id = id.toLowerCase();
|
id = id.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const normalizedOptions = new Options(cmdOptions);
|
||||||
switch (object.toLowerCase()) {
|
switch (object.toLowerCase()) {
|
||||||
case "item":
|
case "item":
|
||||||
return await this.deleteCipher(id, cmd);
|
return await this.deleteCipher(id, normalizedOptions);
|
||||||
case "attachment":
|
case "attachment":
|
||||||
return await this.deleteAttachment(id, cmd);
|
return await this.deleteAttachment(id, normalizedOptions);
|
||||||
case "folder":
|
case "folder":
|
||||||
return await this.deleteFolder(id);
|
return await this.deleteFolder(id);
|
||||||
case "org-collection":
|
case "org-collection":
|
||||||
return await this.deleteOrganizationCollection(id, cmd);
|
return await this.deleteOrganizationCollection(id, normalizedOptions);
|
||||||
default:
|
default:
|
||||||
return Response.badRequest("Unknown object.");
|
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);
|
const cipher = await this.cipherService.get(id);
|
||||||
if (cipher == null) {
|
if (cipher == null) {
|
||||||
return Response.notFound();
|
return Response.notFound();
|
||||||
@@ -54,12 +56,12 @@ export class DeleteCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async deleteAttachment(id: string, options: program.OptionValues) {
|
private async deleteAttachment(id: string, options: Options) {
|
||||||
if (options.itemid == null || options.itemid === "") {
|
if (options.itemId == null || options.itemId === "") {
|
||||||
return Response.badRequest("--itemid <itemid> required.");
|
return Response.badRequest("`itemid` option is required.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const itemId = options.itemid.toLowerCase();
|
const itemId = options.itemId.toLowerCase();
|
||||||
const cipher = await this.cipherService.get(itemId);
|
const cipher = await this.cipherService.get(itemId);
|
||||||
if (cipher == null) {
|
if (cipher == null) {
|
||||||
return Response.notFound();
|
return Response.notFound();
|
||||||
@@ -100,21 +102,33 @@ export class DeleteCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async deleteOrganizationCollection(id: string, options: program.OptionValues) {
|
private async deleteOrganizationCollection(id: string, options: Options) {
|
||||||
if (options.organizationid == null || options.organizationid === "") {
|
if (options.organizationId == null || options.organizationId === "") {
|
||||||
return Response.badRequest("--organizationid <organizationid> required.");
|
return Response.badRequest("`organizationid` options is required.");
|
||||||
}
|
}
|
||||||
if (!Utils.isGuid(id)) {
|
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)) {
|
if (!Utils.isGuid(options.organizationId)) {
|
||||||
return Response.error("`" + options.organizationid + "` is not a GUID.");
|
return Response.badRequest("`" + options.organizationId + "` is not a GUID.");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await this.apiService.deleteCollection(options.organizationid, id);
|
await this.apiService.deleteCollection(options.organizationId, id);
|
||||||
return Response.success();
|
return Response.success();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return Response.error(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 { SymmetricCryptoKey } from "jslib-common/models/domain/symmetricCryptoKey";
|
||||||
|
|
||||||
import { Response } from "jslib-node/cli/models/response";
|
import { Response } from "jslib-node/cli/models/response";
|
||||||
|
import { FileResponse } from "jslib-node/cli/models/response/fileResponse";
|
||||||
|
|
||||||
import { CliUtils } from "../utils";
|
import { CliUtils } from "../utils";
|
||||||
|
|
||||||
@@ -27,7 +28,12 @@ export abstract class DownloadCommand {
|
|||||||
try {
|
try {
|
||||||
const buf = await response.arrayBuffer();
|
const buf = await response.arrayBuffer();
|
||||||
const decBuf = await this.cryptoService.decryptFromBytes(buf, key);
|
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) {
|
} catch (e) {
|
||||||
if (typeof e === "string") {
|
if (typeof e === "string") {
|
||||||
return Response.error(e);
|
return Response.error(e);
|
||||||
|
|||||||
@@ -35,10 +35,10 @@ export class EditCommand {
|
|||||||
async run(
|
async run(
|
||||||
object: string,
|
object: string,
|
||||||
id: string,
|
id: string,
|
||||||
requestJson: string,
|
requestJson: any,
|
||||||
cmd: program.Command
|
cmdOptions: Record<string, any>
|
||||||
): Promise<Response> {
|
): Promise<Response> {
|
||||||
if (requestJson == null || requestJson === "") {
|
if (process.env.BW_SERVE !== "true" && (requestJson == null || requestJson === "")) {
|
||||||
requestJson = await CliUtils.readStdin();
|
requestJson = await CliUtils.readStdin();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,17 +47,22 @@ export class EditCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let req: any = null;
|
let req: any = null;
|
||||||
try {
|
if (typeof requestJson !== "string") {
|
||||||
const reqJson = Buffer.from(requestJson, "base64").toString();
|
req = requestJson;
|
||||||
req = JSON.parse(reqJson);
|
} else {
|
||||||
} catch (e) {
|
try {
|
||||||
return Response.badRequest("Error parsing the encoded request data.");
|
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) {
|
if (id != null) {
|
||||||
id = id.toLowerCase();
|
id = id.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const normalizedOptions = new Options(cmdOptions);
|
||||||
switch (object.toLowerCase()) {
|
switch (object.toLowerCase()) {
|
||||||
case "item":
|
case "item":
|
||||||
return await this.editCipher(id, req);
|
return await this.editCipher(id, req);
|
||||||
@@ -66,7 +71,7 @@ export class EditCommand {
|
|||||||
case "folder":
|
case "folder":
|
||||||
return await this.editFolder(id, req);
|
return await this.editFolder(id, req);
|
||||||
case "org-collection":
|
case "org-collection":
|
||||||
return await this.editOrganizationCollection(id, req, cmd);
|
return await this.editOrganizationCollection(id, req, normalizedOptions);
|
||||||
default:
|
default:
|
||||||
return Response.badRequest("Unknown object.");
|
return Response.badRequest("Unknown object.");
|
||||||
}
|
}
|
||||||
@@ -80,9 +85,7 @@ export class EditCommand {
|
|||||||
|
|
||||||
let cipherView = await cipher.decrypt();
|
let cipherView = await cipher.decrypt();
|
||||||
if (cipherView.isDeleted) {
|
if (cipherView.isDeleted) {
|
||||||
return Response.badRequest(
|
return Response.badRequest("You may not edit a deleted item. Use the restore command first.");
|
||||||
"You may not edit a deleted cipher. Use restore item <id> command first."
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
cipherView = Cipher.toView(req, cipherView);
|
cipherView = Cipher.toView(req, cipherView);
|
||||||
const encCipher = await this.cipherService.encrypt(cipherView);
|
const encCipher = await this.cipherService.encrypt(cipherView);
|
||||||
@@ -104,7 +107,7 @@ export class EditCommand {
|
|||||||
}
|
}
|
||||||
if (cipher.organizationId == null) {
|
if (cipher.organizationId == null) {
|
||||||
return Response.badRequest(
|
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(
|
private async editOrganizationCollection(
|
||||||
id: string,
|
id: string,
|
||||||
req: OrganizationCollectionRequest,
|
req: OrganizationCollectionRequest,
|
||||||
options: program.OptionValues
|
options: Options
|
||||||
) {
|
) {
|
||||||
if (options.organizationid == null || options.organizationid === "") {
|
if (options.organizationId == null || options.organizationId === "") {
|
||||||
return Response.badRequest("--organizationid <organizationid> required.");
|
return Response.badRequest("`organizationid` option is required.");
|
||||||
}
|
}
|
||||||
if (!Utils.isGuid(id)) {
|
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)) {
|
if (!Utils.isGuid(options.organizationId)) {
|
||||||
return Response.error("`" + options.organizationid + "` is not a GUID.");
|
return Response.badRequest("`" + options.organizationId + "` is not a GUID.");
|
||||||
}
|
}
|
||||||
if (options.organizationid !== req.organizationId) {
|
if (options.organizationId !== req.organizationId) {
|
||||||
return Response.error("--organizationid <organizationid> does not match request object.");
|
return Response.badRequest("`organizationid` option does not match request object.");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const orgKey = await this.cryptoService.getOrgKey(req.organizationId);
|
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 { Response } from "jslib-node/cli/models/response";
|
||||||
import { StringResponse } from "jslib-node/cli/models/response/stringResponse";
|
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 { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
|
||||||
|
|
||||||
import { Response } from "jslib-node/cli/models/response";
|
import { Response } from "jslib-node/cli/models/response";
|
||||||
import { StringResponse } from "jslib-node/cli/models/response/stringResponse";
|
import { StringResponse } from "jslib-node/cli/models/response/stringResponse";
|
||||||
|
|
||||||
|
import { CliUtils } from "../utils";
|
||||||
|
|
||||||
export class GenerateCommand {
|
export class GenerateCommand {
|
||||||
constructor(private passwordGenerationService: PasswordGenerationService) {}
|
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 = {
|
const options = {
|
||||||
uppercase: cmdOptions.uppercase || false,
|
uppercase: normalizedOptions.uppercase,
|
||||||
lowercase: cmdOptions.lowercase || false,
|
lowercase: normalizedOptions.lowercase,
|
||||||
number: cmdOptions.number || false,
|
number: normalizedOptions.number,
|
||||||
special: cmdOptions.special || false,
|
special: normalizedOptions.special,
|
||||||
length: cmdOptions.length || 14,
|
length: normalizedOptions.length,
|
||||||
type: cmdOptions.passphrase ? "passphrase" : "password",
|
type: normalizedOptions.type,
|
||||||
wordSeparator: cmdOptions.separator == null ? "-" : cmdOptions.separator,
|
wordSeparator: normalizedOptions.separator,
|
||||||
numWords: cmdOptions.words || 3,
|
numWords: normalizedOptions.words,
|
||||||
capitalize: cmdOptions.capitalize || false,
|
capitalize: normalizedOptions.capitalize,
|
||||||
includeNumber: cmdOptions.includeNumber || false,
|
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 =
|
const enforcedOptions =
|
||||||
await this.passwordGenerationService.enforcePasswordGeneratorPoliciesOnOptions(options);
|
await this.passwordGenerationService.enforcePasswordGeneratorPoliciesOnOptions(options);
|
||||||
const password = await this.passwordGenerationService.generatePassword(enforcedOptions[0]);
|
const password = await this.passwordGenerationService.generatePassword(enforcedOptions[0]);
|
||||||
@@ -44,3 +29,46 @@ export class GenerateCommand {
|
|||||||
return Response.success(res);
|
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 { CipherType } from "jslib-common/enums/cipherType";
|
||||||
|
|
||||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
@@ -71,11 +69,12 @@ export class GetCommand extends DownloadCommand {
|
|||||||
super(cryptoService);
|
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) {
|
if (id != null) {
|
||||||
id = id.toLowerCase();
|
id = id.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const normalizedOptions = new Options(cmdOptions);
|
||||||
switch (object.toLowerCase()) {
|
switch (object.toLowerCase()) {
|
||||||
case "item":
|
case "item":
|
||||||
return await this.getCipher(id);
|
return await this.getCipher(id);
|
||||||
@@ -92,13 +91,13 @@ export class GetCommand extends DownloadCommand {
|
|||||||
case "exposed":
|
case "exposed":
|
||||||
return await this.getExposed(id);
|
return await this.getExposed(id);
|
||||||
case "attachment":
|
case "attachment":
|
||||||
return await this.getAttachment(id, options);
|
return await this.getAttachment(id, normalizedOptions);
|
||||||
case "folder":
|
case "folder":
|
||||||
return await this.getFolder(id);
|
return await this.getFolder(id);
|
||||||
case "collection":
|
case "collection":
|
||||||
return await this.getCollection(id);
|
return await this.getCollection(id);
|
||||||
case "org-collection":
|
case "org-collection":
|
||||||
return await this.getOrganizationCollection(id, options);
|
return await this.getOrganizationCollection(id, normalizedOptions);
|
||||||
case "organization":
|
case "organization":
|
||||||
return await this.getOrganization(id);
|
return await this.getOrganization(id);
|
||||||
case "template":
|
case "template":
|
||||||
@@ -292,12 +291,12 @@ export class GetCommand extends DownloadCommand {
|
|||||||
return Response.success(res);
|
return Response.success(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getAttachment(id: string, options: program.OptionValues) {
|
private async getAttachment(id: string, options: Options) {
|
||||||
if (options.itemid == null || options.itemid === "") {
|
if (options.itemId == null || options.itemId === "") {
|
||||||
return Response.badRequest("--itemid <itemid> required.");
|
return Response.badRequest("--itemid <itemid> required.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const itemId = options.itemid.toLowerCase();
|
const itemId = options.itemId.toLowerCase();
|
||||||
const cipherResponse = await this.getCipher(itemId);
|
const cipherResponse = await this.getCipher(itemId);
|
||||||
if (!cipherResponse.success) {
|
if (!cipherResponse.success) {
|
||||||
return cipherResponse;
|
return cipherResponse;
|
||||||
@@ -412,23 +411,23 @@ export class GetCommand extends DownloadCommand {
|
|||||||
return Response.success(res);
|
return Response.success(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getOrganizationCollection(id: string, options: program.OptionValues) {
|
private async getOrganizationCollection(id: string, options: Options) {
|
||||||
if (options.organizationid == null || options.organizationid === "") {
|
if (options.organizationId == null || options.organizationId === "") {
|
||||||
return Response.badRequest("--organizationid <organizationid> required.");
|
return Response.badRequest("`organizationid` option is required.");
|
||||||
}
|
}
|
||||||
if (!Utils.isGuid(id)) {
|
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)) {
|
if (!Utils.isGuid(options.organizationId)) {
|
||||||
return Response.error("`" + options.organizationid + "` is not a GUID.");
|
return Response.badRequest("`" + options.organizationId + "` is not a GUID.");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const orgKey = await this.cryptoService.getOrgKey(options.organizationid);
|
const orgKey = await this.cryptoService.getOrgKey(options.organizationId);
|
||||||
if (orgKey == null) {
|
if (orgKey == null) {
|
||||||
throw new Error("No encryption key for this organization.");
|
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);
|
const decCollection = new CollectionView(response);
|
||||||
decCollection.name = await this.cryptoService.decryptToUtf8(
|
decCollection.name = await this.cryptoService.decryptToUtf8(
|
||||||
new EncString(response.name),
|
new EncString(response.name),
|
||||||
@@ -536,3 +535,15 @@ export class GetCommand extends DownloadCommand {
|
|||||||
return Response.success(res);
|
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 { CipherView } from "jslib-common/models/view/cipherView";
|
||||||
|
|
||||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
@@ -42,26 +40,27 @@ export class ListCommand {
|
|||||||
private apiService: ApiService
|
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()) {
|
switch (object.toLowerCase()) {
|
||||||
case "items":
|
case "items":
|
||||||
return await this.listCiphers(cmd);
|
return await this.listCiphers(normalizedOptions);
|
||||||
case "folders":
|
case "folders":
|
||||||
return await this.listFolders(cmd);
|
return await this.listFolders(normalizedOptions);
|
||||||
case "collections":
|
case "collections":
|
||||||
return await this.listCollections(cmd);
|
return await this.listCollections(normalizedOptions);
|
||||||
case "org-collections":
|
case "org-collections":
|
||||||
return await this.listOrganizationCollections(cmd);
|
return await this.listOrganizationCollections(normalizedOptions);
|
||||||
case "org-members":
|
case "org-members":
|
||||||
return await this.listOrganizationMembers(cmd);
|
return await this.listOrganizationMembers(normalizedOptions);
|
||||||
case "organizations":
|
case "organizations":
|
||||||
return await this.listOrganizations(cmd);
|
return await this.listOrganizations(normalizedOptions);
|
||||||
default:
|
default:
|
||||||
return Response.badRequest("Unknown object.");
|
return Response.badRequest("Unknown object.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async listCiphers(options: program.OptionValues) {
|
private async listCiphers(options: Options) {
|
||||||
let ciphers: CipherView[];
|
let ciphers: CipherView[];
|
||||||
options.trash = options.trash || false;
|
options.trash = options.trash || false;
|
||||||
if (options.url != null && options.url.trim() !== "") {
|
if (options.url != null && options.url.trim() !== "") {
|
||||||
@@ -71,43 +70,43 @@ export class ListCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
options.folderid != null ||
|
options.folderId != null ||
|
||||||
options.collectionid != null ||
|
options.collectionId != null ||
|
||||||
options.organizationid != null
|
options.organizationId != null
|
||||||
) {
|
) {
|
||||||
ciphers = ciphers.filter((c) => {
|
ciphers = ciphers.filter((c) => {
|
||||||
if (options.trash !== c.isDeleted) {
|
if (options.trash !== c.isDeleted) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (options.folderid != null) {
|
if (options.folderId != null) {
|
||||||
if (options.folderid === "notnull" && c.folderId != null) {
|
if (options.folderId === "notnull" && c.folderId != null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const folderId = options.folderid === "null" ? null : options.folderid;
|
const folderId = options.folderId === "null" ? null : options.folderId;
|
||||||
if (folderId === c.folderId) {
|
if (folderId === c.folderId) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.organizationid != null) {
|
if (options.organizationId != null) {
|
||||||
if (options.organizationid === "notnull" && c.organizationId != null) {
|
if (options.organizationId === "notnull" && c.organizationId != null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const organizationId = options.organizationid === "null" ? null : options.organizationid;
|
const organizationId = options.organizationId === "null" ? null : options.organizationId;
|
||||||
if (organizationId === c.organizationId) {
|
if (organizationId === c.organizationId) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.collectionid != null) {
|
if (options.collectionId != null) {
|
||||||
if (
|
if (
|
||||||
options.collectionid === "notnull" &&
|
options.collectionId === "notnull" &&
|
||||||
c.collectionIds != null &&
|
c.collectionIds != null &&
|
||||||
c.collectionIds.length > 0
|
c.collectionIds.length > 0
|
||||||
) {
|
) {
|
||||||
return true;
|
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)) {
|
if (collectionId == null && (c.collectionIds == null || c.collectionIds.length === 0)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -133,7 +132,7 @@ export class ListCommand {
|
|||||||
return Response.success(res);
|
return Response.success(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async listFolders(options: program.OptionValues) {
|
private async listFolders(options: Options) {
|
||||||
let folders = await this.folderService.getAllDecrypted();
|
let folders = await this.folderService.getAllDecrypted();
|
||||||
|
|
||||||
if (options.search != null && options.search.trim() !== "") {
|
if (options.search != null && options.search.trim() !== "") {
|
||||||
@@ -144,12 +143,12 @@ export class ListCommand {
|
|||||||
return Response.success(res);
|
return Response.success(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async listCollections(options: program.OptionValues) {
|
private async listCollections(options: Options) {
|
||||||
let collections = await this.collectionService.getAllDecrypted();
|
let collections = await this.collectionService.getAllDecrypted();
|
||||||
|
|
||||||
if (options.organizationid != null) {
|
if (options.organizationId != null) {
|
||||||
collections = collections.filter((c) => {
|
collections = collections.filter((c) => {
|
||||||
if (options.organizationid === c.organizationId) {
|
if (options.organizationId === c.organizationId) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -164,14 +163,14 @@ export class ListCommand {
|
|||||||
return Response.success(res);
|
return Response.success(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async listOrganizationCollections(options: program.OptionValues) {
|
private async listOrganizationCollections(options: Options) {
|
||||||
if (options.organizationid == null || options.organizationid === "") {
|
if (options.organizationId == null || options.organizationId === "") {
|
||||||
return Response.badRequest("--organizationid <organizationid> required.");
|
return Response.badRequest("`organizationid` option is required.");
|
||||||
}
|
}
|
||||||
if (!Utils.isGuid(options.organizationid)) {
|
if (!Utils.isGuid(options.organizationId)) {
|
||||||
return Response.error("`" + options.organizationid + "` is not a GUID.");
|
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) {
|
if (organization == null) {
|
||||||
return Response.error("Organization not found.");
|
return Response.error("Organization not found.");
|
||||||
}
|
}
|
||||||
@@ -179,12 +178,12 @@ export class ListCommand {
|
|||||||
try {
|
try {
|
||||||
let response: ApiListResponse<ApiCollectionResponse>;
|
let response: ApiListResponse<ApiCollectionResponse>;
|
||||||
if (organization.canViewAllCollections) {
|
if (organization.canViewAllCollections) {
|
||||||
response = await this.apiService.getCollections(options.organizationid);
|
response = await this.apiService.getCollections(options.organizationId);
|
||||||
} else {
|
} else {
|
||||||
response = await this.apiService.getUserCollections();
|
response = await this.apiService.getUserCollections();
|
||||||
}
|
}
|
||||||
const collections = response.data
|
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)));
|
.map((r) => new Collection(new CollectionData(r as ApiCollectionDetailsResponse)));
|
||||||
let decCollections = await this.collectionService.decryptMany(collections);
|
let decCollections = await this.collectionService.decryptMany(collections);
|
||||||
if (options.search != null && options.search.trim() !== "") {
|
if (options.search != null && options.search.trim() !== "") {
|
||||||
@@ -197,20 +196,20 @@ export class ListCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async listOrganizationMembers(options: program.OptionValues) {
|
private async listOrganizationMembers(options: Options) {
|
||||||
if (options.organizationid == null || options.organizationid === "") {
|
if (options.organizationId == null || options.organizationId === "") {
|
||||||
return Response.badRequest("--organizationid <organizationid> required.");
|
return Response.badRequest("`organizationid` option is required.");
|
||||||
}
|
}
|
||||||
if (!Utils.isGuid(options.organizationid)) {
|
if (!Utils.isGuid(options.organizationId)) {
|
||||||
return Response.error("`" + options.organizationid + "` is not a GUID.");
|
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) {
|
if (organization == null) {
|
||||||
return Response.error("Organization not found.");
|
return Response.error("Organization not found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await this.apiService.getOrganizationUsers(options.organizationid);
|
const response = await this.apiService.getOrganizationUsers(options.organizationId);
|
||||||
const res = new ListResponse(
|
const res = new ListResponse(
|
||||||
response.data.map((r) => {
|
response.data.map((r) => {
|
||||||
const u = new OrganizationUserResponse();
|
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();
|
let organizations = await this.organizationService.getAll();
|
||||||
|
|
||||||
if (options.search != null && options.search.trim() !== "") {
|
if (options.search != null && options.search.trim() !== "") {
|
||||||
@@ -240,3 +239,21 @@ export class ListCommand {
|
|||||||
return Response.success(res);
|
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 { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
|
||||||
|
|
||||||
import { Response } from "jslib-node/cli/models/response";
|
import { Response } from "jslib-node/cli/models/response";
|
||||||
@@ -8,7 +6,7 @@ import { MessageResponse } from "jslib-node/cli/models/response/messageResponse"
|
|||||||
export class LockCommand {
|
export class LockCommand {
|
||||||
constructor(private vaultTimeoutService: VaultTimeoutService) {}
|
constructor(private vaultTimeoutService: VaultTimeoutService) {}
|
||||||
|
|
||||||
async run(cmd: program.Command) {
|
async run() {
|
||||||
await this.vaultTimeoutService.lock();
|
await this.vaultTimeoutService.lock();
|
||||||
process.env.BW_SESSION = null;
|
process.env.BW_SESSION = null;
|
||||||
const res = new MessageResponse("Your vault is locked.", 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 { CipherService } from "jslib-common/abstractions/cipher.service";
|
||||||
|
|
||||||
import { Response } from "jslib-node/cli/models/response";
|
import { Response } from "jslib-node/cli/models/response";
|
||||||
@@ -7,20 +5,20 @@ import { Response } from "jslib-node/cli/models/response";
|
|||||||
export class RestoreCommand {
|
export class RestoreCommand {
|
||||||
constructor(private cipherService: CipherService) {}
|
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) {
|
if (id != null) {
|
||||||
id = id.toLowerCase();
|
id = id.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (object.toLowerCase()) {
|
switch (object.toLowerCase()) {
|
||||||
case "item":
|
case "item":
|
||||||
return await this.restoreCipher(id, cmd);
|
return await this.restoreCipher(id);
|
||||||
default:
|
default:
|
||||||
return Response.badRequest("Unknown object.");
|
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);
|
const cipher = await this.cipherService.get(id);
|
||||||
if (cipher == null) {
|
if (cipher == null) {
|
||||||
return Response.notFound();
|
return Response.notFound();
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import * as program from "commander";
|
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
|
|
||||||
@@ -11,7 +10,6 @@ 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 { Response } from "jslib-node/cli/models/response";
|
||||||
import { StringResponse } from "jslib-node/cli/models/response/stringResponse";
|
|
||||||
|
|
||||||
import { SendResponse } from "../../models/response/sendResponse";
|
import { SendResponse } from "../../models/response/sendResponse";
|
||||||
import { SendTextResponse } from "../../models/response/sendTextResponse";
|
import { SendTextResponse } from "../../models/response/sendTextResponse";
|
||||||
@@ -25,9 +23,9 @@ export class SendCreateCommand {
|
|||||||
private environmentService: EnvironmentService
|
private environmentService: EnvironmentService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async run(requestJson: string, options: program.OptionValues) {
|
async run(requestJson: any, cmdOptions: Record<string, any>) {
|
||||||
let req: any = null;
|
let req: any = null;
|
||||||
if (requestJson == null || requestJson === "") {
|
if (process.env.BW_SERVE !== "true" && (requestJson == null || requestJson === "")) {
|
||||||
requestJson = await CliUtils.readStdin();
|
requestJson = await CliUtils.readStdin();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,15 +33,19 @@ export class SendCreateCommand {
|
|||||||
return Response.badRequest("`requestJson` was not provided.");
|
return Response.badRequest("`requestJson` was not provided.");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
if (typeof requestJson !== "string") {
|
||||||
const reqJson = Buffer.from(requestJson, "base64").toString();
|
req = requestJson;
|
||||||
req = SendResponse.fromJson(reqJson);
|
} else {
|
||||||
|
try {
|
||||||
|
const reqJson = Buffer.from(requestJson, "base64").toString();
|
||||||
|
req = SendResponse.fromJson(reqJson);
|
||||||
|
|
||||||
if (req == null) {
|
if (req == null) {
|
||||||
throw new Error("Null request");
|
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 (
|
if (
|
||||||
@@ -58,10 +60,11 @@ export class SendCreateCommand {
|
|||||||
return Response.badRequest("Unable to parse expirationDate: " + req.expirationDate);
|
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 filePath = req.file?.fileName ?? options.file;
|
||||||
const text = req.text?.text ?? options.text;
|
const text = req.text?.text ?? options.text;
|
||||||
const hidden = req.text?.hidden ?? options.hidden;
|
const hidden = req.text?.hidden ?? options.hidden;
|
||||||
@@ -73,13 +76,19 @@ export class SendCreateCommand {
|
|||||||
|
|
||||||
switch (req.type) {
|
switch (req.type) {
|
||||||
case SendType.File:
|
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())) {
|
if (!(await this.stateService.getCanAccessPremium())) {
|
||||||
return Response.error("Premium status is required to use this feature.");
|
return Response.error("Premium status is required to use this feature.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filePath == null) {
|
if (filePath == null) {
|
||||||
return Response.badRequest(
|
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:
|
case SendType.Text:
|
||||||
if (text == null) {
|
if (text == null) {
|
||||||
return Response.badRequest(
|
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();
|
req.text = new SendTextResponse();
|
||||||
@@ -97,7 +106,7 @@ export class SendCreateCommand {
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return Response.badRequest(
|
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 newSend = await this.sendService.get(encSend.id);
|
||||||
const decSend = await newSend.decrypt();
|
const decSend = await newSend.decrypt();
|
||||||
const res = new SendResponse(decSend, this.environmentService.getWebVaultUrl());
|
const res = new SendResponse(decSend, this.environmentService.getWebVaultUrl());
|
||||||
return Response.success(
|
return Response.success(res);
|
||||||
options.fullObject
|
|
||||||
? res
|
|
||||||
: new StringResponse("Send created! It can be accessed at:\n" + res.accessUrl)
|
|
||||||
);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return Response.error(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 { SendService } from "jslib-common/abstractions/send.service";
|
||||||
import { StateService } from "jslib-common/abstractions/state.service";
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
|
|
||||||
@@ -18,24 +16,29 @@ export class SendEditCommand {
|
|||||||
private getCommand: SendGetCommand
|
private getCommand: SendGetCommand
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async run(encodedJson: string, options: program.OptionValues): Promise<Response> {
|
async run(requestJson: string, cmdOptions: Record<string, any>): Promise<Response> {
|
||||||
if (encodedJson == null || encodedJson === "") {
|
if (process.env.BW_SERVE !== "true" && (requestJson == null || requestJson === "")) {
|
||||||
encodedJson = await CliUtils.readStdin();
|
requestJson = await CliUtils.readStdin();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (encodedJson == null || encodedJson === "") {
|
if (requestJson == null || requestJson === "") {
|
||||||
return Response.badRequest("`encodedJson` was not provided.");
|
return Response.badRequest("`requestJson` was not provided.");
|
||||||
}
|
}
|
||||||
|
|
||||||
let req: SendResponse = null;
|
let req: SendResponse = null;
|
||||||
try {
|
if (typeof requestJson !== "string") {
|
||||||
const reqJson = Buffer.from(encodedJson, "base64").toString();
|
req = requestJson;
|
||||||
req = SendResponse.fromJson(reqJson);
|
} else {
|
||||||
} catch (e) {
|
try {
|
||||||
return Response.badRequest("Error parsing the encoded request data.");
|
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) {
|
if (req.id != null) {
|
||||||
req.id = req.id.toLowerCase();
|
req.id = req.id.toLowerCase();
|
||||||
@@ -76,3 +79,11 @@ export class SendEditCommand {
|
|||||||
return await this.getCommand.run(send.id, {});
|
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 * as program from "commander";
|
||||||
|
|
||||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
|
||||||
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||||
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
||||||
import { SearchService } from "jslib-common/abstractions/search.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) {
|
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);
|
let sends = await this.getSendView(id);
|
||||||
if (sends == null) {
|
if (sends == null) {
|
||||||
return Response.notFound();
|
return Response.notFound();
|
||||||
@@ -36,7 +40,7 @@ export class SendGetCommand extends DownloadCommand {
|
|||||||
let filter = (s: SendView) => true;
|
let filter = (s: SendView) => true;
|
||||||
let selector = async (s: SendView): Promise<Response> =>
|
let selector = async (s: SendView): Promise<Response> =>
|
||||||
Response.success(new SendResponse(s, webVaultUrl));
|
Response.success(new SendResponse(s, webVaultUrl));
|
||||||
if (options.text != null) {
|
if (!serveCommand && options?.text != null) {
|
||||||
filter = (s) => {
|
filter = (s) => {
|
||||||
return filter(s) && s.text != null;
|
return filter(s) && s.text != null;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import * as program from "commander";
|
|
||||||
|
|
||||||
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
||||||
import { SearchService } from "jslib-common/abstractions/search.service";
|
import { SearchService } from "jslib-common/abstractions/search.service";
|
||||||
import { SendService } from "jslib-common/abstractions/send.service";
|
import { SendService } from "jslib-common/abstractions/send.service";
|
||||||
@@ -16,11 +14,12 @@ export class SendListCommand {
|
|||||||
private searchService: SearchService
|
private searchService: SearchService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async run(options: program.OptionValues): Promise<Response> {
|
async run(cmdOptions: Record<string, any>): Promise<Response> {
|
||||||
let sends = await this.sendService.getAllDecrypted();
|
let sends = await this.sendService.getAllDecrypted();
|
||||||
|
|
||||||
if (options.search != null && options.search.trim() !== "") {
|
const normalizedOptions = new Options(cmdOptions);
|
||||||
sends = this.searchService.searchSends(sends, options.search);
|
if (normalizedOptions.search != null && normalizedOptions.search.trim() !== "") {
|
||||||
|
sends = this.searchService.searchSends(sends, normalizedOptions.search);
|
||||||
}
|
}
|
||||||
|
|
||||||
const webVaultUrl = this.environmentService.getWebVaultUrl();
|
const webVaultUrl = this.environmentService.getWebVaultUrl();
|
||||||
@@ -28,3 +27,11 @@ export class SendListCommand {
|
|||||||
return Response.success(res);
|
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 { CipherService } from "jslib-common/abstractions/cipher.service";
|
||||||
|
|
||||||
import { Response } from "jslib-node/cli/models/response";
|
import { Response } from "jslib-node/cli/models/response";
|
||||||
@@ -11,13 +9,8 @@ import { CliUtils } from "../utils";
|
|||||||
export class ShareCommand {
|
export class ShareCommand {
|
||||||
constructor(private cipherService: CipherService) {}
|
constructor(private cipherService: CipherService) {}
|
||||||
|
|
||||||
async run(
|
async run(id: string, organizationId: string, requestJson: string): Promise<Response> {
|
||||||
id: string,
|
if (process.env.BW_SERVE !== "true" && (requestJson == null || requestJson === "")) {
|
||||||
organizationId: string,
|
|
||||||
requestJson: string,
|
|
||||||
cmd: program.Command
|
|
||||||
): Promise<Response> {
|
|
||||||
if (requestJson == null || requestJson === "") {
|
|
||||||
requestJson = await CliUtils.readStdin();
|
requestJson = await CliUtils.readStdin();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,14 +19,18 @@ export class ShareCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let req: string[] = [];
|
let req: string[] = [];
|
||||||
try {
|
if (typeof requestJson !== "string") {
|
||||||
const reqJson = Buffer.from(requestJson, "base64").toString();
|
req = requestJson;
|
||||||
req = JSON.parse(reqJson);
|
} else {
|
||||||
if (req == null || req.length === 0) {
|
try {
|
||||||
return Response.badRequest("You must provide at least one collection id for this item.");
|
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) {
|
if (id != null) {
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import * as program from "commander";
|
|
||||||
|
|
||||||
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
||||||
import { StateService } from "jslib-common/abstractions/state.service";
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
import { SyncService } from "jslib-common/abstractions/sync.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 { SyncService } from "jslib-common/abstractions/sync.service";
|
||||||
|
|
||||||
import { Response } from "jslib-node/cli/models/response";
|
import { Response } from "jslib-node/cli/models/response";
|
||||||
import { MessageResponse } from "jslib-node/cli/models/response/messageResponse";
|
import { MessageResponse } from "jslib-node/cli/models/response/messageResponse";
|
||||||
import { StringResponse } from "jslib-node/cli/models/response/stringResponse";
|
import { StringResponse } from "jslib-node/cli/models/response/stringResponse";
|
||||||
|
|
||||||
|
import { CliUtils } from "src/utils";
|
||||||
|
|
||||||
export class SyncCommand {
|
export class SyncCommand {
|
||||||
constructor(private syncService: SyncService) {}
|
constructor(private syncService: SyncService) {}
|
||||||
|
|
||||||
async run(options: program.OptionValues): Promise<Response> {
|
async run(cmdOptions: Record<string, any>): Promise<Response> {
|
||||||
if (options.last || false) {
|
const normalizedOptions = new Options(cmdOptions);
|
||||||
|
if (normalizedOptions.last) {
|
||||||
return await this.getLastSync();
|
return await this.getLastSync();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
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);
|
const res = new MessageResponse("Syncing complete.", null);
|
||||||
return Response.success(res);
|
return Response.success(res);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -29,3 +30,13 @@ export class SyncCommand {
|
|||||||
return Response.success(res);
|
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 * as inquirer from "inquirer";
|
||||||
|
|
||||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
@@ -26,17 +25,18 @@ export class UnlockCommand {
|
|||||||
private logService: ConsoleLogService
|
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 canInteract = process.env.BW_NOINTERACTION !== "true";
|
||||||
|
const normalizedOptions = new Options(cmdOptions);
|
||||||
if (password == null || password === "") {
|
if (password == null || password === "") {
|
||||||
if (options?.passwordfile) {
|
if (normalizedOptions?.passwordFile) {
|
||||||
password = await NodeUtils.readFirstLine(options.passwordfile);
|
password = await NodeUtils.readFirstLine(normalizedOptions.passwordFile);
|
||||||
} else if (options?.passwordenv) {
|
} else if (normalizedOptions?.passwordEnv) {
|
||||||
if (process.env[options.passwordenv]) {
|
if (process.env[normalizedOptions.passwordEnv]) {
|
||||||
password = process.env[options.passwordenv];
|
password = process.env[normalizedOptions.passwordEnv];
|
||||||
} else {
|
} else {
|
||||||
this.logService.warning(
|
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);
|
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 { GenerateCommand } from "./commands/generate.command";
|
||||||
import { LockCommand } from "./commands/lock.command";
|
import { LockCommand } from "./commands/lock.command";
|
||||||
import { LoginCommand } from "./commands/login.command";
|
import { LoginCommand } from "./commands/login.command";
|
||||||
|
import { ServeCommand } from "./commands/serve.command";
|
||||||
import { StatusCommand } from "./commands/status.command";
|
import { StatusCommand } from "./commands/status.command";
|
||||||
import { SyncCommand } from "./commands/sync.command";
|
import { SyncCommand } from "./commands/sync.command";
|
||||||
import { UnlockCommand } from "./commands/unlock.command";
|
import { UnlockCommand } from "./commands/unlock.command";
|
||||||
@@ -214,7 +215,7 @@ export class Program extends BaseProgram {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const command = new LockCommand(this.main.vaultTimeoutService);
|
const command = new LockCommand(this.main.vaultTimeoutService);
|
||||||
const response = await command.run(cmd);
|
const response = await command.run();
|
||||||
this.processResponse(response);
|
this.processResponse(response);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -462,6 +463,22 @@ export class Program extends BaseProgram {
|
|||||||
const response = await command.run();
|
const response = await command.run();
|
||||||
this.processResponse(response);
|
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) {
|
protected processResponse(response: Response, exitImmediately = false) {
|
||||||
|
|||||||
@@ -170,4 +170,8 @@ export class CliUtils {
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static convertBooleanOption(optionValue: any) {
|
||||||
|
return optionValue || optionValue === "" ? true : false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -346,7 +346,7 @@ export class VaultProgram extends Program {
|
|||||||
|
|
||||||
await this.exitIfLocked();
|
await this.exitIfLocked();
|
||||||
const command = new RestoreCommand(this.main.cipherService);
|
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);
|
this.processResponse(response);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -383,7 +383,7 @@ export class VaultProgram extends Program {
|
|||||||
.action(async (id, organizationId, encodedJson, cmd) => {
|
.action(async (id, organizationId, encodedJson, cmd) => {
|
||||||
await this.exitIfLocked();
|
await this.exitIfLocked();
|
||||||
const command = new ShareCommand(this.main.cipherService);
|
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);
|
this.processResponse(response);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user