From 4e45f0a04f54a2151a2d21a2a53871422ec128eb Mon Sep 17 00:00:00 2001 From: Alejandro Lembke Barrientos Date: Mon, 13 Jan 2025 04:36:45 +0000 Subject: [PATCH] PR-824002: Using proxy instead of a redirect. --- .gitignore | 1 + __tests__/index.test.ts | 21 ++---- dist/app.js | 17 ----- dist/controllers/index.js | 26 ------- dist/routes/index.js | 9 --- dist/types/index.js | 2 - package-lock.json | 149 +++++++++++++++++++++++++++++++++++--- package.json | 4 +- src/app.ts | 52 ++++++++++++- src/controllers/index.ts | 14 ---- src/routes/index.ts | 8 -- 11 files changed, 197 insertions(+), 106 deletions(-) delete mode 100644 dist/app.js delete mode 100644 dist/controllers/index.js delete mode 100644 dist/routes/index.js delete mode 100644 dist/types/index.js delete mode 100644 src/controllers/index.ts delete mode 100644 src/routes/index.ts diff --git a/.gitignore b/.gitignore index 1dcef2d..a0d218e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules +dist .env \ No newline at end of file diff --git a/__tests__/index.test.ts b/__tests__/index.test.ts index ddbe838..ba46fe0 100644 --- a/__tests__/index.test.ts +++ b/__tests__/index.test.ts @@ -1,24 +1,13 @@ import request from 'supertest'; -import express from 'express'; -import { setRoutes } from '../src/routes/index'; import dotenv from 'dotenv'; +import app from '../src/app'; dotenv.config(); -const app = express(); -setRoutes(app); - -describe('GET /', () => { - it('should redirect to CDN URL', async () => { +describe('Proxy Middleware', () => { + it('should proxy to CDN URL', async () => { const response = await request(app).get('/'); - expect(response.status).toBe(302); - expect(response.header.location).toBe(process.env.CDN_URL); + expect(response.status).toBe(200); }); - it('should return 500 if CDN URL is not configured', async () => { - process.env.CDN_URL = ''; - const response = await request(app).get('/'); - expect(response.status).toBe(500); - expect(response.text).toBe('CDN URL not configured'); - }); -}); \ No newline at end of file +}); diff --git a/dist/app.js b/dist/app.js deleted file mode 100644 index 273c343..0000000 --- a/dist/app.js +++ /dev/null @@ -1,17 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -const express_1 = __importDefault(require("express")); -const dotenv_1 = __importDefault(require("dotenv")); -const index_1 = require("./routes/index"); -dotenv_1.default.config(); -const app = (0, express_1.default)(); -const PORT = process.env.PORT || 3000; -app.use(express_1.default.json()); -app.use(express_1.default.urlencoded({ extended: true })); -(0, index_1.setRoutes)(app); -app.listen(PORT, () => { - console.log(`Servidor corriendo en http://localhost:${PORT}`); -}); diff --git a/dist/controllers/index.js b/dist/controllers/index.js deleted file mode 100644 index 75196c5..0000000 --- a/dist/controllers/index.js +++ /dev/null @@ -1,26 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.getIndex = void 0; -const getIndex = (req, res) => __awaiter(void 0, void 0, void 0, function* () { - try { - const cdnUrl = process.env.CDN_URL; - if (!cdnUrl) { - res.status(500).send('CDN URL not configured'); - return; - } - res.redirect(cdnUrl); - } - catch (error) { - res.status(500).send('Internal Server Error'); - } -}); -exports.getIndex = getIndex; diff --git a/dist/routes/index.js b/dist/routes/index.js deleted file mode 100644 index 99d2617..0000000 --- a/dist/routes/index.js +++ /dev/null @@ -1,9 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.setRoutes = setRoutes; -const index_1 = require("../controllers/index"); -function setRoutes(app) { - app.get('/', (req, res) => { - (0, index_1.getIndex)(req, res); - }); -} diff --git a/dist/types/index.js b/dist/types/index.js deleted file mode 100644 index c8ad2e5..0000000 --- a/dist/types/index.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/package-lock.json b/package-lock.json index f9967d3..51bd336 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,10 +10,12 @@ "license": "MIT", "dependencies": { "dotenv": "^16.4.7", - "express": "^4.21.2" + "express": "^4.21.2", + "http-proxy-middleware": "^3.0.3" }, "devDependencies": { "@types/express": "^5.0.0", + "@types/http-proxy-middleware": "^0.19.3", "@types/jest": "^29.5.14", "@types/node": "^22.10.5", "@types/supertest": "^6.0.2", @@ -1196,6 +1198,27 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/http-proxy": { + "version": "1.17.15", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz", + "integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-proxy-middleware": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@types/http-proxy-middleware/-/http-proxy-middleware-0.19.3.tgz", + "integrity": "sha512-lnBTx6HCOUeIJMLbI/LaL5EmdKLhczJY5oeXZpX/cXE4rRqb3RmV7VcMpiEfYkmTjipv3h7IAyIINe4plEv7cA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/http-proxy": "*", + "@types/node": "*" + } + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", @@ -1252,7 +1275,6 @@ "version": "22.10.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.5.tgz", "integrity": "sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.20.0" @@ -1644,7 +1666,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -2299,6 +2320,12 @@ "node": ">= 0.6" } }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -2456,7 +2483,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -2497,6 +2523,26 @@ "node": ">=8" } }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/form-data": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", @@ -2774,6 +2820,60 @@ "node": ">= 0.8" } }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.3.tgz", + "integrity": "sha512-usY0HG5nyDUwtqpiZdETNbmKtw3QQ1jwYFZ9wi5iHzX2BcILwQKtYDJPo7XHTsu5Z0B2Hj3W9NNnbd+AjFWjqg==", + "license": "MIT", + "dependencies": { + "@types/http-proxy": "^1.17.15", + "debug": "^4.3.6", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.3", + "is-plain-object": "^5.0.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/http-proxy-middleware/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/http-proxy-middleware/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -2876,6 +2976,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -2896,16 +3005,36 @@ "node": ">=6" } }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" } }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -3854,7 +3983,6 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -4166,7 +4294,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -4326,6 +4453,12 @@ "node": ">=0.10.0" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "license": "MIT" + }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -4845,7 +4978,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -5023,7 +5155,6 @@ "version": "6.20.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "dev": true, "license": "MIT" }, "node_modules/unpipe": { diff --git a/package.json b/package.json index 034ddba..9347046 100644 --- a/package.json +++ b/package.json @@ -12,10 +12,12 @@ }, "dependencies": { "dotenv": "^16.4.7", - "express": "^4.21.2" + "express": "^4.21.2", + "http-proxy-middleware": "^3.0.3" }, "devDependencies": { "@types/express": "^5.0.0", + "@types/http-proxy-middleware": "^0.19.3", "@types/jest": "^29.5.14", "@types/node": "^22.10.5", "@types/supertest": "^6.0.2", diff --git a/src/app.ts b/src/app.ts index 4425685..6a651d9 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,17 +1,61 @@ import express from 'express'; import dotenv from 'dotenv'; -import { setRoutes } from './routes/index'; +import { createProxyMiddleware } from 'http-proxy-middleware'; +import type { Request, Response } from 'express'; +import { NextFunction } from 'http-proxy-middleware/dist/types'; +import { ClientRequest } from 'http'; dotenv.config(); const app = express(); const PORT = process.env.PORT || 3000; +const cdnUrl = process.env.CDN_URL; +// Configuración del middleware de proxy +const proxyOptions = { + target: cdnUrl, // URL del CDN + changeOrigin: true, // Cambiar el origen para evitar problemas de CORS, + pathRewrite: (path: string) => path.replace("/", ""), + onProxyReq: (proxyReq: ClientRequest, req: Request, res: Response) => { + console.log(`Proxying request: ${req.url}`); + }, + onError: (err: any, req: Request, res: Response) => { + console.error('Proxy error:', err); + if (!cdnUrl) { + res.status(500).send('CDN URL not configured'); + throw new Error('CDN URL not configured'); + } + }, +}; + +// Crear el middleware proxy +const proxyMiddleware = createProxyMiddleware(proxyOptions); + +// Middlewares para manejar JSON y formularios app.use(express.json()); app.use(express.urlencoded({ extended: true })); -setRoutes(app); +// Middleware para validar si cdnUrl está configurado +const validateCdnUrl = (req: Request, res: Response, next: NextFunction) => { + if (!cdnUrl) { + res.status(500).send('CDN URL not configured'); + throw new Error('CDN URL not configured'); + } + next(); +}; -app.listen(PORT, () => { +// Usar el middleware de validación antes del proxy +app.use(validateCdnUrl); +// Configurar el middleware proxy +app.use('/', proxyMiddleware); + +// DO NOT DO app.listen() unless we're testing this directly +if (require.main === module) { +// Iniciar el servidor + app.listen(PORT, () => { console.log(`Servidor corriendo en http://localhost:${PORT}`); -}); \ No newline at end of file + }); +}; + +// Instead do export the app: +export default app; diff --git a/src/controllers/index.ts b/src/controllers/index.ts deleted file mode 100644 index 750bcf7..0000000 --- a/src/controllers/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Request, Response } from 'express'; - -export const getIndex = async (req: Request, res: Response): Promise => { - try { - const cdnUrl = process.env.CDN_URL; - if (!cdnUrl) { - res.status(500).send('CDN URL not configured'); - return; - } - res.redirect(cdnUrl); - } catch (error) { - res.status(500).send('Internal Server Error'); - } -}; \ No newline at end of file diff --git a/src/routes/index.ts b/src/routes/index.ts deleted file mode 100644 index 318bccc..0000000 --- a/src/routes/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Application, Request, Response } from 'express'; -import { getIndex } from '../controllers/index'; - -export function setRoutes(app: Application) { - app.get('/', (req: Request, res: Response) => { - getIndex(req, res); - }); -} \ No newline at end of file