mirror of
https://github.com/bitwarden/browser.git
synced 2025-01-02 18:17:46 +01:00
[AC-2740] Add device-approval to bw serve (#9512)
* Extract bw serve endpoint configuration to a configurator class * Add device-approval endpoints to bw serve
This commit is contained in:
parent
b35930074c
commit
89aa6220ca
@ -1,6 +1,8 @@
|
|||||||
import { program } from "commander";
|
import { program } from "commander";
|
||||||
|
|
||||||
|
import { OssServeConfigurator } from "./oss-serve-configurator";
|
||||||
import { registerOssPrograms } from "./register-oss-programs";
|
import { registerOssPrograms } from "./register-oss-programs";
|
||||||
|
import { ServeProgram } from "./serve.program";
|
||||||
import { ServiceContainer } from "./service-container";
|
import { ServiceContainer } from "./service-container";
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
@ -9,6 +11,10 @@ async function main() {
|
|||||||
|
|
||||||
await registerOssPrograms(serviceContainer);
|
await registerOssPrograms(serviceContainer);
|
||||||
|
|
||||||
|
// ServeProgram is registered separately so it can be overridden by bit-cli
|
||||||
|
const serveConfigurator = new OssServeConfigurator(serviceContainer);
|
||||||
|
new ServeProgram(serviceContainer, serveConfigurator).register();
|
||||||
|
|
||||||
program.parse(process.argv);
|
program.parse(process.argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import * as koaMulter from "@koa/multer";
|
|
||||||
import * as koaRouter from "@koa/router";
|
import * as koaRouter from "@koa/router";
|
||||||
import { OptionValues } from "commander";
|
import { OptionValues } from "commander";
|
||||||
import * as koa from "koa";
|
import * as koa from "koa";
|
||||||
@ -7,170 +6,14 @@ import * as koaJson from "koa-json";
|
|||||||
|
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
|
|
||||||
import { ConfirmCommand } from "../admin-console/commands/confirm.command";
|
import { OssServeConfigurator } from "../oss-serve-configurator";
|
||||||
import { ShareCommand } from "../admin-console/commands/share.command";
|
|
||||||
import { LockCommand } from "../auth/commands/lock.command";
|
|
||||||
import { UnlockCommand } from "../auth/commands/unlock.command";
|
|
||||||
import { Response } from "../models/response";
|
|
||||||
import { FileResponse } from "../models/response/file.response";
|
|
||||||
import { ServiceContainer } from "../service-container";
|
import { ServiceContainer } from "../service-container";
|
||||||
import { GenerateCommand } from "../tools/generate.command";
|
|
||||||
import {
|
|
||||||
SendEditCommand,
|
|
||||||
SendCreateCommand,
|
|
||||||
SendDeleteCommand,
|
|
||||||
SendGetCommand,
|
|
||||||
SendListCommand,
|
|
||||||
SendRemovePasswordCommand,
|
|
||||||
} from "../tools/send";
|
|
||||||
import { CreateCommand } from "../vault/create.command";
|
|
||||||
import { DeleteCommand } from "../vault/delete.command";
|
|
||||||
import { SyncCommand } from "../vault/sync.command";
|
|
||||||
|
|
||||||
import { EditCommand } from "./edit.command";
|
|
||||||
import { GetCommand } from "./get.command";
|
|
||||||
import { ListCommand } from "./list.command";
|
|
||||||
import { RestoreCommand } from "./restore.command";
|
|
||||||
import { StatusCommand } from "./status.command";
|
|
||||||
|
|
||||||
export class ServeCommand {
|
export class ServeCommand {
|
||||||
private listCommand: ListCommand;
|
constructor(
|
||||||
private getCommand: GetCommand;
|
protected serviceContainer: ServiceContainer,
|
||||||
private createCommand: CreateCommand;
|
protected serveConfigurator: OssServeConfigurator,
|
||||||
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 serviceContainer: ServiceContainer) {
|
|
||||||
this.getCommand = new GetCommand(
|
|
||||||
this.serviceContainer.cipherService,
|
|
||||||
this.serviceContainer.folderService,
|
|
||||||
this.serviceContainer.collectionService,
|
|
||||||
this.serviceContainer.totpService,
|
|
||||||
this.serviceContainer.auditService,
|
|
||||||
this.serviceContainer.cryptoService,
|
|
||||||
this.serviceContainer.stateService,
|
|
||||||
this.serviceContainer.searchService,
|
|
||||||
this.serviceContainer.apiService,
|
|
||||||
this.serviceContainer.organizationService,
|
|
||||||
this.serviceContainer.eventCollectionService,
|
|
||||||
this.serviceContainer.billingAccountProfileStateService,
|
|
||||||
);
|
|
||||||
this.listCommand = new ListCommand(
|
|
||||||
this.serviceContainer.cipherService,
|
|
||||||
this.serviceContainer.folderService,
|
|
||||||
this.serviceContainer.collectionService,
|
|
||||||
this.serviceContainer.organizationService,
|
|
||||||
this.serviceContainer.searchService,
|
|
||||||
this.serviceContainer.organizationUserService,
|
|
||||||
this.serviceContainer.apiService,
|
|
||||||
this.serviceContainer.eventCollectionService,
|
|
||||||
);
|
|
||||||
this.createCommand = new CreateCommand(
|
|
||||||
this.serviceContainer.cipherService,
|
|
||||||
this.serviceContainer.folderService,
|
|
||||||
this.serviceContainer.cryptoService,
|
|
||||||
this.serviceContainer.apiService,
|
|
||||||
this.serviceContainer.folderApiService,
|
|
||||||
this.serviceContainer.billingAccountProfileStateService,
|
|
||||||
this.serviceContainer.organizationService,
|
|
||||||
);
|
|
||||||
this.editCommand = new EditCommand(
|
|
||||||
this.serviceContainer.cipherService,
|
|
||||||
this.serviceContainer.folderService,
|
|
||||||
this.serviceContainer.cryptoService,
|
|
||||||
this.serviceContainer.apiService,
|
|
||||||
this.serviceContainer.folderApiService,
|
|
||||||
);
|
|
||||||
this.generateCommand = new GenerateCommand(
|
|
||||||
this.serviceContainer.passwordGenerationService,
|
|
||||||
this.serviceContainer.stateService,
|
|
||||||
);
|
|
||||||
this.syncCommand = new SyncCommand(this.serviceContainer.syncService);
|
|
||||||
this.statusCommand = new StatusCommand(
|
|
||||||
this.serviceContainer.environmentService,
|
|
||||||
this.serviceContainer.syncService,
|
|
||||||
this.serviceContainer.accountService,
|
|
||||||
this.serviceContainer.authService,
|
|
||||||
);
|
|
||||||
this.deleteCommand = new DeleteCommand(
|
|
||||||
this.serviceContainer.cipherService,
|
|
||||||
this.serviceContainer.folderService,
|
|
||||||
this.serviceContainer.apiService,
|
|
||||||
this.serviceContainer.folderApiService,
|
|
||||||
this.serviceContainer.billingAccountProfileStateService,
|
|
||||||
);
|
|
||||||
this.confirmCommand = new ConfirmCommand(
|
|
||||||
this.serviceContainer.apiService,
|
|
||||||
this.serviceContainer.cryptoService,
|
|
||||||
this.serviceContainer.organizationUserService,
|
|
||||||
);
|
|
||||||
this.restoreCommand = new RestoreCommand(this.serviceContainer.cipherService);
|
|
||||||
this.shareCommand = new ShareCommand(this.serviceContainer.cipherService);
|
|
||||||
this.lockCommand = new LockCommand(this.serviceContainer.vaultTimeoutService);
|
|
||||||
this.unlockCommand = new UnlockCommand(
|
|
||||||
this.serviceContainer.accountService,
|
|
||||||
this.serviceContainer.masterPasswordService,
|
|
||||||
this.serviceContainer.cryptoService,
|
|
||||||
this.serviceContainer.stateService,
|
|
||||||
this.serviceContainer.cryptoFunctionService,
|
|
||||||
this.serviceContainer.apiService,
|
|
||||||
this.serviceContainer.logService,
|
|
||||||
this.serviceContainer.keyConnectorService,
|
|
||||||
this.serviceContainer.environmentService,
|
|
||||||
this.serviceContainer.syncService,
|
|
||||||
this.serviceContainer.organizationApiService,
|
|
||||||
async () => await this.serviceContainer.logout(),
|
|
||||||
this.serviceContainer.kdfConfigService,
|
|
||||||
);
|
|
||||||
|
|
||||||
this.sendCreateCommand = new SendCreateCommand(
|
|
||||||
this.serviceContainer.sendService,
|
|
||||||
this.serviceContainer.environmentService,
|
|
||||||
this.serviceContainer.sendApiService,
|
|
||||||
this.serviceContainer.billingAccountProfileStateService,
|
|
||||||
);
|
|
||||||
this.sendDeleteCommand = new SendDeleteCommand(
|
|
||||||
this.serviceContainer.sendService,
|
|
||||||
this.serviceContainer.sendApiService,
|
|
||||||
);
|
|
||||||
this.sendGetCommand = new SendGetCommand(
|
|
||||||
this.serviceContainer.sendService,
|
|
||||||
this.serviceContainer.environmentService,
|
|
||||||
this.serviceContainer.searchService,
|
|
||||||
this.serviceContainer.cryptoService,
|
|
||||||
);
|
|
||||||
this.sendEditCommand = new SendEditCommand(
|
|
||||||
this.serviceContainer.sendService,
|
|
||||||
this.sendGetCommand,
|
|
||||||
this.serviceContainer.sendApiService,
|
|
||||||
this.serviceContainer.billingAccountProfileStateService,
|
|
||||||
);
|
|
||||||
this.sendListCommand = new SendListCommand(
|
|
||||||
this.serviceContainer.sendService,
|
|
||||||
this.serviceContainer.environmentService,
|
|
||||||
this.serviceContainer.searchService,
|
|
||||||
);
|
|
||||||
this.sendRemovePasswordCommand = new SendRemovePasswordCommand(
|
|
||||||
this.serviceContainer.sendService,
|
|
||||||
this.serviceContainer.sendApiService,
|
|
||||||
this.serviceContainer.environmentService,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async run(options: OptionValues) {
|
async run(options: OptionValues) {
|
||||||
const protectOrigin = !options.disableOriginProtection;
|
const protectOrigin = !options.disableOriginProtection;
|
||||||
@ -205,207 +48,7 @@ export class ServeCommand {
|
|||||||
.use(koaBodyParser())
|
.use(koaBodyParser())
|
||||||
.use(koaJson({ pretty: false, param: "pretty" }));
|
.use(koaJson({ pretty: false, param: "pretty" }));
|
||||||
|
|
||||||
router.get("/generate", async (ctx, next) => {
|
this.serveConfigurator.configureRouter(router);
|
||||||
const response = await this.generateCommand.run(ctx.request.query);
|
|
||||||
this.processResponse(ctx.response, response);
|
|
||||||
await next();
|
|
||||||
});
|
|
||||||
|
|
||||||
router.get("/status", async (ctx, next) => {
|
|
||||||
const response = await this.statusCommand.run();
|
|
||||||
this.processResponse(ctx.response, response);
|
|
||||||
await next();
|
|
||||||
});
|
|
||||||
|
|
||||||
router.get("/list/object/:object", async (ctx, next) => {
|
|
||||||
if (await this.errorIfLocked(ctx.response)) {
|
|
||||||
await next();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let response: Response = null;
|
|
||||||
if (ctx.params.object === "send") {
|
|
||||||
response = await this.sendListCommand.run(ctx.request.query);
|
|
||||||
} else {
|
|
||||||
response = await this.listCommand.run(ctx.params.object, ctx.request.query);
|
|
||||||
}
|
|
||||||
this.processResponse(ctx.response, response);
|
|
||||||
await next();
|
|
||||||
});
|
|
||||||
|
|
||||||
router.get("/send/list", async (ctx, next) => {
|
|
||||||
if (await this.errorIfLocked(ctx.response)) {
|
|
||||||
await next();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const response = await this.sendListCommand.run(ctx.request.query);
|
|
||||||
this.processResponse(ctx.response, response);
|
|
||||||
await next();
|
|
||||||
});
|
|
||||||
|
|
||||||
router.post("/sync", async (ctx, next) => {
|
|
||||||
const response = await this.syncCommand.run(ctx.request.query);
|
|
||||||
this.processResponse(ctx.response, response);
|
|
||||||
await next();
|
|
||||||
});
|
|
||||||
|
|
||||||
router.post("/lock", async (ctx, next) => {
|
|
||||||
const response = await this.lockCommand.run();
|
|
||||||
this.processResponse(ctx.response, response);
|
|
||||||
await next();
|
|
||||||
});
|
|
||||||
|
|
||||||
router.post("/unlock", async (ctx, next) => {
|
|
||||||
// Do not allow guessing password location through serve command
|
|
||||||
delete ctx.request.query.passwordFile;
|
|
||||||
delete ctx.request.query.passwordEnv;
|
|
||||||
|
|
||||||
const response = await this.unlockCommand.run(
|
|
||||||
ctx.request.body.password == null ? null : (ctx.request.body.password as string),
|
|
||||||
ctx.request.query,
|
|
||||||
);
|
|
||||||
this.processResponse(ctx.response, response);
|
|
||||||
await next();
|
|
||||||
});
|
|
||||||
|
|
||||||
router.post("/confirm/:object/:id", async (ctx, next) => {
|
|
||||||
if (await this.errorIfLocked(ctx.response)) {
|
|
||||||
await next();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const response = await this.confirmCommand.run(
|
|
||||||
ctx.params.object,
|
|
||||||
ctx.params.id,
|
|
||||||
ctx.request.query,
|
|
||||||
);
|
|
||||||
this.processResponse(ctx.response, response);
|
|
||||||
await next();
|
|
||||||
});
|
|
||||||
|
|
||||||
router.post("/restore/:object/:id", async (ctx, next) => {
|
|
||||||
if (await this.errorIfLocked(ctx.response)) {
|
|
||||||
await next();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const response = await this.restoreCommand.run(ctx.params.object, ctx.params.id);
|
|
||||||
this.processResponse(ctx.response, response);
|
|
||||||
await next();
|
|
||||||
});
|
|
||||||
|
|
||||||
router.post("/move/:id/:organizationId", async (ctx, next) => {
|
|
||||||
if (await this.errorIfLocked(ctx.response)) {
|
|
||||||
await next();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const response = await this.shareCommand.run(
|
|
||||||
ctx.params.id,
|
|
||||||
ctx.params.organizationId,
|
|
||||||
ctx.request.body, // TODO: Check the format of this body for an array of collection ids
|
|
||||||
);
|
|
||||||
this.processResponse(ctx.response, response);
|
|
||||||
await next();
|
|
||||||
});
|
|
||||||
|
|
||||||
router.post("/attachment", koaMulter().single("file"), async (ctx, next) => {
|
|
||||||
if (await this.errorIfLocked(ctx.response)) {
|
|
||||||
await next();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const response = await this.createCommand.run(
|
|
||||||
"attachment",
|
|
||||||
ctx.request.body,
|
|
||||||
ctx.request.query,
|
|
||||||
{
|
|
||||||
fileBuffer: ctx.request.file.buffer,
|
|
||||||
fileName: ctx.request.file.originalname,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
this.processResponse(ctx.response, response);
|
|
||||||
await next();
|
|
||||||
});
|
|
||||||
|
|
||||||
router.post("/send/:id/remove-password", async (ctx, next) => {
|
|
||||||
if (await this.errorIfLocked(ctx.response)) {
|
|
||||||
await next();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const response = await this.sendRemovePasswordCommand.run(ctx.params.id);
|
|
||||||
this.processResponse(ctx.response, response);
|
|
||||||
await next();
|
|
||||||
});
|
|
||||||
|
|
||||||
router.post("/object/:object", async (ctx, next) => {
|
|
||||||
if (await this.errorIfLocked(ctx.response)) {
|
|
||||||
await next();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let response: Response = null;
|
|
||||||
if (ctx.params.object === "send") {
|
|
||||||
response = await this.sendCreateCommand.run(ctx.request.body, ctx.request.query);
|
|
||||||
} else {
|
|
||||||
response = await this.createCommand.run(
|
|
||||||
ctx.params.object,
|
|
||||||
ctx.request.body,
|
|
||||||
ctx.request.query,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
this.processResponse(ctx.response, response);
|
|
||||||
await next();
|
|
||||||
});
|
|
||||||
|
|
||||||
router.put("/object/:object/:id", async (ctx, next) => {
|
|
||||||
if (await this.errorIfLocked(ctx.response)) {
|
|
||||||
await next();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let response: Response = null;
|
|
||||||
if (ctx.params.object === "send") {
|
|
||||||
ctx.request.body.id = ctx.params.id;
|
|
||||||
response = await this.sendEditCommand.run(ctx.request.body, ctx.request.query);
|
|
||||||
} else {
|
|
||||||
response = await this.editCommand.run(
|
|
||||||
ctx.params.object,
|
|
||||||
ctx.params.id,
|
|
||||||
ctx.request.body,
|
|
||||||
ctx.request.query,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
this.processResponse(ctx.response, response);
|
|
||||||
await next();
|
|
||||||
});
|
|
||||||
|
|
||||||
router.get("/object/:object/:id", async (ctx, next) => {
|
|
||||||
if (await this.errorIfLocked(ctx.response)) {
|
|
||||||
await next();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let response: Response = null;
|
|
||||||
if (ctx.params.object === "send") {
|
|
||||||
response = await this.sendGetCommand.run(ctx.params.id, null);
|
|
||||||
} else {
|
|
||||||
response = await this.getCommand.run(ctx.params.object, ctx.params.id, ctx.request.query);
|
|
||||||
}
|
|
||||||
this.processResponse(ctx.response, response);
|
|
||||||
await next();
|
|
||||||
});
|
|
||||||
|
|
||||||
router.delete("/object/:object/:id", async (ctx, next) => {
|
|
||||||
if (await this.errorIfLocked(ctx.response)) {
|
|
||||||
await next();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let response: Response = null;
|
|
||||||
if (ctx.params.object === "send") {
|
|
||||||
response = await this.sendDeleteCommand.run(ctx.params.id);
|
|
||||||
} else {
|
|
||||||
response = await this.deleteCommand.run(
|
|
||||||
ctx.params.object,
|
|
||||||
ctx.params.id,
|
|
||||||
ctx.request.query,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
this.processResponse(ctx.response, response);
|
|
||||||
await next();
|
|
||||||
});
|
|
||||||
|
|
||||||
server
|
server
|
||||||
.use(router.routes())
|
.use(router.routes())
|
||||||
@ -414,31 +57,4 @@ export class ServeCommand {
|
|||||||
this.serviceContainer.logService.info("Listening on " + hostname + ":" + port);
|
this.serviceContainer.logService.info("Listening on " + hostname + ":" + port);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private processResponse(res: koa.Response, commandResponse: Response) {
|
|
||||||
if (!commandResponse.success) {
|
|
||||||
res.status = 400;
|
|
||||||
}
|
|
||||||
if (commandResponse.data instanceof FileResponse) {
|
|
||||||
res.body = commandResponse.data.data;
|
|
||||||
res.attachment(commandResponse.data.fileName);
|
|
||||||
res.set("Content-Type", "application/octet-stream");
|
|
||||||
res.set("Content-Length", commandResponse.data.data.length.toString());
|
|
||||||
} else {
|
|
||||||
res.body = commandResponse;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async errorIfLocked(res: koa.Response) {
|
|
||||||
const authed = await this.serviceContainer.stateService.getIsAuthenticated();
|
|
||||||
if (!authed) {
|
|
||||||
this.processResponse(res, Response.error("You are not logged in."));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (await this.serviceContainer.cryptoService.hasUserKey()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
this.processResponse(res, Response.error("Vault is locked."));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
399
apps/cli/src/oss-serve-configurator.ts
Normal file
399
apps/cli/src/oss-serve-configurator.ts
Normal file
@ -0,0 +1,399 @@
|
|||||||
|
import * as koaMulter from "@koa/multer";
|
||||||
|
import * as koaRouter from "@koa/router";
|
||||||
|
import * as koa from "koa";
|
||||||
|
|
||||||
|
import { ConfirmCommand } from "./admin-console/commands/confirm.command";
|
||||||
|
import { ShareCommand } from "./admin-console/commands/share.command";
|
||||||
|
import { LockCommand } from "./auth/commands/lock.command";
|
||||||
|
import { UnlockCommand } from "./auth/commands/unlock.command";
|
||||||
|
import { EditCommand } from "./commands/edit.command";
|
||||||
|
import { GetCommand } from "./commands/get.command";
|
||||||
|
import { ListCommand } from "./commands/list.command";
|
||||||
|
import { RestoreCommand } from "./commands/restore.command";
|
||||||
|
import { StatusCommand } from "./commands/status.command";
|
||||||
|
import { Response } from "./models/response";
|
||||||
|
import { FileResponse } from "./models/response/file.response";
|
||||||
|
import { ServiceContainer } from "./service-container";
|
||||||
|
import { GenerateCommand } from "./tools/generate.command";
|
||||||
|
import {
|
||||||
|
SendEditCommand,
|
||||||
|
SendCreateCommand,
|
||||||
|
SendDeleteCommand,
|
||||||
|
SendGetCommand,
|
||||||
|
SendListCommand,
|
||||||
|
SendRemovePasswordCommand,
|
||||||
|
} from "./tools/send";
|
||||||
|
import { CreateCommand } from "./vault/create.command";
|
||||||
|
import { DeleteCommand } from "./vault/delete.command";
|
||||||
|
import { SyncCommand } from "./vault/sync.command";
|
||||||
|
|
||||||
|
export class OssServeConfigurator {
|
||||||
|
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 serviceContainer: ServiceContainer) {
|
||||||
|
this.getCommand = new GetCommand(
|
||||||
|
this.serviceContainer.cipherService,
|
||||||
|
this.serviceContainer.folderService,
|
||||||
|
this.serviceContainer.collectionService,
|
||||||
|
this.serviceContainer.totpService,
|
||||||
|
this.serviceContainer.auditService,
|
||||||
|
this.serviceContainer.cryptoService,
|
||||||
|
this.serviceContainer.stateService,
|
||||||
|
this.serviceContainer.searchService,
|
||||||
|
this.serviceContainer.apiService,
|
||||||
|
this.serviceContainer.organizationService,
|
||||||
|
this.serviceContainer.eventCollectionService,
|
||||||
|
this.serviceContainer.billingAccountProfileStateService,
|
||||||
|
);
|
||||||
|
this.listCommand = new ListCommand(
|
||||||
|
this.serviceContainer.cipherService,
|
||||||
|
this.serviceContainer.folderService,
|
||||||
|
this.serviceContainer.collectionService,
|
||||||
|
this.serviceContainer.organizationService,
|
||||||
|
this.serviceContainer.searchService,
|
||||||
|
this.serviceContainer.organizationUserService,
|
||||||
|
this.serviceContainer.apiService,
|
||||||
|
this.serviceContainer.eventCollectionService,
|
||||||
|
);
|
||||||
|
this.createCommand = new CreateCommand(
|
||||||
|
this.serviceContainer.cipherService,
|
||||||
|
this.serviceContainer.folderService,
|
||||||
|
this.serviceContainer.cryptoService,
|
||||||
|
this.serviceContainer.apiService,
|
||||||
|
this.serviceContainer.folderApiService,
|
||||||
|
this.serviceContainer.billingAccountProfileStateService,
|
||||||
|
this.serviceContainer.organizationService,
|
||||||
|
);
|
||||||
|
this.editCommand = new EditCommand(
|
||||||
|
this.serviceContainer.cipherService,
|
||||||
|
this.serviceContainer.folderService,
|
||||||
|
this.serviceContainer.cryptoService,
|
||||||
|
this.serviceContainer.apiService,
|
||||||
|
this.serviceContainer.folderApiService,
|
||||||
|
);
|
||||||
|
this.generateCommand = new GenerateCommand(
|
||||||
|
this.serviceContainer.passwordGenerationService,
|
||||||
|
this.serviceContainer.stateService,
|
||||||
|
);
|
||||||
|
this.syncCommand = new SyncCommand(this.serviceContainer.syncService);
|
||||||
|
this.statusCommand = new StatusCommand(
|
||||||
|
this.serviceContainer.environmentService,
|
||||||
|
this.serviceContainer.syncService,
|
||||||
|
this.serviceContainer.accountService,
|
||||||
|
this.serviceContainer.authService,
|
||||||
|
);
|
||||||
|
this.deleteCommand = new DeleteCommand(
|
||||||
|
this.serviceContainer.cipherService,
|
||||||
|
this.serviceContainer.folderService,
|
||||||
|
this.serviceContainer.apiService,
|
||||||
|
this.serviceContainer.folderApiService,
|
||||||
|
this.serviceContainer.billingAccountProfileStateService,
|
||||||
|
);
|
||||||
|
this.confirmCommand = new ConfirmCommand(
|
||||||
|
this.serviceContainer.apiService,
|
||||||
|
this.serviceContainer.cryptoService,
|
||||||
|
this.serviceContainer.organizationUserService,
|
||||||
|
);
|
||||||
|
this.restoreCommand = new RestoreCommand(this.serviceContainer.cipherService);
|
||||||
|
this.shareCommand = new ShareCommand(this.serviceContainer.cipherService);
|
||||||
|
this.lockCommand = new LockCommand(this.serviceContainer.vaultTimeoutService);
|
||||||
|
this.unlockCommand = new UnlockCommand(
|
||||||
|
this.serviceContainer.accountService,
|
||||||
|
this.serviceContainer.masterPasswordService,
|
||||||
|
this.serviceContainer.cryptoService,
|
||||||
|
this.serviceContainer.stateService,
|
||||||
|
this.serviceContainer.cryptoFunctionService,
|
||||||
|
this.serviceContainer.apiService,
|
||||||
|
this.serviceContainer.logService,
|
||||||
|
this.serviceContainer.keyConnectorService,
|
||||||
|
this.serviceContainer.environmentService,
|
||||||
|
this.serviceContainer.syncService,
|
||||||
|
this.serviceContainer.organizationApiService,
|
||||||
|
async () => await this.serviceContainer.logout(),
|
||||||
|
this.serviceContainer.kdfConfigService,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.sendCreateCommand = new SendCreateCommand(
|
||||||
|
this.serviceContainer.sendService,
|
||||||
|
this.serviceContainer.environmentService,
|
||||||
|
this.serviceContainer.sendApiService,
|
||||||
|
this.serviceContainer.billingAccountProfileStateService,
|
||||||
|
);
|
||||||
|
this.sendDeleteCommand = new SendDeleteCommand(
|
||||||
|
this.serviceContainer.sendService,
|
||||||
|
this.serviceContainer.sendApiService,
|
||||||
|
);
|
||||||
|
this.sendGetCommand = new SendGetCommand(
|
||||||
|
this.serviceContainer.sendService,
|
||||||
|
this.serviceContainer.environmentService,
|
||||||
|
this.serviceContainer.searchService,
|
||||||
|
this.serviceContainer.cryptoService,
|
||||||
|
);
|
||||||
|
this.sendEditCommand = new SendEditCommand(
|
||||||
|
this.serviceContainer.sendService,
|
||||||
|
this.sendGetCommand,
|
||||||
|
this.serviceContainer.sendApiService,
|
||||||
|
this.serviceContainer.billingAccountProfileStateService,
|
||||||
|
);
|
||||||
|
this.sendListCommand = new SendListCommand(
|
||||||
|
this.serviceContainer.sendService,
|
||||||
|
this.serviceContainer.environmentService,
|
||||||
|
this.serviceContainer.searchService,
|
||||||
|
);
|
||||||
|
this.sendRemovePasswordCommand = new SendRemovePasswordCommand(
|
||||||
|
this.serviceContainer.sendService,
|
||||||
|
this.serviceContainer.sendApiService,
|
||||||
|
this.serviceContainer.environmentService,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
configureRouter(router: koaRouter) {
|
||||||
|
router.get("/generate", async (ctx, next) => {
|
||||||
|
const response = await this.generateCommand.run(ctx.request.query);
|
||||||
|
this.processResponse(ctx.response, response);
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get("/status", async (ctx, next) => {
|
||||||
|
const response = await this.statusCommand.run();
|
||||||
|
this.processResponse(ctx.response, response);
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get("/list/object/:object", async (ctx, next) => {
|
||||||
|
if (await this.errorIfLocked(ctx.response)) {
|
||||||
|
await next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let response: Response = null;
|
||||||
|
if (ctx.params.object === "send") {
|
||||||
|
response = await this.sendListCommand.run(ctx.request.query);
|
||||||
|
} else {
|
||||||
|
response = await this.listCommand.run(ctx.params.object, ctx.request.query);
|
||||||
|
}
|
||||||
|
this.processResponse(ctx.response, response);
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get("/send/list", async (ctx, next) => {
|
||||||
|
if (await this.errorIfLocked(ctx.response)) {
|
||||||
|
await next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const response = await this.sendListCommand.run(ctx.request.query);
|
||||||
|
this.processResponse(ctx.response, response);
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/sync", async (ctx, next) => {
|
||||||
|
const response = await this.syncCommand.run(ctx.request.query);
|
||||||
|
this.processResponse(ctx.response, response);
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/lock", async (ctx, next) => {
|
||||||
|
const response = await this.lockCommand.run();
|
||||||
|
this.processResponse(ctx.response, response);
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/unlock", async (ctx, next) => {
|
||||||
|
// Do not allow guessing password location through serve command
|
||||||
|
delete ctx.request.query.passwordFile;
|
||||||
|
delete ctx.request.query.passwordEnv;
|
||||||
|
|
||||||
|
const response = await this.unlockCommand.run(
|
||||||
|
ctx.request.body.password == null ? null : (ctx.request.body.password as string),
|
||||||
|
ctx.request.query,
|
||||||
|
);
|
||||||
|
this.processResponse(ctx.response, response);
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/confirm/:object/:id", async (ctx, next) => {
|
||||||
|
if (await this.errorIfLocked(ctx.response)) {
|
||||||
|
await next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const response = await this.confirmCommand.run(
|
||||||
|
ctx.params.object,
|
||||||
|
ctx.params.id,
|
||||||
|
ctx.request.query,
|
||||||
|
);
|
||||||
|
this.processResponse(ctx.response, response);
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/restore/:object/:id", async (ctx, next) => {
|
||||||
|
if (await this.errorIfLocked(ctx.response)) {
|
||||||
|
await next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const response = await this.restoreCommand.run(ctx.params.object, ctx.params.id);
|
||||||
|
this.processResponse(ctx.response, response);
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/move/:id/:organizationId", async (ctx, next) => {
|
||||||
|
if (await this.errorIfLocked(ctx.response)) {
|
||||||
|
await next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const response = await this.shareCommand.run(
|
||||||
|
ctx.params.id,
|
||||||
|
ctx.params.organizationId,
|
||||||
|
ctx.request.body, // TODO: Check the format of this body for an array of collection ids
|
||||||
|
);
|
||||||
|
this.processResponse(ctx.response, response);
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/attachment", koaMulter().single("file"), async (ctx, next) => {
|
||||||
|
if (await this.errorIfLocked(ctx.response)) {
|
||||||
|
await next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const response = await this.createCommand.run(
|
||||||
|
"attachment",
|
||||||
|
ctx.request.body,
|
||||||
|
ctx.request.query,
|
||||||
|
{
|
||||||
|
fileBuffer: ctx.request.file.buffer,
|
||||||
|
fileName: ctx.request.file.originalname,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
this.processResponse(ctx.response, response);
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/send/:id/remove-password", async (ctx, next) => {
|
||||||
|
if (await this.errorIfLocked(ctx.response)) {
|
||||||
|
await next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const response = await this.sendRemovePasswordCommand.run(ctx.params.id);
|
||||||
|
this.processResponse(ctx.response, response);
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/object/:object", async (ctx, next) => {
|
||||||
|
if (await this.errorIfLocked(ctx.response)) {
|
||||||
|
await next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let response: Response = null;
|
||||||
|
if (ctx.params.object === "send") {
|
||||||
|
response = await this.sendCreateCommand.run(ctx.request.body, ctx.request.query);
|
||||||
|
} else {
|
||||||
|
response = await this.createCommand.run(
|
||||||
|
ctx.params.object,
|
||||||
|
ctx.request.body,
|
||||||
|
ctx.request.query,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.processResponse(ctx.response, response);
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
|
||||||
|
router.put("/object/:object/:id", async (ctx, next) => {
|
||||||
|
if (await this.errorIfLocked(ctx.response)) {
|
||||||
|
await next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let response: Response = null;
|
||||||
|
if (ctx.params.object === "send") {
|
||||||
|
ctx.request.body.id = ctx.params.id;
|
||||||
|
response = await this.sendEditCommand.run(ctx.request.body, ctx.request.query);
|
||||||
|
} else {
|
||||||
|
response = await this.editCommand.run(
|
||||||
|
ctx.params.object,
|
||||||
|
ctx.params.id,
|
||||||
|
ctx.request.body,
|
||||||
|
ctx.request.query,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.processResponse(ctx.response, response);
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get("/object/:object/:id", async (ctx, next) => {
|
||||||
|
if (await this.errorIfLocked(ctx.response)) {
|
||||||
|
await next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let response: Response = null;
|
||||||
|
if (ctx.params.object === "send") {
|
||||||
|
response = await this.sendGetCommand.run(ctx.params.id, null);
|
||||||
|
} else {
|
||||||
|
response = await this.getCommand.run(ctx.params.object, ctx.params.id, ctx.request.query);
|
||||||
|
}
|
||||||
|
this.processResponse(ctx.response, response);
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
|
||||||
|
router.delete("/object/:object/:id", async (ctx, next) => {
|
||||||
|
if (await this.errorIfLocked(ctx.response)) {
|
||||||
|
await next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let response: Response = null;
|
||||||
|
if (ctx.params.object === "send") {
|
||||||
|
response = await this.sendDeleteCommand.run(ctx.params.id);
|
||||||
|
} else {
|
||||||
|
response = await this.deleteCommand.run(
|
||||||
|
ctx.params.object,
|
||||||
|
ctx.params.id,
|
||||||
|
ctx.request.query,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.processResponse(ctx.response, response);
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processResponse(res: koa.Response, commandResponse: Response) {
|
||||||
|
if (!commandResponse.success) {
|
||||||
|
res.status = 400;
|
||||||
|
}
|
||||||
|
if (commandResponse.data instanceof FileResponse) {
|
||||||
|
res.body = commandResponse.data.data;
|
||||||
|
res.attachment(commandResponse.data.fileName);
|
||||||
|
res.set("Content-Type", "application/octet-stream");
|
||||||
|
res.set("Content-Length", commandResponse.data.data.length.toString());
|
||||||
|
} else {
|
||||||
|
res.body = commandResponse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async errorIfLocked(res: koa.Response) {
|
||||||
|
const authed = await this.serviceContainer.stateService.getIsAuthenticated();
|
||||||
|
if (!authed) {
|
||||||
|
this.processResponse(res, Response.error("You are not logged in."));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (await this.serviceContainer.cryptoService.hasUserKey()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.processResponse(res, Response.error("Vault is locked."));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -12,7 +12,6 @@ import { BaseProgram } from "./base-program";
|
|||||||
import { CompletionCommand } from "./commands/completion.command";
|
import { CompletionCommand } from "./commands/completion.command";
|
||||||
import { ConfigCommand } from "./commands/config.command";
|
import { ConfigCommand } from "./commands/config.command";
|
||||||
import { EncodeCommand } from "./commands/encode.command";
|
import { EncodeCommand } from "./commands/encode.command";
|
||||||
import { ServeCommand } from "./commands/serve.command";
|
|
||||||
import { StatusCommand } from "./commands/status.command";
|
import { StatusCommand } from "./commands/status.command";
|
||||||
import { UpdateCommand } from "./commands/update.command";
|
import { UpdateCommand } from "./commands/update.command";
|
||||||
import { Response } from "./models/response";
|
import { Response } from "./models/response";
|
||||||
@ -487,34 +486,5 @@ 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("--hostname <hostname>", "The hostname to bind your API webserver to.")
|
|
||||||
.option("--port <port>", "The port to run your API webserver on.")
|
|
||||||
.option(
|
|
||||||
"--disable-origin-protection",
|
|
||||||
"If set, allows requests with origin header. Warning, this option exists for backwards compatibility reasons and exposes your environment to known CSRF attacks.",
|
|
||||||
)
|
|
||||||
.on("--help", () => {
|
|
||||||
writeLn("\n Notes:");
|
|
||||||
writeLn("");
|
|
||||||
writeLn(" Default hostname is `localhost`.");
|
|
||||||
writeLn(" Use hostname `all` for no hostname binding.");
|
|
||||||
writeLn(" Default port is `8087`.");
|
|
||||||
writeLn("");
|
|
||||||
writeLn(" Examples:");
|
|
||||||
writeLn("");
|
|
||||||
writeLn(" bw serve");
|
|
||||||
writeLn(" bw serve --port 8080");
|
|
||||||
writeLn(" bw serve --hostname bwapi.mydomain.com --port 80");
|
|
||||||
writeLn("", true);
|
|
||||||
})
|
|
||||||
.action(async (cmd) => {
|
|
||||||
await this.exitIfNotAuthed();
|
|
||||||
const command = new ServeCommand(this.serviceContainer);
|
|
||||||
await command.run(cmd);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
49
apps/cli/src/serve.program.ts
Normal file
49
apps/cli/src/serve.program.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import { program } from "commander";
|
||||||
|
|
||||||
|
import { BaseProgram } from "./base-program";
|
||||||
|
import { ServeCommand } from "./commands/serve.command";
|
||||||
|
import { OssServeConfigurator } from "./oss-serve-configurator";
|
||||||
|
import { ServiceContainer } from "./service-container";
|
||||||
|
import { CliUtils } from "./utils";
|
||||||
|
|
||||||
|
const writeLn = CliUtils.writeLn;
|
||||||
|
|
||||||
|
export class ServeProgram extends BaseProgram {
|
||||||
|
constructor(
|
||||||
|
serviceContainer: ServiceContainer,
|
||||||
|
private configurator: OssServeConfigurator,
|
||||||
|
) {
|
||||||
|
super(serviceContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
register() {
|
||||||
|
program
|
||||||
|
.command("serve")
|
||||||
|
.description("Start a RESTful API webserver.")
|
||||||
|
.option("--hostname <hostname>", "The hostname to bind your API webserver to.")
|
||||||
|
.option("--port <port>", "The port to run your API webserver on.")
|
||||||
|
.option(
|
||||||
|
"--disable-origin-protection",
|
||||||
|
"If set, allows requests with origin header. Warning, this option exists for backwards compatibility reasons and exposes your environment to known CSRF attacks.",
|
||||||
|
)
|
||||||
|
.on("--help", () => {
|
||||||
|
writeLn("\n Notes:");
|
||||||
|
writeLn("");
|
||||||
|
writeLn(" Default hostname is `localhost`.");
|
||||||
|
writeLn(" Use hostname `all` for no hostname binding.");
|
||||||
|
writeLn(" Default port is `8087`.");
|
||||||
|
writeLn("");
|
||||||
|
writeLn(" Examples:");
|
||||||
|
writeLn("");
|
||||||
|
writeLn(" bw serve");
|
||||||
|
writeLn(" bw serve --port 8080");
|
||||||
|
writeLn(" bw serve --hostname bwapi.mydomain.com --port 80");
|
||||||
|
writeLn("", true);
|
||||||
|
})
|
||||||
|
.action(async (cmd) => {
|
||||||
|
await this.exitIfNotAuthed();
|
||||||
|
const command = new ServeCommand(this.serviceContainer, this.configurator);
|
||||||
|
await command.run(cmd);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,8 @@ import { MessageResponse } from "@bitwarden/cli/models/response/message.response
|
|||||||
import { OrganizationService } from "@bitwarden/common/admin-console/services/organization/organization.service";
|
import { OrganizationService } from "@bitwarden/common/admin-console/services/organization/organization.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
|
|
||||||
|
import { ServiceContainer } from "../../service-container";
|
||||||
|
|
||||||
export class ApproveAllCommand {
|
export class ApproveAllCommand {
|
||||||
constructor(
|
constructor(
|
||||||
private organizationAuthRequestService: OrganizationAuthRequestService,
|
private organizationAuthRequestService: OrganizationAuthRequestService,
|
||||||
@ -49,4 +51,11 @@ export class ApproveAllCommand {
|
|||||||
return Response.error(e);
|
return Response.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static create(serviceContainer: ServiceContainer) {
|
||||||
|
return new ApproveAllCommand(
|
||||||
|
serviceContainer.organizationAuthRequestService,
|
||||||
|
serviceContainer.organizationService,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
|
|||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
|
|
||||||
import { OrganizationAuthRequestService } from "../../../../bit-common/src/admin-console/auth-requests";
|
import { OrganizationAuthRequestService } from "../../../../bit-common/src/admin-console/auth-requests";
|
||||||
|
import { ServiceContainer } from "../../service-container";
|
||||||
|
|
||||||
export class ApproveCommand {
|
export class ApproveCommand {
|
||||||
constructor(
|
constructor(
|
||||||
@ -51,4 +52,11 @@ export class ApproveCommand {
|
|||||||
return Response.error(e);
|
return Response.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static create(serviceContainer: ServiceContainer) {
|
||||||
|
return new ApproveCommand(
|
||||||
|
serviceContainer.organizationService,
|
||||||
|
serviceContainer.organizationAuthRequestService,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
|
|||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
|
|
||||||
import { OrganizationAuthRequestService } from "../../../../bit-common/src/admin-console/auth-requests";
|
import { OrganizationAuthRequestService } from "../../../../bit-common/src/admin-console/auth-requests";
|
||||||
|
import { ServiceContainer } from "../../service-container";
|
||||||
|
|
||||||
export class DenyAllCommand {
|
export class DenyAllCommand {
|
||||||
constructor(
|
constructor(
|
||||||
@ -46,4 +47,11 @@ export class DenyAllCommand {
|
|||||||
return Response.error(e);
|
return Response.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static create(serviceContainer: ServiceContainer) {
|
||||||
|
return new DenyAllCommand(
|
||||||
|
serviceContainer.organizationService,
|
||||||
|
serviceContainer.organizationAuthRequestService,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
|
|||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
|
|
||||||
import { OrganizationAuthRequestService } from "../../../../bit-common/src/admin-console/auth-requests";
|
import { OrganizationAuthRequestService } from "../../../../bit-common/src/admin-console/auth-requests";
|
||||||
|
import { ServiceContainer } from "../../service-container";
|
||||||
|
|
||||||
export class DenyCommand {
|
export class DenyCommand {
|
||||||
constructor(
|
constructor(
|
||||||
@ -43,4 +44,11 @@ export class DenyCommand {
|
|||||||
return Response.error(e);
|
return Response.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static create(serviceContainer: ServiceContainer) {
|
||||||
|
return new DenyCommand(
|
||||||
|
serviceContainer.organizationService,
|
||||||
|
serviceContainer.organizationAuthRequestService,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,11 +42,7 @@ export class DeviceApprovalProgram extends BaseProgram {
|
|||||||
await this.exitIfFeatureFlagDisabled(FeatureFlag.BulkDeviceApproval);
|
await this.exitIfFeatureFlagDisabled(FeatureFlag.BulkDeviceApproval);
|
||||||
await this.exitIfLocked();
|
await this.exitIfLocked();
|
||||||
|
|
||||||
const cmd = new ListCommand(
|
const cmd = ListCommand.create(this.serviceContainer);
|
||||||
this.serviceContainer.organizationAuthRequestService,
|
|
||||||
this.serviceContainer.organizationService,
|
|
||||||
);
|
|
||||||
|
|
||||||
const response = await cmd.run(options.organizationid);
|
const response = await cmd.run(options.organizationid);
|
||||||
this.processResponse(response);
|
this.processResponse(response);
|
||||||
});
|
});
|
||||||
@ -61,10 +57,7 @@ export class DeviceApprovalProgram extends BaseProgram {
|
|||||||
await this.exitIfFeatureFlagDisabled(FeatureFlag.BulkDeviceApproval);
|
await this.exitIfFeatureFlagDisabled(FeatureFlag.BulkDeviceApproval);
|
||||||
await this.exitIfLocked();
|
await this.exitIfLocked();
|
||||||
|
|
||||||
const cmd = new ApproveCommand(
|
const cmd = ApproveCommand.create(this.serviceContainer);
|
||||||
this.serviceContainer.organizationService,
|
|
||||||
this.serviceContainer.organizationAuthRequestService,
|
|
||||||
);
|
|
||||||
const response = await cmd.run(options.organizationid, id);
|
const response = await cmd.run(options.organizationid, id);
|
||||||
this.processResponse(response);
|
this.processResponse(response);
|
||||||
});
|
});
|
||||||
@ -78,10 +71,7 @@ export class DeviceApprovalProgram extends BaseProgram {
|
|||||||
await this.exitIfFeatureFlagDisabled(FeatureFlag.BulkDeviceApproval);
|
await this.exitIfFeatureFlagDisabled(FeatureFlag.BulkDeviceApproval);
|
||||||
await this.exitIfLocked();
|
await this.exitIfLocked();
|
||||||
|
|
||||||
const cmd = new ApproveAllCommand(
|
const cmd = ApproveAllCommand.create(this.serviceContainer);
|
||||||
this.serviceContainer.organizationAuthRequestService,
|
|
||||||
this.serviceContainer.organizationService,
|
|
||||||
);
|
|
||||||
const response = await cmd.run(options.organizationid);
|
const response = await cmd.run(options.organizationid);
|
||||||
this.processResponse(response);
|
this.processResponse(response);
|
||||||
});
|
});
|
||||||
@ -96,10 +86,7 @@ export class DeviceApprovalProgram extends BaseProgram {
|
|||||||
await this.exitIfFeatureFlagDisabled(FeatureFlag.BulkDeviceApproval);
|
await this.exitIfFeatureFlagDisabled(FeatureFlag.BulkDeviceApproval);
|
||||||
await this.exitIfLocked();
|
await this.exitIfLocked();
|
||||||
|
|
||||||
const cmd = new DenyCommand(
|
const cmd = DenyCommand.create(this.serviceContainer);
|
||||||
this.serviceContainer.organizationService,
|
|
||||||
this.serviceContainer.organizationAuthRequestService,
|
|
||||||
);
|
|
||||||
const response = await cmd.run(options.organizationid, id);
|
const response = await cmd.run(options.organizationid, id);
|
||||||
this.processResponse(response);
|
this.processResponse(response);
|
||||||
});
|
});
|
||||||
@ -113,10 +100,7 @@ export class DeviceApprovalProgram extends BaseProgram {
|
|||||||
await this.exitIfFeatureFlagDisabled(FeatureFlag.BulkDeviceApproval);
|
await this.exitIfFeatureFlagDisabled(FeatureFlag.BulkDeviceApproval);
|
||||||
await this.exitIfLocked();
|
await this.exitIfLocked();
|
||||||
|
|
||||||
const cmd = new DenyAllCommand(
|
const cmd = DenyAllCommand.create(this.serviceContainer);
|
||||||
this.serviceContainer.organizationService,
|
|
||||||
this.serviceContainer.organizationAuthRequestService,
|
|
||||||
);
|
|
||||||
const response = await cmd.run(options.organizationid);
|
const response = await cmd.run(options.organizationid);
|
||||||
this.processResponse(response);
|
this.processResponse(response);
|
||||||
});
|
});
|
||||||
|
@ -1 +1,6 @@
|
|||||||
export { DeviceApprovalProgram } from "./device-approval.program";
|
export * from "./device-approval.program";
|
||||||
|
export * from "./approve.command";
|
||||||
|
export * from "./approve-all.command";
|
||||||
|
export * from "./deny.command";
|
||||||
|
export * from "./deny-all.command";
|
||||||
|
export * from "./list.command";
|
||||||
|
@ -6,6 +6,8 @@ import { ListResponse } from "@bitwarden/cli/models/response/list.response";
|
|||||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
|
|
||||||
|
import { ServiceContainer } from "../../service-container";
|
||||||
|
|
||||||
import { PendingAuthRequestResponse } from "./pending-auth-request.response";
|
import { PendingAuthRequestResponse } from "./pending-auth-request.response";
|
||||||
|
|
||||||
export class ListCommand {
|
export class ListCommand {
|
||||||
@ -39,4 +41,11 @@ export class ListCommand {
|
|||||||
return Response.error(e);
|
return Response.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static create(serviceContainer: ServiceContainer) {
|
||||||
|
return new ListCommand(
|
||||||
|
serviceContainer.organizationAuthRequestService,
|
||||||
|
serviceContainer.organizationService,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
95
bitwarden_license/bit-cli/src/bit-serve-configurator.ts
Normal file
95
bitwarden_license/bit-cli/src/bit-serve-configurator.ts
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
import * as koaRouter from "@koa/router";
|
||||||
|
|
||||||
|
import { OssServeConfigurator } from "@bitwarden/cli/oss-serve-configurator";
|
||||||
|
|
||||||
|
import {
|
||||||
|
ApproveAllCommand,
|
||||||
|
ApproveCommand,
|
||||||
|
DenyAllCommand,
|
||||||
|
DenyCommand,
|
||||||
|
ListCommand,
|
||||||
|
} from "./admin-console/device-approval";
|
||||||
|
import { ServiceContainer } from "./service-container";
|
||||||
|
|
||||||
|
export class BitServeConfigurator extends OssServeConfigurator {
|
||||||
|
constructor(protected override serviceContainer: ServiceContainer) {
|
||||||
|
super(serviceContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
override configureRouter(router: koaRouter): void {
|
||||||
|
// Register OSS endpoints
|
||||||
|
super.configureRouter(router);
|
||||||
|
|
||||||
|
// Register bit endpoints
|
||||||
|
this.serveDeviceApprovals(router);
|
||||||
|
}
|
||||||
|
|
||||||
|
private serveDeviceApprovals(router: koaRouter) {
|
||||||
|
router.get("/device-approval/:organizationId", async (ctx, next) => {
|
||||||
|
if (await this.errorIfLocked(ctx.response)) {
|
||||||
|
await next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await ListCommand.create(this.serviceContainer).run(
|
||||||
|
ctx.params.organizationId,
|
||||||
|
);
|
||||||
|
this.processResponse(ctx.response, response);
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/device-approval/:organizationId/approve-all", async (ctx, next) => {
|
||||||
|
if (await this.errorIfLocked(ctx.response)) {
|
||||||
|
await next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await ApproveAllCommand.create(this.serviceContainer).run(
|
||||||
|
ctx.params.organizationId,
|
||||||
|
);
|
||||||
|
this.processResponse(ctx.response, response);
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/device-approval/:organizationId/approve/:requestId", async (ctx, next) => {
|
||||||
|
if (await this.errorIfLocked(ctx.response)) {
|
||||||
|
await next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await ApproveCommand.create(this.serviceContainer).run(
|
||||||
|
ctx.params.organizationId,
|
||||||
|
ctx.params.requestId,
|
||||||
|
);
|
||||||
|
this.processResponse(ctx.response, response);
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/device-approval/:organizationId/deny-all", async (ctx, next) => {
|
||||||
|
if (await this.errorIfLocked(ctx.response)) {
|
||||||
|
await next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await DenyAllCommand.create(this.serviceContainer).run(
|
||||||
|
ctx.params.organizationId,
|
||||||
|
);
|
||||||
|
this.processResponse(ctx.response, response);
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post("/device-approval/:organizationId/deny/:requestId", async (ctx, next) => {
|
||||||
|
if (await this.errorIfLocked(ctx.response)) {
|
||||||
|
await next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await DenyCommand.create(this.serviceContainer).run(
|
||||||
|
ctx.params.organizationId,
|
||||||
|
ctx.params.requestId,
|
||||||
|
);
|
||||||
|
this.processResponse(ctx.response, response);
|
||||||
|
await next();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,9 @@
|
|||||||
import { program } from "commander";
|
import { program } from "commander";
|
||||||
|
|
||||||
import { registerOssPrograms } from "@bitwarden/cli/register-oss-programs";
|
import { registerOssPrograms } from "@bitwarden/cli/register-oss-programs";
|
||||||
|
import { ServeProgram } from "@bitwarden/cli/serve.program";
|
||||||
|
|
||||||
|
import { BitServeConfigurator } from "./bit-serve-configurator";
|
||||||
import { registerBitPrograms } from "./register-bit-programs";
|
import { registerBitPrograms } from "./register-bit-programs";
|
||||||
import { ServiceContainer } from "./service-container";
|
import { ServiceContainer } from "./service-container";
|
||||||
|
|
||||||
@ -12,6 +14,9 @@ async function main() {
|
|||||||
await registerOssPrograms(serviceContainer);
|
await registerOssPrograms(serviceContainer);
|
||||||
await registerBitPrograms(serviceContainer);
|
await registerBitPrograms(serviceContainer);
|
||||||
|
|
||||||
|
const serveConfigurator = new BitServeConfigurator(serviceContainer);
|
||||||
|
new ServeProgram(serviceContainer, serveConfigurator).register();
|
||||||
|
|
||||||
program.parse(process.argv);
|
program.parse(process.argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user