mirror of
https://github.com/bitwarden/browser
synced 2026-01-28 07:13:29 +00:00
* refactor `canInteract` into a component level usage. - The default service is going to be used in the CLI which won't make use of the UI-related aspects * all nested entities to be imported from the vault * initial add of archive command to the cli * add archive to oss serve * check for deleted cipher when attempting to archive * add searchability/list functionality for archived ciphers * restore an archived cipher * unarchive a cipher when a user is editing it and has lost their premium status * add missing feature flags * re-export only needed services from the vault * add needed await * add prompt when applicable for editing an archived cipher * move cipher archive service into `common/vault` * fix testing code
86 lines
3.0 KiB
TypeScript
86 lines
3.0 KiB
TypeScript
import http from "node:http";
|
|
import net from "node:net";
|
|
|
|
import * as koaRouter from "@koa/router";
|
|
import { OptionValues } from "commander";
|
|
import * as koa from "koa";
|
|
import * as koaBodyParser from "koa-bodyparser";
|
|
import * as koaJson from "koa-json";
|
|
|
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
|
|
|
import { OssServeConfigurator } from "../oss-serve-configurator";
|
|
import { ServiceContainer } from "../service-container/service-container";
|
|
|
|
export class ServeCommand {
|
|
constructor(
|
|
protected serviceContainer: ServiceContainer,
|
|
protected serveConfigurator: OssServeConfigurator,
|
|
) {}
|
|
|
|
async run(options: OptionValues) {
|
|
const protectOrigin = !options.disableOriginProtection;
|
|
const port = options.port || 8087;
|
|
const hostname = options.hostname || "localhost";
|
|
this.serviceContainer.logService.info(
|
|
`Starting server on ${hostname}:${port} with ${
|
|
protectOrigin ? "origin protection" : "no origin protection"
|
|
}`,
|
|
);
|
|
|
|
const server = new koa();
|
|
const router = new koaRouter();
|
|
process.env.BW_SERVE = "true";
|
|
process.env.BW_NOINTERACTION = "true";
|
|
|
|
server
|
|
.use(async (ctx, next) => {
|
|
if (protectOrigin && ctx.headers.origin != undefined) {
|
|
ctx.status = 403;
|
|
this.serviceContainer.logService.warning(
|
|
`Blocking request from "${
|
|
Utils.isNullOrEmpty(ctx.headers.origin)
|
|
? "(Origin header value missing)"
|
|
: ctx.headers.origin
|
|
}"`,
|
|
);
|
|
return;
|
|
}
|
|
await next();
|
|
})
|
|
.use(koaBodyParser())
|
|
.use(koaJson({ pretty: false, param: "pretty" }));
|
|
|
|
await this.serveConfigurator.configureRouter(router);
|
|
|
|
server.use(router.routes()).use(router.allowedMethods());
|
|
|
|
if (hostname.startsWith("fd+connected://")) {
|
|
const fd = parseInt(hostname.slice("fd+connected://".length));
|
|
const httpServer = http.createServer(server.callback());
|
|
const socket = new net.Socket({ fd: fd, readable: true, writable: true });
|
|
// allow idle sockets, incomplete handshakes and slow requests
|
|
httpServer.keepAliveTimeout = 0;
|
|
httpServer.headersTimeout = 0;
|
|
httpServer.timeout = 0;
|
|
socket.pause();
|
|
httpServer.emit("connection", socket);
|
|
socket.resume(); // Let the HTTP parser start reading
|
|
} else if (hostname.startsWith("fd+listening://")) {
|
|
const fd = parseInt(hostname.slice("fd+listening://".length));
|
|
server.listen({ fd }, () => {
|
|
this.serviceContainer.logService.info("Listening on " + hostname);
|
|
});
|
|
} else if (hostname.startsWith("unix://")) {
|
|
const socketPath = hostname.slice("unix://".length);
|
|
server.listen(socketPath, () => {
|
|
this.serviceContainer.logService.info("Listening on " + hostname);
|
|
});
|
|
} else {
|
|
server.listen(port, hostname === "all" ? null : hostname, () => {
|
|
this.serviceContainer.logService.info("Listening on " + hostname + ":" + port);
|
|
});
|
|
}
|
|
}
|
|
}
|