-
Notifications
You must be signed in to change notification settings - Fork 961
Description
Is your feature request related to a problem? Please describe.
The library cannot be used with a strict content security policy because it uses inline styles. When a strict csp is used, the tooltips and hover/click events do not work and the console contains csp violation errors:
Describe the solution you'd like
Preferably, replace inline styles with a stylesheet and class toggling.
Alternatively, provide an api to set a nonce that is used for inline styles.
Describe alternatives you've considered
I am currently monkey patching document.createElement and document.createTextNode to inject a nonce in the dynamically created elements. This is not a secure solution because it effectively allows inline styles when the are injected via these apis. Additionally this requires to use a nonce.
Additional context
Reproduce with the following example file (e.g. with python -m http.server). Toggle the csp at the top:
<!doctype html>
<html>
<head>
<!-- this works -->
<!-- <meta http-equiv="Content-Security-Policy" --> <!-- content="default-src 'self'; script-src-elem 'unsafe-inline' https://cdn.jsdelivr.net; style-src-elem 'unsafe-inline'" /> -->
<!-- this does not works -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src-elem 'unsafe-inline' https://cdn.jsdelivr.net;" />
<style>
body {
margin: 0;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/3d-force-graph"></script>
</head>
<body>
<div id="3d-graph"></div>
<script>
// Random tree
const NODES = 300;
const GROUPS = 12;
const gData = {
nodes: [...Array(NODES).keys()].map((i) => ({
id: i,
group: Math.ceil(Math.random() * GROUPS),
user: i.toString(),
description: i.toString(),
})),
links: [...Array(NODES).keys()]
.filter((id) => id)
.map((id) => ({
source: id,
target: Math.round(Math.random() * (id - 1)),
})),
};
const Graph = new ForceGraph3D(document.getElementById("3d-graph"))
.nodeAutoColorBy("group")
.linkAutoColorBy((d) => gData.nodes[d.source].group)
.linkOpacity(0.5)
.nodeLabel((node) => `${node.user}: ${node.description}`)
.onNodeClick((node) => {
// Aim at node from outside it
const distance = 40;
const distRatio = 1 + distance / Math.hypot(node.x, node.y, node.z);
const newPos =
node.x || node.y || node.z
? {
x: node.x * distRatio,
y: node.y * distRatio,
z: node.z * distRatio,
}
: {x: 0, y: 0, z: distance}; // special case if node is in (0,0,0)
Graph.cameraPosition(
newPos, // new position
node, // lookAt ({ x, y, z })
3000, // ms transition duration
);
})
.graphData(gData);
</script>
</body>
</html>