mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 09:02:25 -05:00 
			
		
		
		
	[feature/bugfix] Probe S3 storage for CSP uri, add config flag for extra URIs (#2134)
* [feature/bugfix] Probe S3 storage for CSP uri, add config flag for extra URIs * env parsing tests, my coy mistress
This commit is contained in:
		
					parent
					
						
							
								45334581ca
							
						
					
				
			
			
				commit
				
					
						4b5a3e01d0
					
				
			
		
					 13 changed files with 343 additions and 110 deletions
				
			
		
							
								
								
									
										144
									
								
								internal/middleware/contentsecuritypolicy.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								internal/middleware/contentsecuritypolicy.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,144 @@ | |||
| // GoToSocial | ||||
| // Copyright (C) GoToSocial Authors admin@gotosocial.org | ||||
| // SPDX-License-Identifier: AGPL-3.0-or-later | ||||
| // | ||||
| // This program is free software: you can redistribute it and/or modify | ||||
| // it under the terms of the GNU Affero General Public License as published by | ||||
| // the Free Software Foundation, either version 3 of the License, or | ||||
| // (at your option) any later version. | ||||
| // | ||||
| // This program is distributed in the hope that it will be useful, | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| // GNU Affero General Public License for more details. | ||||
| // | ||||
| // You should have received a copy of the GNU Affero General Public License | ||||
| // along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
| 
 | ||||
| package middleware | ||||
| 
 | ||||
| import ( | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"codeberg.org/gruf/go-debug" | ||||
| 	"github.com/gin-gonic/gin" | ||||
| ) | ||||
| 
 | ||||
| func ContentSecurityPolicy(extraURIs ...string) gin.HandlerFunc { | ||||
| 	csp := BuildContentSecurityPolicy(extraURIs...) | ||||
| 
 | ||||
| 	return func(c *gin.Context) { | ||||
| 		// Inform the browser we only load | ||||
| 		// CSS/JS/media using the given policy. | ||||
| 		c.Header("Content-Security-Policy", csp) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func BuildContentSecurityPolicy(extraURIs ...string) string { | ||||
| 	const ( | ||||
| 		defaultSrc = "default-src" | ||||
| 		objectSrc  = "object-src" | ||||
| 		imgSrc     = "img-src" | ||||
| 		mediaSrc   = "media-src" | ||||
| 
 | ||||
| 		self = "'self'" | ||||
| 		none = "'none'" | ||||
| 		blob = "blob:" | ||||
| 	) | ||||
| 
 | ||||
| 	// CSP values keyed by directive. | ||||
| 	values := make(map[string][]string, 4) | ||||
| 
 | ||||
| 	/* | ||||
| 		default-src | ||||
| 		https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/default-src | ||||
| 	*/ | ||||
| 
 | ||||
| 	if !debug.DEBUG { | ||||
| 		// Restrictive 'self' policy | ||||
| 		values[defaultSrc] = []string{self} | ||||
| 	} else { | ||||
| 		// If debug is enabled, allow | ||||
| 		// serving things from localhost | ||||
| 		// as well (regardless of port). | ||||
| 		values[defaultSrc] = []string{ | ||||
| 			self, | ||||
| 			"localhost:*", | ||||
| 			"ws://localhost:*", | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* | ||||
| 		object-src | ||||
| 		https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/object-src | ||||
| 	*/ | ||||
| 
 | ||||
| 	// Disallow object-src as recommended. | ||||
| 	values[objectSrc] = []string{none} | ||||
| 
 | ||||
| 	/* | ||||
| 		img-src | ||||
| 		https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/img-src | ||||
| 	*/ | ||||
| 
 | ||||
| 	// Restrictive 'self' policy, | ||||
| 	// include extraURIs, and 'blob:' | ||||
| 	// for previewing uploaded images | ||||
| 	// (header, avi, emojis) in settings. | ||||
| 	values[imgSrc] = append( | ||||
| 		[]string{self, blob}, | ||||
| 		extraURIs..., | ||||
| 	) | ||||
| 
 | ||||
| 	/* | ||||
| 		media-src | ||||
| 		https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/media-src | ||||
| 	*/ | ||||
| 
 | ||||
| 	// Restrictive 'self' policy, | ||||
| 	// include extraURIs. | ||||
| 	values[mediaSrc] = append( | ||||
| 		[]string{self}, | ||||
| 		extraURIs..., | ||||
| 	) | ||||
| 
 | ||||
| 	/* | ||||
| 		Assemble policy directives. | ||||
| 	*/ | ||||
| 
 | ||||
| 	// Iterate through an ordered slice rather than | ||||
| 	// iterating through the map, since we want these | ||||
| 	// policyDirectives in a determinate order. | ||||
| 	policyDirectives := make([]string, 4) | ||||
| 	for i, directive := range []string{ | ||||
| 		defaultSrc, | ||||
| 		objectSrc, | ||||
| 		imgSrc, | ||||
| 		mediaSrc, | ||||
| 	} { | ||||
| 		// Each policy directive should look like: | ||||
| 		// `[directive] [value1] [value2] [etc]` | ||||
| 
 | ||||
| 		// Get assembled values | ||||
| 		// for this directive. | ||||
| 		values := values[directive] | ||||
| 
 | ||||
| 		// Prepend values with | ||||
| 		// the directive name. | ||||
| 		directiveValues := append( | ||||
| 			[]string{directive}, | ||||
| 			values..., | ||||
| 		) | ||||
| 
 | ||||
| 		// Space-separate them. | ||||
| 		policyDirective := strings.Join(directiveValues, " ") | ||||
| 
 | ||||
| 		// Done. | ||||
| 		policyDirectives[i] = policyDirective | ||||
| 	} | ||||
| 
 | ||||
| 	// Content-security-policy looks like this: | ||||
| 	// `Content-Security-Policy: <policy-directive>; <policy-directive>` | ||||
| 	// So join each policy directive appropriately. | ||||
| 	return strings.Join(policyDirectives, "; ") | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue