Created
March 28, 2024 16:45
-
-
Save Jalson1982/02de5c77a13352accc798e969a819f9d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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