Skip to content

Instantly share code, notes, and snippets.

@Jalson1982
Created March 28, 2024 16:45
Show Gist options
  • Save Jalson1982/02de5c77a13352accc798e969a819f9d to your computer and use it in GitHub Desktop.
Save Jalson1982/02de5c77a13352accc798e969a819f9d to your computer and use it in GitHub Desktop.
import express, { Request, Response, Router } from "express";
import http from "http";
import cors from "cors";
import orgRoutes from "./routes/orgs";
import userRoutes from "./routes/users";
import audioRoutes, { PASSIVE_AUDIO_UPLOAD_PATH } from "./routes/audio";
import promptRoutes from "./routes/audio";
import passiveIntervalRoutes from "./routes/passiveInterval";
import batchRoutes from "./routes/batch";
import externalRoutes from "./routes/external";
import dotenv from "dotenv";
import { WebSocketService } from "./handlers/websocket";
import jwt from "jsonwebtoken";
import { expressjwt } from "express-jwt";
import { expressJwtSecret as jwksRsaExpressJwtSecret, GetVerificationKey, SigningKey } from "jwks-rsa";
import jwksClient from "jwks-rsa";
import { envVars } from "./services/env";
import WebSocket, { WebSocketServer } from "ws";
import { UserService } from "./services/data/UserService";
import * as Sentry from "@sentry/node";
dotenv.config();
const authConfig = {
domain: process.env.AUTH0_DOMAIN, // Replace with your Auth0 domain
audience: process.env.AUTH0_AUDIENCE, // Replace with your Auth0 API identifier
};
const authMiddleware = expressjwt({
secret: jwksRsaExpressJwtSecret({
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 5,
jwksUri: `https://${authConfig.domain}/.well-known/jwks.json`,
}) as GetVerificationKey,
audience: authConfig.audience,
issuer: `https://${authConfig.domain}/`,
algorithms: ["RS256"],
});
const app = express();
// Sentry.init({
// dsn: "https://b921b53f5d967a163df23e6492b07ec7@o4506559854411776.ingest.sentry.io/4506599314817024",
// integrations: [
// // enable HTTP calls tracing
// new Sentry.Integrations.Http({ tracing: true }),
// // enable Express.js middleware tracing
// new Sentry.Integrations.Express({ app }),
// new ProfilingIntegration(),
// ],
// // Performance Monitoring
// tracesSampleRate: 1.0, // Capture 100% of the transactions
// // Set sampling rate for profiling - this is relative to tracesSampleRate
// profilesSampleRate: 1.0,
// });
// The request handler must be the first middleware on the app
app.use(Sentry.Handlers.requestHandler());
app.use(express.json());
// // The request handler must be the first middleware on the app
// app.use(Sentry.Handlers.requestHandler());
/****** CONTROLLERS ******/
app.get("/", (req: Request, res: Response) => {
console.log("Hello World!");
res.send("Hello World!");
});
app.get("/debug-sentry", function mainHandler(req, res) {
throw new Error("My first Sentry error!");
});
const protectedRoutes: Router[] = [
// add protected routes here
];
const unprotectedRoutes: Router[] = [
orgRoutes,
userRoutes,
audioRoutes,
promptRoutes,
passiveIntervalRoutes,
batchRoutes,
externalRoutes
// add unprotected routes here
];
export const API_PREFIX = "/api";
protectedRoutes.forEach((route) => {
app.use(API_PREFIX, authMiddleware, route);
});
unprotectedRoutes.forEach((route) => {
app.use(API_PREFIX, route);
});
/****** END CONTROLLERS ******/
app.use(
cors({
origin: ["http://localhost:3000"],
}),
);
// required to read json req bodies
app.use((req, res, next) => {
console.log("req.path", req.path);
if (req.path.includes(PASSIVE_AUDIO_UPLOAD_PATH)) {
// If the path is for file upload, skip express.json()
return next();
}
return express.json({ limit: "10mb" })(req, res, next);
});
// The error handler must be before any other error middleware and after all controllers
// app.use(Sentry.Handlers.errorHandler());
// Optional fallthrough error handler
app.use(function onError(err: any, req: any, res: any, next: any) {
// The error id is attached to `res.sentry` to be returned
// and optionally displayed to the user for support.
res.statusCode = 500;
res.end(res.sentry + "\n");
});
const PORT = 4001;
// Create an HTTP server and pass the Express app
const server = http.createServer(app);
// Attach WebSocket server to the HTTP server
const promptWss = new WebSocketServer({ noServer: true });
const auth0Domain = envVars().auth0Domain;
const client = jwksClient({
jwksUri: `https://${auth0Domain}/.well-known/jwks.json`,
});
const getKey = (header: jwt.JwtHeader, callback: jwt.SigningKeyCallback): void => {
client.getSigningKey(header.kid as string, function (err: Error | null, key?: SigningKey | undefined) {
if (!key) {
console.log("no key");
throw new Error("no key");
}
let signingKey = key.getPublicKey();
callback(null, signingKey);
});
};
server.on("upgrade", (request, socket, head) => {
const token = new URL(request.url as string, `http://${request.headers.host}`).searchParams.get("token");
if (!token) {
socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
socket.destroy();
return;
}
jwt.verify(token, getKey, async (err, decoded) => {
const tokenParts = token.split(".");
const header = JSON.parse(Buffer.from(tokenParts[0], "base64").toString("utf8"));
console.log("err", err);
if (err || !decoded?.sub) {
console.log("err", err);
socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
socket.destroy();
return;
}
if (typeof decoded.sub !== "string") {
throw new Error("decoded.sub is not a string");
}
const userResponse = await UserService.getUserByAuthId(decoded.sub);
promptWss.handleUpgrade(request, socket, head, (ws) => {
promptWss.emit("connection", ws, userResponse);
});
});
// const authUser = { id: "" };
// promptWss.handleUpgrade(request, socket, head, (ws) => {
// console.log("handling upgrade");
// promptWss.emit("connection", ws, authUser);
// });
});
console.log("Setting up prompt websocket");
WebSocketService.handlePromptWebsocket(promptWss);
// Start the server
server.listen(PORT, () => {
console.log(`Server running on port # ${PORT}`);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment