Skip to content

Commit

Permalink
Merge pull request #235 from namecheap/feature/ignore-invalid-ssl
Browse files Browse the repository at this point in the history
feat: provide an ability to ignore invalid SSL certificates while usi…
  • Loading branch information
oleh-momot authored Dec 21, 2020
2 parents 00bffba + 14be11d commit d43c0ed
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 6 deletions.
2 changes: 1 addition & 1 deletion ilc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"single-spa": "5.6.0",
"systemjs": "^6.4.2",
"systemjs-css-extra": "^1.0.2",
"tailorx": "^6.0.0",
"tailorx": "^6.1.0",
"url-join": "^4.0.1",
"uuid": "^3.4.0"
},
Expand Down
16 changes: 16 additions & 0 deletions ilc/server/tailor/parse-override-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,22 @@ module.exports = (cookie, trustedOrigins) => {
const parsedTrustedOrigin = typeof trustedOrigins === 'string' && trustedOrigins.split(',').map(n=>n.trim());
sanitizeSpoofedLinks(overrideConfig.apps, parsedTrustedOrigin);
}

/**
* The following logic needs to ignore invalid SSL certificates for sources that use HTTPS protocol
* It ignores certificates only when a developer uses LDE to work with ILC on production environment
* Due to TailorX can not fetch necessary fragment information for SSR from local environment
*/
if (overrideConfig.apps !== undefined) {
for (let appName in overrideConfig.apps) {
const ssr = overrideConfig.apps[appName].ssr;

if (ssr !== undefined && ssr.src !== undefined && ssr.src.startsWith('https:')) {
overrideConfig.apps[appName].ssr.ignoreInvalidSsl = true;
}
}
}

return overrideConfig;
}
} catch (e) {}
Expand Down
105 changes: 101 additions & 4 deletions ilc/server/tailor/parse-override-config.spec.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,38 @@
import { expect } from 'chai';
const parseOverrideConfig = require('./parse-override-config');

const assignIgnoreInvalidSsl = (ssr, protocol = 'http:') => protocol === 'https:'
? Object.assign({}, ssr, {ignoreInvalidSsl: true})
: ssr;

