All checks were successful
Caddy Manager CI build / docker (push) Successful in 49s
118 lines
4.4 KiB
C#
118 lines
4.4 KiB
C#
using System.Text.RegularExpressions;
|
|
using CaddyManager.Contracts.Caddy;
|
|
|
|
namespace CaddyManager.Services.Caddy;
|
|
|
|
/// <inheritdoc />
|
|
public partial class CaddyConfigurationParsingService: ICaddyConfigurationParsingService
|
|
{
|
|
/// <summary>
|
|
/// Regex to help parse hostnames from a Caddyfile.
|
|
/// This regex only matches hostname declarations at the beginning of lines (column 1 after optional whitespace)
|
|
/// and excludes nested directives like "reverse_proxy target {".
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
[GeneratedRegex(@"(?m)^([^\s\{\r\n][^\{\r\n]*?)\s*\{", RegexOptions.Multiline)]
|
|
private static partial Regex HostnamesRegex();
|
|
|
|
/// <summary>
|
|
/// Regex to help parse hostnames being used in reverse proxy directives.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
[GeneratedRegex(@"(?m)reverse_proxy\s+([^\s\{\}]+)(?:\s*\{)?", RegexOptions.Multiline)]
|
|
private static partial Regex ReverseProxyRegex();
|
|
|
|
/// <inheritdoc />
|
|
public List<string> GetHostnamesFromCaddyfileContent(string caddyfileContent)
|
|
{
|
|
var hostnamesRegex = HostnamesRegex();
|
|
var matches = hostnamesRegex.Matches(caddyfileContent);
|
|
var hostnames = new List<string>();
|
|
foreach (Match match in matches)
|
|
{
|
|
// Split the matched string by commas and trim whitespace
|
|
var splitHostnames = match.Groups[1].Value.Split(',')
|
|
.Select(h => h.Trim())
|
|
.Where(h => !string.IsNullOrWhiteSpace(h))
|
|
.ToList();
|
|
|
|
hostnames.AddRange(splitHostnames);
|
|
}
|
|
// Remove duplicates and return the list
|
|
return [.. hostnames.Distinct()];
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public string GetReverseProxyTargetFromCaddyfileContent(string caddyfileContent)
|
|
{
|
|
var reverseProxyRegex = ReverseProxyRegex();
|
|
var match = reverseProxyRegex.Match(caddyfileContent);
|
|
if (!match.Success) return string.Empty;
|
|
|
|
// Use the captured group which contains the target (e.g., pikachu:3011)
|
|
var targetPart = match.Groups[1].Value.Trim();
|
|
if (string.IsNullOrEmpty(targetPart)) return string.Empty;
|
|
|
|
var targetComponents = targetPart.Split(':');
|
|
if (targetComponents.Length <= 1) return targetPart;
|
|
|
|
// Handle cases like http://backend:9000, 192.168.1.100:3000
|
|
return targetComponents[0];
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public List<int> GetReverseProxyPortsFromCaddyfileContent(string caddyfileContent)
|
|
{
|
|
var reverseProxyRegex = ReverseProxyRegex();
|
|
var matches = reverseProxyRegex.Matches(caddyfileContent);
|
|
var results = new List<int>();
|
|
|
|
foreach (Match match in matches)
|
|
{
|
|
// Use the captured group which contains the target (e.g., pikachu:3011)
|
|
var targetPart = match.Groups[1].Value.Trim();
|
|
if (string.IsNullOrEmpty(targetPart)) continue;
|
|
|
|
var targetComponents = targetPart.Split(':');
|
|
if (targetComponents.Length > 1 && int.TryParse(targetComponents.Last(), out int port))
|
|
{
|
|
results.Add(port);
|
|
}
|
|
}
|
|
|
|
return [.. results.Distinct()];
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public List<string> GetTagsFromCaddyfileContent(string caddyfileContent)
|
|
{
|
|
// Split the content into lines and look for the tags line
|
|
var lines = caddyfileContent.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
|
|
|
foreach (var line in lines)
|
|
{
|
|
var trimmedLine = line.Trim();
|
|
if (trimmedLine.StartsWith("#"))
|
|
{
|
|
// Remove the # and any leading whitespace, then check if it starts with "tags:"
|
|
var afterHash = trimmedLine.Substring(1).TrimStart();
|
|
if (afterHash.StartsWith("tags:", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
// Extract the part after "tags:"
|
|
var tagsString = afterHash.Substring(5).Trim(); // 5 = length of "tags:"
|
|
if (string.IsNullOrWhiteSpace(tagsString))
|
|
return [];
|
|
|
|
// Split by semicolon and clean up each tag
|
|
return [.. tagsString.Split(';')
|
|
.Select(tag => tag.Trim())
|
|
.Where(tag => !string.IsNullOrWhiteSpace(tag))
|
|
.Distinct()];
|
|
}
|
|
}
|
|
}
|
|
|
|
// No tags line found
|
|
return [];
|
|
}
|
|
} |