Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions api/shapes.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ async function getManifold() {
return manifoldInitPromise;
}

export { getManifold };

export function setFlockReference(ref) {
flock = ref;
}
Expand Down
11 changes: 4 additions & 7 deletions docs/CSP_POLICY.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ Content Security Policy (CSP) is defined in two places:
Core flows tested (app load, Blockly interaction, run code in sandbox, project export/import trigger, analytics path) observed these runtime source origins:

- **document / stylesheet / image / font / xhr**: `self` (`http://127.0.0.1:4173` in local smoke run)
- **script**: `self`, `https://www.googletagmanager.com`, `https://unpkg.com`
- **fetch / connect**: `self`, `https://www.google-analytics.com`, `https://unpkg.com`
- **script**: `self`, `https://www.googletagmanager.com`
- **fetch / connect**: `self`, `https://www.google-analytics.com`

## Why each non-self origin is required

Expand All @@ -23,9 +23,6 @@ Core flows tested (app load, Blockly interaction, run code in sandbox, project e
- Optional Google Analytics transport endpoint used by some environments.
- `https://region1.google-analytics.com`
- Regional Google Analytics endpoint used by some environments.
- `https://unpkg.com`
- Used by `manifold-3d` runtime assets (`manifold.js` / `manifold.wasm`) in browser execution.

## Current CSP

Header policy (authoritative):
Expand All @@ -35,11 +32,11 @@ default-src 'self';
base-uri 'self';
form-action 'self';
object-src 'none';
script-src 'self' 'unsafe-inline' 'unsafe-eval' 'wasm-unsafe-eval' https://www.googletagmanager.com https://unpkg.com;
script-src 'self' 'unsafe-inline' 'unsafe-eval' 'wasm-unsafe-eval' https://www.googletagmanager.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: blob: https://www.google-analytics.com https://www.googletagmanager.com;
font-src 'self' data:;
connect-src 'self' https://www.googletagmanager.com https://www.google-analytics.com https://region1.google-analytics.com https://stats.g.doubleclick.net https://unpkg.com;
connect-src 'self' https://www.googletagmanager.com https://www.google-analytics.com https://region1.google-analytics.com https://stats.g.doubleclick.net;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Documentation does not match actual CSP implementation.

The documented connect-src directive differs from what's defined in vite.config.mjs (line 13) and index.html (line 7). The implementation includes a broad https: scheme allowance that is not reflected in this documentation:

Source connect-src value
This doc 'self' https://www.googletagmanager.com https://www.google-analytics.com ...
vite.config.mjs / index.html 'self' https: https://www.googletagmanager.com ...

Please either update the documentation to reflect the actual policy, or remove the https: from the implementation files to match this more restrictive documented policy.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/CSP_POLICY.md` at line 39, The CSP connect-src documented in
CSP_POLICY.md is inconsistent with the runtime policy emitted by the build (the
Vite config and index HTML include a broad "https:" scheme); either update the
documented connect-src line in CSP_POLICY.md to include the https: scheme
alongside the existing hosts, or remove the generic "https:" allowance from the
runtime policy in the Vite configuration and from the meta tag in index HTML so
the implementation matches the restrictive list in the doc—locate the
connect-src declaration in CSP_POLICY.md and the corresponding connect-src
values produced by the Vite config and index HTML and make the values identical.

media-src 'self' data: blob:;
worker-src 'self' blob:;
frame-src 'self';
Expand Down
12 changes: 10 additions & 2 deletions flock.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ import {
setFlockReference as setFlockMovement,
} from "./api/movement";
import { flockModels, setFlockReference as setFlockModels } from "./api/models";
import { flockShapes, setFlockReference as setFlockShapes } from "./api/shapes";
import { flockShapes, setFlockReference as setFlockShapes, getManifold } from "./api/shapes";
import {
flockTransform,
setFlockReference as setFlockTransform,
Expand Down Expand Up @@ -1258,7 +1258,15 @@ export const flock = {
flock.abortController = new AbortController();

try {
await flock.BABYLON.InitializeCSG2Async();
// Pre-load the manifold-3d wasm module (which already redirects
// its WASM fetch to the locally-served /wasm/manifold.wasm via
// locateFile) and inject it into BabylonJS so InitializeCSG2Async
// never fetches from unpkg.com.
const manifoldWasm = await getManifold();
await flock.BABYLON.InitializeCSG2Async({
manifoldInstance: manifoldWasm.Manifold,
manifoldMeshInstance: manifoldWasm.Mesh,
});
} catch (error) {
console.error("Error initializing CSG2:", error);
}
Expand Down
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; base-uri 'self'; form-action 'self'; object-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval' 'wasm-unsafe-eval' https://www.googletagmanager.com https://unpkg.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https://www.google-analytics.com https://www.googletagmanager.com; font-src 'self' data:; connect-src 'self' https: https://www.googletagmanager.com https://www.google-analytics.com https://region1.google-analytics.com https://stats.g.doubleclick.net https://unpkg.com; media-src 'self' data: blob:; worker-src 'self' blob:; frame-src 'self'; manifest-src 'self'"
content="default-src 'self'; base-uri 'self'; form-action 'self'; object-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval' 'wasm-unsafe-eval' https://www.googletagmanager.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https://www.google-analytics.com https://www.googletagmanager.com; font-src 'self' data:; connect-src 'self' https: https://www.googletagmanager.com https://www.google-analytics.com https://region1.google-analytics.com https://stats.g.doubleclick.net; media-src 'self' data: blob:; worker-src 'self' blob:; frame-src 'self'; manifest-src 'self'"
/>
<title>Flock XR - Creative coding in 3D</title>
<meta name="description" content="Flock XR: The free 3D coding and creation tool for young people.">
Expand Down
2 changes: 1 addition & 1 deletion vite.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const isProduction = process.env.NODE_ENV === 'production';
const BASE_URL = process.env.VITE_BASE_URL || '/';

// `frame-ancestors` is only enforced from HTTP headers (ignored in CSP meta tags).
const CSP_META_POLICY = "default-src 'self'; base-uri 'self'; form-action 'self'; object-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval' 'wasm-unsafe-eval' https://www.googletagmanager.com https://unpkg.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https://www.google-analytics.com https://www.googletagmanager.com; font-src 'self' data:; connect-src 'self' https: https://www.googletagmanager.com https://www.google-analytics.com https://region1.google-analytics.com https://stats.g.doubleclick.net https://unpkg.com; media-src 'self' data: blob:; worker-src 'self' blob:; frame-src 'self'; manifest-src 'self'";
const CSP_META_POLICY = "default-src 'self'; base-uri 'self'; form-action 'self'; object-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval' 'wasm-unsafe-eval' https://www.googletagmanager.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https://www.google-analytics.com https://www.googletagmanager.com; font-src 'self' data:; connect-src 'self' https: https://www.googletagmanager.com https://www.google-analytics.com https://region1.google-analytics.com https://stats.g.doubleclick.net; media-src 'self' data: blob:; worker-src 'self' blob:; frame-src 'self'; manifest-src 'self'";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

connect-src includes overly broad https: scheme allowance.

The CSP policy contains connect-src 'self' https: ... which permits connections to any HTTPS endpoint. This undermines the security benefit of removing unpkg.com, since the policy now allows fetching from any external HTTPS origin.

If the intent is to allow arbitrary HTTPS connections (e.g., for user-provided URLs), this is acceptable but should be documented. Otherwise, consider removing https: and explicitly listing only the required origins.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@vite.config.mjs` at line 13, The CSP string in CSP_META_POLICY contains a
broad connect-src token "https:" which allows any HTTPS origin; update the
CSP_META_POLICY definition to remove the "https:" scheme from the connect-src
directive and instead list only the explicit required origins (e.g.,
https://www.googletagmanager.com, https://www.google-analytics.com,
https://region1.google-analytics.com, https://stats.g.doubleclick.net) or, if
you intentionally want to permit arbitrary HTTPS endpoints, add a clear comment
above CSP_META_POLICY documenting that decision and its risks; locate and edit
the CSP_META_POLICY constant in vite.config.mjs and adjust the connect-src
clause accordingly.

const CSP_HEADER_POLICY = `${CSP_META_POLICY}; frame-ancestors 'self'`;

export default {
Expand Down
Loading