Skip to content

CORS headers to use BOPTEST from browser #760

@bertrandkerres

Description

@bertrandkerres

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions