mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-08-22 01:36:43 +02:00
Compare commits
5 Commits
@mermaid-j
...
sidv/neste
Author | SHA1 | Date | |
---|---|---|---|
![]() |
6359ab504f | ||
![]() |
7171237b96 | ||
![]() |
066883f4cd | ||
![]() |
c534d3d364 | ||
![]() |
4db72f5357 |
2
.github/workflows/e2e-timings.yml
vendored
2
.github/workflows/e2e-timings.yml
vendored
@@ -58,7 +58,7 @@ jobs:
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Commit and create pull request
|
||||
uses: peter-evans/create-pull-request@1310d7dab503600742045e6fd4b84dda64352858
|
||||
uses: peter-evans/create-pull-request@cb4d3bfce175d44325c6b7697f81e0afe8a79bdf
|
||||
with:
|
||||
add-paths: |
|
||||
cypress/timings.json
|
||||
|
@@ -12,7 +12,7 @@
|
||||
|
||||
> **addDirective**(`directive`): `void`
|
||||
|
||||
Defined in: [packages/mermaid/src/config.ts:188](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.ts#L188)
|
||||
Defined in: [packages/mermaid/src/config.ts:202](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.ts#L202)
|
||||
|
||||
Pushes in a directive to the configuration
|
||||
|
||||
|
@@ -12,7 +12,7 @@
|
||||
|
||||
> **reset**(`config`): `void`
|
||||
|
||||
Defined in: [packages/mermaid/src/config.ts:221](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.ts#L221)
|
||||
Defined in: [packages/mermaid/src/config.ts:235](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.ts#L235)
|
||||
|
||||
## reset
|
||||
|
||||
|
@@ -10,7 +10,7 @@
|
||||
|
||||
# Function: sanitize()
|
||||
|
||||
> **sanitize**(`options`): `void`
|
||||
> **sanitize**(`options`, `path`): `void`
|
||||
|
||||
Defined in: [packages/mermaid/src/config.ts:146](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.ts#L146)
|
||||
|
||||
@@ -31,6 +31,10 @@ options in-place
|
||||
|
||||
The potential setConfig parameter
|
||||
|
||||
### path
|
||||
|
||||
`string`\[] = `[]`
|
||||
|
||||
## Returns
|
||||
|
||||
`void`
|
||||
|
@@ -34,6 +34,92 @@ describe('when working with site config', () => {
|
||||
expect(cfg.fontSize).toBe(config_0.fontSize);
|
||||
expect(cfg.securityLevel).toBe(config_0.securityLevel);
|
||||
});
|
||||
|
||||
it('should respect nested secure keys when applying directives', () => {
|
||||
const config_0: MermaidConfig = {
|
||||
fontFamily: 'foo-font',
|
||||
themeVariables: {
|
||||
fontSize: 16,
|
||||
fontFamily: 'default-font',
|
||||
},
|
||||
secure: [
|
||||
...configApi.defaultConfig.secure!,
|
||||
'themeVariables.fontSize',
|
||||
'themeVariables.fontFamily',
|
||||
],
|
||||
};
|
||||
configApi.setSiteConfig(config_0);
|
||||
const directive: MermaidConfig = {
|
||||
fontFamily: 'baf',
|
||||
themeVariables: {
|
||||
fontSize: 24, // shouldn't be changed
|
||||
fontFamily: 'new-font', // shouldn't be changed
|
||||
primaryColor: '#ff0000', // should be allowed
|
||||
},
|
||||
};
|
||||
const cfg: MermaidConfig = configApi.updateCurrentConfig(config_0, [directive]);
|
||||
expect(cfg.fontFamily).toEqual(directive.fontFamily);
|
||||
expect(cfg.themeVariables!.fontSize).toBe(config_0.themeVariables!.fontSize);
|
||||
expect(cfg.themeVariables!.fontFamily).toBe(config_0.themeVariables!.fontFamily);
|
||||
expect(cfg.themeVariables!.primaryColor).toBe(directive.themeVariables!.primaryColor);
|
||||
});
|
||||
|
||||
it('should handle deeply nested secure keys', () => {
|
||||
const config_0: MermaidConfig = {
|
||||
flowchart: {
|
||||
nodeSpacing: 50,
|
||||
rankSpacing: 50,
|
||||
curve: 'basis',
|
||||
htmlLabels: true,
|
||||
useMaxWidth: true,
|
||||
diagramPadding: 8,
|
||||
},
|
||||
secure: [
|
||||
...configApi.defaultConfig.secure!,
|
||||
'flowchart.nodeSpacing',
|
||||
'flowchart.rankSpacing',
|
||||
],
|
||||
};
|
||||
configApi.setSiteConfig(config_0);
|
||||
const directive: MermaidConfig = {
|
||||
flowchart: {
|
||||
nodeSpacing: 100, // shouldn't be changed
|
||||
rankSpacing: 100, // shouldn't be changed
|
||||
curve: 'linear', // should be allowed
|
||||
htmlLabels: false, // should be allowed
|
||||
},
|
||||
};
|
||||
const cfg: MermaidConfig = configApi.updateCurrentConfig(config_0, [directive]);
|
||||
expect(cfg.flowchart!.nodeSpacing).toBe(config_0.flowchart!.nodeSpacing);
|
||||
expect(cfg.flowchart!.rankSpacing).toBe(config_0.flowchart!.rankSpacing);
|
||||
expect(cfg.flowchart!.curve).toBe(directive.flowchart!.curve);
|
||||
expect(cfg.flowchart!.htmlLabels).toBe(directive.flowchart!.htmlLabels);
|
||||
expect(cfg.flowchart!.diagramPadding).toBe(config_0.flowchart!.diagramPadding);
|
||||
});
|
||||
|
||||
it('should handle mixed top-level and nested secure keys', () => {
|
||||
const config_0: MermaidConfig = {
|
||||
fontFamily: 'foo-font',
|
||||
themeVariables: {
|
||||
fontSize: 16,
|
||||
primaryColor: '#000000',
|
||||
},
|
||||
secure: [...configApi.defaultConfig.secure!, 'fontFamily', 'themeVariables.fontSize'],
|
||||
};
|
||||
configApi.setSiteConfig(config_0);
|
||||
const directive: MermaidConfig = {
|
||||
fontFamily: 'new-font', // shouldn't be changed
|
||||
themeVariables: {
|
||||
fontSize: 24, // shouldn't be changed
|
||||
primaryColor: '#ff0000', // should be allowed
|
||||
},
|
||||
};
|
||||
const cfg: MermaidConfig = configApi.updateCurrentConfig(config_0, [directive]);
|
||||
expect(cfg.fontFamily).toBe(config_0.fontFamily);
|
||||
expect(cfg.themeVariables!.fontSize).toBe(config_0.themeVariables!.fontSize);
|
||||
expect(cfg.themeVariables!.primaryColor).toBe(directive.themeVariables!.primaryColor);
|
||||
});
|
||||
|
||||
it('should allow setting partial options', () => {
|
||||
const defaultConfig = configApi.getConfig();
|
||||
|
||||
|
@@ -143,17 +143,29 @@ export const getConfig = (): MermaidConfig => {
|
||||
*
|
||||
* @param options - The potential setConfig parameter
|
||||
*/
|
||||
export const sanitize = (options: any) => {
|
||||
export const sanitize = (options: any, path: string[] = []) => {
|
||||
if (!options) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Checking that options are not in the list of excluded options
|
||||
['secure', ...(siteConfig.secure ?? [])].forEach((key) => {
|
||||
if (Object.hasOwn(options, key)) {
|
||||
// DO NOT attempt to print options[key] within `${}` as a malicious script
|
||||
// can exploit the logger's attempt to stringify the value and execute arbitrary code
|
||||
log.debug(`Denied attempt to modify a secure key ${key}`, options[key]);
|
||||
delete options[key];
|
||||
['secure', ...(siteConfig.secure ?? [])].forEach((secureKey) => {
|
||||
const securePath = secureKey.split('.');
|
||||
|
||||
// Check if current path matches the secure key path
|
||||
if (path.length >= securePath.length - 1) {
|
||||
const targetKey = securePath[securePath.length - 1];
|
||||
const pathSuffix = path.slice(-(securePath.length - 1));
|
||||
const pathPrefix = securePath.slice(0, -1);
|
||||
|
||||
const isMatch =
|
||||
securePath.length === 1 ? path.length === 0 : pathSuffix.join('.') === pathPrefix.join('.');
|
||||
|
||||
if (isMatch && Object.hasOwn(options, targetKey)) {
|
||||
const fullPath = path.length > 0 ? `${path.join('.')}.${secureKey}` : secureKey;
|
||||
log.debug(`Denied attempt to modify a secure key ${fullPath}`, options[targetKey]);
|
||||
delete options[targetKey];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -163,6 +175,7 @@ export const sanitize = (options: any) => {
|
||||
delete options[key];
|
||||
}
|
||||
});
|
||||
|
||||
// Check that there no attempts of xss, there should be no tags at all in the directive
|
||||
// blocking data urls as base64 urls can contain svg's with inline script tags
|
||||
Object.keys(options).forEach((key) => {
|
||||
@@ -174,8 +187,9 @@ export const sanitize = (options: any) => {
|
||||
) {
|
||||
delete options[key];
|
||||
}
|
||||
if (typeof options[key] === 'object') {
|
||||
sanitize(options[key]);
|
||||
if (typeof options[key] === 'object' && options[key] !== null) {
|
||||
// Recursively sanitize nested objects with updated path
|
||||
sanitize(options[key], [...path, key]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
Reference in New Issue
Block a user