-
Notifications
You must be signed in to change notification settings - Fork 83
Description
Related to the architecture described in #759 , there's also an issue with accessing BOPTEST from a browser related to CORS. Essentially, when contacting BOPTEST from a web browser, the browser will refuse to fetch from BOPTEST (if the browser doesn't run in unsafe mode).
In order to allow browsers to fetch and display BOPTEST data, the BOPTEST web service would need to:
- Respond to preflight requests (
OPTIONS {endpoint}
, e.g.OPTIONS /results
with some specific headers) with a correct response - Add a header entry to the actual request (e.g.
PUT /results
)
I've built two small middleware handlers that solve the problem for the test case interaction endpoints, but I don't know about the administrative endpoints like /users/:userid
etc that might also require authentication.
In service/web/server/src/routes/middleware.js
:
export function handleCorsPreflight(req, res, next, allowedMethods) {
if (req.method === 'OPTIONS') {
const origin = req.header('Origin');
res.setHeader('Vary', 'Origin');
if (origin && isValidOrigin(origin)) {
console.log("Pre-flight allowed: ", origin)
res.setHeader('Access-Control-Allow-Origin', origin);
res.setHeader('Access-Control-Allow-Methods', allowedMethods);
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.setHeader('Access-Control-Max-Age', '86400'); // Cache preflight response for 24 hours
res.sendStatus(204); // No Content
} else {
console.log("Pre-flight rejected: ", origin)
res.sendStatus(405); // Method Not Allowed
}
} else {
next();
}
}
export function addCorsOriginHdr(req, res, next) {
const origin = req.header('Origin');
if (origin && isValidOrigin(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin);
res.setHeader('Vary', 'Origin');
}
next()
}
function isValidOrigin(origin) {
const allowedOriginRegex = /^http:\/\/localhost:\d+$/; // e.g. all http://localhost:port
return allowedOriginRegex.test(origin)
}
In service/web/server/src/routes/boptestRoutes.js
:
// Example for PUT /forecast
/*
Register OPTIONS pre-flight
This is required for all PUT requests, as well as POST with json content
Not required for GET
*/
boptestRoutes.options('/forecast/:testid',
(req, res, next) => middleware.handleCorsPreflight(req, res, next, "PUT")
)
// The addCorsOriginHdr middleware needs to be added to all requests, i.e. also GET and POST
boptestRoutes.put('/forecast/:testid',
param('testid').custom(validateTestid),
middleware.validationResponse,
middleware.addCorsOriginHdr, // This is new, rest as before
async (req, res, next) => {
...
}
);
Should I make a PR to add those @dhblum @kbenne ?
PS: The demo frontend (early version) is here: https://github.com/bertrandkerres/boptest-frontend