diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/IResourceTool.cs b/WelsonJS.Toolkit/WelsonJS.Launcher/IResourceTool.cs
new file mode 100644
index 0000000..cbd71b7
--- /dev/null
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/IResourceTool.cs
@@ -0,0 +1,25 @@
+using System.Net;
+using System.Threading.Tasks;
+
+namespace WelsonJS.Launcher
+{
+ ///
+ /// Defines a contract for resource tools that can handle specific HTTP requests.
+ ///
+ public interface IResourceTool
+ {
+ ///
+ /// Determines whether this tool can handle the specified path.
+ ///
+ /// The request path to check.
+ /// True if this tool can handle the request; otherwise, false.
+ bool CanHandle(string path);
+ ///
+ /// Asynchronously processes the HTTP request for the specified path.
+ ///
+ /// The HTTP listener context containing request and response objects.
+ /// The request path to handle.
+ /// A task representing the asynchronous operation.
+ Task HandleAsync(HttpListenerContext context, string path);
+ }
+}
\ No newline at end of file
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/MainForm.cs b/WelsonJS.Toolkit/WelsonJS.Launcher/MainForm.cs
index 420c8b8..11e21e5 100644
--- a/WelsonJS.Toolkit/WelsonJS.Launcher/MainForm.cs
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/MainForm.cs
@@ -5,7 +5,6 @@ using System.IO.Compression;
using System.Security.Principal;
using System.Threading.Tasks;
using System.Windows.Forms;
-using WelsonJS.Launcher.Tools;
namespace WelsonJS.Launcher
{
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/Program.cs b/WelsonJS.Toolkit/WelsonJS.Launcher/Program.cs
index 899200f..aebad66 100644
--- a/WelsonJS.Toolkit/WelsonJS.Launcher/Program.cs
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/Program.cs
@@ -5,7 +5,6 @@ using System.Linq;
using System.Threading;
using System.Windows.Forms;
using System.Configuration;
-using WelsonJS.Launcher.Tools;
namespace WelsonJS.Launcher
{
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.Designer.cs b/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.Designer.cs
index c4f5ce7..c4557b5 100644
--- a/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.Designer.cs
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.Designer.cs
@@ -60,6 +60,24 @@ namespace WelsonJS.Launcher.Properties {
}
}
+ ///
+ /// 과(와) 유사한 지역화된 문자열을 찾습니다.
+ ///
+ internal static string AzureAiServiceApiKey {
+ get {
+ return ResourceManager.GetString("AzureAiServiceApiKey", resourceCulture);
+ }
+ }
+
+ ///
+ /// https://ai-catswords656881030318.services.ai.azure.com/models/chat/completions?api-version=2024-05-01-preview과(와) 유사한 지역화된 문자열을 찾습니다.
+ ///
+ internal static string AzureAiServiceUrl {
+ get {
+ return ResourceManager.GetString("AzureAiServiceUrl", resourceCulture);
+ }
+ }
+
///
/// https://copilot.microsoft.com/과(와) 유사한 지역화된 문자열을 찾습니다.
///
@@ -69,6 +87,24 @@ namespace WelsonJS.Launcher.Properties {
}
}
+ ///
+ /// http://localhost:9222/과(와) 유사한 지역화된 문자열을 찾습니다.
+ ///
+ internal static string DevToolsPrefix {
+ get {
+ return ResourceManager.GetString("DevToolsPrefix", resourceCulture);
+ }
+ }
+
+ ///
+ /// 1.1.1.1과(와) 유사한 지역화된 문자열을 찾습니다.
+ ///
+ internal static string DnsServerAddress {
+ get {
+ return ResourceManager.GetString("DnsServerAddress", resourceCulture);
+ }
+ }
+
///
/// (아이콘)과(와) 유사한 System.Drawing.Icon 형식의 지역화된 리소스를 찾습니다.
///
@@ -186,5 +222,41 @@ namespace WelsonJS.Launcher.Properties {
return ResourceManager.GetString("ResourceServerPrefix", resourceCulture);
}
}
+
+ ///
+ /// 141.101.82.1과(와) 유사한 지역화된 문자열을 찾습니다.
+ ///
+ internal static string WhoisClientAddress {
+ get {
+ return ResourceManager.GetString("WhoisClientAddress", resourceCulture);
+ }
+ }
+
+ ///
+ /// https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois/whois.jsp과(와) 유사한 지역화된 문자열을 찾습니다.
+ ///
+ internal static string WhoisReferrerUrl {
+ get {
+ return ResourceManager.GetString("WhoisReferrerUrl", resourceCulture);
+ }
+ }
+
+ ///
+ /// https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois.jsc과(와) 유사한 지역화된 문자열을 찾습니다.
+ ///
+ internal static string WhoisServerUrl {
+ get {
+ return ResourceManager.GetString("WhoisServerUrl", resourceCulture);
+ }
+ }
+
+ ///
+ /// Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36 Edg/134.0.3124.77과(와) 유사한 지역화된 문자열을 찾습니다.
+ ///
+ internal static string WhoisUserAgent {
+ get {
+ return ResourceManager.GetString("WhoisUserAgent", resourceCulture);
+ }
+ }
}
}
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.resx b/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.resx
index a947a72..6be5c75 100644
--- a/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.resx
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/Properties/Resources.resx
@@ -157,4 +157,28 @@
http://localhost:3000/
+
+ http://localhost:9222/
+
+
+
+
+
+ https://ai-catswords656881030318.services.ai.azure.com/models/chat/completions?api-version=2024-05-01-preview
+
+
+ 1.1.1.1
+
+
+ 141.101.82.1
+
+
+ https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois/whois.jsp
+
+
+ https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois.jsc
+
+
+ Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36 Edg/134.0.3124.77
+
\ No newline at end of file
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceServer.cs b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceServer.cs
new file mode 100644
index 0000000..8538054
--- /dev/null
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceServer.cs
@@ -0,0 +1,210 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Reflection;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using System.Xml.Linq;
+
+namespace WelsonJS.Launcher
+{
+ public class ResourceServer
+ {
+ private readonly HttpListener _listener;
+ private CancellationTokenSource _cts;
+ private Task _serverTask;
+ private bool _isRunning;
+ private string _prefix;
+ private string _resourceName;
+ private List _resourceTools = new List();
+
+ public ResourceServer(string prefix, string resourceName)
+ {
+ _prefix = prefix;
+ _listener = new HttpListener();
+ _listener.Prefixes.Add(prefix);
+ _resourceName = resourceName;
+
+ // Add resource tools
+ _resourceTools.Add(new ResourceTools.Completion(this));
+ _resourceTools.Add(new ResourceTools.Config(this));
+ _resourceTools.Add(new ResourceTools.DevTools(this));
+ _resourceTools.Add(new ResourceTools.DnsQuery(this));
+ _resourceTools.Add(new ResourceTools.Tfa(this));
+ _resourceTools.Add(new ResourceTools.Whois(this));
+ }
+
+ public string GetPrefix()
+ {
+ return _prefix;
+ }
+
+ public void Start()
+ {
+ if (_isRunning) return;
+
+ _isRunning = true;
+ _cts = new CancellationTokenSource();
+ _listener.Start();
+
+ // Open the web browser
+ Program.OpenWebBrowser(_prefix);
+
+ // Run a task with cancellation token
+ _serverTask = Task.Run(() => ListenLoop(_cts.Token));
+ }
+
+ public void Stop()
+ {
+ _isRunning = false;
+ _cts.Cancel();
+ _listener.Stop();
+
+ MessageBox.Show("Server stopped.");
+ }
+
+ public bool IsRunning()
+ {
+ return _isRunning;
+ }
+
+ private async Task ListenLoop(CancellationToken token)
+ {
+ while (!token.IsCancellationRequested && _isRunning)
+ {
+ try
+ {
+ await ProcessRequest(await _listener.GetContextAsync());
+ }
+ catch (Exception ex)
+ {
+ if (token.IsCancellationRequested || !_isRunning) break;
+ MessageBox.Show($"Error: {ex.Message}");
+ }
+ }
+ }
+
+ private async Task ProcessRequest(HttpListenerContext context)
+ {
+ string path = context.Request.Url.AbsolutePath.TrimStart('/');
+
+ // Serve the favicon.ico file
+ if ("favicon.ico".Equals(path, StringComparison.OrdinalIgnoreCase))
+ {
+ ServeResource(context, GetResource("favicon"), "image/x-icon");
+ return;
+ }
+
+ // Serve from a resource tool
+ foreach(var tool in _resourceTools)
+ {
+
+ if (tool.CanHandle(path))
+ {
+ await tool.HandleAsync(context, path);
+ return;
+ }
+ }
+
+ // Serve from a resource name
+ ServeResource(context, GetResource(_resourceName), "text/html");
+ }
+
+ public void ServeResource(HttpListenerContext context)
+ {
+ ServeResource(context, "Not Found", "application/xml", 404);
+ }
+
+ public void ServeResource(HttpListenerContext context, byte[] data, string mimeType = "text/html", int statusCode = 200)
+ {
+ string xmlHeader = "";
+
+ if (data == null) {
+ data = Encoding.UTF8.GetBytes(xmlHeader + "\r\nCould not find the resource.");
+ mimeType = "application/xml";
+ statusCode = 404;
+ }
+
+ context.Response.StatusCode = statusCode;
+ context.Response.ContentType = mimeType;
+ context.Response.ContentLength64 = data.Length;
+ using (Stream outputStream = context.Response.OutputStream)
+ {
+ outputStream.Write(data, 0, data.Length);
+ }
+ }
+
+ public void ServeResource(HttpListenerContext context, string data, string mimeType = "text/html", int statusCode = 200)
+ {
+ string xmlHeader = "";
+
+ if (data == null)
+ {
+ data = xmlHeader + "\r\nCould not find the resource.";
+ mimeType = "application/xml";
+ statusCode = 404;
+ }
+ else if (mimeType == "application/xml" && !data.StartsWith(" executables = new List();
+ private ResourceServer Server;
+ private const string Prefix = "completion/";
+ private List Executables = new List();
- public ExecutablesCollector()
+ public Completion(ResourceServer server)
{
+ Server = server;
+
new Task(() =>
{
- executables.AddRange(GetInstalledSoftwareExecutables());
- executables.AddRange(GetExecutablesFromPath());
- executables.AddRange(GetExecutablesFromNetFx());
+ Executables.AddRange(GetInstalledSoftwareExecutables());
+ Executables.AddRange(GetExecutablesFromPath());
+ Executables.AddRange(GetExecutablesFromNetFx());
}).Start();
}
- public List GetExecutables()
+ public bool CanHandle(string path)
{
- return executables;
+ return path.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase);
+ }
+
+ public async Task HandleAsync(HttpListenerContext context, string path)
+ {
+ string word = path.Substring(Prefix.Length);
+
+ try
+ {
+ CompletionItem[] completionItems = Executables
+ .Where(exec => exec.IndexOf(word, 0, StringComparison.OrdinalIgnoreCase) > -1)
+ .Take(100) // Limit the number of results
+ .Select(exec => new CompletionItem
+ {
+ Label = Path.GetFileName(exec),
+ Kind = "Text",
+ Documentation = $"An executable file: {exec}",
+ InsertText = exec
+ })
+ .ToArray();
+
+ XElement response = new XElement("suggestions",
+ completionItems.Select(item => new XElement("item",
+ new XElement("label", item.Label),
+ new XElement("kind", item.Kind),
+ new XElement("documentation", item.Documentation),
+ new XElement("insertText", item.InsertText)
+ ))
+ );
+
+ Server.ServeResource(context, response.ToString(), "application/xml");
+ }
+ catch (Exception ex)
+ {
+ Server.ServeResource(context, $"Failed to process completion request. {ex.Message}", "application/xml", 500);
+ }
+
+ await Task.Delay(0);
}
private List GetInstalledSoftwareExecutables()
@@ -157,4 +200,12 @@ namespace WelsonJS.Launcher.Tools
return executables;
}
}
+
+ public class CompletionItem
+ {
+ public string Label { get; set; }
+ public string Kind { get; set; }
+ public string Documentation { get; set; }
+ public string InsertText { get; set; }
+ }
}
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Config.cs b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Config.cs
new file mode 100644
index 0000000..e07dc84
--- /dev/null
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Config.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Net;
+using System.Threading.Tasks;
+
+namespace WelsonJS.Launcher.ResourceTools
+{
+ public class Config : IResourceTool
+ {
+ private ResourceServer Server;
+ private const string Prefix = "config/";
+
+ public Config(ResourceServer server)
+ {
+ Server = server;
+ }
+
+ public bool CanHandle(string path)
+ {
+ return path.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase);
+ }
+
+ public async Task HandleAsync(HttpListenerContext context, string path)
+ {
+ string configName = path.Substring(Prefix.Length);
+
+ try
+ {
+ string configValue = Program.GetAppConfig(configName);
+ Server.ServeResource(context, configValue, "text/plain");
+ }
+ catch (Exception ex)
+ {
+ Server.ServeResource(context, $"Failed to process Config request. {ex.Message}", "application/xml", 500);
+ }
+
+ await Task.Delay(0);
+ }
+ }
+}
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/DevTools.cs b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/DevTools.cs
new file mode 100644
index 0000000..890e9fa
--- /dev/null
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/DevTools.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Net;
+using System.Net.Http;
+using System.Threading.Tasks;
+
+namespace WelsonJS.Launcher.ResourceTools
+{
+ public class DevTools : IResourceTool
+ {
+ private ResourceServer Server;
+ private const string Prefix = "devtools/";
+ private const double Timeout = 5000;
+
+ public DevTools(ResourceServer server)
+ {
+ Server = server;
+ }
+
+ public bool CanHandle(string path)
+ {
+ return path.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase);
+ }
+
+ public async Task HandleAsync(HttpListenerContext context, string path)
+ {
+ string endpoint = path.Substring(Prefix.Length);
+
+ try
+ {
+ using (HttpClient client = new HttpClient())
+ {
+ client.Timeout = TimeSpan.FromMilliseconds(Timeout);
+
+ string url = Program.GetAppConfig("DevToolsPrefix") + endpoint;
+ string data = await client.GetStringAsync(url);
+
+ Server.ServeResource(context, data, "application/json");
+ }
+ }
+ catch (Exception ex)
+ {
+ Server.ServeResource(context, $"Failed to process DevTools request. {ex.Message}", "application/xml", 500);
+ }
+ }
+ }
+}
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/Tools/DnsQuery.cs b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/DnsQuery.cs
similarity index 82%
rename from WelsonJS.Toolkit/WelsonJS.Launcher/Tools/DnsQuery.cs
rename to WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/DnsQuery.cs
index 1a82ead..c911791 100644
--- a/WelsonJS.Toolkit/WelsonJS.Launcher/Tools/DnsQuery.cs
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/DnsQuery.cs
@@ -1,22 +1,66 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
-using System.Linq;
+using System.Threading.Tasks;
-namespace WelsonJS.Launcher.Tools
+namespace WelsonJS.Launcher.ResourceTools
{
- public class DnsQuery
+ public class DnsQuery : IResourceTool
{
- private static readonly Random _random = new Random();
- private readonly string _dnsServer;
+ private ResourceServer Server;
+ private const string Prefix = "dns-query/";
+ private string DnsServer;
private const int DnsPort = 53;
private const int Timeout = 5000;
+ private static readonly Random _random = new Random();
- public DnsQuery(string dnsServer = "8.8.8.8")
+ public DnsQuery(ResourceServer server)
{
- _dnsServer = dnsServer;
+ Server = server;
+ DnsServer = Program.GetAppConfig("DnsServerAddress");
+ }
+
+ public bool CanHandle(string path)
+ {
+ return path.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase);
+ }
+
+ public async Task HandleAsync(HttpListenerContext context, string path)
+ {
+ string query = path.Substring(Prefix.Length);
+
+ if (string.IsNullOrWhiteSpace(query) || query.Length > 255)
+ {
+ Server.ServeResource(context, "Invalid query parameter", "application/xml", 400);
+ return;
+ }
+
+ try
+ {
+ Dictionary> allRecords = QueryAll(query);
+
+ StringBuilder result = new StringBuilder();
+ foreach (var recordType in allRecords.Keys)
+ {
+ result.AppendLine($"\n{recordType} Records:");
+ foreach (var record in allRecords[recordType])
+ {
+ result.AppendLine(record);
+ }
+ }
+
+ string data = result.ToString();
+ Server.ServeResource(context, data, "text/plain", 200);
+ }
+ catch (Exception ex)
+ {
+ Server.ServeResource(context, $"Failed to process DNS query. {ex.Message}", "application/xml", 500);
+ }
+
+ await Task.Delay(0);
}
public List QueryA(string domain) => QueryDns(domain, 1);
@@ -62,7 +106,7 @@ namespace WelsonJS.Launcher.Tools
}
// Basic domain format validation
- if (domain.Length > 255 ||
+ if (domain.Length > 255 ||
!domain.Split('.').All(part => part.Length > 0 && part.Length <= 63))
{
records.Add("Error: Invalid domain format");
@@ -71,17 +115,18 @@ namespace WelsonJS.Launcher.Tools
try
{
- UdpClient udpClient = new UdpClient(_dnsServer, DnsPort);
- udpClient.Client.ReceiveTimeout = Timeout;
+ using (UdpClient udpClient = new UdpClient(DnsServer, DnsPort))
+ {
+ udpClient.Client.ReceiveTimeout = Timeout;
- byte[] request = CreateDnsQuery(domain, type);
- udpClient.Send(request, request.Length);
+ byte[] request = CreateDnsQuery(domain, type);
+ udpClient.Send(request, request.Length);
- IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, DnsPort);
- byte[] response = udpClient.Receive(ref remoteEP);
+ IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, DnsPort);
+ byte[] response = udpClient.Receive(ref remoteEP);
- records.AddRange(ParseDnsResponse(response, type));
- udpClient.Close();
+ records.AddRange(ParseDnsResponse(response, type));
+ }
}
catch (Exception ex)
{
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/Tools/Tfa.cs b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Tfa.cs
similarity index 72%
rename from WelsonJS.Toolkit/WelsonJS.Launcher/Tools/Tfa.cs
rename to WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Tfa.cs
index 615e668..a6e68df 100644
--- a/WelsonJS.Toolkit/WelsonJS.Launcher/Tools/Tfa.cs
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Tfa.cs
@@ -2,13 +2,42 @@
using System.Linq;
using System.Security.Cryptography;
using System.Collections.Generic;
+using System.Net;
+using System.Threading.Tasks;
-namespace WelsonJS.Launcher.Tools
+namespace WelsonJS.Launcher.ResourceTools
{
- public class Tfa
+ public class Tfa : IResourceTool
{
+ private ResourceServer Server;
+ private const string Prefix = "tfa/";
private const string Base32Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
+ public Tfa(ResourceServer server)
+ {
+ Server = server;
+ }
+
+ public bool CanHandle(string path)
+ {
+ return path.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase);
+ }
+
+ public async Task HandleAsync(HttpListenerContext context, string path)
+ {
+ string endpoint = path.Substring(Prefix.Length);
+
+ if (endpoint.Equals("pubkey"))
+ {
+ Server.ServeResource(context, GetPubKey(), "text/plain", 200);
+ return;
+ }
+
+ Server.ServeResource(context);
+
+ await Task.Delay(0);
+ }
+
public int GetOtp(string key)
{
byte[] binaryKey = DecodeBase32(key.Replace(" ", ""));
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Whois.cs b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Whois.cs
new file mode 100644
index 0000000..b748c48
--- /dev/null
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Whois.cs
@@ -0,0 +1,64 @@
+using System.Net;
+using System.Threading.Tasks;
+using System;
+using System.Net.Http;
+using System.Text;
+
+namespace WelsonJS.Launcher.ResourceTools
+{
+ public class Whois : IResourceTool
+ {
+ private ResourceServer Server;
+ private const string Prefix = "whois/";
+ private const int Timeout = 5000;
+
+ public Whois(ResourceServer server)
+ {
+ Server = server;
+ }
+
+ public bool CanHandle(string path)
+ {
+ return path.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase);
+ }
+
+ public async Task HandleAsync(HttpListenerContext context, string path)
+ {
+ string query = path.Substring(Prefix.Length);
+
+ if (string.IsNullOrWhiteSpace(query) || query.Length > 255)
+ {
+ Server.ServeResource(context, "Invalid query parameter", "application/xml", 400);
+ return;
+ }
+
+ using (var client = new HttpClient())
+ {
+ client.Timeout = TimeSpan.FromMilliseconds(Timeout);
+
+ string clientAddress = Program.GetAppConfig("WhoisClientAddress");
+
+ HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, Program.GetAppConfig("WhoisServerUrl"))
+ {
+ Content = new StringContent($"query={Uri.EscapeDataString(query)}&ip={clientAddress}", Encoding.UTF8, "application/x-www-form-urlencoded")
+ };
+
+ request.Headers.Add("Accept", "*/*");
+ request.Headers.Add("User-Agent", Program.GetAppConfig("WhoisUserAgent"));
+ client.DefaultRequestHeaders.Referrer = new Uri(Program.GetAppConfig("WhoisReferrerUrl"));
+
+ try
+ {
+ HttpResponseMessage response = await client.SendAsync(request);
+ string responseBody = await response.Content.ReadAsStringAsync();
+
+ Server.ServeResource(context, responseBody, "text/plain", (int)response.StatusCode);
+ }
+ catch (Exception ex)
+ {
+ Server.ServeResource(context, $"Failed to process WHOIS request. {ex.Message}", "application/xml", 500);
+ }
+ }
+ }
+ }
+}
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/Tools/ResourceServer.cs b/WelsonJS.Toolkit/WelsonJS.Launcher/Tools/ResourceServer.cs
deleted file mode 100644
index 8f69700..0000000
--- a/WelsonJS.Toolkit/WelsonJS.Launcher/Tools/ResourceServer.cs
+++ /dev/null
@@ -1,395 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Net.Http;
-using System.Reflection;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-using System.Xml.Linq;
-
-namespace WelsonJS.Launcher.Tools
-{
- public class ResourceServer
- {
- private readonly HttpListener _listener;
- private CancellationTokenSource _cts;
- private Task _serverTask;
- private bool _isRunning;
- private string _prefix;
- private string _resourceName;
- private ExecutablesCollector _executablesCollector;
-
- public ResourceServer(string prefix, string resourceName)
- {
- _prefix = prefix;
- _listener = new HttpListener();
- _listener.Prefixes.Add(prefix);
- _resourceName = resourceName;
- _executablesCollector = new ExecutablesCollector();
- }
-
- public string GetPrefix()
- {
- return _prefix;
- }
-
- public void Start()
- {
- if (_isRunning) return;
-
- _isRunning = true;
- _cts = new CancellationTokenSource();
- _listener.Start();
-
- // Open the web browser
- Program.OpenWebBrowser(_prefix);
-
- // Run a task with cancellation token
- _serverTask = Task.Run(() => ListenLoop(_cts.Token));
- }
-
- public void Stop()
- {
- _isRunning = false;
- _cts.Cancel();
- _listener.Stop();
-
- MessageBox.Show("Server stopped.");
- }
-
- public bool IsRunning()
- {
- return _isRunning;
- }
-
- private async Task ListenLoop(CancellationToken token)
- {
- while (!token.IsCancellationRequested && _isRunning)
- {
- try
- {
- await ProcessRequest(await _listener.GetContextAsync());
- }
- catch (Exception ex)
- {
- if (token.IsCancellationRequested || !_isRunning) break;
- MessageBox.Show($"Error: {ex.Message}");
- }
- }
- }
-
- private async Task ProcessRequest(HttpListenerContext context)
- {
- string path = context.Request.Url.AbsolutePath.TrimStart('/');
-
- // Serve the favicon.ico file
- if ("favicon.ico".Equals(path, StringComparison.OrdinalIgnoreCase))
- {
- ServeResource(context, GetResource("favicon"), "image/x-icon");
- return;
- }
-
- // Serve the code completion (word suggestion)
- const string completionPrefix = "completion/";
- if (path.StartsWith(completionPrefix, StringComparison.OrdinalIgnoreCase))
- {
- ServeCompletion(context, path.Substring(completionPrefix.Length));
- return;
- }
-
- // Serve the DevTools Protocol
- const string devtoolsPrefix = "devtools/";
- if (path.StartsWith(devtoolsPrefix, StringComparison.OrdinalIgnoreCase))
- {
- await ServeDevTools(context, path.Substring(devtoolsPrefix.Length));
- return;
- }
-
- // Serve WHOIS request (use KRNIC server)
- const string whoisPrefix = "whois/";
- if (path.StartsWith(whoisPrefix, StringComparison.OrdinalIgnoreCase))
- {
- await ServeWhoisRequest(context, path.Substring(whoisPrefix.Length));
- return;
- }
-
- // Serve DNS Query request (use Google DNS server)
- const string dnsQueryPrefix = "dns-query/";
- if (path.StartsWith(dnsQueryPrefix, StringComparison.OrdinalIgnoreCase))
- {
- ServeDnsQueryRequest(context, path.Substring(dnsQueryPrefix.Length));
- return;
- }
-
- // Serve TFA request
- const string tfaPrefix = "tfa/";
- if (path.StartsWith(tfaPrefix, StringComparison.OrdinalIgnoreCase))
- {
- ServeTfaRequest(context, path.Substring(tfaPrefix.Length));
- return;
- }
-
- // Serve a value of App Config request
- const string configPrefix = "config/";
- if (path.StartsWith(configPrefix, StringComparison.OrdinalIgnoreCase))
- {
- ServeConfigRequest(context, path.Substring(configPrefix.Length));
- return;
- }
-
- // Serve a resource
- ServeResource(context, GetResource(_resourceName), "text/html");
- }
-
- private void ServeCompletion(HttpListenerContext context, string word)
- {
- try
- {
- List executables = _executablesCollector.GetExecutables();
-
- CompletionItem[] completionItems = executables
- .Where(exec => exec.IndexOf(word, 0, StringComparison.OrdinalIgnoreCase) > -1)
- .Take(100) // Limit the number of results
- .Select(exec => new CompletionItem
- {
- Label = Path.GetFileName(exec),
- Kind = "Text",
- Documentation = $"An executable file: {exec}",
- InsertText = exec
- })
- .ToArray();
-
- XElement response = new XElement("suggestions",
- completionItems.Select(item => new XElement("item",
- new XElement("label", item.Label),
- new XElement("kind", item.Kind),
- new XElement("documentation", item.Documentation),
- new XElement("insertText", item.InsertText)
- ))
- );
-
- ServeResource(context, response.ToString(), "application/xml");
- }
- catch (Exception ex)
- {
- ServeResource(context, $"Failed to process completion request. {ex.Message}", "application/xml", 500);
- }
- }
-
- private async Task ServeDevTools(HttpListenerContext context, string endpoint)
- {
- try
- {
- using (HttpClient client = new HttpClient())
- {
- string url = "http://localhost:9222/" + endpoint;
- string data = await client.GetStringAsync(url);
-
- ServeResource(context, data, "application/json");
- }
- }
- catch (Exception ex)
- {
- ServeResource(context, $"Failed to process DevTools request. {ex.Message}", "application/xml", 500);
- }
- }
-
- private async Task ServeWhoisRequest(HttpListenerContext context, string query)
- {
- if (string.IsNullOrWhiteSpace(query) || query.Length > 255)
- {
- ServeResource(context, "Invalid query parameter", "application/xml", 400);
- return;
- }
-
- string whoisServerUrl = "https://xn--c79as89aj0e29b77z.xn--3e0b707e";
-
- using (var client = new HttpClient())
- {
- client.Timeout = TimeSpan.FromSeconds(10);
-
- HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, $"{whoisServerUrl}/kor/whois.jsc")
- {
- Content = new StringContent($"query={Uri.EscapeDataString(query)}&ip=141.101.82.1", Encoding.UTF8, "application/x-www-form-urlencoded")
- };
-
- request.Headers.Add("Accept", "*/*");
- request.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36 Edg/134.0.3124.77");
- client.DefaultRequestHeaders.Referrer = new Uri($"{whoisServerUrl}/kor/whois/whois.jsp");
-
- try
- {
- HttpResponseMessage response = await client.SendAsync(request);
- string responseBody = await response.Content.ReadAsStringAsync();
-
- ServeResource(context, responseBody, "text/plain", (int)response.StatusCode);
- }
- catch (Exception ex)
- {
- ServeResource(context, $"Failed to process WHOIS request. {ex.Message}", "application/xml", 500);
- }
- }
- }
-
- private void ServeDnsQueryRequest(HttpListenerContext context, string query)
- {
- if (string.IsNullOrWhiteSpace(query) || query.Length > 255)
- {
- ServeResource(context, "Invalid query parameter", "application/xml", 400);
- return;
- }
-
- try
- {
- DnsQuery dns = new DnsQuery();
- Dictionary> allRecords = dns.QueryAll(query);
-
- StringBuilder result = new StringBuilder();
- foreach (var recordType in allRecords.Keys)
- {
- result.AppendLine($"\n{recordType} Records:");
- foreach (var record in allRecords[recordType])
- {
- result.AppendLine(record);
- }
- }
-
- string data = result.ToString();
- ServeResource(context, data, "text/plain", 200);
- }
- catch (Exception ex)
- {
- ServeResource(context, $"Failed to process DNS query. {ex.Message}", "application/xml", 500);
- }
- }
-
- private void ServeTfaRequest(HttpListenerContext context, string endpoint)
- {
- Tfa _tfa = new Tfa();
-
- if (endpoint.Equals("pubkey"))
- {
- ServeResource(context, _tfa.GetPubKey(), "text/plain", 200);
- return;
- }
-
- ServeResource(context);
- }
-
- public void ServeConfigRequest(HttpListenerContext context, string key)
- {
- string value = Program.GetAppConfig(key);
- if (!String.IsNullOrEmpty(value))
- {
- ServeResource(context, value, "text/plain", 200);
- return;
- }
-
- ServeResource(context);
- }
-
- private void ServeResource(HttpListenerContext context)
- {
- ServeResource(context, "Not Found", "application/xml", 404);
- }
-
- private void ServeResource(HttpListenerContext context, byte[] data, string mimeType = "text/html", int statusCode = 200)
- {
- string xmlHeader = "";
-
- if (data == null) {
- data = Encoding.UTF8.GetBytes(xmlHeader + "\r\nCould not find the resource.");
- mimeType = "application/xml";
- statusCode = 404;
- }
-
- context.Response.StatusCode = statusCode;
- context.Response.ContentType = mimeType;
- context.Response.ContentLength64 = data.Length;
- using (Stream outputStream = context.Response.OutputStream)
- {
- outputStream.Write(data, 0, data.Length);
- }
- }
-
- private void ServeResource(HttpListenerContext context, string data, string mimeType = "text/html", int statusCode = 200)
- {
- string xmlHeader = "";
-
- if (data == null)
- {
- data = xmlHeader + "\r\nCould not find the resource.";
- mimeType = "application/xml";
- statusCode = 404;
- }
- else if (mimeType == "application/xml" && !data.StartsWith("
-
+
+
+
+
+
+
+
Form
EnvForm.cs
-
Form
@@ -101,8 +106,7 @@
GlobalSettingsForm.cs
-
-
+
EnvForm.cs
@@ -161,5 +165,6 @@
+
\ No newline at end of file
diff --git a/WelsonJS.Toolkit/WelsonJS.Launcher/app.config b/WelsonJS.Toolkit/WelsonJS.Launcher/app.config
index e4e97f2..0a85782 100644
--- a/WelsonJS.Toolkit/WelsonJS.Launcher/app.config
+++ b/WelsonJS.Toolkit/WelsonJS.Launcher/app.config
@@ -4,8 +4,14 @@
+
+
+
+
+
+