@eeacms/volto-cca-policy 0.3.81 → 0.3.83

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,10 +4,11 @@ All notable changes to this project will be documented in this file. Dates are d
4
4
 
5
5
  Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
6
6
 
7
- ### [0.3.81](https://github.com/eea/volto-cca-policy/compare/1.0.0-alpha.1...0.3.81) - 26 August 2025
7
+ ### [0.3.83](https://github.com/eea/volto-cca-policy/compare/1.0.0-alpha.1...0.3.83) - 10 September 2025
8
8
 
9
9
  #### :rocket: Dependency updates
10
10
 
11
+ - Release @eeacms/volto-searchlib@2.1.10 [EEA Jenkins - [`ec1bf82`](https://github.com/eea/volto-cca-policy/commit/ec1bf82df7258b9df4e2496b98aa7a8eccdbeb17)]
11
12
  - Release @eeacms/volto-searchlib@2.1.8 [EEA Jenkins - [`4518eba`](https://github.com/eea/volto-cca-policy/commit/4518ebac718c205eac0fd80583efc564ecf8ae69)]
12
13
  - Release @eeacms/volto-searchlib@2.1.7 [EEA Jenkins - [`ef5499d`](https://github.com/eea/volto-cca-policy/commit/ef5499dfc12182ac38af1283bbc87fd154891a6c)]
13
14
 
@@ -24,7 +25,8 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
24
25
 
25
26
  #### :hammer_and_wrench: Others
26
27
 
27
- - Show image in mission sig profile header; add reduxAsyncConnect to initialReducersBlacklist [Tiberiu Ichim - [`442b089`](https://github.com/eea/volto-cca-policy/commit/442b089083958aff76a6c985aac1441a2cf43ae1)]
28
+ - Add customization for server.jsx [Tiberiu Ichim - [`c625d39`](https://github.com/eea/volto-cca-policy/commit/c625d397493ca9c1bcbd4083dd0b93969d89ef97)]
29
+ - Remove customizations for server, to benefit from CSP headers implemented in eea-website-theme [Tiberiu Ichim - [`0c9ce15`](https://github.com/eea/volto-cca-policy/commit/0c9ce154c68a589ad6a0c553b36ea6e4f155ed09)]
28
30
  - Refs #290787 - sum of countries [Tripon Eugen - [`f1033cf`](https://github.com/eea/volto-cca-policy/commit/f1033cf0beca2d7cace3d1ee2bc93d03cbf7b3c8)]
29
31
  - Refs #290787 - contry map update flat/round earth and diffrent countries list [Tripon Eugen - [`6009e9f`](https://github.com/eea/volto-cca-policy/commit/6009e9f2ef28aeacd8f27d2735e0270822a13a5e)]
30
32
  ### [1.0.0-alpha.1](https://github.com/eea/volto-cca-policy/compare/1.0.0-alpha.0...1.0.0-alpha.1) - 28 July 2025
@@ -108,7 +110,19 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
108
110
  - Add some loadable for components [Tiberiu Ichim - [`1793962`](https://github.com/eea/volto-cca-policy/commit/179396211c66a6a2465b2d1b6c0f2afc40fc7189)]
109
111
  - Refs #284961 - test [Tripon Eugen - [`c989f1f`](https://github.com/eea/volto-cca-policy/commit/c989f1f8638c0c5233c5c49f8673c9a2cdc7937e)]
110
112
  - Refs #284961 - add translations [Tripon Eugen - [`04ee988`](https://github.com/eea/volto-cca-policy/commit/04ee988c086d393b9b37ce1ea8d24f5e84f266aa)]
111
- ### [1.0.0-alpha.0](https://github.com/eea/volto-cca-policy/compare/0.3.80...1.0.0-alpha.0) - 15 July 2025
113
+ ### [1.0.0-alpha.0](https://github.com/eea/volto-cca-policy/compare/0.3.82...1.0.0-alpha.0) - 15 July 2025
114
+
115
+ ### [0.3.82](https://github.com/eea/volto-cca-policy/compare/0.3.81...0.3.82) - 5 September 2025
116
+
117
+ #### :rocket: Dependency updates
118
+
119
+ - Release @eeacms/volto-searchlib@2.1.10 [EEA Jenkins - [`ec1bf82`](https://github.com/eea/volto-cca-policy/commit/ec1bf82df7258b9df4e2496b98aa7a8eccdbeb17)]
120
+
121
+ ### [0.3.81](https://github.com/eea/volto-cca-policy/compare/0.3.80...0.3.81) - 26 August 2025
122
+
123
+ #### :house: Internal changes
124
+
125
+ - style: Automated code fix [eea-jenkins - [`f8934ba`](https://github.com/eea/volto-cca-policy/commit/f8934baf29317bb81cb5a816bfe66ee1724e040f)]
112
126
 
113
127
  ### [0.3.80](https://github.com/eea/volto-cca-policy/compare/0.3.79...0.3.80) - 25 August 2025
114
128
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-cca-policy",
3
- "version": "0.3.81",
3
+ "version": "0.3.83",
4
4
  "description": "@eeacms/volto-cca-policy: Volto add-on",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: IDM2 A-Team",
@@ -34,7 +34,7 @@
34
34
  "@eeacms/volto-embed": "*",
35
35
  "@eeacms/volto-globalsearch": "2.1.2",
36
36
  "@eeacms/volto-openlayers-map": "1.0.1",
37
- "@eeacms/volto-searchlib": "2.1.8",
37
+ "@eeacms/volto-searchlib": "2.1.10",
38
38
  "@eeacms/volto-slate-label": "1.0.1",
39
39
  "@eeacms/volto-tabs-block": "9.0.3",
40
40
  "@elastic/search-ui": "1.21.2",
@@ -0,0 +1,2 @@
1
+ copied from volto-eea-website-theme sha 5fa9b49d4619f893baa0330ee45f5b2e90eeb72c
2
+ server.jsx is customized to not crash when it doesn't find .po translation files.
@@ -1,6 +1,3 @@
1
- /* Original: https://github.com/plone/volto/blob/16.x.x/src/server.jsx */
2
- /* Line: 59 - Fix crash when a supported language it's not in volto/locales folder */
3
-
4
1
  /* eslint no-console: 0 */
5
2
  import '@plone/volto/config'; // This is the bootstrap for the global config - server side
6
3
  import { existsSync, lstatSync, readFileSync } from 'fs';
@@ -20,7 +17,7 @@ import { resetServerContext } from 'react-beautiful-dnd';
20
17
  import { CookiesProvider } from 'react-cookie';
21
18
  import cookiesMiddleware from 'universal-cookie-express';
22
19
  import debug from 'debug';
23
- // import crypto from 'crypto';
20
+ import crypto from 'crypto';
24
21
 
25
22
  import routes from '@plone/volto/routes';
26
23
  import config from '@plone/volto/registry';
@@ -49,7 +46,18 @@ import {
49
46
  } from '@plone/volto/helpers/AsyncConnect';
50
47
 
51
48
  let locales = {};
49
+ const isCSP = process.env.CSP_HEADER || config.settings.serverConfig.csp;
50
+
51
+ // if (config.settings) {
52
+ // config.settings.supportedLanguages.forEach((lang) => {
53
+ // const langFileName = toGettextLang(lang);
54
+ // import('@root/../locales/' + langFileName + '.json').then((locale) => {
55
+ // locales = { ...locales, [toReactIntlLang(lang)]: locale.default };
56
+ // });
57
+ // });
58
+ // }
52
59
 
60
+ // customized
53
61
  if (config.settings) {
54
62
  config.settings.supportedLanguages.forEach((lang) => {
55
63
  const langFileName = toGettextLang(lang);
@@ -64,18 +72,7 @@ if (config.settings) {
64
72
  // end customization
65
73
  });
66
74
  }
67
-
68
- // function buildCSPHeader(opts, nonce) {
69
- // return Object.keys(opts)
70
- // .sort()
71
- // .reduce((acc, key) => {
72
- // return [
73
- // ...acc,
74
- // `${key} ${opts[key].replaceAll('{nonce}', `'nonce-${nonce}'`)}`,
75
- // ];
76
- // }, [])
77
- // .join('; ');
78
- // }
75
+ //end customized
79
76
 
80
77
  function reactIntlErrorHandler(error) {
81
78
  debug('i18n')(error);
@@ -84,8 +81,8 @@ function reactIntlErrorHandler(error) {
84
81
  const supported = new locale.Locales(keys(languages), 'en');
85
82
 
86
83
  const server = express()
87
- .set('etag', false)
88
84
  .disable('x-powered-by')
85
+ .set('etag', false)
89
86
  .head('/*', function (req, res) {
90
87
  // Support for HEAD requests. Required by start-test utility in CI.
91
88
  res.send('');
@@ -125,7 +122,28 @@ server.use(function (err, req, res, next) {
125
122
  }
126
123
  });
127
124
 
125
+ function buildCSPHeader(opts, nonce) {
126
+ if (typeof opts === 'string') {
127
+ //CSP_HEADER
128
+ return opts.replaceAll('{nonce}', `'nonce-${nonce}'`);
129
+ }
130
+ return Object.keys(opts)
131
+ .sort()
132
+ .reduce((acc, key) => {
133
+ return [
134
+ ...acc,
135
+ `${key} ${opts[key].replaceAll('{nonce}', `'nonce-${nonce}'`)}`,
136
+ ];
137
+ }, [])
138
+ .join('; ');
139
+ }
140
+
128
141
  function setupServer(req, res, next) {
142
+ if (isCSP) {
143
+ const nonce = crypto.randomBytes(16).toString('base64');
144
+ res.locals.nonce = nonce;
145
+ }
146
+
129
147
  const api = new Api(req);
130
148
 
131
149
  const lang = toReactIntlLang(
@@ -199,7 +217,11 @@ function setupServer(req, res, next) {
199
217
  }
200
218
 
201
219
  server.get('/*', (req, res) => {
202
- const { errorHandler } = res.locals;
220
+ const { errorHandler, nonce } = res.locals;
221
+
222
+ if (isCSP) {
223
+ res.setHeader('Content-Security-Policy', buildCSPHeader(isCSP, nonce));
224
+ }
203
225
 
204
226
  const api = new Api(req);
205
227
 
@@ -265,7 +287,7 @@ server.get('/*', (req, res) => {
265
287
  : store.getState().content.data?.language?.token ||
266
288
  config.settings.defaultLanguage;
267
289
 
268
- if (toBackendLang(initialLang) !== contentLang) {
290
+ if (toBackendLang(initialLang) !== contentLang && url !== '/') {
269
291
  const newLang = toReactIntlLang(
270
292
  new locale.Locales(contentLang).best(supported).toString(),
271
293
  );
@@ -310,6 +332,7 @@ server.get('/*', (req, res) => {
310
332
  ${renderToString(
311
333
  <Html
312
334
  extractor={extractor}
335
+ nonce={nonce}
313
336
  markup={markup}
314
337
  store={store}
315
338
  extractScripts={
@@ -331,6 +354,7 @@ server.get('/*', (req, res) => {
331
354
  ${renderToString(
332
355
  <Html
333
356
  extractor={extractor}
357
+ nonce={nonce}
334
358
  markup={markup}
335
359
  store={store}
336
360
  criticalCss={readCriticalCss(req)}
@@ -1,213 +0,0 @@
1
- /**
2
- * Html helper.
3
- * @module helpers/Html
4
- */
5
-
6
- import React, { Component } from 'react';
7
- import PropTypes from 'prop-types';
8
- import Helmet from '@plone/volto/helpers/Helmet/Helmet';
9
- import serialize from 'serialize-javascript';
10
- import { join } from 'lodash';
11
- import BodyClass from '@plone/volto/helpers/BodyClass/BodyClass';
12
- import { runtimeConfig } from '@plone/volto/runtime_config';
13
- import config from '@plone/volto/registry';
14
-
15
- const CRITICAL_CSS_TEMPLATE = `function alter() {
16
- document.querySelectorAll("head link[rel='prefetch']").forEach(function(el) { el.rel = 'stylesheet'});
17
- }
18
- if (window.addEventListener) {
19
- window.addEventListener('DOMContentLoaded', alter, false)
20
- } else {
21
- window.onload=alter
22
- }`;
23
-
24
- export const loadReducers = (state = {}) => {
25
- const { settings } = config;
26
- return Object.assign(
27
- {},
28
- ...Object.keys(state).map((name) =>
29
- settings.initialReducersBlacklist.includes(name)
30
- ? {}
31
- : { [name]: state[name] },
32
- ),
33
- );
34
- };
35
-
36
- /**
37
- * Html class.
38
- * Wrapper component containing HTML metadata and boilerplate tags.
39
- * Used in server-side code only to wrap the string output of the
40
- * rendered route component.
41
- *
42
- * The only thing this component doesn't (and can't) include is the
43
- * HTML doctype declaration, which is added to the rendered output
44
- * by the server.js file.
45
- *
46
- * Critical.css behaviour: when a file `public/critical.css` is present, the
47
- * loading of stylesheets is changed. The styles in critical.css are inlined in
48
- * the generated HTML, and the whole story needs to change completely: instead
49
- * of treating stylesheets as priority for rendering, we want to defer their
50
- * loading as much as possible. So we change the stylesheets to be prefetched
51
- * and we switch their rel back to stylesheets at document ready event.
52
- *
53
- * @function Html
54
- * @param {Object} props Component properties.
55
- * @param {Object} props.assets Assets to be rendered.
56
- * @param {Object} props.component Content to be rendered as child node.
57
- * @param {Object} props.store Store object.
58
- * @returns {string} Markup of the not found page.
59
- */
60
-
61
- /**
62
- * Html class.
63
- * @class Html
64
- * @extends Component
65
- */
66
- class Html extends Component {
67
- /**
68
- * Property types.
69
- * @property {Object} propTypes Property types.
70
- * @static
71
- */
72
- static propTypes = {
73
- extractor: PropTypes.shape({
74
- getLinkElements: PropTypes.func.isRequired,
75
- getScriptElements: PropTypes.func.isRequired,
76
- getStyleElements: PropTypes.func.isRequired,
77
- }).isRequired,
78
- markup: PropTypes.string.isRequired,
79
- store: PropTypes.shape({
80
- getState: PropTypes.func,
81
- }).isRequired,
82
- nonce: PropTypes.string,
83
- };
84
-
85
- /**
86
- * Render method.
87
- * @method render
88
- * @returns {string} Markup for the component.
89
- */
90
- render() {
91
- const { extractor, markup, store, criticalCss, apiPath, publicURL, nonce } =
92
- this.props;
93
- const head = Helmet.rewind();
94
- const bodyClass = join(BodyClass.rewind(), ' ');
95
- const htmlAttributes = head.htmlAttributes.toComponent();
96
-
97
- return (
98
- <html lang={htmlAttributes.lang}>
99
- <head>
100
- <meta charSet="utf-8" />
101
- {head.base.toComponent()}
102
- {head.title.toComponent()}
103
- {head.meta.toComponent()}
104
- {head.link.toComponent()}
105
- {head.script.toComponent()}
106
-
107
- {React.createElement('script', {
108
- nonce: nonce,
109
- dangerouslySetInnerHTML: {
110
- __html: `window.env = ${serialize({
111
- ...runtimeConfig,
112
- // Seamless mode requirement, the client need to know where the API is located
113
- // if not set in the API_PATH
114
- ...(apiPath && {
115
- apiPath,
116
- }),
117
- ...(publicURL && {
118
- publicURL,
119
- }),
120
- })};`,
121
- },
122
- })}
123
- <link
124
- rel="sitemap"
125
- type="application/xml"
126
- title="Sitemap"
127
- href="/sitemap-index.xml"
128
- ></link>
129
- <link rel="icon" href="/favicon.ico" sizes="any" />
130
- <link rel="icon" href="/icon.svg" type="image/svg+xml" />
131
- <link
132
- rel="apple-touch-icon"
133
- sizes="180x180"
134
- href="/apple-touch-icon.png"
135
- />
136
- <link rel="manifest" href="/site.webmanifest" />
137
- <meta name="generator" content="Plone 6 - https://plone.org" />
138
- <meta name="viewport" content="width=device-width, initial-scale=1" />
139
- <meta name="apple-mobile-web-app-capable" content="yes" />
140
- {process.env.NODE_ENV === 'production' && criticalCss && (
141
- <style
142
- dangerouslySetInnerHTML={{ __html: this.props.criticalCss }}
143
- />
144
- )}
145
- {/* Add the crossorigin while in development */}
146
- {extractor.getLinkElements().map((elem) =>
147
- React.cloneElement(elem, {
148
- crossOrigin:
149
- process.env.NODE_ENV === 'production' ? undefined : 'true',
150
- rel: !criticalCss
151
- ? elem.props.rel
152
- : elem.props.as === 'style'
153
- ? 'prefetch'
154
- : elem.props.rel,
155
- }),
156
- )}
157
- {/* Styles in development are loaded with Webpack's style-loader, in production,
158
- they need to be static*/}
159
- {process.env.NODE_ENV === 'production' ? (
160
- criticalCss ? (
161
- <>
162
- <script
163
- dangerouslySetInnerHTML={{
164
- __html: CRITICAL_CSS_TEMPLATE,
165
- }}
166
- ></script>
167
- {extractor.getStyleElements().map((elem) => (
168
- <noscript>
169
- {React.cloneElement(elem, {
170
- rel: 'stylesheet',
171
- crossOrigin:
172
- process.env.NODE_ENV === 'production'
173
- ? undefined
174
- : 'true',
175
- })}
176
- </noscript>
177
- ))}
178
- </>
179
- ) : (
180
- extractor.getStyleElements()
181
- )
182
- ) : undefined}
183
- </head>
184
- <body className={bodyClass}>
185
- <div role="navigation" aria-label="Toolbar" id="toolbar" />
186
- <div id="main" dangerouslySetInnerHTML={{ __html: markup }} />
187
- <div role="complementary" aria-label="Sidebar" id="sidebar" />
188
- {React.createElement('script', {
189
- nonce: nonce,
190
- dangerouslySetInnerHTML: {
191
- __html: `window.__data=${serialize(
192
- loadReducers(store.getState()),
193
- )};`,
194
- },
195
- charSet: 'UTF-8',
196
- })}
197
- {/* Add the crossorigin while in development */}
198
- {this.props.extractScripts !== false
199
- ? extractor.getScriptElements().map((elem) =>
200
- React.cloneElement(elem, {
201
- nonce: nonce,
202
- crossOrigin:
203
- process.env.NODE_ENV === 'production' ? undefined : 'true',
204
- }),
205
- )
206
- : ''}
207
- </body>
208
- </html>
209
- );
210
- }
211
- }
212
-
213
- export default Html;