using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using AxCopilot.Models; using AxCopilot.SDK; using AxCopilot.Services; namespace AxCopilot.Handlers; public class UrlAliasHandler : IActionHandler { private readonly SettingsService _settings; private static readonly HashSet AllowedSchemes = new HashSet(StringComparer.OrdinalIgnoreCase) { "http", "https", "ftp", "ftps", "ms-settings", "mailto", "file" }; public string? Prefix => "@"; public PluginMetadata Metadata => new PluginMetadata("url-alias", "URL 별칭", "1.0", "AX"); public UrlAliasHandler(SettingsService settings) { _settings = settings; } public Task> GetItemsAsync(string query, CancellationToken ct) { IEnumerable result = _settings.Settings.Aliases.Where((AliasEntry a) => a.Type == "url" && (string.IsNullOrEmpty(query) || a.Key.Contains(query, StringComparison.OrdinalIgnoreCase))).Select(delegate(AliasEntry a) { string faviconPath = GetFaviconPath(a.Target); return new LauncherItem(a.Key, a.Description ?? a.Target, faviconPath, a, a.Target, "\ue774"); }); return Task.FromResult(result); } public Task ExecuteAsync(LauncherItem item, CancellationToken ct) { if (item.Data is AliasEntry aliasEntry) { string text = Environment.ExpandEnvironmentVariables(aliasEntry.Target); if (!IsAllowedUrl(text)) { LogService.Warn("허용되지 않는 URL 스킴: " + text); return Task.CompletedTask; } Process.Start(new ProcessStartInfo(text) { UseShellExecute = true }); } return Task.CompletedTask; } private static bool IsAllowedUrl(string url) { if (!Uri.TryCreate(url, UriKind.Absolute, out Uri result)) { return false; } return AllowedSchemes.Contains(result.Scheme); } private static string? GetFaviconPath(string url) { try { if (!url.StartsWith("http", StringComparison.OrdinalIgnoreCase)) { url = "https://" + url; } string text = new Uri(url).Host.ToLowerInvariant(); string text2 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "AxCopilot", "favicons", text + ".png"); if (File.Exists(text2)) { return text2; } FaviconService.GetFavicon(url); return null; } catch { return null; } } }