feat: add origin checking for graphql

This commit is contained in:
Alexis Tyler
2021-06-28 18:05:41 +09:30
parent 4da6b285a3
commit 2d7a70dc0c
4 changed files with 71 additions and 4 deletions
+4 -2
View File
@@ -20,7 +20,8 @@ export interface Paths {
'myservers-base': string;
'myservers-config': string;
'myservers-env': string;
'machine-id': string;
'ssl-certificate': string;
'extra-origins': string;
}
const thisDir = __dirname;
@@ -53,7 +54,8 @@ export const defaultPaths = new Map<keyof Paths, string>([
['myservers-base', '/boot/config/plugins/dynamix.my.servers/'],
['myservers-config', '/boot/config/plugins/dynamix.my.servers/myservers.cfg'],
['myservers-env', '/boot/config/plugins/dynamix.my.servers/env'],
['machine-id', '/etc/machine-id']
['ssl-certificate', '/boot/config/ssl/certs/certificate_bundle.pem'],
['extra-origins', '/boot/config/plugins/dynamix.my.servers/extra-origins.json']
]);
/**
+61 -2
View File
@@ -7,17 +7,20 @@ import fs from 'fs';
import net from 'net';
import path from 'path';
import execa from 'execa';
import cors from 'cors';
import stoppable from 'stoppable';
import chokidar from 'chokidar';
import express from 'express';
import http from 'http';
import WebSocket from 'ws';
import { pki } from 'node-forge';
import { ApolloServer } from 'apollo-server-express';
import { log, config, utils, paths, pubsub, coreLogger } from './core';
import { log, config, paths, pubsub, coreLogger } from './core';
import { getEndpoints, globalErrorHandler, exitApp, cleanStdout, sleep } from './core/utils';
import { graphql } from './graphql';
import packageJson from '../package.json';
import display from './graphql/resolvers/query/display';
import { networkState, varState } from './core/states';
const configFilePath = path.join(paths.get('dynamix-base')!, 'case-model.cfg');
const customImageFilePath = path.join(paths.get('dynamix-base')!, 'case-model.png');
@@ -37,8 +40,64 @@ chokidar.watch(customImageFilePath).on('all', updatePubsub);
*/
const app = express();
// Graphql port
const port = process.env.PORT ?? String(config.get('port'));
const attemptJSONParse = (text: string, fallback: any) => {
try {
return JSON.parse(text);
} catch {
return fallback;
}
};
// Cors options
const invalidOrigin = 'The CORS policy for this site does not allow access from the specified Origin.';
const certPem = fs.readFileSync(paths.get('ssl-certificate')!, 'utf-8');
const { hash } = pki.certificateFromPem(certPem).subject;
// Get extra origins from the user
const extraOriginPath = paths.get('extra-origins');
// To add extra origins create a file at the "extra-origins" path
const extraOrigins = extraOriginPath ? attemptJSONParse(fs.readFileSync(extraOriginPath, 'utf-8'), []) : [];
// Get local ip from first ethernet adapter in the "network" state
const localIp = networkState.data[0].ipaddr[0];
// Get webui port
const originPort = varState.data.port;
// Allow http://tower.local:${port}, http://${ip}:${port} and https://${hash}.unraid.net:${port}
const allowedOrigins = [
// The webui
'http://tower.local',
`http://${localIp}${originPort}`,
`https://${hash}.unraid.net:${originPort}`,
// Other endpoints should be added below
extraOrigins
];
// Cors
app.use(cors({
origin: function (origin, callback) {
// Disallow requests with no origin
// (like mobile apps or curl requests)
if (!origin) {
callback(new Error(invalidOrigin), false);
return;
}
// Only allow known origins
if (!allowedOrigins.includes(origin)) {
callback(new Error(invalidOrigin), false);
return;
}
callback(null, true);
}
}));
// Add Unraid API version header
app.use(async (_req, res, next) => {
// Only get the machine ID on first request
@@ -203,7 +262,7 @@ export const server = {
if (isNaN(parseInt(port, 10))) {
try {
fs.unlinkSync(port);
} catch {}
} catch { }
}
// Run callback
+5
View File
@@ -10506,6 +10506,11 @@
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
},
"node-forge": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
"integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA=="
},
"node-int64": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
+1
View File
@@ -103,6 +103,7 @@
"nchan": "^1.0.10",
"node-cache": "5.1.2",
"node-fetch": "^2.6.1",
"node-forge": "^0.10.0",
"node-window-polyfill": "^1.0.2",
"number-to-color": "^0.5.0",
"observable-to-promise": "^1.0.0",