mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
200 lines
5.5 KiB
TypeScript
200 lines
5.5 KiB
TypeScript
import logger from "./Logger";
|
|
import Dictionary from "../../Types/Dictionary";
|
|
import GenericFunction from "../../Types/GenericFunction";
|
|
import { JSONObject, JSONObjectOrArray } from "../../Types/JSON";
|
|
import JSONWebTokenData from "../../Types/JsonWebTokenData";
|
|
import ObjectID from "../../Types/ObjectID";
|
|
import {
|
|
UserGlobalAccessPermission,
|
|
UserTenantAccessPermission,
|
|
} from "../../Types/Permission";
|
|
import Port from "../../Types/Port";
|
|
import UserType from "../../Types/UserType";
|
|
import "ejs";
|
|
import express from "express";
|
|
import { Server, createServer } from "http";
|
|
|
|
export type RequestHandler = express.RequestHandler;
|
|
export type NextFunction = express.NextFunction;
|
|
|
|
export const ExpressStatic: GenericFunction = express.static;
|
|
export const ExpressJson: GenericFunction = express.json;
|
|
export const ExpressUrlEncoded: GenericFunction = express.urlencoded;
|
|
export const ExpressRaw: GenericFunction = express.raw;
|
|
|
|
export type ProbeRequest = {
|
|
id: ObjectID;
|
|
};
|
|
|
|
export type ExpressRequest = express.Request;
|
|
export type ExpressResponse = express.Response;
|
|
export type ExpressApplication = express.Application;
|
|
export type ExpressRouter = express.Router;
|
|
|
|
export interface OneUptimeRequest extends express.Request {
|
|
bearerTokenData?: JSONObject | string | undefined; // if bearer token is passed then this is populated.
|
|
probe?: ProbeRequest;
|
|
userType?: UserType;
|
|
userAuthorization?: JSONWebTokenData;
|
|
tenantId?: ObjectID;
|
|
userGlobalAccessPermission?: UserGlobalAccessPermission;
|
|
userTenantAccessPermission?: Dictionary<UserTenantAccessPermission>; // tenantId <-> UserTenantAccessPermission;
|
|
rawFormUrlEncodedBody?: string;
|
|
rawBody?: string; // Raw body for signature verification (JSON or URL-encoded)
|
|
}
|
|
|
|
export interface OneUptimeResponse extends express.Response {
|
|
logBody: JSONObjectOrArray;
|
|
}
|
|
|
|
export type RequestDeviceInfo = {
|
|
deviceName?: string;
|
|
deviceType?: string;
|
|
deviceOS?: string;
|
|
deviceBrowser?: string;
|
|
};
|
|
|
|
type HeaderValue = string | Array<string> | null | undefined;
|
|
|
|
class Express {
|
|
private static app: express.Application;
|
|
private static httpServer: Server;
|
|
|
|
public static getRouter(): express.Router {
|
|
return express.Router();
|
|
}
|
|
|
|
public static setupExpress(): void {
|
|
this.app = express();
|
|
}
|
|
|
|
public static getHttpServer(): Server {
|
|
return this.httpServer;
|
|
}
|
|
|
|
public static getExpressApp(): express.Application {
|
|
if (!this.app) {
|
|
this.setupExpress();
|
|
}
|
|
|
|
return this.app;
|
|
}
|
|
|
|
public static async launchApplication(
|
|
appName: string,
|
|
port?: Port,
|
|
): Promise<express.Application> {
|
|
if (!this.app) {
|
|
this.setupExpress();
|
|
}
|
|
|
|
if (!this.httpServer) {
|
|
this.httpServer = createServer(this.app);
|
|
}
|
|
|
|
type ResolveFunction = (app: express.Application) => void;
|
|
|
|
return new Promise<express.Application>((resolve: ResolveFunction) => {
|
|
this.httpServer.listen(port?.toNumber() || this.app.get("port"), () => {
|
|
logger.debug(
|
|
`${appName} server started on port: ${port?.toNumber() || this.app.get("port")}`,
|
|
);
|
|
return resolve(this.app);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
export default Express;
|
|
|
|
export const headerValueToString: (value: HeaderValue) => string | undefined = (
|
|
value: HeaderValue,
|
|
): string | undefined => {
|
|
if (Array.isArray(value)) {
|
|
return value.length > 0 ? value[0] : undefined;
|
|
}
|
|
|
|
if (typeof value === "string" && value.trim().length > 0) {
|
|
return value.trim();
|
|
}
|
|
|
|
return undefined;
|
|
};
|
|
|
|
export const extractDeviceInfo: (req: ExpressRequest) => RequestDeviceInfo = (
|
|
req: ExpressRequest,
|
|
): RequestDeviceInfo => {
|
|
const body: JSONObject = (req.body || {}) as JSONObject;
|
|
const data: JSONObject = (body["data"] as JSONObject) || {};
|
|
|
|
const getValue: (key: string) => string | undefined = (
|
|
key: string,
|
|
): string | undefined => {
|
|
const headerKey: string = key.toLowerCase();
|
|
const camelKey: string = headerKey
|
|
.split("-")
|
|
.map((part: string, index: number) => {
|
|
if (index === 0) {
|
|
return part;
|
|
}
|
|
|
|
return part.charAt(0).toUpperCase() + part.slice(1);
|
|
})
|
|
.join("");
|
|
|
|
return (
|
|
headerValueToString(req.headers[`x-${headerKey}`]) ||
|
|
headerValueToString(body[camelKey] as HeaderValue) ||
|
|
headerValueToString(data[camelKey] as HeaderValue) ||
|
|
headerValueToString(body[key] as HeaderValue) ||
|
|
headerValueToString(data[key] as HeaderValue)
|
|
);
|
|
};
|
|
|
|
const result: RequestDeviceInfo = {};
|
|
|
|
const deviceName: string | undefined = getValue("device-name");
|
|
if (deviceName) {
|
|
result.deviceName = deviceName;
|
|
}
|
|
|
|
const deviceType: string | undefined = getValue("device-type");
|
|
if (deviceType) {
|
|
result.deviceType = deviceType;
|
|
}
|
|
|
|
const deviceOS: string | undefined = getValue("device-os");
|
|
if (deviceOS) {
|
|
result.deviceOS = deviceOS;
|
|
}
|
|
|
|
const deviceBrowser: string | undefined = getValue("device-browser");
|
|
if (deviceBrowser) {
|
|
result.deviceBrowser = deviceBrowser;
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
export const getClientIp: (req: ExpressRequest) => string | undefined = (
|
|
req: ExpressRequest,
|
|
): string | undefined => {
|
|
const forwarded: string | Array<string> | undefined = req.headers[
|
|
"x-forwarded-for"
|
|
] as string | Array<string> | undefined;
|
|
|
|
if (Array.isArray(forwarded) && forwarded.length > 0) {
|
|
return forwarded[0]?.split(",")[0]?.trim();
|
|
}
|
|
|
|
if (typeof forwarded === "string" && forwarded.trim().length > 0) {
|
|
return forwarded.split(",")[0]?.trim();
|
|
}
|
|
|
|
if (req.socket?.remoteAddress) {
|
|
return req.socket.remoteAddress;
|
|
}
|
|
|
|
return req.ip;
|
|
};
|