Skip to content

Commit 87117f4

Browse files
feat(core): ARC-78 added CSP
feat(security): implement CSP via react-helmet-async in React frontend
1 parent 576af26 commit 87117f4

File tree

7 files changed

+123
-10
lines changed

7 files changed

+123
-10
lines changed

.env.development.example

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
VITE_CSP_DEFAULT_SRC=
2+
VITE_CSP_SCRIPT_SRC=
3+
VITE_CSP_STYLE_SRC=
4+
VITE_CSP_IMG_SRC=
5+
VITE_CSP_CONNECT_SRC=
6+
VITE_CSP_OBJECT_SRC=
7+
VITE_CSP_BASE_URI=
8+
VITE_CSP_FORM_ACTION=
9+
VITE_CSP_BLOCK_ALL_MIXED_CONTENT=

.env.production.example

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
VITE_CSP_DEFAULT_SRC=
2+
VITE_CSP_SCRIPT_SRC=
3+
VITE_CSP_STYLE_SRC=
4+
VITE_CSP_IMG_SRC=
5+
VITE_CSP_CONNECT_SRC=
6+
VITE_CSP_OBJECT_SRC=
7+
VITE_CSP_BASE_URI=
8+
VITE_CSP_FORM_ACTION=
9+
VITE_CSP_BLOCK_ALL_MIXED_CONTENT=

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
.env.test.local
2020
.env.production.local
2121
.env.production
22+
.env.development
2223

2324
npm-debug.log*
2425
yarn-debug.log*

package-lock.json

Lines changed: 56 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"react-beautiful-dnd": "^13.1.1",
4444
"react-copy-to-clipboard": "^5.1.0",
4545
"react-dom": "^18.2.0",
46+
"react-helmet-async": "^2.0.5",
4647
"react-idle-timer": "^5.7.2",
4748
"react-redux": "^8.1.0",
4849
"react-router": "^6.4.3",

src/Components/CSP.tsx

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import {Helmet} from 'react-helmet-async';
2+
3+
const CSPMeta = () => {
4+
const env = import.meta.env;
5+
const directives: string[] = [];
6+
Object.entries(env).forEach(([key, rawValue]) => {
7+
if (!key.startsWith('VITE_CSP_')) return;
8+
9+
const directiveKey = key
10+
.replace(/^VITE_CSP_/, '')
11+
.replace(/_/g, '-')
12+
.toLowerCase();
13+
14+
let value;
15+
if (rawValue === 'true') {
16+
value = true;
17+
} else if (rawValue === 'false') {
18+
value = false;
19+
} else {
20+
value = rawValue;
21+
}
22+
23+
if (typeof value === 'boolean') {
24+
if (value) {
25+
directives.push(`${directiveKey};`);
26+
}
27+
} else {
28+
directives.push(`${directiveKey} ${value};`);
29+
}
30+
});
31+
32+
const csp = directives.join(' ').trim();
33+
34+
return (
35+
<Helmet>
36+
<meta httpEquiv="Content-Security-Policy" content={csp} />
37+
</Helmet>
38+
);
39+
};
40+
41+
export default CSPMeta;

src/index.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import React from 'react';
22
import ReactDOM from 'react-dom/client';
3+
import {HelmetProvider} from 'react-helmet-async';
34
import AppWrapper from './AppWrapper';
4-
5+
import CSPMeta from './Components/CSP';
56
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
67

78
root.render(
89
<React.StrictMode>
9-
<AppWrapper />
10+
<HelmetProvider>
11+
<CSPMeta />
12+
<AppWrapper />
13+
</HelmetProvider>
1014
</React.StrictMode>,
1115
);

0 commit comments

Comments
 (0)