diff --git a/src/common/vars.ts b/src/common/vars.ts
index 03d3f1c63d..ef39088258 100644
--- a/src/common/vars.ts
+++ b/src/common/vars.ts
@@ -30,11 +30,11 @@ export const webpackDevServerPort = 9009;
// Special runtime paths
defineGlobal("__static", {
get() {
- if (isDevelopment) {
- return path.resolve(contextDir, "static");
- }
+ const root = isDevelopment
+ ? contextDir
+ : (process.resourcesPath ?? contextDir);
- return path.resolve(process.resourcesPath, "static");
+ return path.resolve(root, "static");
}
});
diff --git a/src/main/__test__/router.test.ts b/src/main/__test__/router.test.ts
index 8c2fa9c822..393f2a035b 100644
--- a/src/main/__test__/router.test.ts
+++ b/src/main/__test__/router.test.ts
@@ -1,40 +1,42 @@
import { Router } from "../router";
-const staticRoot = __dirname;
-
-class TestRouter extends Router {
- protected resolveStaticRootPath() {
- return staticRoot;
- }
-}
-
describe("Router", () => {
it("blocks path traversal attacks", async () => {
- const router = new TestRouter();
- const res = {
+ const response: any = {
statusCode: 200,
end: jest.fn()
};
- await router.handleStaticFile("../index.ts", res as any, {} as any, 0);
+ await (Router as any).handleStaticFile({
+ params: {
+ path: "../index.ts",
+ },
+ response,
+ raw: {},
+ });
- expect(res.statusCode).toEqual(404);
+ expect(response.statusCode).toEqual(404);
});
it("serves files under static root", async () => {
- const router = new TestRouter();
- const res = {
+ const response: any = {
statusCode: 200,
write: jest.fn(),
setHeader: jest.fn(),
end: jest.fn()
};
- const req = {
+ const req: any = {
url: ""
};
- await router.handleStaticFile("router.test.ts", res as any, req as any, 0);
+ await (Router as any).handleStaticFile({
+ params: {
+ path: "router.test.ts",
+ },
+ response,
+ raw: { req },
+ });
- expect(res.statusCode).toEqual(200);
+ expect(response.statusCode).toEqual(200);
});
});
diff --git a/src/main/lens-api.ts b/src/main/lens-api.ts
deleted file mode 100644
index fafeffce91..0000000000
--- a/src/main/lens-api.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import http from "http";
-
-export abstract class LensApi {
- protected respondJson(res: http.ServerResponse, content: {}, status = 200) {
- this.respond(res, JSON.stringify(content), "application/json", status);
- }
-
- protected respondText(res: http.ServerResponse, content: string, status = 200) {
- this.respond(res, content, "text/plain", status);
- }
-
- protected respond(res: http.ServerResponse, content: string, contentType: string, status = 200) {
- res.setHeader("Content-Type", contentType);
- res.statusCode = status;
- res.end(content);
- }
-}
diff --git a/src/main/router.ts b/src/main/router.ts
index 6fa14e1444..5a53eac9df 100644
--- a/src/main/router.ts
+++ b/src/main/router.ts
@@ -5,7 +5,7 @@ import path from "path";
import { readFile } from "fs-extra";
import { Cluster } from "./cluster";
import { apiPrefix, appName, publicPath, isDevelopment, webpackDevServerPort } from "../common/vars";
-import { helmRoute, kubeconfigRoute, metricsRoute, portForwardRoute, resourceApplierRoute, versionRoute } from "./routes";
+import { HelmApiRoute, KubeconfigRoute, MetricsRoute, PortForwardRoute, ResourceApplierApiRoute, VersionRoute } from "./routes";
import logger from "./logger";
export interface RouterRequestOpts {
@@ -38,18 +38,29 @@ export interface LensApiRequest
{
}
}
+function getMimeType(filename: string) {
+ const mimeTypes: Record = {
+ html: "text/html",
+ txt: "text/plain",
+ css: "text/css",
+ gif: "image/gif",
+ jpg: "image/jpeg",
+ png: "image/png",
+ svg: "image/svg+xml",
+ js: "application/javascript",
+ woff2: "font/woff2",
+ ttf: "font/ttf"
+ };
+
+ return mimeTypes[path.extname(filename).slice(1)] || "text/plain";
+}
+
export class Router {
- protected router: any;
- protected staticRootPath: string;
+ protected router = new Call.Router();
+ protected static rootPath = path.resolve(__static);
public constructor() {
- this.router = new Call.Router();
this.addRoutes();
- this.staticRootPath = this.resolveStaticRootPath();
- }
-
- protected resolveStaticRootPath() {
- return path.resolve(__static);
}
public async route(cluster: Cluster, req: http.IncomingMessage, res: http.ServerResponse): Promise {
@@ -90,97 +101,80 @@ export class Router {
};
}
- protected getMimeType(filename: string) {
- const mimeTypes: Record = {
- html: "text/html",
- txt: "text/plain",
- css: "text/css",
- gif: "image/gif",
- jpg: "image/jpeg",
- png: "image/png",
- svg: "image/svg+xml",
- js: "application/javascript",
- woff2: "font/woff2",
- ttf: "font/ttf"
- };
+ protected static async handleStaticFile({ params, response, raw: { req } }: LensApiRequest): Promise {
+ let filePath = params.path;
- return mimeTypes[path.extname(filename).slice(1)] || "text/plain";
- }
+ for (let retryCount = 0; retryCount < 5; retryCount += 1) {
+ const asset = path.join(Router.rootPath, filePath);
+ const normalizedFilePath = path.resolve(asset);
- async handleStaticFile(filePath: string, res: http.ServerResponse, req: http.IncomingMessage, retryCount = 0) {
- const asset = path.join(this.staticRootPath, filePath);
- const normalizedFilePath = path.resolve(asset);
+ if (!normalizedFilePath.startsWith(Router.rootPath)) {
+ response.statusCode = 404;
- if (!normalizedFilePath.startsWith(this.staticRootPath)) {
- res.statusCode = 404;
- res.end();
+ return response.end();
+ }
- return;
+ try {
+ const filename = path.basename(req.url);
+ // redirect requests to [appName].js, [appName].html /sockjs-node/ to webpack-dev-server (for hot-reload support)
+ const toWebpackDevServer = filename.includes(appName) || filename.includes("hot-update") || req.url.includes("sockjs-node");
+
+ if (isDevelopment && toWebpackDevServer) {
+ const redirectLocation = `http://localhost:${webpackDevServerPort}${req.url}`;
+
+ response.statusCode = 307;
+ response.setHeader("Location", redirectLocation);
+
+ return response.end();
+ }
+
+ const data = await readFile(asset);
+
+ response.setHeader("Content-Type", getMimeType(asset));
+ response.write(data);
+ response.end();
+ } catch (err) {
+ if (retryCount > 5) {
+ logger.error("handleStaticFile:", err.toString());
+ response.statusCode = 404;
+
+ return response.end();
+ }
+
+ filePath = `${publicPath}/${appName}.html`;
+ }
}
- try {
- const filename = path.basename(req.url);
- // redirect requests to [appName].js, [appName].html /sockjs-node/ to webpack-dev-server (for hot-reload support)
- const toWebpackDevServer = filename.includes(appName) || filename.includes("hot-update") || req.url.includes("sockjs-node");
-
- if (isDevelopment && toWebpackDevServer) {
- const redirectLocation = `http://localhost:${webpackDevServerPort}${req.url}`;
-
- res.statusCode = 307;
- res.setHeader("Location", redirectLocation);
- res.end();
-
- return;
- }
- const data = await readFile(asset);
-
- res.setHeader("Content-Type", this.getMimeType(asset));
- res.write(data);
- res.end();
- } catch (err) {
- if (retryCount > 5) {
- logger.error("handleStaticFile:", err.toString());
- res.statusCode = 404;
- res.end();
-
- return;
- }
- this.handleStaticFile(`${publicPath}/${appName}.html`, res, req, Math.max(retryCount, 0) + 1);
- }
}
protected addRoutes() {
// Static assets
- this.router.add(
- { method: "get", path: "/{path*}" },
- ({ params, response, raw: { req } }: LensApiRequest) => {
- this.handleStaticFile(params.path, response, req);
- });
+ this.router.add({ method: "get", path: "/{path*}" }, Router.handleStaticFile);
- this.router.add({ method: "get", path: "/version"}, versionRoute.getVersion.bind(versionRoute));
- this.router.add({ method: "get", path: `${apiPrefix}/kubeconfig/service-account/{namespace}/{account}` }, kubeconfigRoute.routeServiceAccountRoute.bind(kubeconfigRoute));
+ this.router.add({ method: "get", path: "/version" }, VersionRoute.getVersion);
+ this.router.add({ method: "get", path: `${apiPrefix}/kubeconfig/service-account/{namespace}/{account}` }, KubeconfigRoute.routeServiceAccountRoute);
// Metrics API
- this.router.add({ method: "post", path: `${apiPrefix}/metrics` }, metricsRoute.routeMetrics.bind(metricsRoute));
+ this.router.add({ method: "post", path: `${apiPrefix}/metrics` }, MetricsRoute.routeMetrics);
// Port-forward API
- this.router.add({ method: "post", path: `${apiPrefix}/pods/{namespace}/{resourceType}/{resourceName}/port-forward/{port}` }, portForwardRoute.routePortForward.bind(portForwardRoute));
+ this.router.add({ method: "post", path: `${apiPrefix}/pods/{namespace}/{resourceType}/{resourceName}/port-forward/{port}` }, PortForwardRoute.routePortForward);
// Helm API
- this.router.add({ method: "get", path: `${apiPrefix}/v2/charts` }, helmRoute.listCharts.bind(helmRoute));
- this.router.add({ method: "get", path: `${apiPrefix}/v2/charts/{repo}/{chart}` }, helmRoute.getChart.bind(helmRoute));
- this.router.add({ method: "get", path: `${apiPrefix}/v2/charts/{repo}/{chart}/values` }, helmRoute.getChartValues.bind(helmRoute));
+ this.router.add({ method: "get", path: `${apiPrefix}/v2/charts` }, HelmApiRoute.listCharts);
+ this.router.add({ method: "get", path: `${apiPrefix}/v2/charts/{repo}/{chart}` }, HelmApiRoute.getChart);
+ this.router.add({ method: "get", path: `${apiPrefix}/v2/charts/{repo}/{chart}/values` }, HelmApiRoute.getChartValues);
- this.router.add({ method: "post", path: `${apiPrefix}/v2/releases` }, helmRoute.installChart.bind(helmRoute));
- this.router.add({ method: `put`, path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.updateRelease.bind(helmRoute));
- this.router.add({ method: `put`, path: `${apiPrefix}/v2/releases/{namespace}/{release}/rollback` }, helmRoute.rollbackRelease.bind(helmRoute));
- this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace?}` }, helmRoute.listReleases.bind(helmRoute));
- this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.getRelease.bind(helmRoute));
- this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}/values` }, helmRoute.getReleaseValues.bind(helmRoute));
- this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}/history` }, helmRoute.getReleaseHistory.bind(helmRoute));
- this.router.add({ method: "delete", path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.deleteRelease.bind(helmRoute));
+ this.router.add({ method: "post", path: `${apiPrefix}/v2/releases` }, HelmApiRoute.installChart);
+ this.router.add({ method: `put`, path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, HelmApiRoute.updateRelease);
+ this.router.add({ method: `put`, path: `${apiPrefix}/v2/releases/{namespace}/{release}/rollback` }, HelmApiRoute.rollbackRelease);
+ this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace?}` }, HelmApiRoute.listReleases);
+ this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, HelmApiRoute.getRelease);
+ this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}/values` }, HelmApiRoute.getReleaseValues);
+ this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}/history` }, HelmApiRoute.getReleaseHistory);
+ this.router.add({ method: "delete", path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, HelmApiRoute.deleteRelease);
// Resource Applier API
- this.router.add({ method: "post", path: `${apiPrefix}/stack` }, resourceApplierRoute.applyResource.bind(resourceApplierRoute));
+ this.router.add({ method: "post", path: `${apiPrefix}/stack` }, ResourceApplierApiRoute.applyResource);
}
}
diff --git a/src/main/routes/helm-route.ts b/src/main/routes/helm-route.ts
index e530e2edf0..89e229b626 100644
--- a/src/main/routes/helm-route.ts
+++ b/src/main/routes/helm-route.ts
@@ -1,143 +1,141 @@
import { LensApiRequest } from "../router";
import { helmService } from "../helm/helm-service";
-import { LensApi } from "../lens-api";
+import { respondJson, respondText } from "../utils/http-responses";
import logger from "../logger";
-class HelmApiRoute extends LensApi {
- public async listCharts(request: LensApiRequest) {
+export class HelmApiRoute {
+ static async listCharts(request: LensApiRequest) {
const { response } = request;
const charts = await helmService.listCharts();
- this.respondJson(response, charts);
+ respondJson(response, charts);
}
- public async getChart(request: LensApiRequest) {
+ static async getChart(request: LensApiRequest) {
const { params, query, response } = request;
try {
const chart = await helmService.getChart(params.repo, params.chart, query.get("version"));
- this.respondJson(response, chart);
+ respondJson(response, chart);
} catch (error) {
- this.respondText(response, error, 422);
+ respondText(response, error, 422);
}
}
- public async getChartValues(request: LensApiRequest) {
+ static async getChartValues(request: LensApiRequest) {
const { params, query, response } = request;
try {
const values = await helmService.getChartValues(params.repo, params.chart, query.get("version"));
- this.respondJson(response, values);
+ respondJson(response, values);
} catch (error) {
- this.respondText(response, error, 422);
+ respondText(response, error, 422);
}
}
- public async installChart(request: LensApiRequest) {
+ static async installChart(request: LensApiRequest) {
const { payload, cluster, response } = request;
try {
const result = await helmService.installChart(cluster, payload);
- this.respondJson(response, result, 201);
+ respondJson(response, result, 201);
} catch (error) {
logger.debug(error);
- this.respondText(response, error, 422);
+ respondText(response, error, 422);
}
}
- public async updateRelease(request: LensApiRequest) {
+ static async updateRelease(request: LensApiRequest) {
const { cluster, params, payload, response } = request;
try {
const result = await helmService.updateRelease(cluster, params.release, params.namespace, payload );
- this.respondJson(response, result);
+ respondJson(response, result);
} catch (error) {
logger.debug(error);
- this.respondText(response, error, 422);
+ respondText(response, error, 422);
}
}
- public async rollbackRelease(request: LensApiRequest) {
+ static async rollbackRelease(request: LensApiRequest) {
const { cluster, params, payload, response } = request;
try {
const result = await helmService.rollback(cluster, params.release, params.namespace, payload.revision);
- this.respondJson(response, result);
+ respondJson(response, result);
} catch (error) {
logger.debug(error);
- this.respondText(response, error, 422);
+ respondText(response, error, 422);
}
}
- public async listReleases(request: LensApiRequest) {
+ static async listReleases(request: LensApiRequest) {
const { cluster, params, response } = request;
try {
const result = await helmService.listReleases(cluster, params.namespace);
- this.respondJson(response, result);
+ respondJson(response, result);
} catch(error) {
logger.debug(error);
- this.respondText(response, error, 422);
+ respondText(response, error, 422);
}
}
- public async getRelease(request: LensApiRequest) {
+ static async getRelease(request: LensApiRequest) {
const { cluster, params, response } = request;
try {
const result = await helmService.getRelease(cluster, params.release, params.namespace);
- this.respondJson(response, result);
+ respondJson(response, result);
} catch (error) {
logger.debug(error);
- this.respondText(response, error, 422);
+ respondText(response, error, 422);
}
}
- public async getReleaseValues(request: LensApiRequest) {
+ static async getReleaseValues(request: LensApiRequest) {
const { cluster, params, response, query } = request;
try {
const result = await helmService.getReleaseValues(cluster, params.release, params.namespace, query.has("all"));
- this.respondText(response, result);
+ respondText(response, result);
} catch (error) {
logger.debug(error);
- this.respondText(response, error, 422);
+ respondText(response, error, 422);
}
}
- public async getReleaseHistory(request: LensApiRequest) {
+ static async getReleaseHistory(request: LensApiRequest) {
const { cluster, params, response } = request;
try {
const result = await helmService.getReleaseHistory(cluster, params.release, params.namespace);
- this.respondJson(response, result);
+ respondJson(response, result);
} catch (error) {
logger.debug(error);
- this.respondText(response, error, 422);
+ respondText(response, error, 422);
}
}
- public async deleteRelease(request: LensApiRequest) {
+ static async deleteRelease(request: LensApiRequest) {
const { cluster, params, response } = request;
try {
const result = await helmService.deleteRelease(cluster, params.release, params.namespace);
- this.respondJson(response, result);
+ respondJson(response, result);
} catch (error) {
logger.debug(error);
- this.respondText(response, error, 422);
+ respondText(response, error, 422);
}
}
}
-
-export const helmRoute = new HelmApiRoute();
diff --git a/src/main/routes/kubeconfig-route.ts b/src/main/routes/kubeconfig-route.ts
index bad5ecd57a..d2e3941a29 100644
--- a/src/main/routes/kubeconfig-route.ts
+++ b/src/main/routes/kubeconfig-route.ts
@@ -1,5 +1,5 @@
import { LensApiRequest } from "../router";
-import { LensApi } from "../lens-api";
+import { respondJson } from "../utils/http-responses";
import { Cluster } from "../cluster";
import { CoreV1Api, V1Secret } from "@kubernetes/client-node";
@@ -40,9 +40,8 @@ function generateKubeConfig(username: string, secret: V1Secret, cluster: Cluster
};
}
-class KubeconfigRoute extends LensApi {
-
- public async routeServiceAccountRoute(request: LensApiRequest) {
+export class KubeconfigRoute {
+ static async routeServiceAccountRoute(request: LensApiRequest) {
const { params, response, cluster} = request;
const client = (await cluster.getProxyKubeconfig()).makeApiClient(CoreV1Api);
const secretList = await client.listNamespacedSecret(params.namespace);
@@ -53,8 +52,6 @@ class KubeconfigRoute extends LensApi {
});
const data = generateKubeConfig(params.account, secret, cluster);
- this.respondJson(response, data);
+ respondJson(response, data);
}
}
-
-export const kubeconfigRoute = new KubeconfigRoute();
diff --git a/src/main/routes/metrics-route.ts b/src/main/routes/metrics-route.ts
index b6fbdadb61..0dec1fc1ff 100644
--- a/src/main/routes/metrics-route.ts
+++ b/src/main/routes/metrics-route.ts
@@ -1,6 +1,6 @@
import _ from "lodash";
import { LensApiRequest } from "../router";
-import { LensApi } from "../lens-api";
+import { respondJson } from "../utils/http-responses";
import { Cluster, ClusterMetadataKey } from "../cluster";
import { ClusterPrometheusMetadata } from "../../common/cluster-store";
import logger from "../logger";
@@ -41,8 +41,8 @@ async function loadMetrics(promQueries: string[], cluster: Cluster, prometheusPa
return Promise.all(queries.map(loadMetric));
}
-class MetricsRoute extends LensApi {
- async routeMetrics({ response, cluster, payload, query }: LensApiRequest) {
+export class MetricsRoute {
+ static async routeMetrics({ response, cluster, payload, query }: LensApiRequest) {
const queryParams: IMetricsQuery = Object.fromEntries(query.entries());
const prometheusMetadata: ClusterPrometheusMetadata = {};
@@ -57,20 +57,19 @@ class MetricsRoute extends LensApi {
if (!prometheusPath) {
prometheusMetadata.success = false;
- this.respondJson(response, {});
- return;
+ return respondJson(response, {});
}
// return data in same structure as query
if (typeof payload === "string") {
const [data] = await loadMetrics([payload], cluster, prometheusPath, queryParams);
- this.respondJson(response, data);
+ respondJson(response, data);
} else if (Array.isArray(payload)) {
const data = await loadMetrics(payload, cluster, prometheusPath, queryParams);
- this.respondJson(response, data);
+ respondJson(response, data);
} else {
const queries = Object.entries(payload).map(([queryName, queryOpts]) => (
(prometheusProvider.getQueries(queryOpts) as Record)[queryName]
@@ -78,16 +77,14 @@ class MetricsRoute extends LensApi {
const result = await loadMetrics(queries, cluster, prometheusPath, queryParams);
const data = Object.fromEntries(Object.keys(payload).map((metricName, i) => [metricName, result[i]]));
- this.respondJson(response, data);
+ respondJson(response, data);
}
prometheusMetadata.success = true;
} catch {
prometheusMetadata.success = false;
- this.respondJson(response, {});
+ respondJson(response, {});
} finally {
cluster.metadata[ClusterMetadataKey.PROMETHEUS] = prometheusMetadata;
}
}
}
-
-export const metricsRoute = new MetricsRoute();
diff --git a/src/main/routes/port-forward-route.ts b/src/main/routes/port-forward-route.ts
index 6edd81e537..ca8be52dcd 100644
--- a/src/main/routes/port-forward-route.ts
+++ b/src/main/routes/port-forward-route.ts
@@ -1,11 +1,11 @@
import { LensApiRequest } from "../router";
-import { LensApi } from "../lens-api";
import { spawn, ChildProcessWithoutNullStreams } from "child_process";
import { Kubectl } from "../kubectl";
import { shell } from "electron";
import * as tcpPortUsed from "tcp-port-used";
import logger from "../logger";
import { getPortFrom } from "../utils/get-port";
+import { respondJson } from "../utils/http-responses";
interface PortForwardArgs {
clusterId: string;
@@ -95,9 +95,8 @@ class PortForward {
}
}
-class PortForwardRoute extends LensApi {
-
- public async routePortForward(request: LensApiRequest) {
+export class PortForwardRoute {
+ static async routePortForward(request: LensApiRequest) {
const { params, response, cluster} = request;
const { namespace, port, resourceType, resourceName } = params;
let portForward = PortForward.getPortforward({
@@ -117,18 +116,14 @@ class PortForwardRoute extends LensApi {
const started = await portForward.start();
if (!started) {
- this.respondJson(response, {
+ return respondJson(response, {
message: "Failed to open port-forward"
}, 400);
-
- return;
}
}
portForward.open();
- this.respondJson(response, {});
+ respondJson(response, {});
}
}
-
-export const portForwardRoute = new PortForwardRoute();
diff --git a/src/main/routes/resource-applier-route.ts b/src/main/routes/resource-applier-route.ts
index 1e532dde46..6183ece931 100644
--- a/src/main/routes/resource-applier-route.ts
+++ b/src/main/routes/resource-applier-route.ts
@@ -1,19 +1,17 @@
import { LensApiRequest } from "../router";
-import { LensApi } from "../lens-api";
+import { respondJson, respondText } from "../utils/http-responses";
import { ResourceApplier } from "../resource-applier";
-class ResourceApplierApiRoute extends LensApi {
- public async applyResource(request: LensApiRequest) {
+export class ResourceApplierApiRoute {
+ static async applyResource(request: LensApiRequest) {
const { response, cluster, payload } = request;
try {
const resource = await new ResourceApplier(cluster).apply(payload);
- this.respondJson(response, [resource], 200);
+ respondJson(response, [resource], 200);
} catch (error) {
- this.respondText(response, error, 422);
+ respondText(response, error, 422);
}
}
}
-
-export const resourceApplierRoute = new ResourceApplierApiRoute();
diff --git a/src/main/routes/version-route.ts b/src/main/routes/version-route.ts
index 81ada9eca7..8eaa96ca17 100644
--- a/src/main/routes/version-route.ts
+++ b/src/main/routes/version-route.ts
@@ -1,13 +1,11 @@
import { LensApiRequest } from "../router";
-import { LensApi } from "../lens-api";
+import { respondJson } from "../utils/http-responses";
import { getAppVersion } from "../../common/utils";
-class VersionRoute extends LensApi {
- public async getVersion(request: LensApiRequest) {
+export class VersionRoute {
+ static async getVersion(request: LensApiRequest) {
const { response } = request;
- this.respondJson(response, { version: getAppVersion()}, 200);
+ respondJson(response, { version: getAppVersion()}, 200);
}
}
-
-export const versionRoute = new VersionRoute();
diff --git a/src/main/utils/http-responses.ts b/src/main/utils/http-responses.ts
new file mode 100644
index 0000000000..d41b124fb6
--- /dev/null
+++ b/src/main/utils/http-responses.ts
@@ -0,0 +1,15 @@
+import http from "http";
+
+export function respondJson(res: http.ServerResponse, content: any, status = 200) {
+ respond(res, JSON.stringify(content), "application/json", status);
+}
+
+export function respondText(res: http.ServerResponse, content: string, status = 200) {
+ respond(res, content, "text/plain", status);
+}
+
+export function respond(res: http.ServerResponse, content: string, contentType: string, status = 200) {
+ res.setHeader("Content-Type", contentType);
+ res.statusCode = status;
+ res.end(content);
+}