mirror of
				https://github.com/mermaid-js/mermaid.git
				synced 2025-10-31 02:44:17 +01:00 
			
		
		
		
	Compare commits
	
		
			1 Commits
		
	
	
		
			mermaid@11
			...
			sidv/neste
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 6359ab504f | 
| @@ -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