diff --git a/jest.config.js b/jest.config.js index c0cc49e..51802e8 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,5 +1,12 @@ module.exports = { + // A list of paths to directories that Jest should use to search for files in + roots: [ + "./src/" + ], + // Compile Typescript transform: { '^.+\\.(ts|tsx)$': 'ts-jest' - } + }, + // Default value for FlareSolverr maxTimeout is 60000 + testTimeout: 70000 } diff --git a/src/app.ts b/src/app.ts index 9d10922..1192581 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,5 +1,5 @@ import log from './services/log' -import {Request, Response} from 'express'; +import {NextFunction, Request, Response} from 'express'; import {getUserAgent} from "./services/sessions"; import {controllerV1} from "./controllers/v1"; @@ -16,12 +16,31 @@ app.use(bodyParser.json({ } })); +// Access log +app.use(function(req: Request, res: Response, next: NextFunction) { + if (req.url != '/health') { + // count the request for the log prefix + log.incRequests() + // build access message + let body = ""; + if (req.method == 'POST' && req.body) { + body += " body: " + try { + body += JSON.stringify(req.body) + } catch(e) { + body += req.body + } + } + log.info(`Incoming request => ${req.method} ${req.url}${body}`); + } + next(); +}); + // ********************************************************************************************************************* // Routes -// show welcome message +// Show welcome message app.get("/", ( req: Request, res: Response ) => { - log.info(`Incoming request: /`); res.send({ "msg": "FlareSolverr is ready!", "version": version, @@ -29,20 +48,15 @@ app.get("/", ( req: Request, res: Response ) => { }); }); -// health endpoint. this endpoint is special because it doesn't print traces +// Health endpoint. this endpoint is special because it doesn't print traces app.get("/health", ( req: Request, res: Response ) => { res.send({ "status": "ok" }); }); -// controller v1 +// Controller v1 app.post("/v1", async( req: Request, res: Response ) => { - // count the request for the log prefix - log.incRequests() - - const params = req.body; - log.info(`Incoming request: /v1 Params: ${JSON.stringify(params)}`); await controllerV1(req, res); }); @@ -50,7 +64,20 @@ app.post("/v1", async( req: Request, res: Response ) => { // Unknown paths or verbs app.use(function (req : Request, res : Response) { - res.status(404).send({"error": "Unknown resource or HTTP verb"}) + res.status(404) + .send({"error": "Unknown resource or HTTP verb"}) +}) + +// Errors +app.use(function (err: any, req: Request, res: Response, next: NextFunction) { + if (err) { + let msg = 'Invalid request: ' + err; + msg = msg.replace("\n", "").replace("\r", "") + log.error(msg) + res.send({"error": msg}) + } else { + next() + } }) module.exports = app; diff --git a/src/services/log.ts b/src/services/log.ts index 3b2e11d..b999bd4 100644 --- a/src/services/log.ts +++ b/src/services/log.ts @@ -22,10 +22,13 @@ function toIsoString(date: Date) { } export default { - incRequests: () => { requests++ }, + incRequests: () => { + requests++ + }, html(html: string) { - if (LOG_HTML) - this.debug(html) + if (LOG_HTML) { + this.debug(html) + } }, ...require('console-log-level')( {level: process.env.LOG_LEVEL || 'info', diff --git a/src/tests/app.test.ts b/src/tests/app.test.ts index e34962c..b894399 100644 --- a/src/tests/app.test.ts +++ b/src/tests/app.test.ts @@ -2,20 +2,29 @@ import {Response} from "superagent"; import {V1ResponseBase, V1ResponseSession, V1ResponseSessions, V1ResponseSolution} from "../controllers/v1" -import {testWebBrowserInstallation} from "../services/sessions"; const request = require("supertest"); const app = require("../app"); +const sessions = require('../services/sessions'); const version: string = require('../../package.json').version const googleUrl = "https://www.google.com"; const postUrl = "https://ptsv2.com/t/qv4j3-1634496523"; const cfUrl = "https://pirateiro.com/torrents/?search=harry"; const cfCaptchaUrl = "https://idope.se" +const proxyUrl = "http://127.0.0.1:8888" beforeAll(async () => { // Init session - await testWebBrowserInstallation(); + await sessions.testWebBrowserInstallation(); +}); + +afterEach(async () => { + // Clean sessions + const sessionList = sessions.list(); + for (const session of sessionList) { + await sessions.destroy(session); + } }); describe("Test '/' path", () => { @@ -51,8 +60,6 @@ describe("Test '/wrong' path", () => { }); describe("Test '/v1' path", () => { - jest.setTimeout(70000); - test("Cmd 'request.bad' should fail", async () => { const payload = { "cmd": "request.bad", @@ -207,7 +214,7 @@ describe("Test '/v1' path", () => { "cmd": "request.get", "url": googleUrl, "proxy": { - "url": "http://127.0.0.1:8888" + "url": proxyUrl } } const response: Response = await request(app).post("/v1").send(payload); @@ -222,35 +229,35 @@ describe("Test '/v1' path", () => { }); // todo: credentials are not working - // test("Cmd 'request.get' should return OK with 'proxy' param with credentials", async () => { - // /* - // To configure TinyProxy in local: - // * sudo vim /etc/tinyproxy/tinyproxy.conf - // * edit => LogFile "/tmp/tinyproxy.log" - // * edit => Syslog Off - // * add => BasicAuth testuser testpass - // * sudo tinyproxy -d - // * sudo tail -f /tmp/tinyproxy.log - // */ - // const payload = { - // "cmd": "request.get", - // "url": googleUrl, - // "proxy": { - // "url": "http://127.0.0.1:8888", - // "username": "testuser", - // "password": "testpass" - // } - // } - // const response: Response = await request(app).post("/v1").send(payload); - // expect(response.statusCode).toBe(200); - // - // const apiResponse: V1ResponseSolution = response.body; - // expect(apiResponse.status).toBe("ok"); - // - // const solution = apiResponse.solution; - // expect(solution.url).toContain(googleUrl) - // expect(solution.status).toContain(200) - // }); + test.skip("Cmd 'request.get' should return OK with 'proxy' param with credentials", async () => { + /* + To configure TinyProxy in local: + * sudo vim /etc/tinyproxy/tinyproxy.conf + * edit => LogFile "/tmp/tinyproxy.log" + * edit => Syslog Off + * add => BasicAuth testuser testpass + * sudo tinyproxy -d + * sudo tail -f /tmp/tinyproxy.log + */ + const payload = { + "cmd": "request.get", + "url": googleUrl, + "proxy": { + "url": proxyUrl, + "username": "testuser", + "password": "testpass" + } + } + const response: Response = await request(app).post("/v1").send(payload); + expect(response.statusCode).toBe(200); + + const apiResponse: V1ResponseSolution = response.body; + expect(apiResponse.status).toBe("ok"); + + const solution = apiResponse.solution; + expect(solution.url).toContain(googleUrl) + expect(solution.status).toContain(200) + }); test("Cmd 'request.get' should fail with wrong 'proxy' param", async () => { const payload = { @@ -288,7 +295,7 @@ describe("Test '/v1' path", () => { test("Cmd 'request.get' should return fail with bad domain", async () => { const payload = { "cmd": "request.get", - "url": "https://www.google.combad", + "url": "https://www.google.combad" } const response: Response = await request(app).post("/v1").send(payload); expect(response.statusCode).toBe(500); @@ -449,7 +456,7 @@ describe("Test '/v1' path", () => { expect(apiResponse.status).toBe("ok"); expect(apiResponse.message).toBe("The session has been removed."); expect(apiResponse.startTimestamp).toBeGreaterThan(1000); - expect(apiResponse.endTimestamp).toBeGreaterThan(apiResponse.startTimestamp); + expect(apiResponse.endTimestamp).toBeGreaterThanOrEqual(apiResponse.startTimestamp); expect(apiResponse.version).toBe(version); });