| 
									
										
										
										
											2023-03-12 16:00:57 +01:00
										 |  |  | // 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/>. | 
					
						
							| 
									
										
										
										
											2022-05-16 14:13:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | package config | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2025-01-27 19:21:13 +01:00
										 |  |  | 	"net/netip" | 
					
						
							| 
									
										
										
										
											2024-07-31 20:44:18 +08:00
										 |  |  | 	"net/url" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2022-05-16 14:13:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-11 11:09:31 +02:00
										 |  |  | 	"github.com/miekg/dns" | 
					
						
							| 
									
										
										
										
											2023-11-17 11:35:28 +01:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/gtserror" | 
					
						
							|  |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/language" | 
					
						
							| 
									
										
										
										
											2022-07-19 09:47:55 +01:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/log" | 
					
						
							| 
									
										
										
										
											2022-05-16 14:13:19 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-17 11:35:28 +01:00
										 |  |  | // Validate validates global config settings. | 
					
						
							| 
									
										
										
										
											2022-05-16 14:13:19 +02:00
										 |  |  | func Validate() error { | 
					
						
							| 
									
										
										
										
											2023-11-17 11:35:28 +01:00
										 |  |  | 	// Gather all validation errors in | 
					
						
							|  |  |  | 	// easily readable format for admins. | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		errs gtserror.MultiError | 
					
						
							|  |  |  | 		errf = func(format string, a ...any) { | 
					
						
							|  |  |  | 			errs = append(errs, fmt.Errorf(format, a...)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2022-05-16 14:13:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-17 11:35:28 +01:00
										 |  |  | 	// `host` | 
					
						
							| 
									
										
										
										
											2022-06-11 11:09:31 +02:00
										 |  |  | 	host := GetHost() | 
					
						
							|  |  |  | 	if host == "" { | 
					
						
							| 
									
										
										
										
											2023-11-17 11:35:28 +01:00
										 |  |  | 		errf("%s must be set", HostFlag()) | 
					
						
							| 
									
										
										
										
											2022-05-16 14:13:19 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-17 11:35:28 +01:00
										 |  |  | 	// If `account-domain` and `host` | 
					
						
							|  |  |  | 	// are set, `host` must be a valid | 
					
						
							|  |  |  | 	// subdomain of `account-domain`. | 
					
						
							| 
									
										
										
										
											2022-06-11 11:09:31 +02:00
										 |  |  | 	if host != "" { | 
					
						
							| 
									
										
										
										
											2023-11-17 11:35:28 +01:00
										 |  |  | 		ad := GetAccountDomain() | 
					
						
							|  |  |  | 		if ad == "" { | 
					
						
							|  |  |  | 			// `account-domain` not set, fall | 
					
						
							|  |  |  | 			// back by setting it to `host`. | 
					
						
							| 
									
										
										
										
											2022-06-11 11:09:31 +02:00
										 |  |  | 			SetAccountDomain(GetHost()) | 
					
						
							| 
									
										
										
										
											2023-11-17 11:35:28 +01:00
										 |  |  | 		} else if !dns.IsSubDomain(ad, host) { | 
					
						
							|  |  |  | 			errf( | 
					
						
							|  |  |  | 				"%s %s is not a valid subdomain of %s %s", | 
					
						
							|  |  |  | 				AccountDomainFlag(), ad, HostFlag(), host, | 
					
						
							|  |  |  | 			) | 
					
						
							| 
									
										
										
										
											2022-06-11 11:09:31 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-17 11:35:28 +01:00
										 |  |  | 	// Ensure `protocol` sensibly set. | 
					
						
							| 
									
										
										
										
											2022-05-30 13:41:24 +01:00
										 |  |  | 	switch proto := GetProtocol(); proto { | 
					
						
							| 
									
										
										
										
											2022-05-16 14:13:19 +02:00
										 |  |  | 	case "https": | 
					
						
							| 
									
										
										
										
											2023-11-17 11:35:28 +01:00
										 |  |  | 		// No problem. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-16 14:13:19 +02:00
										 |  |  | 	case "http": | 
					
						
							| 
									
										
										
										
											2023-11-17 11:35:28 +01:00
										 |  |  | 		log.Warnf( | 
					
						
							|  |  |  | 			nil, | 
					
						
							|  |  |  | 			"%s was set to 'http'; this should *only* be used for debugging and tests!", | 
					
						
							|  |  |  | 			ProtocolFlag(), | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-16 14:13:19 +02:00
										 |  |  | 	case "": | 
					
						
							| 
									
										
										
										
											2023-11-17 11:35:28 +01:00
										 |  |  | 		errf("%s must be set", ProtocolFlag()) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-16 14:13:19 +02:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2023-11-17 11:35:28 +01:00
										 |  |  | 		errf( | 
					
						
							|  |  |  | 			"%s must be set to either http or https, provided value was %s", | 
					
						
							|  |  |  | 			ProtocolFlag(), proto, | 
					
						
							|  |  |  | 		) | 
					
						
							| 
									
										
										
										
											2022-05-16 14:13:19 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-17 11:35:28 +01:00
										 |  |  | 	// `federation-mode` should be | 
					
						
							|  |  |  | 	// "blocklist" or "allowlist". | 
					
						
							|  |  |  | 	switch fediMode := GetInstanceFederationMode(); fediMode { | 
					
						
							| 
									
										
										
										
											2023-09-21 12:12:04 +02:00
										 |  |  | 	case InstanceFederationModeBlocklist, InstanceFederationModeAllowlist: | 
					
						
							| 
									
										
										
										
											2023-11-17 11:35:28 +01:00
										 |  |  | 		// No problem. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-21 12:12:04 +02:00
										 |  |  | 	case "": | 
					
						
							| 
									
										
										
										
											2023-11-17 11:35:28 +01:00
										 |  |  | 		errf("%s must be set", InstanceFederationModeFlag()) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-21 12:12:04 +02:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2023-11-17 11:35:28 +01:00
										 |  |  | 		errf( | 
					
						
							|  |  |  | 			"%s must be set to either blocklist or allowlist, provided value was %s", | 
					
						
							|  |  |  | 			InstanceFederationModeFlag(), fediMode, | 
					
						
							|  |  |  | 		) | 
					
						
							| 
									
										
										
										
											2023-09-21 12:12:04 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-17 11:35:28 +01:00
										 |  |  | 	// Parse `instance-languages`, and | 
					
						
							|  |  |  | 	// set enriched version into config. | 
					
						
							|  |  |  | 	parsedLangs, err := language.InitLangs(GetInstanceLanguages().TagStrs()) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		errf( | 
					
						
							|  |  |  | 			"%s could not be parsed as an array of valid BCP47 language tags: %v", | 
					
						
							|  |  |  | 			InstanceLanguagesFlag(), err, | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		// Parsed successfully, put enriched | 
					
						
							|  |  |  | 		// versions in config immediately. | 
					
						
							|  |  |  | 		SetInstanceLanguages(parsedLangs) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-04 16:52:42 +01:00
										 |  |  | 	// `instance-stats-mode` should be | 
					
						
							|  |  |  | 	// "", "zero", "serve", or "baffle" | 
					
						
							|  |  |  | 	switch statsMode := GetInstanceStatsMode(); statsMode { | 
					
						
							|  |  |  | 	case InstanceStatsModeDefault, InstanceStatsModeZero, InstanceStatsModeServe, InstanceStatsModeBaffle: | 
					
						
							|  |  |  | 		// No problem. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		errf( | 
					
						
							|  |  |  | 			"%s must be set to empty string, zero, serve, or baffle, provided value was %s", | 
					
						
							|  |  |  | 			InstanceFederationModeFlag(), statsMode, | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-17 11:35:28 +01:00
										 |  |  | 	// `web-assets-base-dir`. | 
					
						
							| 
									
										
										
										
											2022-09-04 14:41:42 +02:00
										 |  |  | 	webAssetsBaseDir := GetWebAssetBaseDir() | 
					
						
							|  |  |  | 	if webAssetsBaseDir == "" { | 
					
						
							| 
									
										
										
										
											2023-11-17 11:35:28 +01:00
										 |  |  | 		errf("%s must be set", WebAssetBaseDirFlag()) | 
					
						
							| 
									
										
										
										
											2022-09-04 14:41:42 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-31 20:44:18 +08:00
										 |  |  | 	// `storage-s3-redirect-url` | 
					
						
							|  |  |  | 	if s3RedirectURL := GetStorageS3RedirectURL(); s3RedirectURL != "" { | 
					
						
							|  |  |  | 		if strings.HasSuffix(s3RedirectURL, "/") { | 
					
						
							|  |  |  | 			errf( | 
					
						
							|  |  |  | 				"%s must not end with a trailing slash", | 
					
						
							|  |  |  | 				StorageS3RedirectURLFlag(), | 
					
						
							|  |  |  | 			) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if url, err := url.Parse(s3RedirectURL); err != nil { | 
					
						
							|  |  |  | 			errf( | 
					
						
							|  |  |  | 				"%s invalid: %w", | 
					
						
							|  |  |  | 				StorageS3RedirectURLFlag(), err, | 
					
						
							|  |  |  | 			) | 
					
						
							|  |  |  | 		} else if url.Scheme != "https" && url.Scheme != "http" { | 
					
						
							|  |  |  | 			errf( | 
					
						
							|  |  |  | 				"%s scheme must be https or http", | 
					
						
							|  |  |  | 				StorageS3RedirectURLFlag(), | 
					
						
							|  |  |  | 			) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-17 11:35:28 +01:00
										 |  |  | 	// Custom / LE TLS settings. | 
					
						
							|  |  |  | 	// | 
					
						
							|  |  |  | 	// Only one of custom certs or LE can be set, | 
					
						
							|  |  |  | 	// and if using custom certs then all relevant | 
					
						
							|  |  |  | 	// values must be provided. | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		tlsChain     = GetTLSCertificateChain() | 
					
						
							|  |  |  | 		tlsKey       = GetTLSCertificateKey() | 
					
						
							|  |  |  | 		tlsChainFlag = TLSCertificateChainFlag() | 
					
						
							|  |  |  | 		tlsKeyFlag   = TLSCertificateKeyFlag() | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2023-03-04 18:24:02 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if GetLetsEncryptEnabled() && (tlsChain != "" || tlsKey != "") { | 
					
						
							| 
									
										
										
										
											2023-11-17 11:35:28 +01:00
										 |  |  | 		errf( | 
					
						
							|  |  |  | 			"%s cannot be true when %s and/or %s are also set", | 
					
						
							|  |  |  | 			LetsEncryptEnabledFlag(), tlsChainFlag, tlsKeyFlag, | 
					
						
							|  |  |  | 		) | 
					
						
							| 
									
										
										
										
											2023-03-04 18:24:02 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (tlsChain != "" && tlsKey == "") || (tlsChain == "" && tlsKey != "") { | 
					
						
							| 
									
										
										
										
											2023-11-17 11:35:28 +01:00
										 |  |  | 		errf( | 
					
						
							|  |  |  | 			"%s and %s need to both be set or unset", | 
					
						
							|  |  |  | 			tlsChainFlag, tlsKeyFlag, | 
					
						
							|  |  |  | 		) | 
					
						
							| 
									
										
										
										
											2022-05-16 14:13:19 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-27 19:21:13 +01:00
										 |  |  | 	// Parse `advanced-rate-limit-exceptions` and set | 
					
						
							|  |  |  | 	// parsed versions on config to avoid reparsing calls. | 
					
						
							|  |  |  | 	rles := GetAdvancedRateLimitExceptions() | 
					
						
							|  |  |  | 	rlesParsed := make([]netip.Prefix, 0, len(rles)) | 
					
						
							|  |  |  | 	for _, rle := range rles { | 
					
						
							|  |  |  | 		parsed, err := netip.ParsePrefix(rle) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			errf( | 
					
						
							|  |  |  | 				"invalid entry %s in %s: %w", | 
					
						
							|  |  |  | 				rle, AdvancedRateLimitExceptionsFlag(), err, | 
					
						
							|  |  |  | 			) | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		rlesParsed = append(rlesParsed, parsed) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	SetAdvancedRateLimitExceptionsParsed(rlesParsed) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-17 11:35:28 +01:00
										 |  |  | 	return errs.Combine() | 
					
						
							| 
									
										
										
										
											2022-05-16 14:13:19 +02:00
										 |  |  | } |