mirror of
https://github.com/gnh1201/welsonjs.git
synced 2025-05-08 12:46:05 +00:00
Merge pull request #218 from gnh1201/dev
Refactor an endpoints of the web based editor
This commit is contained in:
commit
d38e26ba67
25
WelsonJS.Toolkit/WelsonJS.Launcher/IResourceTool.cs
Normal file
25
WelsonJS.Toolkit/WelsonJS.Launcher/IResourceTool.cs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace WelsonJS.Launcher
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Defines a contract for resource tools that can handle specific HTTP requests.
|
||||||
|
/// </summary>
|
||||||
|
public interface IResourceTool
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this tool can handle the specified path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The request path to check.</param>
|
||||||
|
/// <returns>True if this tool can handle the request; otherwise, false.</returns>
|
||||||
|
bool CanHandle(string path);
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously processes the HTTP request for the specified path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The HTTP listener context containing request and response objects.</param>
|
||||||
|
/// <param name="path">The request path to handle.</param>
|
||||||
|
/// <returns>A task representing the asynchronous operation.</returns>
|
||||||
|
Task HandleAsync(HttpListenerContext context, string path);
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,6 @@ using System.IO.Compression;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using WelsonJS.Launcher.Tools;
|
|
||||||
|
|
||||||
namespace WelsonJS.Launcher
|
namespace WelsonJS.Launcher
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,7 +5,6 @@ using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using System.Configuration;
|
using System.Configuration;
|
||||||
using WelsonJS.Launcher.Tools;
|
|
||||||
|
|
||||||
namespace WelsonJS.Launcher
|
namespace WelsonJS.Launcher
|
||||||
{
|
{
|
||||||
|
|
|
@ -60,6 +60,24 @@ namespace WelsonJS.Launcher.Properties {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||||
|
/// </summary>
|
||||||
|
internal static string AzureAiServiceApiKey {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("AzureAiServiceApiKey", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// https://ai-catswords656881030318.services.ai.azure.com/models/chat/completions?api-version=2024-05-01-preview과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||||
|
/// </summary>
|
||||||
|
internal static string AzureAiServiceUrl {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("AzureAiServiceUrl", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// https://copilot.microsoft.com/과(와) 유사한 지역화된 문자열을 찾습니다.
|
/// https://copilot.microsoft.com/과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -69,6 +87,24 @@ namespace WelsonJS.Launcher.Properties {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// http://localhost:9222/과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||||
|
/// </summary>
|
||||||
|
internal static string DevToolsPrefix {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("DevToolsPrefix", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 1.1.1.1과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||||
|
/// </summary>
|
||||||
|
internal static string DnsServerAddress {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("DnsServerAddress", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// (아이콘)과(와) 유사한 System.Drawing.Icon 형식의 지역화된 리소스를 찾습니다.
|
/// (아이콘)과(와) 유사한 System.Drawing.Icon 형식의 지역화된 리소스를 찾습니다.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -186,5 +222,41 @@ namespace WelsonJS.Launcher.Properties {
|
||||||
return ResourceManager.GetString("ResourceServerPrefix", resourceCulture);
|
return ResourceManager.GetString("ResourceServerPrefix", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 141.101.82.1과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||||
|
/// </summary>
|
||||||
|
internal static string WhoisClientAddress {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("WhoisClientAddress", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois/whois.jsp과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||||
|
/// </summary>
|
||||||
|
internal static string WhoisReferrerUrl {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("WhoisReferrerUrl", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois.jsc과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||||
|
/// </summary>
|
||||||
|
internal static string WhoisServerUrl {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("WhoisServerUrl", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||||
|
/// </summary>
|
||||||
|
internal static string WhoisUserAgent {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("WhoisUserAgent", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,4 +157,28 @@
|
||||||
<data name="ResourceServerPrefix" xml:space="preserve">
|
<data name="ResourceServerPrefix" xml:space="preserve">
|
||||||
<value>http://localhost:3000/</value>
|
<value>http://localhost:3000/</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="DevToolsPrefix" xml:space="preserve">
|
||||||
|
<value>http://localhost:9222/</value>
|
||||||
|
</data>
|
||||||
|
<data name="AzureAiServiceApiKey" xml:space="preserve">
|
||||||
|
<value />
|
||||||
|
</data>
|
||||||
|
<data name="AzureAiServiceUrl" xml:space="preserve">
|
||||||
|
<value>https://ai-catswords656881030318.services.ai.azure.com/models/chat/completions?api-version=2024-05-01-preview</value>
|
||||||
|
</data>
|
||||||
|
<data name="DnsServerAddress" xml:space="preserve">
|
||||||
|
<value>1.1.1.1</value>
|
||||||
|
</data>
|
||||||
|
<data name="WhoisClientAddress" xml:space="preserve">
|
||||||
|
<value>141.101.82.1</value>
|
||||||
|
</data>
|
||||||
|
<data name="WhoisReferrerUrl" xml:space="preserve">
|
||||||
|
<value>https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois/whois.jsp</value>
|
||||||
|
</data>
|
||||||
|
<data name="WhoisServerUrl" xml:space="preserve">
|
||||||
|
<value>https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois.jsc</value>
|
||||||
|
</data>
|
||||||
|
<data name="WhoisUserAgent" xml:space="preserve">
|
||||||
|
<value>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</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
210
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceServer.cs
Normal file
210
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceServer.cs
Normal file
|
@ -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<IResourceTool> _resourceTools = new List<IResourceTool>();
|
||||||
|
|
||||||
|
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, "<error>Not Found</error>", "application/xml", 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ServeResource(HttpListenerContext context, byte[] data, string mimeType = "text/html", int statusCode = 200)
|
||||||
|
{
|
||||||
|
string xmlHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
|
||||||
|
|
||||||
|
if (data == null) {
|
||||||
|
data = Encoding.UTF8.GetBytes(xmlHeader + "\r\n<error>Could not find the resource.</error>");
|
||||||
|
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 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
|
||||||
|
|
||||||
|
if (data == null)
|
||||||
|
{
|
||||||
|
data = xmlHeader + "\r\n<error>Could not find the resource.</error>";
|
||||||
|
mimeType = "application/xml";
|
||||||
|
statusCode = 404;
|
||||||
|
}
|
||||||
|
else if (mimeType == "application/xml" && !data.StartsWith("<?xml"))
|
||||||
|
{
|
||||||
|
data = xmlHeader + "\r\n" + data;
|
||||||
|
}
|
||||||
|
|
||||||
|
ServeResource(context, Encoding.UTF8.GetBytes(data), mimeType, statusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] GetResource(string resourceName)
|
||||||
|
{
|
||||||
|
// Try to fetch embedded resource.
|
||||||
|
byte[] data = GetEmbeddedResource(typeof(Program).Namespace + "." + resourceName);
|
||||||
|
if (data != null) return data;
|
||||||
|
|
||||||
|
// Fallback: Try to fetch resource from ResourceManager.
|
||||||
|
return GetResourceFromManager(resourceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] GetEmbeddedResource(string fullResourceName)
|
||||||
|
{
|
||||||
|
Assembly assembly = Assembly.GetExecutingAssembly();
|
||||||
|
using (Stream stream = assembly.GetManifestResourceStream(fullResourceName))
|
||||||
|
{
|
||||||
|
if (stream != null)
|
||||||
|
{
|
||||||
|
using (MemoryStream memoryStream = new MemoryStream())
|
||||||
|
{
|
||||||
|
stream.CopyTo(memoryStream);
|
||||||
|
return memoryStream.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] GetResourceFromManager(string resourceName)
|
||||||
|
{
|
||||||
|
object resourceObject = Properties.Resources.ResourceManager.GetObject(resourceName);
|
||||||
|
switch (resourceObject)
|
||||||
|
{
|
||||||
|
case byte[] resourceBytes:
|
||||||
|
return resourceBytes;
|
||||||
|
case System.Drawing.Icon icon:
|
||||||
|
return ConvertIconToBytes(icon);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] ConvertIconToBytes(System.Drawing.Icon icon)
|
||||||
|
{
|
||||||
|
using (MemoryStream memoryStream = new MemoryStream())
|
||||||
|
{
|
||||||
|
icon.Save(memoryStream);
|
||||||
|
return memoryStream.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,29 +3,72 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace WelsonJS.Launcher.Tools
|
namespace WelsonJS.Launcher.ResourceTools
|
||||||
{
|
{
|
||||||
public class ExecutablesCollector
|
public class Completion : IResourceTool
|
||||||
{
|
{
|
||||||
private List<string> executables = new List<string>();
|
private ResourceServer Server;
|
||||||
|
private const string Prefix = "completion/";
|
||||||
|
private List<string> Executables = new List<string>();
|
||||||
|
|
||||||
public ExecutablesCollector()
|
public Completion(ResourceServer server)
|
||||||
{
|
{
|
||||||
|
Server = server;
|
||||||
|
|
||||||
new Task(() =>
|
new Task(() =>
|
||||||
{
|
{
|
||||||
executables.AddRange(GetInstalledSoftwareExecutables());
|
Executables.AddRange(GetInstalledSoftwareExecutables());
|
||||||
executables.AddRange(GetExecutablesFromPath());
|
Executables.AddRange(GetExecutablesFromPath());
|
||||||
executables.AddRange(GetExecutablesFromNetFx());
|
Executables.AddRange(GetExecutablesFromNetFx());
|
||||||
}).Start();
|
}).Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<string> 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, $"<error>Failed to process completion request. {ex.Message}</error>", "application/xml", 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Delay(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<string> GetInstalledSoftwareExecutables()
|
private List<string> GetInstalledSoftwareExecutables()
|
||||||
|
@ -157,4 +200,12 @@ namespace WelsonJS.Launcher.Tools
|
||||||
return executables;
|
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; }
|
||||||
|
}
|
||||||
}
|
}
|
39
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Config.cs
Normal file
39
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Config.cs
Normal file
|
@ -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, $"<error>Failed to process Config request. {ex.Message}</error>", "application/xml", 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Delay(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
46
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/DevTools.cs
Normal file
46
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/DevTools.cs
Normal file
|
@ -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, $"<error>Failed to process DevTools request. {ex.Message}</error>", "application/xml", 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,22 +1,66 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
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 ResourceServer Server;
|
||||||
private readonly string _dnsServer;
|
private const string Prefix = "dns-query/";
|
||||||
|
private string DnsServer;
|
||||||
private const int DnsPort = 53;
|
private const int DnsPort = 53;
|
||||||
private const int Timeout = 5000;
|
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, "<error>Invalid query parameter</error>", "application/xml", 400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Dictionary<string, List<string>> 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, $"<error>Failed to process DNS query. {ex.Message}</error>", "application/xml", 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Delay(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<string> QueryA(string domain) => QueryDns(domain, 1);
|
public List<string> QueryA(string domain) => QueryDns(domain, 1);
|
||||||
|
@ -62,7 +106,7 @@ namespace WelsonJS.Launcher.Tools
|
||||||
}
|
}
|
||||||
|
|
||||||
// Basic domain format validation
|
// Basic domain format validation
|
||||||
if (domain.Length > 255 ||
|
if (domain.Length > 255 ||
|
||||||
!domain.Split('.').All(part => part.Length > 0 && part.Length <= 63))
|
!domain.Split('.').All(part => part.Length > 0 && part.Length <= 63))
|
||||||
{
|
{
|
||||||
records.Add("Error: Invalid domain format");
|
records.Add("Error: Invalid domain format");
|
||||||
|
@ -71,17 +115,18 @@ namespace WelsonJS.Launcher.Tools
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
UdpClient udpClient = new UdpClient(_dnsServer, DnsPort);
|
using (UdpClient udpClient = new UdpClient(DnsServer, DnsPort))
|
||||||
udpClient.Client.ReceiveTimeout = Timeout;
|
{
|
||||||
|
udpClient.Client.ReceiveTimeout = Timeout;
|
||||||
|
|
||||||
byte[] request = CreateDnsQuery(domain, type);
|
byte[] request = CreateDnsQuery(domain, type);
|
||||||
udpClient.Send(request, request.Length);
|
udpClient.Send(request, request.Length);
|
||||||
|
|
||||||
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, DnsPort);
|
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, DnsPort);
|
||||||
byte[] response = udpClient.Receive(ref remoteEP);
|
byte[] response = udpClient.Receive(ref remoteEP);
|
||||||
|
|
||||||
records.AddRange(ParseDnsResponse(response, type));
|
records.AddRange(ParseDnsResponse(response, type));
|
||||||
udpClient.Close();
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
|
@ -2,13 +2,42 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Collections.Generic;
|
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";
|
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)
|
public int GetOtp(string key)
|
||||||
{
|
{
|
||||||
byte[] binaryKey = DecodeBase32(key.Replace(" ", ""));
|
byte[] binaryKey = DecodeBase32(key.Replace(" ", ""));
|
64
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Whois.cs
Normal file
64
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Whois.cs
Normal file
|
@ -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, "<error>Invalid query parameter</error>", "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, $"<error>Failed to process WHOIS request. {ex.Message}</error>", "application/xml", 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<string> 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, $"<error>Failed to process completion request. {ex.Message}</error>", "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, $"<error>Failed to process DevTools request. {ex.Message}</error>", "application/xml", 500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ServeWhoisRequest(HttpListenerContext context, string query)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(query) || query.Length > 255)
|
|
||||||
{
|
|
||||||
ServeResource(context, "<error>Invalid query parameter</error>", "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, $"<error>Failed to process WHOIS request. {ex.Message}</error>", "application/xml", 500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ServeDnsQueryRequest(HttpListenerContext context, string query)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(query) || query.Length > 255)
|
|
||||||
{
|
|
||||||
ServeResource(context, "<error>Invalid query parameter</error>", "application/xml", 400);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
DnsQuery dns = new DnsQuery();
|
|
||||||
Dictionary<string, List<string>> 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, $"<error>Failed to process DNS query. {ex.Message}</error>", "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, "<error>Not Found</error>", "application/xml", 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ServeResource(HttpListenerContext context, byte[] data, string mimeType = "text/html", int statusCode = 200)
|
|
||||||
{
|
|
||||||
string xmlHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
|
|
||||||
|
|
||||||
if (data == null) {
|
|
||||||
data = Encoding.UTF8.GetBytes(xmlHeader + "\r\n<error>Could not find the resource.</error>");
|
|
||||||
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 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
|
|
||||||
|
|
||||||
if (data == null)
|
|
||||||
{
|
|
||||||
data = xmlHeader + "\r\n<error>Could not find the resource.</error>";
|
|
||||||
mimeType = "application/xml";
|
|
||||||
statusCode = 404;
|
|
||||||
}
|
|
||||||
else if (mimeType == "application/xml" && !data.StartsWith("<?xml"))
|
|
||||||
{
|
|
||||||
data = xmlHeader + "\r\n" + data;
|
|
||||||
}
|
|
||||||
|
|
||||||
ServeResource(context, Encoding.UTF8.GetBytes(data), mimeType, statusCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] GetResource(string resourceName)
|
|
||||||
{
|
|
||||||
// Try to fetch embedded resource.
|
|
||||||
byte[] data = GetEmbeddedResource(typeof(Program).Namespace + "." + resourceName);
|
|
||||||
if (data != null) return data;
|
|
||||||
|
|
||||||
// Fallback: Try to fetch resource from ResourceManager.
|
|
||||||
return GetResourceFromManager(resourceName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] GetEmbeddedResource(string fullResourceName)
|
|
||||||
{
|
|
||||||
Assembly assembly = Assembly.GetExecutingAssembly();
|
|
||||||
using (Stream stream = assembly.GetManifestResourceStream(fullResourceName))
|
|
||||||
{
|
|
||||||
if (stream != null)
|
|
||||||
{
|
|
||||||
using (MemoryStream memoryStream = new MemoryStream())
|
|
||||||
{
|
|
||||||
stream.CopyTo(memoryStream);
|
|
||||||
return memoryStream.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] GetResourceFromManager(string resourceName)
|
|
||||||
{
|
|
||||||
object resourceObject = Properties.Resources.ResourceManager.GetObject(resourceName);
|
|
||||||
switch (resourceObject)
|
|
||||||
{
|
|
||||||
case byte[] resourceBytes:
|
|
||||||
return resourceBytes;
|
|
||||||
case System.Drawing.Icon icon:
|
|
||||||
return ConvertIconToBytes(icon);
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] ConvertIconToBytes(System.Drawing.Icon icon)
|
|
||||||
{
|
|
||||||
using (MemoryStream memoryStream = new MemoryStream())
|
|
||||||
{
|
|
||||||
icon.Save(memoryStream);
|
|
||||||
return memoryStream.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CompletionItem
|
|
||||||
{
|
|
||||||
public string Label { get; set; }
|
|
||||||
public string Kind { get; set; }
|
|
||||||
public string Documentation { get; set; }
|
|
||||||
public string InsertText { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -73,14 +73,19 @@
|
||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="System.Xml.Linq" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Tools\DnsQuery.cs" />
|
<Compile Include="IResourceTool.cs" />
|
||||||
|
<Compile Include="ResourceTools\Config.cs" />
|
||||||
|
<Compile Include="ResourceTools\Completion.cs" />
|
||||||
|
<Compile Include="ResourceTools\DevTools.cs" />
|
||||||
|
<Compile Include="ResourceTools\DnsQuery.cs" />
|
||||||
|
<Compile Include="ResourceTools\Tfa.cs" />
|
||||||
|
<Compile Include="ResourceTools\Whois.cs" />
|
||||||
<Compile Include="EnvForm.cs">
|
<Compile Include="EnvForm.cs">
|
||||||
<SubType>Form</SubType>
|
<SubType>Form</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="EnvForm.Designer.cs">
|
<Compile Include="EnvForm.Designer.cs">
|
||||||
<DependentUpon>EnvForm.cs</DependentUpon>
|
<DependentUpon>EnvForm.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Tools\ExecutablesCollector.cs" />
|
|
||||||
<Compile Include="InstancesForm.cs">
|
<Compile Include="InstancesForm.cs">
|
||||||
<SubType>Form</SubType>
|
<SubType>Form</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
@ -101,8 +106,7 @@
|
||||||
<Compile Include="GlobalSettingsForm.Designer.cs">
|
<Compile Include="GlobalSettingsForm.Designer.cs">
|
||||||
<DependentUpon>GlobalSettingsForm.cs</DependentUpon>
|
<DependentUpon>GlobalSettingsForm.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Tools\ResourceServer.cs" />
|
<Compile Include="ResourceServer.cs" />
|
||||||
<Compile Include="Tools\Tfa.cs" />
|
|
||||||
<EmbeddedResource Include="EnvForm.resx">
|
<EmbeddedResource Include="EnvForm.resx">
|
||||||
<DependentUpon>EnvForm.cs</DependentUpon>
|
<DependentUpon>EnvForm.cs</DependentUpon>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
@ -161,5 +165,6 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="editor.html" />
|
<EmbeddedResource Include="editor.html" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup />
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
|
@ -4,8 +4,14 @@
|
||||||
<add key="ResourceServerPrefix" value="http://localhost:3000/"/>
|
<add key="ResourceServerPrefix" value="http://localhost:3000/"/>
|
||||||
<add key="RepositoryUrl" value="https://github.com/gnh1201/welsonjs"/>
|
<add key="RepositoryUrl" value="https://github.com/gnh1201/welsonjs"/>
|
||||||
<add key="CopilotUrl" value="https://copilot.microsoft.com/"/>
|
<add key="CopilotUrl" value="https://copilot.microsoft.com/"/>
|
||||||
|
<add key="DevToolsPrefix" value="http://localhost:9222/"/>
|
||||||
<add key="AzureAiServiceUrl" value="https://ai-catswords656881030318.services.ai.azure.com/models/chat/completions?api-version=2024-05-01-preview"/>
|
<add key="AzureAiServiceUrl" value="https://ai-catswords656881030318.services.ai.azure.com/models/chat/completions?api-version=2024-05-01-preview"/>
|
||||||
<add key="AzureAiServiceApiKey" value=""/>
|
<add key="AzureAiServiceApiKey" value=""/>
|
||||||
|
<add key="WhoisServerUrl" value="https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois.jsc"/>
|
||||||
|
<add key="WhoisReferrerUrl" value="https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois/whois.jsp"/>
|
||||||
|
<add key="WhoisUserAgent" value="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"/>
|
||||||
|
<add key="WhoisClientAddress" value="141.101.82.1"/>
|
||||||
|
<add key="DnsServerAddress" value="1.1.1.1"/>
|
||||||
</appSettings>
|
</appSettings>
|
||||||
<startup>
|
<startup>
|
||||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/>
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user