Fix $ not being escaped in .env.production file generated by mastodon:setup (#23012)
				
					
				
			* Fix `$` not being escaped in `.env.production` file generated by `mastodon:setup` * Improve robustness of dotenv escaping
This commit is contained in:
		
							parent
							
								
									2ba14097ff
								
							
						
					
					
						commit
						a65f86ae55
					
				| @ -395,18 +395,11 @@ namespace :mastodon do | ||||
|         incompatible_syntax = false | ||||
| 
 | ||||
|         env_contents = env.each_pair.map do |key, value| | ||||
|           if value.is_a?(String) && value =~ /[\s\#\\"]/ | ||||
|             incompatible_syntax = true | ||||
|           value = value.to_s | ||||
|           escaped = dotenv_escape(value) | ||||
|           incompatible_syntax = true if value != escaped | ||||
| 
 | ||||
|             if value =~ /[']/ | ||||
|               value = value.to_s.gsub(/[\\"\$]/) { |x| "\\#{x}" } | ||||
|               "#{key}=\"#{value}\"" | ||||
|             else | ||||
|               "#{key}='#{value}'" | ||||
|             end | ||||
|           else | ||||
|             "#{key}=#{value}" | ||||
|           end | ||||
|           escaped | ||||
|         end.join("\n") | ||||
| 
 | ||||
|         generated_header = "# Generated with mastodon:setup on #{Time.now.utc}\n\n".dup | ||||
| @ -519,3 +512,49 @@ def disable_log_stdout! | ||||
|   HttpLog.configuration.logger = dev_null | ||||
|   Paperclip.options[:log]      = false | ||||
| end | ||||
| 
 | ||||
| def dotenv_escape(value) | ||||
|   # Dotenv has its own parser, which unfortunately deviates somewhat from | ||||
|   # what shells actually do. | ||||
|   # | ||||
|   # In particular, we can't use Shellwords::escape because it outputs a | ||||
|   # non-quotable string, while Dotenv requires `#` to always be in quoted | ||||
|   # strings. | ||||
|   # | ||||
|   # Therefore, we need to write our own escape code… | ||||
|   # Dotenv's parser has a *lot* of edge cases, and I think not every | ||||
|   # ASCII string can even be represented into something Dotenv can parse, | ||||
|   # so this is a best effort thing. | ||||
|   # | ||||
|   # In particular, strings with all the following probably cannot be | ||||
|   # escaped: | ||||
|   # - `#`, or ends with spaces, which requires some form of quoting (simply escaping won't work) | ||||
|   # - `'` (single quote), preventing us from single-quoting | ||||
|   # - `\` followed by either `r` or `n` | ||||
| 
 | ||||
|   # No character that would cause Dotenv trouble | ||||
|   return value unless /[\s\#\\"'$]/.match?(value) | ||||
| 
 | ||||
|   # As long as the value doesn't include single quotes, we can safely | ||||
|   # rely on single quotes | ||||
|   return "'#{value}'" unless /[']/.match?(value) | ||||
| 
 | ||||
|   # If the value contains the string '\n' or '\r' we simply can't use | ||||
|   # a double-quoted string, because Dotenv will expand \n or \r no | ||||
|   # matter how much escaping we add. | ||||
|   double_quoting_disallowed = /\\[rn]/.match?(value) | ||||
| 
 | ||||
|   value = value.gsub(double_quoting_disallowed ? /[\\"'\s]/ : /[\\"']/) { |x| "\\#{x}" } | ||||
| 
 | ||||
|   # Dotenv is especially tricky with `$` as unbalanced | ||||
|   # parenthesis will make it not unescape `\$` as `$`… | ||||
| 
 | ||||
|   # Variables | ||||
|   value = value.gsub(/\$(?!\()/) { |x| "\\#{x}" } | ||||
|   # Commands | ||||
|   value = value.gsub(/\$(?<cmd>\((?:[^()]|\g<cmd>)+\))/) { |x| "\\#{x}" } | ||||
| 
 | ||||
|   value = "\"#{value}\"" unless double_quoting_disallowed | ||||
| 
 | ||||
|   value | ||||
| end | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user