Skip to content

Commit 28e309b

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

File tree

7 files changed

+117
-10
lines changed

7 files changed

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