mirror of
https://github.com/gnh1201/welsonjs.git
synced 2025-11-27 18:11:20 +00:00
Merge pull request #333 from gnh1201/dev
Refactor IP query to support multiple providers
This commit is contained in:
commit
3542dc24b4
|
|
@ -150,24 +150,6 @@ namespace WelsonJS.Launcher.Properties {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 과(와) 유사한 지역화된 문자열을 찾습니다.
|
|
||||||
/// </summary>
|
|
||||||
internal static string CriminalIpApiKey {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("CriminalIpApiKey", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// https://api.criminalip.io/v1/과(와) 유사한 지역화된 문자열을 찾습니다.
|
|
||||||
/// </summary>
|
|
||||||
internal static string CriminalIpApiPrefix {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("CriminalIpApiPrefix", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// yyyy-MM-dd HH:mm:ss과(와) 유사한 지역화된 문자열을 찾습니다.
|
/// yyyy-MM-dd HH:mm:ss과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -295,6 +277,42 @@ namespace WelsonJS.Launcher.Properties {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||||
|
/// </summary>
|
||||||
|
internal static string IpQueryApiKey {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("IpQueryApiKey", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||||
|
/// </summary>
|
||||||
|
internal static string IpQueryApiKey2 {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("IpQueryApiKey2", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// https://api.criminalip.io/v1/과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||||
|
/// </summary>
|
||||||
|
internal static string IpQueryApiPrefix {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("IpQueryApiPrefix", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// https://api.abuseipdb.com/api/v2/과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||||
|
/// </summary>
|
||||||
|
internal static string IpQueryApiPrefix2 {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("IpQueryApiPrefix2", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// false과(와) 유사한 지역화된 문자열을 찾습니다.
|
/// false과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -190,10 +190,10 @@
|
||||||
<data name="HttpClientTimeout" xml:space="preserve">
|
<data name="HttpClientTimeout" xml:space="preserve">
|
||||||
<value>90</value>
|
<value>90</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="CriminalIpApiKey" xml:space="preserve">
|
<data name="IpQueryApiKey" xml:space="preserve">
|
||||||
<value />
|
<value />
|
||||||
</data>
|
</data>
|
||||||
<data name="CriminalIpApiPrefix" xml:space="preserve">
|
<data name="IpQueryApiPrefix" xml:space="preserve">
|
||||||
<value>https://api.criminalip.io/v1/</value>
|
<value>https://api.criminalip.io/v1/</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DateTimeFormat" xml:space="preserve">
|
<data name="DateTimeFormat" xml:space="preserve">
|
||||||
|
|
@ -214,4 +214,10 @@
|
||||||
<data name="ChromiumAppMode" xml:space="preserve">
|
<data name="ChromiumAppMode" xml:space="preserve">
|
||||||
<value>true</value>
|
<value>true</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="IpQueryApiKey2" xml:space="preserve">
|
||||||
|
<value />
|
||||||
|
</data>
|
||||||
|
<data name="IpQueryApiPrefix2" xml:space="preserve">
|
||||||
|
<value>https://api.abuseipdb.com/api/v2/</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -6,7 +6,6 @@
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
@ -45,8 +44,6 @@ namespace WelsonJS.Launcher.ResourceTools
|
||||||
|
|
||||||
public async Task HandleAsync(HttpListenerContext context, string path)
|
public async Task HandleAsync(HttpListenerContext context, string path)
|
||||||
{
|
{
|
||||||
await Task.Delay(0);
|
|
||||||
|
|
||||||
string word = path.Substring(Prefix.Length);
|
string word = path.Substring(Prefix.Length);
|
||||||
|
|
||||||
try
|
try
|
||||||
|
|
@ -121,10 +118,7 @@ namespace WelsonJS.Launcher.ResourceTools
|
||||||
.Select(p => p.Trim())
|
.Select(p => p.Trim())
|
||||||
.Where(p => !string.IsNullOrEmpty(p));
|
.Where(p => !string.IsNullOrEmpty(p));
|
||||||
|
|
||||||
foreach (string path in paths)
|
paths.ToList().ForEach(x => SearchAllExecutables(x, SearchOption.TopDirectoryOnly));
|
||||||
{
|
|
||||||
SearchAllExecutables(path, SearchOption.TopDirectoryOnly);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DiscoverFromProgramDirectories()
|
private void DiscoverFromProgramDirectories()
|
||||||
|
|
@ -153,10 +147,7 @@ namespace WelsonJS.Launcher.ResourceTools
|
||||||
Path.Combine(userProfile, "scoop", "apps")
|
Path.Combine(userProfile, "scoop", "apps")
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (string path in paths)
|
paths.ToList().ForEach(x => SearchAllExecutables(x));
|
||||||
{
|
|
||||||
SearchAllExecutables(path);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SearchAllExecutables(string path, SearchOption searchOption = SearchOption.AllDirectories, int maxFiles = 1000)
|
private void SearchAllExecutables(string path, SearchOption searchOption = SearchOption.AllDirectories, int maxFiles = 1000)
|
||||||
|
|
@ -184,10 +175,7 @@ namespace WelsonJS.Launcher.ResourceTools
|
||||||
|
|
||||||
private void AddDiscoveredExecutables(List<string> executableFiles)
|
private void AddDiscoveredExecutables(List<string> executableFiles)
|
||||||
{
|
{
|
||||||
foreach (var executableFile in executableFiles)
|
executableFiles.ForEach(x => DiscoveredExecutables.Add(x));
|
||||||
{
|
|
||||||
DiscoveredExecutables.Add(executableFile);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SafeDiscoverAsync(Action discoveryMethod)
|
private async Task SafeDiscoverAsync(Action discoveryMethod)
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,28 @@
|
||||||
// CitiQuery.cs
|
// IpQuery.cs
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
// SPDX-FileCopyrightText: 2025 Catswords OSS and WelsonJS Contributors
|
// SPDX-FileCopyrightText: 2025 Catswords OSS and WelsonJS Contributors
|
||||||
// https://github.com/gnh1201/welsonjs
|
// https://github.com/gnh1201/welsonjs
|
||||||
//
|
//
|
||||||
|
// PLEASE NOTE:
|
||||||
|
// Requires joining the IP Query API providers to provide IP information.
|
||||||
|
// WelsonJS has no affiliation with any IP Query API providers.
|
||||||
|
//
|
||||||
|
// Providers:
|
||||||
|
// 1) CriminalIP -> IpQueryApiPrefix, IpQueryApiKey
|
||||||
|
// 2) AbuseIPDB -> IpQueryApiPrefix2, IpQueryApiKey2
|
||||||
|
//
|
||||||
|
// XML response structure:
|
||||||
|
// <result target="1.1.1.1">
|
||||||
|
// <response provider="criminalip" status="200"><text>{"...json..."}</text></response>
|
||||||
|
// <response provider="abuseipdb" status="200"><text>{"...json..."}</text></response>
|
||||||
|
// </result>
|
||||||
|
//
|
||||||
using System;
|
using System;
|
||||||
using System.Net.Http;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Web;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace WelsonJS.Launcher.ResourceTools
|
namespace WelsonJS.Launcher.ResourceTools
|
||||||
{
|
{
|
||||||
|
|
@ -29,37 +45,121 @@ namespace WelsonJS.Launcher.ResourceTools
|
||||||
{
|
{
|
||||||
return path.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase);
|
return path.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task HandleAsync(HttpListenerContext context, string path)
|
public async Task HandleAsync(HttpListenerContext context, string path)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string target = path.Substring(Prefix.Length).Trim();
|
string target = path.Substring(Prefix.Length).Trim();
|
||||||
string apiKey = Program.GetAppConfig("CriminalIpApiKey");
|
if (string.IsNullOrWhiteSpace(target))
|
||||||
if (string.IsNullOrEmpty(apiKey))
|
|
||||||
{
|
{
|
||||||
await Server.ServeResource(context, "<error>Missing API key</error>", "application/xml", 500);
|
await Server.ServeResource(context, "<error>Missing IP target</error>", "application/xml", 400);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string encoded = Uri.EscapeDataString(target);
|
string crimPrefix = Program.GetAppConfig("IpQueryApiPrefix");
|
||||||
string apiPrefix = Program.GetAppConfig("CriminalIpApiPrefix");
|
string crimKey = Program.GetAppConfig("IpQueryApiKey");
|
||||||
string url = $"{apiPrefix}asset/ip/report?ip={encoded}&full=true";
|
|
||||||
|
|
||||||
var request = new HttpRequestMessage(HttpMethod.Get, url);
|
string abusePrefix = Program.GetAppConfig("IpQueryApiPrefix2");
|
||||||
request.Headers.Add("x-api-key", apiKey);
|
string abuseKey = Program.GetAppConfig("IpQueryApiKey2");
|
||||||
request.Headers.Add("User-Agent", context.Request.UserAgent);
|
|
||||||
|
|
||||||
HttpResponseMessage response = await _httpClient.SendAsync(request);
|
var root = new XElement("result", new XAttribute("target", target));
|
||||||
string content = await response.Content.ReadAsStringAsync();
|
|
||||||
|
|
||||||
context.Response.StatusCode = (int)response.StatusCode;
|
var p1 = QueryProviderAsync(context, target, "criminalip", crimPrefix, crimKey);
|
||||||
await Server.ServeResource(context, content, "application/json", (int)response.StatusCode);
|
var p2 = QueryProviderAsync(context, target, "abuseipdb", abusePrefix, abuseKey);
|
||||||
|
|
||||||
|
await Task.WhenAll(p1, p2);
|
||||||
|
|
||||||
|
root.Add(p1.Result);
|
||||||
|
root.Add(p2.Result);
|
||||||
|
|
||||||
|
bool anySuccess =
|
||||||
|
(int.TryParse((string)p1.Result.Attribute("status"), out var s1) && s1 >= 200 && s1 < 300) ||
|
||||||
|
(int.TryParse((string)p2.Result.Attribute("status"), out var s2) && s2 >= 200 && s2 < 300);
|
||||||
|
|
||||||
|
int httpCode = anySuccess ? 200 : 502;
|
||||||
|
|
||||||
|
context.Response.StatusCode = httpCode;
|
||||||
|
await Server.ServeResource(context, root.ToString(), "application/xml", httpCode);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await Server.ServeResource(context, $"<error>{ex.Message}</error>", "application/xml", 500);
|
_logger.Error("Error processing IP query request: " + ex.Message);
|
||||||
|
await Server.ServeResource(context, "<error>" + WebUtility.HtmlEncode(ex.Message) + "</error>", "application/xml", 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<XElement> QueryProviderAsync(HttpListenerContext ctx, string ip, string provider, string prefix, string key)
|
||||||
|
{
|
||||||
|
var node = new XElement("response", new XAttribute("provider", provider));
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(prefix) || string.IsNullOrWhiteSpace(key))
|
||||||
|
{
|
||||||
|
node.Add(new XAttribute("status", 503));
|
||||||
|
node.Add(new XElement("error", "Missing configuration for " + provider));
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HttpRequestMessage req = BuildProviderRequest(ctx, ip, provider, prefix, key);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (HttpResponseMessage resp = await _httpClient.SendAsync(req))
|
||||||
|
using (JsSerializer ser = new JsSerializer())
|
||||||
|
{
|
||||||
|
string body = ser.Pretty(await resp.Content.ReadAsStringAsync(), 4);
|
||||||
|
node.Add(new XAttribute("status", (int)resp.StatusCode));
|
||||||
|
node.Add(new XElement("text", body));
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
req.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
node.Add(new XAttribute("status", 500));
|
||||||
|
node.Add(new XElement("error", ex.Message));
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static HttpRequestMessage BuildProviderRequest(HttpListenerContext ctx, string ip, string provider, string prefix, string key)
|
||||||
|
{
|
||||||
|
HttpRequestMessage req;
|
||||||
|
|
||||||
|
if (string.Equals(provider, "criminalip", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
string url = prefix.TrimEnd('/') + "/asset/ip/report?ip=" + Uri.EscapeDataString(ip) + "&full=true";
|
||||||
|
req = new HttpRequestMessage(HttpMethod.Get, url);
|
||||||
|
req.Headers.TryAddWithoutValidation("x-api-key", key);
|
||||||
|
}
|
||||||
|
else if (string.Equals(provider, "abuseipdb", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var ub = new UriBuilder(prefix.TrimEnd('/') + "/check");
|
||||||
|
var q = HttpUtility.ParseQueryString(ub.Query);
|
||||||
|
q["ipAddress"] = ip;
|
||||||
|
q["maxAgeInDays"] = "90";
|
||||||
|
q["verbose"] = "";
|
||||||
|
ub.Query = q.ToString();
|
||||||
|
|
||||||
|
req = new HttpRequestMessage(HttpMethod.Get, ub.Uri);
|
||||||
|
req.Headers.TryAddWithoutValidation("Accept", "application/json");
|
||||||
|
req.Headers.TryAddWithoutValidation("Key", key);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Unsupported provider: " + provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(ctx.Request.UserAgent))
|
||||||
|
{
|
||||||
|
req.Headers.TryAddWithoutValidation("User-Agent", ctx.Request.UserAgent);
|
||||||
|
}
|
||||||
|
|
||||||
|
return req;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -37,6 +37,7 @@ namespace WelsonJS.Launcher.ResourceTools
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(query) || query.Length > 255)
|
if (string.IsNullOrWhiteSpace(query) || query.Length > 255)
|
||||||
{
|
{
|
||||||
|
_logger.Error("Invalid WHOIS query parameter.");
|
||||||
await Server.ServeResource(context, "<error>Invalid query parameter</error>", "application/xml", 400);
|
await Server.ServeResource(context, "<error>Invalid query parameter</error>", "application/xml", 400);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -61,6 +62,7 @@ namespace WelsonJS.Launcher.ResourceTools
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
_logger.Error("Error processing WHOIS request: " + ex.Message);
|
||||||
await Server.ServeResource(context, $"<error>Failed to process WHOIS request. {ex.Message}</error>", "application/xml", 500);
|
await Server.ServeResource(context, $"<error>Failed to process WHOIS request. {ex.Message}</error>", "application/xml", 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,7 @@
|
||||||
<Reference Include="System.Drawing" />
|
<Reference Include="System.Drawing" />
|
||||||
<Reference Include="System.IO.Compression.FileSystem" />
|
<Reference Include="System.IO.Compression.FileSystem" />
|
||||||
<Reference Include="System.Net.Http" />
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Web" />
|
||||||
<Reference Include="System.Windows.Forms" />
|
<Reference Include="System.Windows.Forms" />
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,10 @@
|
||||||
<add key="BlobStoragePrefix" value="https://catswords.blob.core.windows.net/welsonjs/"/>
|
<add key="BlobStoragePrefix" value="https://catswords.blob.core.windows.net/welsonjs/"/>
|
||||||
<add key="BlobConfigUrl" value="https://catswords.blob.core.windows.net/welsonjs/blob.config.xml"/>
|
<add key="BlobConfigUrl" value="https://catswords.blob.core.windows.net/welsonjs/blob.config.xml"/>
|
||||||
<add key="HttpClientTimeout" value="90"/>
|
<add key="HttpClientTimeout" value="90"/>
|
||||||
<add key="CitiApiKey" value=""/>
|
<add key="IpQueryApiKey" value=""/>
|
||||||
<add key="CitiApiPrefix" value="https://api.criminalip.io/v1/"/>
|
<add key="IpQueryApiPrefix" value="https://api.criminalip.io/v1/"/>
|
||||||
|
<add key="IpQueryApiKey2" value=""/>
|
||||||
|
<add key="IpQueryApiPrefix2" value="https://api.abuseipdb.com/api/v2/"/>
|
||||||
<add key="DateTimeFormat" value="yyyy-MM-dd HH:mm:ss"/>
|
<add key="DateTimeFormat" value="yyyy-MM-dd HH:mm:ss"/>
|
||||||
<add key="NativeRequireSigned" value="false"/>
|
<add key="NativeRequireSigned" value="false"/>
|
||||||
</appSettings>
|
</appSettings>
|
||||||
|
|
|
||||||
|
|
@ -589,59 +589,62 @@
|
||||||
appendTextToEditor("\n// IP address is required.");
|
appendTextToEditor("\n// IP address is required.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const apiKey = settingsRef.current.CriminalIpApiKey;
|
|
||||||
if (!apiKey || apiKey.trim() === '') {
|
|
||||||
appendTextToEditor("\n// Criminal IP API key is not set.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const apiPrefix = settingsRef.current.CriminalIpApiPrefix;
|
|
||||||
const ip = encodeURIComponent(hostname.trim());
|
const ip = encodeURIComponent(hostname.trim());
|
||||||
|
|
||||||
axios.get(`/ip-query/${hostname}`).then(response => {
|
axios.get(`/ip-query/${hostname}`).then(res => {
|
||||||
if (!response) {
|
if (!res || !res.data) {
|
||||||
appendTextToEditor("\n// No data returned from Criminal IP.");
|
appendTextToEditor("\n// No data returned from server.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const lines = [];
|
// Parse XML and keep attributes (provider, status)
|
||||||
lines.push(`/*\nCriminal IP Report: ${hostname}\n`);
|
const parser = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: "@_" });
|
||||||
|
const parsed = parser.parse(res.data);
|
||||||
// network port data
|
|
||||||
lines.push(`## Network ports:`);
|
// Expected XML:
|
||||||
if (response.port.data.length == 0) {
|
// <result target="...">
|
||||||
lines.push(`* No open ports found.`);
|
// <response provider="criminalip" status="200">
|
||||||
} else {
|
// <text>{ "...raw json..." }</text>
|
||||||
response.port.data.forEach(x => {
|
// </response>
|
||||||
lines.push(`### ${x.open_port_no}/${x.socket}`);
|
// <response provider="abuseipdb" status="200">
|
||||||
lines.push(`* Application: ${x.app_name} ${x.app_version}`);
|
// <text>{ "...raw json..." }</text>
|
||||||
lines.push(`* Discovered hostnames: ${x.dns_names}`);
|
// </response>
|
||||||
lines.push(`* Confirmed Time: ${x.confirmed_time}`);
|
// </result>
|
||||||
});
|
|
||||||
|
// Normalize to an array of <response> nodes
|
||||||
|
const responsesNode = parsed?.result?.response;
|
||||||
|
const responses = Array.isArray(responsesNode)
|
||||||
|
? responsesNode
|
||||||
|
: (responsesNode ? [responsesNode] : []);
|
||||||
|
|
||||||
|
if (responses.length === 0) {
|
||||||
|
appendTextToEditor("\n// No <response> nodes found.");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// vulnerability data
|
// Extract each <response><text> content and print
|
||||||
lines.push(`## Vulnerabilities:`);
|
let out = "\n// --- IP Query Results ---";
|
||||||
if (response.vulnerability.data.length == 0) {
|
for (const r of responses) {
|
||||||
lines.push(`* No vulnerabilities found.`);
|
const provider = r?.["@_provider"] || "unknown";
|
||||||
} else {
|
const status = r?.["@_status"] || "n/a";
|
||||||
response.vulnerability.data.forEach(x => {
|
|
||||||
lines.push(`### ${x.cve_id}`);
|
// Fast-XML-Parser usually makes <text> a string, but be safe:
|
||||||
lines.push(`* ${x.cve_description}`);
|
let txt = r?.text;
|
||||||
lines.push(`* CVSSV2 Score: ${x.cvssv2_score}`);
|
if (txt && typeof txt === "object") {
|
||||||
lines.push(`* CVSSV3 Score: ${x.cvssv3_score}`);
|
// If parser produced an object with a '#text' key or similar
|
||||||
});
|
txt = txt["#text"] || JSON.stringify(txt);
|
||||||
|
}
|
||||||
|
if (txt == null) txt = "";
|
||||||
|
|
||||||
|
out += `\n// provider=${provider}, status=${status}\n${txt}\n`;
|
||||||
}
|
}
|
||||||
|
out = "\n/*" + out + "*/\n";
|
||||||
|
|
||||||
lines.push(`*/\n`);
|
appendTextToEditor(out);
|
||||||
const report = lines.join('\n');
|
pushPromptMessage("system", out);
|
||||||
|
|
||||||
appendTextToEditor(report);
|
|
||||||
pushPromptMessage("system", report);
|
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
appendTextToEditor(`\n// Failed to query Criminal IP: ${error.message}`);
|
appendTextToEditor(`\n// Failed to query the IP: ${error.message}`);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user