1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-12-20 16:07:45 +01:00
bitwarden-browser/apps/cli/src/oss-serve-configurator.ts
Matt Gibson 9c1e2ebd67
Typescript-strict-plugin (#12235)
* Use typescript-strict-plugin to iteratively turn on strict

* Add strict testing to pipeline

Can be executed locally through either `npm run test:types` for full type checking including spec files, or `npx tsc-strict` for only tsconfig.json included files.

* turn on strict for scripts directory

* Use plugin for all tsconfigs in monorepo

vscode is capable of executing tsc with plugins, but uses the most relevant tsconfig to do so. If the plugin is not a part of that config, it is skipped and developers get no feedback of strict compile time issues. These updates remedy that at the cost of slightly more complex removal of the plugin when the time comes.

* remove plugin from configs that extend one that already has it

* Update workspace settings to honor strict plugin

* Apply strict-plugin to native message test runner

* Update vscode workspace to use root tsc version

* `./node_modules/.bin/update-strict-comments` 🤖

This is a one-time operation. All future files should adhere to strict type checking.

* Add fixme to `ts-strict-ignore` comments

* `update-strict-comments` 🤖

repeated for new merge files
2024-12-09 20:58:50 +01:00

410 lines
14 KiB
TypeScript

// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
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/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.keyService,
this.serviceContainer.encryptService,
this.serviceContainer.searchService,
this.serviceContainer.apiService,
this.serviceContainer.organizationService,
this.serviceContainer.eventCollectionService,
this.serviceContainer.billingAccountProfileStateService,
this.serviceContainer.accountService,
);
this.listCommand = new ListCommand(
this.serviceContainer.cipherService,
this.serviceContainer.folderService,
this.serviceContainer.collectionService,
this.serviceContainer.organizationService,
this.serviceContainer.searchService,
this.serviceContainer.organizationUserApiService,
this.serviceContainer.apiService,
this.serviceContainer.eventCollectionService,
);
this.createCommand = new CreateCommand(
this.serviceContainer.cipherService,
this.serviceContainer.folderService,
this.serviceContainer.keyService,
this.serviceContainer.encryptService,
this.serviceContainer.apiService,
this.serviceContainer.folderApiService,
this.serviceContainer.billingAccountProfileStateService,
this.serviceContainer.organizationService,
this.serviceContainer.accountService,
);
this.editCommand = new EditCommand(
this.serviceContainer.cipherService,
this.serviceContainer.folderService,
this.serviceContainer.keyService,
this.serviceContainer.encryptService,
this.serviceContainer.apiService,
this.serviceContainer.folderApiService,
this.serviceContainer.accountService,
);
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.serviceContainer.cipherAuthorizationService,
);
this.confirmCommand = new ConfirmCommand(
this.serviceContainer.apiService,
this.serviceContainer.keyService,
this.serviceContainer.encryptService,
this.serviceContainer.organizationUserApiService,
);
this.restoreCommand = new RestoreCommand(this.serviceContainer.cipherService);
this.shareCommand = new ShareCommand(
this.serviceContainer.cipherService,
this.serviceContainer.accountService,
);
this.lockCommand = new LockCommand(this.serviceContainer.vaultTimeoutService);
this.unlockCommand = new UnlockCommand(
this.serviceContainer.accountService,
this.serviceContainer.masterPasswordService,
this.serviceContainer.keyService,
this.serviceContainer.userVerificationService,
this.serviceContainer.cryptoFunctionService,
this.serviceContainer.logService,
this.serviceContainer.keyConnectorService,
this.serviceContainer.environmentService,
this.serviceContainer.syncService,
this.serviceContainer.organizationApiService,
async () => await this.serviceContainer.logout(),
);
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.encryptService,
);
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.keyService.hasUserKey()) {
return false;
}
this.processResponse(res, Response.error("Vault is locked."));
return true;
}
}