Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Poc hosted UI #3374

Draft
wants to merge 27 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 50 additions & 24 deletions backend/common.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
import PinoHttp from 'pino-http';
import { handleDockerDesktopSubsitution } from './docker-desktop-substitution';
import { filters } from './request-filters';
import { handleDockerDesktopSubsitution } from './docker-desktop-substitution';

const https = require('https');
const express = require('express');
const path = require('path');
const fs = require('fs');
const uuid = require('uuid').v4;

const K8S_Keys = {
URL: 'x-cluster-url',
CA: 'x-cluster-certificate-authority-data',
CLIENT_CA: 'x-client-certificate-data',
CLIENT_KEY_DATA: 'x-client-key-data',
AUTH: 'x-k8s-authorization',
};

// https://github.tools.sap/sgs/SAP-Global-Trust-List/blob/master/approved.pem
const certs = fs.readFileSync('certs.pem', 'utf8');

Expand Down Expand Up @@ -58,24 +66,24 @@ export const makeHandleRequest = () => {

return async (req, res) => {
logger(req, res);
let headersData;
let k8sData;
try {
headersData = extractHeadersData(req);
k8sData = extractK8sData(req);
} catch (e) {
req.log.error('Headers error:' + e.message);
res.status(400).send('Headers are missing or in a wrong format.');
return;
}

try {
filters.forEach(filter => filter(req, headersData));
filters.forEach(filter => filter(req, k8sData));
} catch (e) {
req.log.error('Filters rejected the request: ' + e.message);
res.status(400).send('Request ID: ' + req.id);
return;
}

const { targetApiServer, ca, cert, key, authorization } = headersData;
const { targetApiServer, ca, cert, key, authorization } = k8sData;

const headers = authorization
? { ...req.headers, authorization }
Expand All @@ -92,24 +100,26 @@ export const makeHandleRequest = () => {
cert,
key,
};

workaroundForNodeMetrics(req);

const k8sRequest = https.request(options, function(k8sResponse) {
if (
k8sResponse.headers &&
(k8sResponse.headers['Content-Type']?.includes('\\') ||
(k8sResponse.headers['content-type']?.includes('\\') ||
k8sResponse.headers['content-encoding']?.includes('\\'))
)
return throwInternalServerError(
'Response headers are potentially dangerous',
);

// change all 503 into 502
console.log('MIME type', k8sResponse.headers['content-type']);
const statusCode =
k8sResponse.statusCode === 503 ? 502 : k8sResponse.statusCode;

res.writeHead(statusCode, {
'Content-Type': k8sResponse.headers['Content-Type'] || 'text/json',
'Content-Type': k8sResponse.headers['content-type'] || 'text/json',
'Content-Encoding': k8sResponse.headers['content-encoding'] || '',
});
k8sResponse.pipe(res);
Expand All @@ -136,28 +146,44 @@ export const serveMonaco = app => {
app.use('/vs', express.static(path.join(__dirname, '/core-ui/vs')));
};

function extractHeadersData(req) {
function extractK8sData(req) {
const urlHeader = 'x-cluster-url';
const caHeader = 'x-cluster-certificate-authority-data';
const clientCAHeader = 'x-client-certificate-data';
const clientKeyDataHeader = 'x-client-key-data';
const authorizationHeader = 'x-k8s-authorization';

const targetApiServer = handleDockerDesktopSubsitution(
new URL(req.headers[urlHeader]),
);
const ca = decodeHeaderToBuffer(req.headers[caHeader]) || certs;
const cert = decodeHeaderToBuffer(req.headers[clientCAHeader]);
const key = decodeHeaderToBuffer(req.headers[clientKeyDataHeader]);
const authorization = req.headers[authorizationHeader];
let k8sData = null;
let k8sUrl = req.headers[K8S_Keys.URL];
// If url is not in headers we will try to extract it from cookies
if (k8sUrl) {
k8sData = req.headers;
} else {
let cookies = {};
Object.keys(req.cookies).forEach(key => {
cookies[key.toLowerCase()] = req.cookies[key];
});
k8sUrl = cookies[K8S_Keys.URL];
k8sData = cookies;
}

delete req.headers[urlHeader];
delete req.headers[caHeader];
delete req.headers[clientCAHeader];
delete req.headers[clientKeyDataHeader];
delete req.headers[authorizationHeader];
const targetApiServer = handleDockerDesktopSubsitution(new URL(k8sUrl));
const { ca, cert, key, authorization } = getK8SData(k8sData);

delete req.headers.host; // remove host in order not to confuse APIServer
deleteK8sHeaders(req.headers);

return { targetApiServer, ca, cert, key, authorization };
}

function getK8SData(data) {
const ca = decodeHeaderToBuffer(data[K8S_Keys.CA]) || certs;
const cert = decodeHeaderToBuffer(data[K8S_Keys.CLIENT_CA]);
const key = decodeHeaderToBuffer(data[K8S_Keys.CLIENT_KEY_DATA]);
const authorization = data[K8S_Keys.AUTH];
return { ca, cert, key, authorization };
}

function deleteK8sHeaders(headers) {
delete headers[K8S_Keys.URL];
delete headers[K8S_Keys.CA];
delete headers[K8S_Keys.CLIENT_CA];
delete headers[K8S_Keys.CLIENT_KEY_DATA];
delete headers[K8S_Keys.AUTH];
}
3 changes: 3 additions & 0 deletions backend/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { makeHandleRequest, serveStaticApp, serveMonaco } from './common';
import { handleTracking } from './tracking.js';
import jsyaml from 'js-yaml';
import cookieParser from 'cookie-parser';
//import { requestLogger } from './utils/other'; //uncomment this to log the outgoing traffic

const express = require('express');
Expand Down Expand Up @@ -34,6 +35,8 @@ const app = express();
app.disable('x-powered-by');
app.use(express.raw({ type: '*/*', limit: '100mb' }));

app.use(cookieParser());

const gzipEnabled = global.config.features?.GZIP?.isEnabled;
if (gzipEnabled)
app.use(
Expand Down
Loading
Loading