const getExampleObject = (ip = '10.1.150.223', protocol = 'http:') => (
{
apps: {
'@portal/one': {
spaBundle: `${protocol}//${ip}:2273/api/fragment/uilandingpages/app.js`,
ssr: {
ssr: assignIgnoreInvalidSsl({
src: `${protocol}//${ip}/api/fragment/uilandingpages/`
}
}, protocol)
},
'@portal/two': {
spaBundle: `${protocol}//${ip}:2222/example.js`,
ssr: {
ssr: assignIgnoreInvalidSsl({
src: `${protocol}//${ip}/`,
timeout: 1000,
}, protocol),
kind: 'primary',
},
'@portal/three': {
spaBundle: `${protocol}//${ip}:3333/example.js`,
ssr: {
timeout: 1000,
},
kind: 'primary',
},
'@portal/four': {
spaBundle: `${protocol}//${ip}:4444/example.js`,
kind: 'primary',
},
},
routes: [
{
Expand Down Expand Up @@ -47,6 +62,15 @@ const getSanitizedObject = () => (
},
kind: 'primary',
},
'@portal/three': {
ssr: {
timeout: 1000,
},
kind: 'primary',
},
'@portal/four': {
kind: 'primary',
},
},
routes: [
{
Expand All @@ -65,7 +89,48 @@ const getSanitizedObject = () => (
);

const getExampleCookies = (ip = '10.1.150.223', protocol = 'http:') => {
const value = encodeURIComponent(JSON.stringify(getExampleObject(ip, protocol)));
const value = encodeURIComponent(JSON.stringify({
apps: {
'@portal/one': {
spaBundle: `${protocol}//${ip}:2273/api/fragment/uilandingpages/app.js`,
ssr: {
src: `${protocol}//${ip}/api/fragment/uilandingpages/`
},
},
'@portal/two': {
spaBundle: `${protocol}//${ip}:2222/example.js`,
ssr: {
src: `${protocol}//${ip}/`,
timeout: 1000,
},
kind: 'primary',
},
'@portal/three': {
spaBundle: `${protocol}//${ip}:3333/example.js`,
ssr: {
timeout: 1000,
},
kind: 'primary',
},
'@portal/four': {
spaBundle: `${protocol}//${ip}:4444/example.js`,
kind: 'primary',
},
},
routes: [
{
routeId: 104,
route: '/domains/',
next: false,
slots: {
body: {
appName: '@portal/two',
kind: null,
},
},
},
],
}));

return `foo=bar; ILC-overrideConfig=${value}; foo2=bar2`;
};
Expand Down Expand Up @@ -95,6 +160,38 @@ describe('overrideConfig', () => {
});
});

describe('ignoring invalid SSL certificates while SSR', () => {
it('should add ignoring invalid SSL certificates when an app SSR source has HTTPS protocol', async () => {
const exampleCookies = getExampleCookies('10.1.150.223', 'https:');
const config = parseOverrideConfig(exampleCookies);

expect(config.apps['@portal/one'].ssr.ignoreInvalidSsl).to.be.true;
expect(config.apps['@portal/two'].ssr.ignoreInvalidSsl).to.be.true;
expect(config.apps['@portal/three'].ssr.ignoreInvalidSsl).to.be.undefined;
expect(config.apps['@portal/four'].ssr).to.be.undefined;
});

it('should not add ignoring invalid SSL certificates when an app SSR source has HTTP protocol', async () => {
const exampleCookies = getExampleCookies('10.1.150.223', 'http:');
const config = parseOverrideConfig(exampleCookies);

expect(config.apps['@portal/one'].ssr.ignoreInvalidSsl).to.be.undefined;
expect(config.apps['@portal/two'].ssr.ignoreInvalidSsl).to.be.undefined;
expect(config.apps['@portal/three'].ssr.ignoreInvalidSsl).to.be.undefined;
expect(config.apps['@portal/four'].ssr).to.be.undefined;
});

it('should not add ignoring invalid SSL certificates when an app SSR source has no protocol', async () => {
const exampleCookies = getExampleCookies('10.1.150.223', '');
const config = parseOverrideConfig(exampleCookies);

expect(config.apps['@portal/one'].ssr.ignoreInvalidSsl).to.be.undefined;
expect(config.apps['@portal/two'].ssr.ignoreInvalidSsl).to.be.undefined;
expect(config.apps['@portal/three'].ssr.ignoreInvalidSsl).to.be.undefined;
expect(config.apps['@portal/four'].ssr).to.be.undefined;
});
});

describe('not sanitized', () => {
it('should not sanitize valid private ip with http', async () => {
const exampleCookies = getExampleCookies('10.1.150.223', 'http:');
Expand Down
7 changes: 7 additions & 0 deletions ilc/server/tailor/server-router.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,17 @@ module.exports = class ServerRouter {
}

const ssrOpts = deepmerge({}, appInfo.ssr);

if (typeof ssrOpts.src !== 'string') {
throw new this.errors.RouterError({message: 'No url specified for fragment!', data: {appInfo}});
}

if (ssrOpts.ignoreInvalidSsl === true) {
ssrOpts['ignore-invalid-ssl'] = true;
}

delete ssrOpts.ignoreInvalidSsl;

const url = new URL(ssrOpts.src);
const fragmentName = makeAppId(appName, slotName);
const fragmentKind = slotData.kind || appInfo.kind;
Expand Down
4 changes: 3 additions & 1 deletion ilc/server/tailor/server-router.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ describe('server router', () => {
ssr: {
timeout: 4000,
src: 'https://somewhere.com/apps?prop=value',
ignoreInvalidSsl: true,
},
},
'@portal/news': {
Expand Down Expand Up @@ -311,7 +312,7 @@ describe('server router', () => {
`<fragment id="${registryConfig.apps['@portal/navbar'].name}" slot="navbar" timeout="${registryConfig.apps['@portal/navbar'].ssr.timeout}" src="${expectedNavbarUrl.toString()}"></fragment>` +
`<fragment id="${registryConfig.apps['@portal/footer'].name}" slot="footer" timeout="${registryConfig.apps['@portal/footer'].ssr.timeout}" src="${expectedFooterUrl.toString()}" primary="true"></fragment>` +
`<fragment id="${registryConfig.apps['contact'].name}" slot="contact" timeout="${registryConfig.apps.contact.ssr.timeout}" src="${expectedContactUrl.toString()}"></fragment>` +
`<fragment id="${registryConfig.apps['apps'].name}" slot="apps" timeout="${registryConfig.apps.apps.ssr.timeout}" src="${expectedAppsUrl.toString()}"></fragment>`;
`<fragment id="${registryConfig.apps['apps'].name}" slot="apps" timeout="${registryConfig.apps.apps.ssr.timeout}" src="${expectedAppsUrl.toString()}" ignore-invalid-ssl="true"></fragment>`;

const router = new ServerRouter(logger);

Expand Down Expand Up @@ -371,6 +372,7 @@ describe('server router', () => {
ssr: {
timeout: 4000,
src: 'https://somewhere.com/apps?prop=value',
ignoreInvalidSsl: false,
},
},
};
Expand Down

0 comments on commit d43c0ed

Please sign in to comment.