Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
Arnaud Varin authored Mar 15, 2023
1 parent e3829f4 commit 9d4d5db
Show file tree
Hide file tree
Showing 14 changed files with 3,349 additions and 0 deletions.
Binary file added assets/textcard.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
118 changes: 118 additions & 0 deletions development-server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* Copyright © 2020. TIBCO Software Inc.
* This file is subject to the license terms contained
* in the license file that is distributed with this file.
*/

//@ts-check

/**
* # Spotfire mods development server
* The purpose of the development server is to simplify the development of mods. The development server mimics the way the Spotfire runtime works in regards to cross origin requests and content security policies.
*/

const liveServer = require("live-server");
const path = require("path");
const fs = require("fs");
const { promisify } = require("util");
const readFile = promisify(fs.readFile);
const readdir = promisify(fs.readdir);

const manifestName = "mod-manifest.json";
const rootDirectory = process.argv[2] || "./src/";
const scenario = process.argv[3];

// The development server tries to mimic the CSP policy used by the Spotfire runtime.
const allowedExternalResources = new Set();
let declaredExternalResourcesInManifest = [];

main();

async function main() {
await readExternalResourcesFromManifest();

// If test scenario, run the server for a short while
if (scenario === "test") {
setTimeout(function () {
return process.exit(0);
}, 5000);
}
liveServer.start({
port: 8090,
noCssInject: true,
cors: false,
// @ts-ignore
open: "/" + manifestName,
root: rootDirectory,
wait: 250, // Waits for all changes, before reloading. Defaults to 0 sec.
middleware: [cacheRedirect]
});
}

/**
* Read external resources from the mod manifest placed in the root directory.
*/
async function readExternalResourcesFromManifest() {
const rootDirectoryAbsolutePath = path.resolve(rootDirectory);
const files = await readdir(rootDirectoryAbsolutePath);

if (files.find((fileName) => fileName == manifestName)) {
const manifestPath = path.join(rootDirectoryAbsolutePath, manifestName);

await readExternalResources();
fs.watch(manifestPath, {}, readExternalResources);

async function readExternalResources() {
let content = await readFile(manifestPath, { encoding: "utf-8" });

try {
let json = JSON.parse(content);
declaredExternalResourcesInManifest = json.externalResources || [];
} catch (err) {}
}
} else {
console.warn("Could not find a mod-manifest.json in the root directory", rootDirectoryAbsolutePath);
}
}

/**
* Middleware to manage caching and CSP headers.
* @param {any} req - request object
* @param {any} res - response object
* @param {any} next - next callback to invoke the next middleware
*/
function cacheRedirect(req, res, next) {
const isCorsRequest = req.headers.origin != undefined;
const requestFromOutsideSandbox = req.headers.origin != "null";

// Prevent CORS requests from the sandboxed iframe. E.g module loading will not work in embedded mode.
if (isCorsRequest && requestFromOutsideSandbox) {
allowedExternalResources.add(req.headers.origin);

res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.setHeader("Access-Control-Allow-Origin", "*");
}

// Turn off caching on everything to avoid stale CSP headers etc. in the browser.
// This also ensures that live server can inject its websocket snippet in .html pages it serves to the mod iframe.
res.setHeader("Cache-Control", "no-store");

if (req.method !== "GET") {
next();
return;
}

// Set same security headers in the development server as in the Spotfire runtime.
res.setHeader(
"content-security-policy",
`sandbox allow-scripts; default-src 'self' 'unsafe-eval' 'unsafe-hashes' 'unsafe-inline' blob: data: ${[
...allowedExternalResources.values(),
...declaredExternalResourcesInManifest
].join(" ")}`
);

// CSP header used by older browsers where the CSP policy is not fully supported.
res.setHeader("x-content-security-policy", "sandbox allow-scripts");

next();
}
32 changes: 32 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "mod-starter",
"version": "1.0.0",
"description": "",
"scripts": {
"start": "npm install && npm run server",
"server": "node development-server.js src"
},
"keywords": [],
"author": "Emanuel Dellsén, Hartmut Fischer, Jonatan Vaara, Alexander Strand & Karl Västgård",
"license": "ISC",
"devDependencies": {
"clean-css": "^4.2.3",
"husky": "^4.3.0",
"live-server": "^1.2.1",
"prettier": "^2.1.2",
"pretty-quick": "^3.0.2"
},
"dependencies": {
"clipboardy": "^2.3.0",
"eslint": "^7.10.0",
"html-minifier": "^4.0.0",
"minify": "^6.0.0",
"minimist": "^1.2.5",
"puppeteer": "^5.3.1"
},
"husky": {
"hooks": {
"pre-commit": "pretty-quick --staged"
}
}
}
Loading

0 comments on commit 9d4d5db

Please sign in to comment.