Files
ps.ipam/classlib/Helpers/RequestHelper.cs

375 lines
13 KiB
C#

namespace PS.IPAM.Helpers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PS.IPAM;
public static class RequestHelper
{
// Handler for testing - allows injecting a mock HTTP handler
public static HttpMessageHandler? TestHttpHandler { get; set; }
public static async Task<object?> InvokeRequest(
string method,
controllers controller,
types? type = null,
subcontrollers? subController = null,
object? parameters = null,
string[]? identifiers = null,
bool ignoreSsl = false)
{
var tokenStatus = SessionManager.TestSession();
if (tokenStatus == "NoToken")
{
throw new Exception("No session available!");
}
if (tokenStatus == "Expired")
{
await UpdateSession();
}
var session = SessionManager.CurrentSession;
if (session == null)
{
throw new Exception("No session available!");
}
var uri = $"{session.URL}/api/{session.AppID}/{controller}";
if (subController != null)
{
uri += $"/{subController}";
}
if (identifiers != null && identifiers.Length > 0)
{
uri += $"/{string.Join("/", identifiers)}/";
}
using var client = SessionManager.CreateHttpClient(ignoreSsl, TestHttpHandler);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
switch (session.AuthType)
{
case AuthType.credentials:
client.DefaultRequestHeaders.Add("token", session.Token);
break;
case AuthType.token:
client.DefaultRequestHeaders.Add("phpipam-token", session.Token);
break;
}
HttpResponseMessage? response = null;
try
{
if (method == "GET")
{
response = await client.GetAsync(uri);
}
else if (method == "POST")
{
var jsonContent = parameters != null ? JsonConvert.SerializeObject(parameters) : "{}";
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
response = await client.PostAsync(uri, content);
}
else if (method == "PATCH")
{
var jsonContent = parameters != null ? JsonConvert.SerializeObject(parameters) : "{}";
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
var request = new HttpRequestMessage(new HttpMethod("PATCH"), uri)
{
Content = content
};
response = await client.SendAsync(request);
}
else if (method == "DELETE")
{
response = await client.DeleteAsync(uri);
}
if (response == null)
{
return null;
}
var responseContent = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
{
return null;
}
throw new HttpRequestException($"Request failed with status {response.StatusCode}");
}
if (string.IsNullOrEmpty(responseContent))
{
return null;
}
var jsonResponse = JsonConvert.DeserializeObject<dynamic>(responseContent);
if (jsonResponse == null)
{
return null;
}
if (type.HasValue)
{
return ConvertToTypedObjects(jsonResponse, type.Value);
}
return jsonResponse.data;
}
catch (HttpRequestException ex)
{
if (ex.Message.Contains("404"))
{
return null;
}
throw;
}
}
private static object? ConvertToTypedObjects(dynamic jsonResponse, types type)
{
if (jsonResponse?.data == null)
{
return null;
}
var data = jsonResponse.data;
if (data is JArray array)
{
return array.Select(item => ConvertSingleObject(item, type)).ToList();
}
else
{
return ConvertSingleObject(data, type);
}
}
private static object? ConvertSingleObject(dynamic item, types type)
{
var jobject = item as JObject;
if (jobject == null)
{
return null;
}
var customFields = new Dictionary<string, object>();
foreach (var prop in jobject.Properties())
{
if (prop.Name.StartsWith("custom_"))
{
customFields[prop.Name] = prop.Value?.ToObject<object>() ?? new object();
}
}
switch (type)
{
case types.Address:
return CreateAddress(jobject, customFields);
case types.Vlan:
return CreateVlan(jobject, customFields);
case types.Subnetwork:
return CreateSubnetwork(jobject, customFields);
case types.Vrf:
return CreateVrf(jobject, customFields);
case types.Section:
return CreateSection(jobject);
case types.Tag:
return CreateTag(jobject);
case types.Nameserver:
return CreateNameserver(jobject);
case types.Domain:
return CreateDomain(jobject);
default:
return jobject.ToObject<object>();
}
}
private static Address CreateAddress(JObject jobject, Dictionary<string, object> customFields)
{
return new Address(
jobject["id"]?.ToObject<int>() ?? 0,
jobject["subnetId"]?.ToObject<int>() ?? 0,
jobject["ip"]?.ToString() ?? "",
jobject["is_gateway"]?.ToObject<bool>() ?? false,
jobject["description"]?.ToString() ?? "",
jobject["hostname"]?.ToString() ?? "",
jobject["mac"]?.ToString() ?? "",
jobject["owner"]?.ToString() ?? "",
jobject["tag"]?.ToObject<int>() ?? 0,
jobject["deviceId"]?.ToObject<int>() ?? 0,
jobject["location"]?.ToString() ?? "",
jobject["port"]?.ToString() ?? "",
jobject["note"]?.ToString() ?? "",
jobject["lastSeen"]?.ToObject<DateTime?>(),
jobject["excludePing"]?.ToObject<bool>() ?? false,
jobject["PTRignore"]?.ToObject<bool>() ?? false,
jobject["PTR"]?.ToObject<int>() ?? 0,
jobject["firewallAddressObject"]?.ToString() ?? "",
jobject["editDate"]?.ToObject<DateTime?>(),
jobject["customer_id"]?.ToObject<int>() ?? 0,
customFields.Count > 0 ? customFields : null
);
}
private static Vlan CreateVlan(JObject jobject, Dictionary<string, object> customFields)
{
return new Vlan(
jobject["vlanId"]?.ToObject<int>() ?? 0,
jobject["domainId"]?.ToObject<int>() ?? 0,
jobject["name"]?.ToString() ?? "",
jobject["number"]?.ToObject<int>() ?? 0,
jobject["description"]?.ToString() ?? "",
jobject["editDate"]?.ToObject<DateTime?>(),
jobject["customer_id"]?.ToObject<int>() ?? 0,
customFields.Count > 0 ? customFields : null
);
}
private static Subnetwork CreateSubnetwork(JObject jobject, Dictionary<string, object> customFields)
{
var props = jobject.Properties().ToList();
return new Subnetwork(
jobject["id"]?.ToObject<int>() ?? 0,
jobject["subnet"]?.ToString() ?? "",
jobject["mask"]?.ToObject<int>() ?? 0,
jobject["sectionId"]?.ToObject<int>() ?? 0,
jobject["description"]?.ToString() ?? "",
jobject["linked_subnet"]?.ToString() ?? "",
jobject["firewallAddressObject"]?.ToString() ?? "",
jobject["vrfId"]?.ToObject<int>() ?? 0,
jobject["masterSubnetId"]?.ToObject<int>() ?? 0,
jobject["allowRequests"]?.ToObject<bool>() ?? false,
jobject["vlanId"]?.ToObject<int>() ?? 0,
jobject["showName"]?.ToObject<bool>() ?? false,
jobject["deviceId"]?.ToObject<int>() ?? 0,
jobject["permissions"]?.ToString() ?? "",
jobject["pingSubnet"]?.ToObject<bool>() ?? false,
jobject["discoverSubnet"]?.ToObject<bool>() ?? false,
jobject["resolveDNS"]?.ToObject<bool>() ?? false,
jobject["DNSrecursive"]?.ToObject<bool>() ?? false,
jobject["DNSrecords"]?.ToObject<bool>() ?? false,
jobject["nameserverId"]?.ToObject<int>() ?? 0,
jobject["scanAgent"]?.ToObject<bool>() ?? false,
jobject["isFolder"]?.ToObject<bool>() ?? false,
jobject["isFull"]?.ToObject<bool>() ?? false,
jobject["isPool"]?.ToObject<bool>() ?? false,
jobject["state"]?.ToObject<int>() ?? 0,
jobject["threshold"]?.ToObject<int>() ?? 0,
jobject["location"]?.ToObject<int>() ?? 0,
jobject["editDate"]?.ToObject<DateTime?>(),
jobject["lastScan"]?.ToObject<DateTime?>(),
jobject["lastDiscovery"]?.ToObject<DateTime?>(),
jobject["calculation"]?.ToObject<object>() ?? new object(),
customFields.Count > 0 ? customFields : null
);
}
private static Vrf CreateVrf(JObject jobject, Dictionary<string, object> customFields)
{
return new Vrf(
jobject["id"]?.ToObject<int>() ?? 0,
jobject["name"]?.ToString() ?? "",
jobject["rd"]?.ToString() ?? "",
jobject["description"]?.ToString() ?? "",
jobject["sections"]?.ToString() ?? "",
jobject["editDate"]?.ToObject<DateTime?>(),
customFields.Count > 0 ? customFields : null
);
}
private static Section CreateSection(JObject jobject)
{
return new Section(
jobject["id"]?.ToObject<int>() ?? 0,
jobject["name"]?.ToString() ?? "",
jobject["description"]?.ToString() ?? "",
jobject["masterSection"]?.ToObject<int>() ?? 0,
jobject["permissions"]?.ToString() ?? "",
jobject["strictMode"]?.ToObject<bool>() ?? false,
jobject["subnetOrdering"]?.ToString() ?? "",
jobject["order"]?.ToObject<int>() ?? 0,
jobject["editDate"]?.ToObject<DateTime?>(),
jobject["showSubnet"]?.ToObject<bool>() ?? false,
jobject["showVlan"]?.ToObject<bool>() ?? false,
jobject["showVRF"]?.ToObject<bool>() ?? false,
jobject["showSupernetOnly"]?.ToObject<bool>() ?? false,
jobject["DNS"]?.ToObject<int>() ?? 0
);
}
private static Tag CreateTag(JObject jobject)
{
return new Tag(
jobject["id"]?.ToObject<int>() ?? 0,
jobject["type"]?.ToString() ?? "",
jobject["showtag"]?.ToObject<bool>() ?? false,
jobject["bgcolor"]?.ToString() ?? "",
jobject["fgcolor"]?.ToString() ?? "",
jobject["compress"]?.ToString() ?? "",
jobject["locked"]?.ToString() ?? "",
jobject["updateTag"]?.ToObject<bool>() ?? false
);
}
private static Nameserver CreateNameserver(JObject jobject)
{
return new Nameserver(
jobject["id"]?.ToObject<int>() ?? 0,
jobject["name"]?.ToString() ?? "",
jobject["nameservers"]?.ToString() ?? "",
jobject["description"]?.ToString() ?? "",
jobject["permissions"]?.ToString() ?? "",
jobject["editDate"]?.ToObject<DateTime?>()
);
}
private static Domain CreateDomain(JObject jobject)
{
return new Domain(
jobject["id"]?.ToObject<int>() ?? 0,
jobject["name"]?.ToString() ?? "",
jobject["description"]?.ToString() ?? "",
jobject["sections"]?.ToString() ?? ""
);
}
private static async Task UpdateSession()
{
var session = SessionManager.CurrentSession;
if (session == null)
{
throw new Exception("No session available!");
}
var tokenStatus = SessionManager.TestSession();
if (tokenStatus == "Valid")
{
// Just refresh the token
var result = await InvokeRequest("PATCH", controllers.user, null, null, null, null);
// Token refresh doesn't return expires in the same format, so we'll skip updating expires
return;
}
if (tokenStatus == "Expired" && session.Credentials is PSCredential creds)
{
await SessionManager.CreateSessionWithCredentials(
session.URL,
session.AppID,
creds,
false
);
}
}
}