Skip to content

Commit 26a23be

Browse files
committed
Protect against multiple instantiations of FidesJS and GPP (#6416)
1 parent 920b3de commit 26a23be

18 files changed

Lines changed: 299 additions & 29 deletions

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ Changes can also be flagged with a GitHub label for tracking purposes. The URL o
2424

2525
## [2.67.1](https://github.com/ethyca/fides/compare/2.67.0...2.67.1)
2626

27+
### Added
28+
- Added protection against multiple FidesJS script loading on the same page with configurable override option [#6416](https://github.com/ethyca/fides/pull/6416)
29+
2730
### Fixed
2831
- Fix default tab not being set in the integration detail page for Manual Tasks integrations [#6417](https://github.com/ethyca/fides/pull/6417)
2932

clients/fides-js/docs/interfaces/FidesOptions.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,3 +346,21 @@ Whether to show the modal immediately on page load.
346346

347347
- "immediate" = skips banner and shows the modal immediately on page load
348348
- "default" = shows the modal when the "manage preferences" link is clicked (default behavior)
349+
350+
***
351+
352+
### fides\_unsupported\_repeated\_script\_loading?
353+
354+
> `optional` **fides\_unsupported\_repeated\_script\_loading**: `"enabled_acknowledge_not_supported"` \| `"disabled"`
355+
356+
Controls handling of unsupported repeated script loading scenarios. When
357+
FidesJS is loaded multiple times on the same page, this setting determines
358+
the behavior.
359+
360+
- "enabled_acknowledge_not_supported" = allows repeated loading but acknowledges
361+
this is not a supported configuration
362+
- "disabled" = prevents repeated script loading entirely
363+
364+
See [Troubleshooting](/docs/dev-docs/js/troubleshooting) for more information.
365+
366+
Defaults to `"disabled"`.

clients/fides-js/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,19 @@
1212
],
1313
"exports": {
1414
".": {
15+
"module": "./dist/fides.mjs",
1516
"import": "./dist/fides.mjs",
1617
"require": "./dist/fides.js",
1718
"types": "./dist/fides.d.ts"
1819
},
1920
"./headless": {
21+
"module": "./dist/fides-headless.mjs",
2022
"import": "./dist/fides-headless.mjs",
2123
"require": "./dist/fides-headless.js",
2224
"types": "./dist/fides-headless.d.ts"
2325
},
2426
"./tcf": {
27+
"module": "./dist/fides-tcf.mjs",
2528
"import": "./dist/fides-tcf.mjs",
2629
"require": "./dist/fides-tcf.js",
2730
"types": "./dist/fides-tcf.d.ts"

clients/fides-js/rollup.config.mjs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ import fs from "fs";
1414
import jsxRemoveAttributes from "rollup-plugin-jsx-remove-attributes";
1515
import { importFidesPackageVersion } from "../build-utils.js";
1616

17-
const NAME = "fides";
17+
const GLOBAL_NAME = "Fides";
18+
const FILE_NAME = "fides";
1819
const IS_DEV = process.env.NODE_ENV === "development";
1920
const IS_TEST = process.env.IS_TEST === "true";
2021
const GZIP_SIZE_ERROR_KB = 50; // fail build if bundle size exceeds this
@@ -32,6 +33,8 @@ const GZIP_SIZE_HEADLESS_WARN_KB = 20;
3233
const GZIP_SIZE_GPP_ERROR_KB = 40;
3334
const GZIP_SIZE_GPP_WARN_KB = 35;
3435

36+
const multipleLoadingMessage = `${GLOBAL_NAME} detected that it was already loaded on this page, aborting execution! See https://www.ethyca.com/docs/dev-docs/js/troubleshooting for more information.`;
37+
3538
const preactAliases = {
3639
entries: [
3740
{ find: "react", replacement: "preact/compat" },
@@ -117,22 +120,22 @@ const fidesScriptsJSPlugins = ({ name, gzipWarnSizeKb, gzipErrorSizeKb }) => [
117120

118121
const SCRIPTS = [
119122
{
120-
name: NAME,
123+
name: FILE_NAME,
121124
gzipWarnSizeKb: GZIP_SIZE_WARN_KB,
122125
gzipErrorSizeKb: GZIP_SIZE_ERROR_KB,
123126
},
124127
{
125-
name: `${NAME}-tcf`,
128+
name: `${FILE_NAME}-tcf`,
126129
gzipWarnSizeKb: GZIP_SIZE_TCF_WARN_KB,
127130
gzipErrorSizeKb: GZIP_SIZE_TCF_ERROR_KB,
128131
},
129132
{
130-
name: `${NAME}-headless`,
133+
name: `${FILE_NAME}-headless`,
131134
gzipWarnSizeKb: GZIP_SIZE_HEADLESS_WARN_KB,
132135
gzipErrorSizeKb: GZIP_SIZE_HEADLESS_ERROR_KB,
133136
},
134137
{
135-
name: `${NAME}-ext-gpp`,
138+
name: `${FILE_NAME}-ext-gpp`,
136139
gzipWarnSizeKb: GZIP_SIZE_GPP_WARN_KB,
137140
gzipErrorSizeKb: GZIP_SIZE_GPP_ERROR_KB,
138141
isExtension: true,
@@ -169,12 +172,16 @@ SCRIPTS.forEach(({ name, gzipErrorSizeKb, gzipWarnSizeKb, isExtension }) => {
169172
{
170173
// Intended for browser <script> tag - defines `Fides` global. Also supports UMD loaders.
171174
file: `dist/${name}.js`,
172-
name: isExtension ? undefined : "Fides",
175+
name: isExtension ? undefined : GLOBAL_NAME,
173176
format: isExtension ? "es" : "umd",
174177
sourcemap: IS_DEV ? "inline" : false,
175178
amd: {
176179
define: undefined, // prevent the bundle from registering itself as an AMD module, even if an AMD loader (like RequireJS) is present on the page. This allows FidesJS to use Rollup's `umd` format to support both `iife` and `cjs` modules, but excludes AMD.
177180
},
181+
// Use the "banner" option to prepend a defensive check into the code to guard against loading FidesJS multiple times on the same page
182+
banner: isExtension
183+
? undefined
184+
: `if(typeof ${GLOBAL_NAME}!=="undefined" && ${GLOBAL_NAME}.options?.fidesUnsupportedRepeatedScriptLoading!=="enabled_acknowledge_not_supported") {throw new Error("${multipleLoadingMessage}");}`,
178185
},
179186
],
180187
onLog,

clients/fides-js/src/docs/fides-options.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,4 +306,21 @@ export interface FidesOptions {
306306
*
307307
*/
308308
fides_modal_display?: "immediate" | "default";
309+
310+
/**
311+
* Controls handling of unsupported repeated script loading scenarios. When
312+
* FidesJS is loaded multiple times on the same page, this setting determines
313+
* the behavior.
314+
*
315+
* - "enabled_acknowledge_not_supported" = allows repeated loading but acknowledges
316+
* this is not a supported configuration
317+
* - "disabled" = prevents repeated script loading entirely
318+
*
319+
* See [Troubleshooting](/docs/dev-docs/js/troubleshooting) for more information.
320+
*
321+
* Defaults to `"disabled"`.
322+
*/
323+
fides_unsupported_repeated_script_loading?:
324+
| "enabled_acknowledge_not_supported"
325+
| "disabled";
309326
}

clients/fides-js/src/fides-ext-gpp.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,11 @@ const initializeGppCmpApi = () => {
303303
});
304304
};
305305
window.addEventListener("FidesInitializing", (event) => {
306-
if (event.detail.extraDetails?.gppEnabled) {
306+
if (
307+
event.detail.extraDetails?.gppEnabled &&
308+
typeof window !== "undefined" &&
309+
!window.Fides?.initialized
310+
) {
307311
initializeGppCmpApi();
308312
}
309313
});

clients/fides-js/src/lib/consent-constants.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,12 @@ export const FIDES_OVERRIDE_OPTIONS_VALIDATOR_MAP: FidesOverrideValidatorMap[] =
129129
overrideKey: "fides_modal_display",
130130
validationRegex: /^(immediate|default)$/,
131131
},
132+
{
133+
overrideName: "fidesUnsupportedRepeatedScriptLoading",
134+
overrideType: "string",
135+
overrideKey: "fides_unsupported_repeated_script_loading",
136+
validationRegex: /^(enabled_acknowledge_not_supported|disabled)$/,
137+
},
132138
];
133139

134140
/**

clients/fides-js/src/lib/consent-types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,11 @@ export interface FidesInitOptions {
185185
*
186186
*/
187187
fidesModalDisplay?: "immediate" | "default";
188+
189+
// Controls handling of unsupported repeated script loading
190+
fidesUnsupportedRepeatedScriptLoading?:
191+
| "enabled_acknowledge_not_supported"
192+
| "disabled";
188193
}
189194

190195
/**
@@ -838,6 +843,7 @@ export type FidesInitOptionsOverrides = Pick<
838843
| "fidesInitializedEventMode"
839844
| "fidesModalDefaultView"
840845
| "fidesModalDisplay"
846+
| "fidesUnsupportedRepeatedScriptLoading"
841847
>;
842848

843849
export type FidesExperienceTranslationOverrides = {

clients/fides-js/src/lib/debugger.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
* @param isDebugMode boolean whether or not to enable the debugger
44
*/
55
export const initializeDebugger = (isDebugMode: boolean) => {
6-
if (typeof window !== "undefined" && !window.fidesDebugger) {
7-
// eslint-disable-next-line no-console
8-
window.fidesDebugger = isDebugMode ? console.log : () => {};
6+
if (typeof window !== "undefined") {
7+
if (!window.fidesDebugger) {
8+
// eslint-disable-next-line no-console
9+
window.fidesDebugger = isDebugMode ? console.log : () => {};
10+
}
911
} else {
1012
// avoid any errors if window is not defined
1113
(globalThis as any).fidesDebugger = () => {};

clients/privacy-center/app/server-environment.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ export type PrivacyCenterClientSettings = Pick<
7373
| "FIDES_CONSENT_NON_APPLICABLE_FLAG_MODE"
7474
| "FIDES_CONSENT_FLAG_TYPE"
7575
| "FIDES_INITIALIZED_EVENT_MODE"
76+
| "FIDES_UNSUPPORTED_REPEATED_SCRIPT_LOADING"
7677
>;
7778

7879
export type Styles = string;
@@ -338,6 +339,8 @@ export const getClientSettings = (): PrivacyCenterClientSettings => {
338339
settings.FIDES_CONSENT_NON_APPLICABLE_FLAG_MODE,
339340
FIDES_CONSENT_FLAG_TYPE: settings.FIDES_CONSENT_FLAG_TYPE,
340341
FIDES_INITIALIZED_EVENT_MODE: settings.FIDES_INITIALIZED_EVENT_MODE,
342+
FIDES_UNSUPPORTED_REPEATED_SCRIPT_LOADING:
343+
settings.FIDES_UNSUPPORTED_REPEATED_SCRIPT_LOADING,
341344
};
342345

343346
return clientSettings;

0 commit comments

Comments
 (0)