mirror of
				https://github.com/strapi/strapi.git
				synced 2025-10-31 09:56:44 +00:00 
			
		
		
		
	Merge branch 'develop' into sec/updateMySQL2
This commit is contained in:
		
						commit
						94739c5a56
					
				
							
								
								
									
										2
									
								
								.github/workflows/tests.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/tests.yml
									
									
									
									
										vendored
									
									
								
							| @ -295,7 +295,6 @@ jobs: | ||||
|           MYSQL_USER: strapi | ||||
|           MYSQL_PASSWORD: strapi | ||||
|           MYSQL_DATABASE: strapi_test | ||||
|           MYSQL_AUTHENTICATION_PLUGIN: mysql_native_password | ||||
|         options: >- | ||||
|           --health-cmd="mysqladmin ping" | ||||
|           --health-interval=10s | ||||
| @ -450,7 +449,6 @@ jobs: | ||||
|           MYSQL_USER: strapi | ||||
|           MYSQL_PASSWORD: strapi | ||||
|           MYSQL_DATABASE: strapi_test | ||||
|           MYSQL_AUTHENTICATION_PLUGIN: mysql_native_password | ||||
|         options: >- | ||||
|           --health-cmd="mysqladmin ping" | ||||
|           --health-interval=10s | ||||
|  | ||||
| @ -16,7 +16,6 @@ services: | ||||
|   mysql: | ||||
|     image: mysql | ||||
|     restart: always | ||||
|     command: --default-authentication-plugin=mysql_native_password | ||||
|     environment: | ||||
|       MYSQL_DATABASE: strapi_test | ||||
|       MYSQL_USER: strapi | ||||
|  | ||||
| @ -0,0 +1,65 @@ | ||||
| import Koa from 'koa'; | ||||
| import request from 'supertest'; | ||||
| import { security } from '../security'; | ||||
| 
 | ||||
| const parseCspHeader = (csp: string) => | ||||
|   Object.fromEntries( | ||||
|     csp | ||||
|       .split(';') | ||||
|       .map((directive) => directive.split(' ')) | ||||
|       .map(([k, ...v]) => [k, v]) | ||||
|   ); | ||||
| 
 | ||||
| describe('Security middleware', () => { | ||||
|   describe('Content security policy', () => { | ||||
|     // GIVEN
 | ||||
|     const app = new Koa(); | ||||
|     const securityMiddleware = security( | ||||
|       { | ||||
|         contentSecurityPolicy: { | ||||
|           useDefaults: true, | ||||
|           directives: { | ||||
|             'script-src': ["'self'", 'https://cdn.custom.com'], | ||||
|             upgradeInsecureRequests: null, | ||||
|           }, | ||||
|         }, | ||||
|       }, | ||||
|       { | ||||
|         strapi: { | ||||
|           plugin: () => null, | ||||
|         } as any, | ||||
|       } | ||||
|     )!; | ||||
| 
 | ||||
|     // WHEN
 | ||||
|     app.use(securityMiddleware); | ||||
|     const agent = request.agent(app.callback()); | ||||
| 
 | ||||
|     // THEN
 | ||||
|     it.each(['/', '/admin', '/api'])( | ||||
|       'includes user custom CSP directives in GET %s response', | ||||
|       async (path) => { | ||||
|         await agent.get(path).expect((req) => { | ||||
|           const csp = parseCspHeader(req.header['content-security-policy']); | ||||
|           expect(csp['script-src']).toContain('https://cdn.custom.com'); | ||||
|         }); | ||||
|       } | ||||
|     ); | ||||
|     it('includes required default CSP directives in GET /admin response', async () => { | ||||
|       await agent.get('/admin').expect((req) => { | ||||
|         const csp = parseCspHeader(req.header['content-security-policy']); | ||||
|         expect(csp['script-src']).toContain("'unsafe-inline'"); | ||||
|         expect(csp['connect-src']).toContain('ws:'); | ||||
|       }); | ||||
|     }); | ||||
|     it('includes required default CSP directives in GET /documentation response', async () => { | ||||
|       await agent.get('/documentation').expect((req) => { | ||||
|         const csp = parseCspHeader(req.header['content-security-policy']); | ||||
|         expect(csp['script-src']).toContain("'unsafe-inline'"); | ||||
|         expect(csp['script-src']).toContain('cdn.jsdelivr.net'); | ||||
|         expect(csp['img-src']).toContain('strapi.io'); | ||||
|         expect(csp['img-src']).toContain('cdn.jsdelivr.net'); | ||||
|       }); | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
| @ -1,4 +1,4 @@ | ||||
| import { defaultsDeep, merge } from 'lodash/fp'; | ||||
| import { defaultsDeep, mergeWith } from 'lodash/fp'; | ||||
| import helmet, { KoaHelmet } from 'koa-helmet'; | ||||
| 
 | ||||
| import type { Common } from '@strapi/types'; | ||||
| @ -29,6 +29,14 @@ const defaults: Config = { | ||||
|   }, | ||||
| }; | ||||
| 
 | ||||
| const mergeConfig = (existingConfig: Config, newConfig: Config) => { | ||||
|   return mergeWith( | ||||
|     (obj, src) => (Array.isArray(obj) && Array.isArray(src) ? obj.concat(src) : undefined), | ||||
|     existingConfig, | ||||
|     newConfig | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| export const security: Common.MiddlewareFactory<Config> = | ||||
|   (config, { strapi }) => | ||||
|   (ctx, next) => { | ||||
| @ -42,7 +50,7 @@ export const security: Common.MiddlewareFactory<Config> = | ||||
|     } | ||||
| 
 | ||||
|     if (ctx.method === 'GET' && specialPaths.some((str) => ctx.path.startsWith(str))) { | ||||
|       helmetConfig = merge(helmetConfig, { | ||||
|       helmetConfig = mergeConfig(helmetConfig, { | ||||
|         contentSecurityPolicy: { | ||||
|           directives: { | ||||
|             'script-src': ["'self'", "'unsafe-inline'", 'cdn.jsdelivr.net'], | ||||
| @ -53,7 +61,7 @@ export const security: Common.MiddlewareFactory<Config> = | ||||
|     } | ||||
| 
 | ||||
|     if (ctx.method === 'GET' && ['/admin'].some((str) => ctx.path.startsWith(str))) { | ||||
|       helmetConfig = merge(helmetConfig, { | ||||
|       helmetConfig = mergeConfig(helmetConfig, { | ||||
|         contentSecurityPolicy: { | ||||
|           directives: { | ||||
|             'script-src': ["'self'", "'unsafe-inline'"], | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Alexandre BODIN
						Alexandre BODIN