From a00048aaac8d11b3afac368ede45b59f47067aaa Mon Sep 17 00:00:00 2001 From: Michael C Date: Wed, 21 Sep 2022 19:39:03 -0400 Subject: [PATCH] add getIP test cases, misc others --- .nycrc.json | 8 ++- src/app.ts | 1 + test/cases/addUserAsVIP.ts | 49 ++++++++++++++ test/cases/getIP.ts | 109 +++++++++++++++++++++++++++++++ test/cases/testUtils.ts | 43 +++++++++++- test/cases/userCounter.ts | 1 - test/mocks/mockExpressRequest.ts | 33 ++++++++++ 7 files changed, 240 insertions(+), 4 deletions(-) create mode 100644 test/cases/getIP.ts create mode 100644 test/mocks/mockExpressRequest.ts diff --git a/.nycrc.json b/.nycrc.json index af6eab0..ae148eb 100644 --- a/.nycrc.json +++ b/.nycrc.json @@ -1,10 +1,14 @@ { "extends": "@istanbuljs/nyc-config-typescript", "check-coverage": false, + "ski-full": true, + "reporter": ["text", "html"], + "include": [ + "src/**/*.ts" + ], "exclude": [ "src/routes/addUnlistedVideo.ts", "src/cronjob/downvoteSegmentArchiveJob.ts", "src/databases/*" - ], - "reporter": ["text", "html"] + ] } \ No newline at end of file diff --git a/src/app.ts b/src/app.ts index f68507e..e7ba2c1 100644 --- a/src/app.ts +++ b/src/app.ts @@ -200,6 +200,7 @@ function setupRoutes(router: Router) { router.get("/api/generateToken/:type", generateTokenRequest); router.get("/api/verifyToken", verifyTokenRequest); + /* instanbul ignore next */ if (config.postgres?.enabled) { router.get("/database", (req, res) => dumpDatabase(req, res, true)); router.get("/database.json", (req, res) => dumpDatabase(req, res, false)); diff --git a/test/cases/addUserAsVIP.ts b/test/cases/addUserAsVIP.ts index 49aba60..ebbcd6f 100644 --- a/test/cases/addUserAsVIP.ts +++ b/test/cases/addUserAsVIP.ts @@ -10,6 +10,10 @@ const checkUserVIP = (publicID: string) => db.prepare("get", `SELECT "userID" FR const adminPrivateUserID = "testUserId"; const permVIP1 = "addVIP_permaVIPOne"; const publicPermVIP1 = getHash(permVIP1) as HashedUserID; +const permVIP2 = "addVIP_permaVIPTwo"; +const publicPermVIP2 = getHash(permVIP2) as HashedUserID; +const permVIP3 = "addVIP_permaVIPThree"; +const publicPermVIP3 = getHash(permVIP3) as HashedUserID; const endpoint = "/api/addUserAsVIP"; const addUserAsVIP = (userID: string, enabled: boolean, adminUserID = adminPrivateUserID) => client({ @@ -41,6 +45,16 @@ describe("addVIP test", function() { }) .catch(err => done(err)); }); + it("Should be able to add second user as VIP", (done) => { + addUserAsVIP(publicPermVIP2, true) + .then(async res => { + assert.strictEqual(res.status, 200); + const row = await checkUserVIP(publicPermVIP2); + assert.ok(row); + done(); + }) + .catch(err => done(err)); + }); it("Should return 403 with invalid adminID", (done) => { addUserAsVIP(publicPermVIP1, true, "Invalid_Admin_User_ID") .then(res => { @@ -89,4 +103,39 @@ describe("addVIP test", function() { }) .catch(err => done(err)); }); + it("Should remove VIP if enabled is false", (done) => { + client({ + method: "POST", + url: endpoint, + params: { + userID: publicPermVIP2, + adminUserID: adminPrivateUserID, + enabled: "invalid-text" + } + }) + .then(async res => { + assert.strictEqual(res.status, 200); + const row = await checkUserVIP(publicPermVIP2); + assert.ok(!row); + done(); + }) + .catch(err => done(err)); + }); + it("Should remove VIP if enabled is missing", (done) => { + client({ + method: "POST", + url: endpoint, + params: { + userID: publicPermVIP3, + adminUserID: adminPrivateUserID + } + }) + .then(async res => { + assert.strictEqual(res.status, 200); + const row = await checkUserVIP(publicPermVIP3); + assert.ok(!row); + done(); + }) + .catch(err => done(err)); + }); }); \ No newline at end of file diff --git a/test/cases/getIP.ts b/test/cases/getIP.ts new file mode 100644 index 0000000..f761e01 --- /dev/null +++ b/test/cases/getIP.ts @@ -0,0 +1,109 @@ +import sinon from "sinon"; +import { config } from "../../src/config"; +import assert from "assert"; +const mode = "production"; +let stub: sinon.SinonStub; +let stub2: sinon.SinonStub; +import { createRequest } from "../mocks/mockExpressRequest"; +import { getIP } from "../../src/utils/getIP"; + +const v4RequestOptions = { + headers: { + "x-forwarded-for": "127.0.1.1", + "cf-connecting-ip": "127.0.1.2", + "x-real-ip": "127.0.1.3", + }, + ip: "127.0.1.5", + socket: { + remoteAddress: "127.0.1.4" + } +}; +const v6RequestOptions = { + headers: { + "x-forwarded-for": "[100::1]", + "cf-connecting-ip": "[100::2]", + "x-real-ip": "[100::3]", + }, + ip: "[100::5]", + socket: { + remoteAddress: "[100::4]" + } +}; +const v4MockRequest = createRequest(v4RequestOptions); +const v6MockRequest = createRequest(v6RequestOptions); + +const expectedIP4 = { + "X-Forwarded-For": "127.0.1.1", + "Cloudflare": "127.0.1.2", + "X-Real-IP": "127.0.1.3", + "default": "127.0.1.4", +}; + +const expectedIP6 = { + "X-Forwarded-For": "[100::1]", + "Cloudflare": "[100::2]", + "X-Real-IP": "[100::3]", + "default": "[100::4]", +}; + +describe("getIP stubs", () => { + before(() => stub = sinon.stub(config, "mode").value(mode)); + after(() => stub.restore()); + + it("Should return production mode if stub worked", (done) => { + assert.strictEqual(config.mode, mode); + done(); + }); +}); + +describe("getIP array tests", () => { + beforeEach(() => stub = sinon.stub(config, "mode").value(mode)); + afterEach(() => { + stub.restore(); + stub2.restore(); + }); + + for (const [key, value] of Object.entries(expectedIP4)) { + it(`Should return correct IPv4 from ${key}`, (done) => { + stub2 = sinon.stub(config, "behindProxy").value(key); + const ip = getIP(v4MockRequest); + assert.strictEqual(config.behindProxy, key); + assert.strictEqual(ip, value); + done(); + }); + } + + for (const [key, value] of Object.entries(expectedIP6)) { + it(`Should return correct IPv6 from ${key}`, (done) => { + stub2 = sinon.stub(config, "behindProxy").value(key); + const ip = getIP(v6MockRequest); + assert.strictEqual(config.behindProxy, key); + assert.strictEqual(ip, value); + done(); + }); + } +}); + +describe("getIP true tests", () => { + before(() => stub = sinon.stub(config, "mode").value(mode)); + after(() => { + stub.restore(); + stub2.restore(); + }); + + it(`Should return correct IPv4 from with bool true`, (done) => { + stub2 = sinon.stub(config, "behindProxy").value(true); + const ip = getIP(v4MockRequest); + assert.strictEqual(config.behindProxy, "X-Forwarded-For"); + assert.strictEqual(ip, expectedIP4["X-Forwarded-For"]); + done(); + }); + + it(`Should return correct IPv4 from with string true`, (done) => { + stub2 = sinon.stub(config, "behindProxy").value("true"); + const ip = getIP(v4MockRequest); + assert.strictEqual(config.behindProxy, "X-Forwarded-For"); + assert.strictEqual(ip, expectedIP4["X-Forwarded-For"]); + done(); + }); +}); \ No newline at end of file diff --git a/test/cases/testUtils.ts b/test/cases/testUtils.ts index 78818c8..29bfe60 100644 --- a/test/cases/testUtils.ts +++ b/test/cases/testUtils.ts @@ -1,5 +1,5 @@ import assert from "assert"; -import { partialDeepEquals } from "../utils/partialDeepEquals"; +import { partialDeepEquals, mixedDeepEquals } from "../utils/partialDeepEquals"; describe("Test utils ", () => { it("objectContain", () => { @@ -135,4 +135,45 @@ describe("Test utils ", () => { } ), "Did not match partial child array"); }); + it("mixedDeepEquals exists", () => { + assert(!mixedDeepEquals({ + name: "lorem", + values: [{ + name: "ipsum", + }], + child: { + name: "dolor", + }, + ignore: true + }, { + name: "lorem", + values: [{ + name: "ipsum", + }], + child: { + name: "dolor", + }, + ignore: false + })); + }); + it("mixedDeepEquals noProperty", () => { + assert(!mixedDeepEquals({ + name: "lorem", + values: [{ + name: "ipsum", + }], + child: { + name: "dolor", + } + }, { + name: "lorem", + values: [{ + name: "ipsum", + }], + child: { + name: "dolor", + }, + ignore: false + })); + }); }); \ No newline at end of file diff --git a/test/cases/userCounter.ts b/test/cases/userCounter.ts index 120e0e8..8215ce1 100644 --- a/test/cases/userCounter.ts +++ b/test/cases/userCounter.ts @@ -3,7 +3,6 @@ import assert from "assert"; import { config } from "../../src/config"; import { getHash } from "../../src/utils/getHash"; - describe("userCounter", () => { it("Should return 200", function (done) { if (!config.userCounterURL) this.skip(); // skip if no userCounterURL is set diff --git a/test/mocks/mockExpressRequest.ts b/test/mocks/mockExpressRequest.ts new file mode 100644 index 0000000..7ad4ae0 --- /dev/null +++ b/test/mocks/mockExpressRequest.ts @@ -0,0 +1,33 @@ +const nullStub = (): any => null; + +export const createRequest = (options: any) => ({ + app: {}, + baseUrl: "", + body: {}, + cookies: {}, + fresh: true, + headers: {}, + hostname: "example.com", + ip: "", + ips: [], + method: "GET", + originalUrl: "/", + params: {}, + path: "/", + protocol: "https", + query: {}, + route: {}, + secure: true, + signedCookies: {}, + stale: false, + subdomains: [], + xhr: true, + accepts: nullStub(), + acceptsCharsets: nullStub(), + acceptsEncodings: nullStub(), + acceptsLanguages: nullStub(), + get: nullStub(), + is: nullStub(), + range: nullStub(), + ...options +});