Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@itwin/imodel-browser-react",
"comment": "Add CSP nonce support to the MUI iTwin and iModel DataGrid table views.",
"type": "patch"
}
],
"packageName": "@itwin/imodel-browser-react"
}
10 changes: 10 additions & 0 deletions packages/modules/imodel-browser/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ Contains components that let the user browse the iModels of a context and select

When making changes to the src, run `rushx start` in the dev folder to enable source watching and rebuild, so the storybook dev-server will have access to updated code on successful code compilation.

## Content Security Policy for MUI Components

Some MUI components create runtime `<style>` elements. Applications with a nonce-based Content Security Policy can pass the current document nonce to `ITwinGridMUI` or `IModelGridMUI`:

```tsx
<IModelGridMUI {...props} nonce={cspNonce} />
```

The nonce must match the value in the document's `style-src` or `style-src-elem` directive.

## Changelog

See complete CHANGELOG [here](https://github.com/iTwin/admin-components-react/blob/main/packages/modules/imodel-browser/CHANGELOG.md)
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
import "@testing-library/jest-dom";

import { render, screen } from "@testing-library/react";
import React from "react";

import { IModelTableMUI } from "./iModelGrid/IModelTableMUI";
import { ITwinTableMUI } from "./ITwinGrid/ITwinTableMUI";

jest.mock("@mui/x-data-grid", () => ({
DataGrid: ({ nonce }: { nonce?: string }) => (
<div data-testid="data-grid" data-nonce={nonce} />
),
}));
Comment thread
Copilot marked this conversation as resolved.

const nonce = "test-csp-nonce";

describe("MUI table CSP nonce", () => {
it("forwards the nonce to the iTwin DataGrid", () => {
render(
<ITwinTableMUI
iTwins={[]}
strings={{} as any}
iTwinFavorites={new Set()}
addITwinToFavorites={jest.fn()}
removeITwinFromFavorites={jest.fn()}
refetchITwins={jest.fn()}
nonce={nonce}
/>
);

expect(screen.getByTestId("data-grid")).toHaveAttribute(
"data-nonce",
nonce
);
});

it("forwards the nonce to the iModel DataGrid", () => {
render(
<IModelTableMUI
iModels={[]}
strings={{} as any}
refetchIModels={jest.fn()}
nonce={nonce}
/>
);

expect(screen.getByTestId("data-grid")).toHaveAttribute(
"data-nonce",
nonce
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ export interface ITwinGridPropsMUI
tileOverrides?: Partial<ITwinTilePropsMUI>;
/** Overrides for table column definitions and visibility in cells viewMode */
tableOverrides?: ITwinTableOverridesMUI;
/**
* Nonce applied to `<style>` elements. Required if your application uses a Content Security Policy (CSP) that restricts inline styles.
*/
nonce?: string;
/** Localized string overrides - falls back to default English strings if not provided */
stringsOverrides?: Partial<ITwinGridStringsMUI>;
}
Expand All @@ -99,6 +103,7 @@ export const ITwinGridMUI = ({
viewMode,
tableOverrides,
className,
nonce,
}: ITwinGridPropsMUI) => {
const {
iTwinFavorites,
Expand Down Expand Up @@ -287,6 +292,7 @@ export const ITwinGridMUI = ({
tableOverrides={tableOverrides}
isLoading={fetchStatus === DataStatus.Fetching}
fetchMore={fetchMore}
nonce={nonce}
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ export interface ITwinTableMUIProps {
isLoading?: boolean;
/** Called when more data should be loaded. */
fetchMore?: (() => void) | false;
/**
* Nonce applied to `<style>` elements. Required if your application uses a Content Security Policy (CSP) that restricts inline styles.
*/
nonce?: string;
}

/**
Expand All @@ -85,6 +89,7 @@ export const ITwinTableMUI = ({
} = {},
isLoading,
fetchMore,
nonce,
}: ITwinTableMUIProps) => {
// Eagerly load all available data so the table has the full dataset
// for client-side pagination and sorting.
Expand Down Expand Up @@ -187,6 +192,7 @@ export const ITwinTableMUI = ({
<DataGrid<ITwinFull>
rows={iTwins}
columns={columns}
nonce={nonce}
loading={isLoading}
onRowClick={
actions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ export interface IModelGridMUIProps
/** Static props to apply over each tile, mainly used for tileProps, overrides IModelGrid provided values */
tileOverrides?: Partial<IModelTileMUIProps>;
tableOverrides?: IModelTableOverridesMUI;
/**
* Nonce applied to `<style>` elements. Required if your application uses a Content Security Policy (CSP) that restricts inline styles.
*/
nonce?: string;
stringsOverrides?: Partial<IModelGridStringsMUI>;
}

Expand Down Expand Up @@ -149,6 +153,7 @@ const IModelGridInternal = ({
onRefetch,
dataMode = "internal",
disableAddToRecents = false,
nonce,
}: IModelGridMUIProps) => {
const [sort, setSort] = React.useState<IModelSortOptions>(sortOptions);

Expand Down Expand Up @@ -408,6 +413,7 @@ const IModelGridInternal = ({
tableOverrides={tableOverrides}
isLoading={fetchStatus === DataStatus.Fetching}
fetchMore={fetchMore}
nonce={nonce}
data-testid="imodel-table"
/>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ export interface IModelTableMUIProps {
isLoading?: boolean;
/** Called when more data should be loaded. */
fetchMore?: (() => void) | false;
/**
* Nonce applied to `<style>` elements. Required if your application uses a Content Security Policy (CSP) that restricts inline styles.
*/
nonce?: string;
}

/**
Expand All @@ -79,6 +83,7 @@ export const IModelTableMUI = ({
} = {},
isLoading,
fetchMore,
nonce,
}: IModelTableMUIProps) => {
// Eagerly load all available data so the table has the full dataset
// for client-side pagination and sorting.
Expand Down Expand Up @@ -187,6 +192,7 @@ export const IModelTableMUI = ({
<DataGrid<IModelFull>
rows={iModels}
columns={columns}
nonce={nonce}
loading={isLoading}
onRowClick={
actions
Expand Down
Loading