Skip to content

Commit 31a0d0e

Browse files
feat: ENG-8920 Add support for CSP nonce attribute in Gen 1 SDK (#4080)
## Description - Add support for CSP `nonce` attribute in Gen 1 SDK _Loom_ https://www.loom.com/share/34f7db2b1b884afb94443ca2daa97b0f
1 parent c843564 commit 31a0d0e

File tree

7 files changed

+27
-3
lines changed

7 files changed

+27
-3
lines changed

.changeset/purple-kings-report.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@builder.io/react": patch
3+
---
4+
5+
feat: add `nonce` support for Content Security Policy

packages/react/src/blocks/PersonalizationContainer.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ export function PersonalizationContainer(props: PersonalizationContainerProps) {
106106
</template>
107107
))}
108108
<script
109+
nonce={builderStore.context.nonce}
109110
id={`variants-script-${props.builderBlock?.id}`}
110111
dangerouslySetInnerHTML={{
111112
__html: getPersonalizationScript(
@@ -123,6 +124,7 @@ export function PersonalizationContainer(props: PersonalizationContainerProps) {
123124
/>
124125
</div>
125126
<script
127+
nonce={builderStore.context.nonce}
126128
dangerouslySetInnerHTML={{
127129
__html: `
128130
window.__hydrated = window.__hydrated || {};
@@ -194,6 +196,7 @@ export function PersonalizationContainer(props: PersonalizationContainerProps) {
194196
)}
195197
</div>
196198
<script
199+
nonce={builderStore.context.nonce}
197200
dangerouslySetInnerHTML={{
198201
__html: `
199202
window.__hydrated = window.__hydrated || {};

packages/react/src/blocks/Router.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ class RouterComponent extends React.Component<PropsWithChildren<RouterProps>> {
262262
return (
263263
<div className="builder-router" data-model={model}>
264264
{/* TODO: move to emotion */}
265-
<style>{`
265+
<style nonce={state.context.nonce}>{`
266266
@keyframes builderLoadingSpinner {
267267
0% {
268268
transform: rotate(0deg);
@@ -297,6 +297,7 @@ class RouterComponent extends React.Component<PropsWithChildren<RouterProps>> {
297297
options={{
298298
key: Builder.isEditing ? undefined : this.model + ':' + url, // TODO: other custom targets specify if should refetch components on change
299299
}}
300+
nonce={state.context.nonce}
300301
>
301302
{/* TODO: builder blocks option for loading stuff */}
302303
{/* TODO: input for builder blocks for this */}

packages/react/src/blocks/Symbol.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ class SymbolComponent extends React.Component<PropsWithChildren<SymbolProps>> {
172172
hydrate={state.state?._hydrate}
173173
builderBlock={this.props.builderBlock}
174174
dataOnly={this.props.dataOnly}
175+
nonce={state.context.nonce}
175176
>
176177
{/* TODO: builder blocks option for loading stuff */}
177178
{this.props.children}

packages/react/src/components/builder-component.component.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,11 @@ export interface BuilderComponentProps {
298298
* Pass a list of custom components to register with Builder.io.
299299
*/
300300
customComponents?: Array<RegisteredComponent>;
301+
302+
/**
303+
* CSP nonce to allow the loading and execution of a script or style tag when Content-Security-Policy is enabled.
304+
*/
305+
nonce?: string;
301306
}
302307

303308
export interface BuilderComponentState {
@@ -439,6 +444,7 @@ export class BuilderComponent extends React.Component<
439444
context: {
440445
...props.context,
441446
apiKey: this.props.apiKey || builder.apiKey,
447+
nonce: this.props.nonce,
442448
},
443449
state: Object.assign(this.rootState, {
444450
...(this.inlinedContent && this.inlinedContent.data && this.inlinedContent.data.state),
@@ -1097,6 +1103,7 @@ export class BuilderComponent extends React.Component<
10971103
}
10981104
contentError={this.props.contentError}
10991105
modelName={this.name || 'page'}
1106+
nonce={this.props.nonce}
11001107
>
11011108
{(data, loading, fullData) => {
11021109
if (this.props.dataOnly) {
@@ -1191,6 +1198,7 @@ export class BuilderComponent extends React.Component<
11911198
>
11921199
{!codegen && this.getCss(data) && (
11931200
<style
1201+
nonce={this.props.nonce}
11941202
ref={ref => (this.styleRef = ref)}
11951203
className="builder-custom-styles"
11961204
dangerouslySetInnerHTML={{

packages/react/src/components/builder-content.component.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ export type BuilderContentProps<ContentType> = {
5050
* Required if `inline` is set to `true`.
5151
*/
5252
content?: Content;
53+
/**
54+
* CSP nonce to allow the loading and execution of a script or style tag when Content-Security-Policy is enabled.
55+
*/
56+
nonce?: string;
5357
} & ({ model: string } | { modelName: string }); // model and modelName are aliases of the same thing¸
5458

5559
/**
@@ -314,7 +318,7 @@ export class BuilderContent<ContentType extends object = any> extends React.Comp
314318
const useData: any = this.data;
315319
const TagName = this.props.dataOnly ? NoWrap : 'div';
316320
return (
317-
<VariantsProvider initialContent={useData}>
321+
<VariantsProvider initialContent={useData} nonce={this.props.nonce}>
318322
{(variants, renderScript) => {
319323
return (
320324
<React.Fragment>

packages/react/src/components/variants-provider.component.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,10 @@ const variantsScript = (variantsString: string, contentId: string) =>
9999
interface VariantsProviderProps {
100100
initialContent: BuilderContent;
101101
children: (variants: BuilderContent[], renderScript?: () => JSX.Element) => JSX.Element;
102+
nonce?: string;
102103
}
103104

104-
export const VariantsProvider = ({ initialContent, children }: VariantsProviderProps) => {
105+
export const VariantsProvider = ({ initialContent, children, nonce }: VariantsProviderProps) => {
105106
if (Builder.isBrowser && !builder.canTrack) {
106107
return children([initialContent]);
107108
}
@@ -126,6 +127,7 @@ export const VariantsProvider = ({ initialContent, children }: VariantsProviderP
126127
);
127128
const renderScript = () => (
128129
<script
130+
nonce={nonce}
129131
id={`variants-script-${initialContent.id}`}
130132
dangerouslySetInnerHTML={{
131133
__html: variantsScript(variantsJson, initialContent.id!),

0 commit comments

Comments
 (0)