ligo/tools/webide/packages/server/src/index.ts
2020-04-25 10:51:01 +00:00

98 lines
3.3 KiB
TypeScript

import cors from 'cors';
import express from 'express';
import fs from 'fs';
import { dirname, join } from 'path';
import { compileContractHandler } from './handlers/compile-contract';
import { compileExpressionHandler } from './handlers/compile-expression';
import { compileStorageHandler } from './handlers/compile-storage';
import { deployHandler } from './handlers/deploy';
import { dryRunHandler } from './handlers/dry-run';
import { evaluateValueHandler } from './handlers/evaluate-value';
import { runFunctionHandler } from './handlers/run-function';
import { shareHandler } from './handlers/share';
import { sharedLinkHandler } from './handlers/shared-link';
import { loadDefaultState } from './load-state';
import { errorLoggerMiddleware, loggerMiddleware } from './logger';
require('./metrics');
const bodyParser = require('body-parser');
const escape = require('escape-html');
const prometheus = require('express-prometheus-middleware');
const app = express();
const APP_PORT = 8080;
const metrics = express();
const METRICS_PORT = 8081;
const corsOptions = {
origin: [
'https://ligolang.org',
'http://localhost:3000',
'http://localhost:1234'
],
optionsSuccessStatus: 200
};
const appRootDirectory =
process.env['STATIC_ASSETS'] ||
dirname(require.resolve('../../client/package.json'));
const appBundleDirectory = join(appRootDirectory, 'build');
app.use(bodyParser.json());
app.use(loggerMiddleware);
app.use(
prometheus({
metricsPath: '/metrics',
collectDefaultMetrics: true,
collectDefaultBuckets: true,
requestDurationBuckets: [0.5, 0.6, 0.7, 1, 10, 20, 30, 60],
metricsApp: metrics
})
);
const file = fs.readFileSync(join(appBundleDirectory, 'index.html'));
const template = (defaultState: string = '{}') => {
return file.toString().replace(
`<div id="root"></div>`,
// Injecting a script that contains a default state (Might want to refactor this if we do ssr)
// Adding an div containing the initial state this is vulnerable to xss
// To avoid vulnerability we escape it and then parse the content into a global variable
`
<input type="hidden" id="initialState" value="${escape(defaultState)}" />
<div id="root"></div>
<script>var defaultServerState = JSON.parse(document.getElementById("initialState").value); document.getElementById("initialState").remove()</script>`
);
};
app.use('^/$', async (_, res) =>
res.send(template(JSON.stringify(await loadDefaultState(appBundleDirectory))))
);
app.use(express.static(appBundleDirectory));
app.options('/api/share', cors(corsOptions));
app.get(
`/p/:hash([0-9a-zA-Z\-\_]+)`,
sharedLinkHandler(appBundleDirectory, template)
);
app.post('/api/compile-contract', compileContractHandler);
app.post('/api/compile-expression', compileExpressionHandler);
app.post('/api/compile-storage', compileStorageHandler);
app.post('/api/dry-run', dryRunHandler);
app.post('/api/share', cors(corsOptions), shareHandler);
app.post('/api/evaluate-value', evaluateValueHandler);
app.post('/api/run-function', runFunctionHandler);
app.post('/api/deploy', deployHandler);
app.use(errorLoggerMiddleware);
app.listen(APP_PORT, () => {
console.log(`API listening on: ${APP_PORT}`);
});
metrics.listen(METRICS_PORT, () => {
console.log(`Metrics listening on: ${METRICS_PORT}`);
});