233 lines
9.3 KiB
TypeScript
233 lines
9.3 KiB
TypeScript
import { tap, expect } from '@push.rocks/tapbundle';
|
|
import * as plugins from '../ts/plugins.js';
|
|
import type { IForwardConfig, TForwardingType } from '../ts/forwarding/config/forwarding-types.js';
|
|
|
|
// First, import the components directly to avoid issues with compiled modules
|
|
import { ForwardingHandlerFactory } from '../ts/forwarding/factory/forwarding-factory.js';
|
|
import { httpOnly, tlsTerminateToHttp, tlsTerminateToHttps, httpsPassthrough } from '../ts/forwarding/config/forwarding-types.js';
|
|
// Import route-based helpers
|
|
import {
|
|
createHttpRoute,
|
|
createHttpsTerminateRoute,
|
|
createHttpsPassthroughRoute,
|
|
createHttpToHttpsRedirect,
|
|
createCompleteHttpsServer
|
|
} from '../ts/proxies/smart-proxy/utils/route-helpers.js';
|
|
|
|
const helpers = {
|
|
httpOnly,
|
|
tlsTerminateToHttp,
|
|
tlsTerminateToHttps,
|
|
httpsPassthrough
|
|
};
|
|
|
|
// Route-based utility functions for testing
|
|
function findRouteForDomain(routes: any[], domain: string): any {
|
|
return routes.find(route => {
|
|
const domains = Array.isArray(route.match.domains)
|
|
? route.match.domains
|
|
: [route.match.domains];
|
|
|
|
return domains.some(d => {
|
|
// Handle wildcard domains
|
|
if (d.startsWith('*.')) {
|
|
const suffix = d.substring(2);
|
|
return domain.endsWith(suffix) && domain.split('.').length > suffix.split('.').length;
|
|
}
|
|
return d === domain;
|
|
});
|
|
});
|
|
}
|
|
|
|
tap.test('ForwardingHandlerFactory - apply defaults based on type', async () => {
|
|
// HTTP-only defaults
|
|
const httpConfig: IForwardConfig = {
|
|
type: 'http-only',
|
|
target: { host: 'localhost', port: 3000 }
|
|
};
|
|
|
|
const expandedHttpConfig = ForwardingHandlerFactory.applyDefaults(httpConfig);
|
|
expect(expandedHttpConfig.http?.enabled).toEqual(true);
|
|
|
|
// HTTPS-passthrough defaults
|
|
const passthroughConfig: IForwardConfig = {
|
|
type: 'https-passthrough',
|
|
target: { host: 'localhost', port: 443 }
|
|
};
|
|
|
|
const expandedPassthroughConfig = ForwardingHandlerFactory.applyDefaults(passthroughConfig);
|
|
expect(expandedPassthroughConfig.https?.forwardSni).toEqual(true);
|
|
expect(expandedPassthroughConfig.http?.enabled).toEqual(false);
|
|
|
|
// HTTPS-terminate-to-http defaults
|
|
const terminateToHttpConfig: IForwardConfig = {
|
|
type: 'https-terminate-to-http',
|
|
target: { host: 'localhost', port: 3000 }
|
|
};
|
|
|
|
const expandedTerminateToHttpConfig = ForwardingHandlerFactory.applyDefaults(terminateToHttpConfig);
|
|
expect(expandedTerminateToHttpConfig.http?.enabled).toEqual(true);
|
|
expect(expandedTerminateToHttpConfig.http?.redirectToHttps).toEqual(true);
|
|
expect(expandedTerminateToHttpConfig.acme?.enabled).toEqual(true);
|
|
expect(expandedTerminateToHttpConfig.acme?.maintenance).toEqual(true);
|
|
|
|
// HTTPS-terminate-to-https defaults
|
|
const terminateToHttpsConfig: IForwardConfig = {
|
|
type: 'https-terminate-to-https',
|
|
target: { host: 'localhost', port: 8443 }
|
|
};
|
|
|
|
const expandedTerminateToHttpsConfig = ForwardingHandlerFactory.applyDefaults(terminateToHttpsConfig);
|
|
expect(expandedTerminateToHttpsConfig.http?.enabled).toEqual(true);
|
|
expect(expandedTerminateToHttpsConfig.http?.redirectToHttps).toEqual(true);
|
|
expect(expandedTerminateToHttpsConfig.acme?.enabled).toEqual(true);
|
|
expect(expandedTerminateToHttpsConfig.acme?.maintenance).toEqual(true);
|
|
});
|
|
|
|
tap.test('ForwardingHandlerFactory - validate configuration', async () => {
|
|
// Valid configuration
|
|
const validConfig: IForwardConfig = {
|
|
type: 'http-only',
|
|
target: { host: 'localhost', port: 3000 }
|
|
};
|
|
|
|
expect(() => ForwardingHandlerFactory.validateConfig(validConfig)).not.toThrow();
|
|
|
|
// Invalid configuration - missing target
|
|
const invalidConfig1: any = {
|
|
type: 'http-only'
|
|
};
|
|
|
|
expect(() => ForwardingHandlerFactory.validateConfig(invalidConfig1)).toThrow();
|
|
|
|
// Invalid configuration - invalid port
|
|
const invalidConfig2: IForwardConfig = {
|
|
type: 'http-only',
|
|
target: { host: 'localhost', port: 0 }
|
|
};
|
|
|
|
expect(() => ForwardingHandlerFactory.validateConfig(invalidConfig2)).toThrow();
|
|
|
|
// Invalid configuration - HTTP disabled for HTTP-only
|
|
const invalidConfig3: IForwardConfig = {
|
|
type: 'http-only',
|
|
target: { host: 'localhost', port: 3000 },
|
|
http: { enabled: false }
|
|
};
|
|
|
|
expect(() => ForwardingHandlerFactory.validateConfig(invalidConfig3)).toThrow();
|
|
|
|
// Invalid configuration - HTTP enabled for HTTPS passthrough
|
|
const invalidConfig4: IForwardConfig = {
|
|
type: 'https-passthrough',
|
|
target: { host: 'localhost', port: 443 },
|
|
http: { enabled: true }
|
|
};
|
|
|
|
expect(() => ForwardingHandlerFactory.validateConfig(invalidConfig4)).toThrow();
|
|
});
|
|
tap.test('Route Management - manage route configurations', async () => {
|
|
// Create an array to store routes
|
|
const routes: any[] = [];
|
|
|
|
// Add a route configuration
|
|
const httpRoute = createHttpRoute('example.com', { host: 'localhost', port: 3000 });
|
|
routes.push(httpRoute);
|
|
|
|
// Check that the configuration was added
|
|
expect(routes.length).toEqual(1);
|
|
expect(routes[0].match.domains).toEqual('example.com');
|
|
expect(routes[0].action.type).toEqual('forward');
|
|
expect(routes[0].action.target.host).toEqual('localhost');
|
|
expect(routes[0].action.target.port).toEqual(3000);
|
|
|
|
// Find a route for a domain
|
|
const foundRoute = findRouteForDomain(routes, 'example.com');
|
|
expect(foundRoute).toBeDefined();
|
|
|
|
// Remove a route configuration
|
|
const initialLength = routes.length;
|
|
const domainToRemove = 'example.com';
|
|
const indexToRemove = routes.findIndex(route => {
|
|
const domains = Array.isArray(route.match.domains) ? route.match.domains : [route.match.domains];
|
|
return domains.includes(domainToRemove);
|
|
});
|
|
|
|
if (indexToRemove !== -1) {
|
|
routes.splice(indexToRemove, 1);
|
|
}
|
|
|
|
expect(routes.length).toEqual(initialLength - 1);
|
|
|
|
// Check that the configuration was removed
|
|
expect(routes.length).toEqual(0);
|
|
|
|
// Check that no route exists anymore
|
|
const notFoundRoute = findRouteForDomain(routes, 'example.com');
|
|
expect(notFoundRoute).toBeUndefined();
|
|
});
|
|
|
|
tap.test('Route Management - support wildcard domains', async () => {
|
|
// Create an array to store routes
|
|
const routes: any[] = [];
|
|
|
|
// Add a wildcard domain route
|
|
const wildcardRoute = createHttpRoute('*.example.com', { host: 'localhost', port: 3000 });
|
|
routes.push(wildcardRoute);
|
|
|
|
// Find a route for a subdomain
|
|
const foundRoute = findRouteForDomain(routes, 'test.example.com');
|
|
expect(foundRoute).toBeDefined();
|
|
|
|
// Find a route for a different domain (should not match)
|
|
const notFoundRoute = findRouteForDomain(routes, 'example.org');
|
|
expect(notFoundRoute).toBeUndefined();
|
|
});
|
|
tap.test('Route Helper Functions - create HTTP route', async () => {
|
|
const route = createHttpRoute('example.com', { host: 'localhost', port: 3000 });
|
|
expect(route.match.domains).toEqual('example.com');
|
|
expect(route.match.ports).toEqual(80);
|
|
expect(route.action.type).toEqual('forward');
|
|
expect(route.action.target.host).toEqual('localhost');
|
|
expect(route.action.target.port).toEqual(3000);
|
|
});
|
|
|
|
tap.test('Route Helper Functions - create HTTPS terminate route', async () => {
|
|
const route = createHttpsTerminateRoute('example.com', { host: 'localhost', port: 3000 });
|
|
expect(route.match.domains).toEqual('example.com');
|
|
expect(route.match.ports).toEqual(443);
|
|
expect(route.action.type).toEqual('forward');
|
|
expect(route.action.target.host).toEqual('localhost');
|
|
expect(route.action.target.port).toEqual(3000);
|
|
expect(route.action.tls?.mode).toEqual('terminate');
|
|
expect(route.action.tls?.certificate).toEqual('auto');
|
|
});
|
|
|
|
tap.test('Route Helper Functions - create complete HTTPS server', async () => {
|
|
const routes = createCompleteHttpsServer('example.com', { host: 'localhost', port: 8443 });
|
|
expect(routes.length).toEqual(2);
|
|
|
|
// HTTPS route
|
|
expect(routes[0].match.domains).toEqual('example.com');
|
|
expect(routes[0].match.ports).toEqual(443);
|
|
expect(routes[0].action.type).toEqual('forward');
|
|
expect(routes[0].action.target.host).toEqual('localhost');
|
|
expect(routes[0].action.target.port).toEqual(8443);
|
|
expect(routes[0].action.tls?.mode).toEqual('terminate');
|
|
|
|
// HTTP redirect route
|
|
expect(routes[1].match.domains).toEqual('example.com');
|
|
expect(routes[1].match.ports).toEqual(80);
|
|
expect(routes[1].action.type).toEqual('redirect');
|
|
});
|
|
|
|
tap.test('Route Helper Functions - create HTTPS passthrough route', async () => {
|
|
const route = createHttpsPassthroughRoute('example.com', { host: 'localhost', port: 443 });
|
|
expect(route.match.domains).toEqual('example.com');
|
|
expect(route.match.ports).toEqual(443);
|
|
expect(route.action.type).toEqual('forward');
|
|
expect(route.action.target.host).toEqual('localhost');
|
|
expect(route.action.target.port).toEqual(443);
|
|
expect(route.action.tls?.mode).toEqual('passthrough');
|
|
});
|
|
export default tap.start(); |