File: Model\EnvHelpers.cs
Web Access
Project: src\src\Aspire.Dashboard\Aspire.Dashboard.csproj (Aspire.Dashboard)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Text;
 
namespace Aspire.Dashboard.Model;
 
/// <summary>
/// Helper methods for working with environment variables.
/// </summary>
internal static class EnvHelpers
{
    /// <summary>
    /// Converts environment variables to .env file format.
    /// </summary>
    /// <param name="environmentVariables">The environment variables to convert as key-value pairs.</param>
    /// <returns>A string in .env file format.</returns>
    public static string ConvertToEnvFormat(IEnumerable<KeyValuePair<string, string?>> environmentVariables)
    {
        var builder = new StringBuilder();
 
        foreach (var envVar in environmentVariables.OrderBy(e => e.Key, StringComparer.OrdinalIgnoreCase))
        {
            // Format: KEY=VALUE
            // Handle values that contain special characters by quoting them if needed
            var value = envVar.Value ?? string.Empty;
 
            // Quote values that contain spaces, quotes, or other special characters
            if (NeedsQuoting(value))
            {
                // Escape special characters
                value = value.Replace("\\", "\\\\")  // Backslashes first
                             .Replace("\"", "\\\"")  // Quotes
                             .Replace("\n", "\\n")   // Newlines
                             .Replace("\r", "\\r")   // Carriage returns
                             .Replace("\t", "\\t");  // Tabs
                builder.AppendLine(System.Globalization.CultureInfo.InvariantCulture, $"{envVar.Key}=\"{value}\"");
            }
            else
            {
                builder.AppendLine(System.Globalization.CultureInfo.InvariantCulture, $"{envVar.Key}={value}");
            }
        }
 
        return builder.ToString();
    }
 
    /// <summary>
    /// Determines if a value needs to be quoted in a .env file.
    /// </summary>
    private static bool NeedsQuoting(string value)
    {
        if (string.IsNullOrEmpty(value))
        {
            return false;
        }
 
        // Quote if contains special characters that have meaning in .env files or shells:
        // - Space: word separator
        // - Double/single quotes: string delimiters
        // - $: variable interpolation
        // - \: escape character
        // - Newline/carriage return/tab: control characters
        // - #: comment character (if unquoted, everything after # is a comment)
        // - `: command substitution in some shells
        // - =: prevents parsing ambiguity (e.g., KEY=key=value vs KEY="key=value")
        // - Leading/trailing whitespace: would be trimmed
        return value.Contains(' ') ||
               value.Contains('"') ||
               value.Contains('\'') ||
               value.Contains('$') ||
               value.Contains('\\') ||
               value.Contains('\n') ||
               value.Contains('\r') ||
               value.Contains('\t') ||
               value.Contains('#') ||
               value.Contains('`') ||
               value.Contains('=') ||
               char.IsWhiteSpace(value[0]) ||
               char.IsWhiteSpace(value[^1]);
    }
}