|
@@ -1,105 +1,105 @@
|
|
|
-/* eslint-disable arrow-body-style */
|
|
|
|
|
|
|
+import {
|
|
|
|
|
+ vi,
|
|
|
|
|
+ beforeEach,
|
|
|
|
|
+ describe, test, expect,
|
|
|
|
|
+} from 'vitest';
|
|
|
|
|
|
|
|
-describe('safeRedirect', () => {
|
|
|
|
|
- let registerSafeRedirect;
|
|
|
|
|
|
|
+import type { Request } from 'express';
|
|
|
|
|
+
|
|
|
|
|
+import registerSafeRedirectFactory, { type ResWithSafeRedirect } from './safe-redirect';
|
|
|
|
|
|
|
|
|
|
+describe('safeRedirect', () => {
|
|
|
const whitelistOfHosts = [
|
|
const whitelistOfHosts = [
|
|
|
'white1.example.com:8080',
|
|
'white1.example.com:8080',
|
|
|
'white2.example.com',
|
|
'white2.example.com',
|
|
|
];
|
|
];
|
|
|
-
|
|
|
|
|
- beforeEach(async() => {
|
|
|
|
|
- registerSafeRedirect = require('~/server/middlewares/safe-redirect')(whitelistOfHosts);
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ const registerSafeRedirect = registerSafeRedirectFactory(whitelistOfHosts);
|
|
|
|
|
|
|
|
describe('res.safeRedirect', () => {
|
|
describe('res.safeRedirect', () => {
|
|
|
// setup req/res/next
|
|
// setup req/res/next
|
|
|
|
|
+ const getFunc = vi.fn().mockReturnValue('example.com');
|
|
|
const req = {
|
|
const req = {
|
|
|
protocol: 'http',
|
|
protocol: 'http',
|
|
|
hostname: 'example.com',
|
|
hostname: 'example.com',
|
|
|
- get: jest.fn().mockReturnValue('example.com'),
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ get: getFunc,
|
|
|
|
|
+ } as any as Request;
|
|
|
|
|
+
|
|
|
|
|
+ const redirect = vi.fn();
|
|
|
const res = {
|
|
const res = {
|
|
|
- redirect: jest.fn().mockReturnValue('redirect'),
|
|
|
|
|
- };
|
|
|
|
|
- const next = jest.fn();
|
|
|
|
|
|
|
+ redirect,
|
|
|
|
|
+ } as any as ResWithSafeRedirect;
|
|
|
|
|
+ const next = vi.fn();
|
|
|
|
|
+
|
|
|
|
|
+ beforeEach(() => {
|
|
|
|
|
+ getFunc.mockClear();
|
|
|
|
|
+ redirect.mockClear();
|
|
|
|
|
+ next.mockClear();
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
test('redirects to \'/\' because specified url causes open redirect vulnerability', () => {
|
|
test('redirects to \'/\' because specified url causes open redirect vulnerability', () => {
|
|
|
registerSafeRedirect(req, res, next);
|
|
registerSafeRedirect(req, res, next);
|
|
|
|
|
|
|
|
- const result = res.safeRedirect('//evil.example.com');
|
|
|
|
|
|
|
+ res.safeRedirect('//evil.example.com');
|
|
|
|
|
|
|
|
expect(next).toHaveBeenCalledTimes(1);
|
|
expect(next).toHaveBeenCalledTimes(1);
|
|
|
- expect(req.get).toHaveBeenCalledTimes(1);
|
|
|
|
|
expect(req.get).toHaveBeenCalledWith('host');
|
|
expect(req.get).toHaveBeenCalledWith('host');
|
|
|
expect(res.redirect).toHaveBeenCalledTimes(1);
|
|
expect(res.redirect).toHaveBeenCalledTimes(1);
|
|
|
expect(res.redirect).toHaveBeenCalledWith('/');
|
|
expect(res.redirect).toHaveBeenCalledWith('/');
|
|
|
- expect(result).toBe('redirect');
|
|
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
test('redirects to \'/\' because specified host without port is not in whitelist', () => {
|
|
test('redirects to \'/\' because specified host without port is not in whitelist', () => {
|
|
|
registerSafeRedirect(req, res, next);
|
|
registerSafeRedirect(req, res, next);
|
|
|
|
|
|
|
|
- const result = res.safeRedirect('http://white1.example.com/path/to/page');
|
|
|
|
|
|
|
+ res.safeRedirect('http://white1.example.com/path/to/page');
|
|
|
|
|
|
|
|
expect(next).toHaveBeenCalledTimes(1);
|
|
expect(next).toHaveBeenCalledTimes(1);
|
|
|
- expect(req.get).toHaveBeenCalledTimes(1);
|
|
|
|
|
expect(req.get).toHaveBeenCalledWith('host');
|
|
expect(req.get).toHaveBeenCalledWith('host');
|
|
|
expect(res.redirect).toHaveBeenCalledTimes(1);
|
|
expect(res.redirect).toHaveBeenCalledTimes(1);
|
|
|
expect(res.redirect).toHaveBeenCalledWith('/');
|
|
expect(res.redirect).toHaveBeenCalledWith('/');
|
|
|
- expect(result).toBe('redirect');
|
|
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
test('redirects to the specified local url', () => {
|
|
test('redirects to the specified local url', () => {
|
|
|
registerSafeRedirect(req, res, next);
|
|
registerSafeRedirect(req, res, next);
|
|
|
|
|
|
|
|
- const result = res.safeRedirect('/path/to/page');
|
|
|
|
|
|
|
+ res.safeRedirect('/path/to/page');
|
|
|
|
|
|
|
|
expect(next).toHaveBeenCalledTimes(1);
|
|
expect(next).toHaveBeenCalledTimes(1);
|
|
|
- expect(req.get).toHaveBeenCalledTimes(1);
|
|
|
|
|
expect(req.get).toHaveBeenCalledWith('host');
|
|
expect(req.get).toHaveBeenCalledWith('host');
|
|
|
expect(res.redirect).toHaveBeenCalledTimes(1);
|
|
expect(res.redirect).toHaveBeenCalledTimes(1);
|
|
|
expect(res.redirect).toHaveBeenCalledWith('http://example.com/path/to/page');
|
|
expect(res.redirect).toHaveBeenCalledWith('http://example.com/path/to/page');
|
|
|
- expect(result).toBe('redirect');
|
|
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
test('redirects to the specified local url (fqdn)', () => {
|
|
test('redirects to the specified local url (fqdn)', () => {
|
|
|
registerSafeRedirect(req, res, next);
|
|
registerSafeRedirect(req, res, next);
|
|
|
|
|
|
|
|
- const result = res.safeRedirect('http://example.com/path/to/page');
|
|
|
|
|
|
|
+ res.safeRedirect('http://example.com/path/to/page');
|
|
|
|
|
|
|
|
expect(next).toHaveBeenCalledTimes(1);
|
|
expect(next).toHaveBeenCalledTimes(1);
|
|
|
- expect(req.get).toHaveBeenCalledTimes(1);
|
|
|
|
|
expect(req.get).toHaveBeenCalledWith('host');
|
|
expect(req.get).toHaveBeenCalledWith('host');
|
|
|
expect(res.redirect).toHaveBeenCalledTimes(1);
|
|
expect(res.redirect).toHaveBeenCalledTimes(1);
|
|
|
expect(res.redirect).toHaveBeenCalledWith('http://example.com/path/to/page');
|
|
expect(res.redirect).toHaveBeenCalledWith('http://example.com/path/to/page');
|
|
|
- expect(result).toBe('redirect');
|
|
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
test('redirects to the specified whitelisted url (white1.example.com:8080)', () => {
|
|
test('redirects to the specified whitelisted url (white1.example.com:8080)', () => {
|
|
|
registerSafeRedirect(req, res, next);
|
|
registerSafeRedirect(req, res, next);
|
|
|
|
|
|
|
|
- const result = res.safeRedirect('http://white1.example.com:8080/path/to/page');
|
|
|
|
|
|
|
+ res.safeRedirect('http://white1.example.com:8080/path/to/page');
|
|
|
|
|
|
|
|
expect(next).toHaveBeenCalledTimes(1);
|
|
expect(next).toHaveBeenCalledTimes(1);
|
|
|
- expect(req.get).toHaveBeenCalledTimes(1);
|
|
|
|
|
expect(req.get).toHaveBeenCalledWith('host');
|
|
expect(req.get).toHaveBeenCalledWith('host');
|
|
|
expect(res.redirect).toHaveBeenCalledTimes(1);
|
|
expect(res.redirect).toHaveBeenCalledTimes(1);
|
|
|
expect(res.redirect).toHaveBeenCalledWith('http://white1.example.com:8080/path/to/page');
|
|
expect(res.redirect).toHaveBeenCalledWith('http://white1.example.com:8080/path/to/page');
|
|
|
- expect(result).toBe('redirect');
|
|
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
test('redirects to the specified whitelisted url (white2.example.com:8080)', () => {
|
|
test('redirects to the specified whitelisted url (white2.example.com:8080)', () => {
|
|
|
registerSafeRedirect(req, res, next);
|
|
registerSafeRedirect(req, res, next);
|
|
|
|
|
|
|
|
- const result = res.safeRedirect('http://white2.example.com:8080/path/to/page');
|
|
|
|
|
|
|
+ res.safeRedirect('http://white2.example.com:8080/path/to/page');
|
|
|
|
|
|
|
|
expect(next).toHaveBeenCalledTimes(1);
|
|
expect(next).toHaveBeenCalledTimes(1);
|
|
|
- expect(req.get).toHaveBeenCalledTimes(1);
|
|
|
|
|
expect(req.get).toHaveBeenCalledWith('host');
|
|
expect(req.get).toHaveBeenCalledWith('host');
|
|
|
expect(res.redirect).toHaveBeenCalledTimes(1);
|
|
expect(res.redirect).toHaveBeenCalledTimes(1);
|
|
|
expect(res.redirect).toHaveBeenCalledWith('http://white2.example.com:8080/path/to/page');
|
|
expect(res.redirect).toHaveBeenCalledWith('http://white2.example.com:8080/path/to/page');
|
|
|
- expect(result).toBe('redirect');
|
|
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
});
|
|
});
|