namespace PS.IPAM.Helpers; using System; using System.Management.Automation; using System.Net.Http; using System.Net.Http.Headers; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; /// /// Manages phpIPAM API sessions including creation, validation, and lifecycle. /// public static class SessionManager { private static Session? _currentSession; /// /// Gets or sets the current active session. /// public static Session? CurrentSession { get => _currentSession; set => _currentSession = value; } /// /// Tests the current session status. /// /// The session status indicating validity or issues. public static SessionStatus GetSessionStatus() { if (_currentSession == null) { return SessionStatus.NoSession; } if (_currentSession.Expires == null) { return SessionStatus.Valid; } return _currentSession.Expires < DateTime.Now ? SessionStatus.Expired : SessionStatus.Valid; } /// /// Creates a new session using username/password credentials. /// /// The phpIPAM server URL. /// The API application ID. /// The PowerShell credential object. /// Whether to ignore SSL certificate errors. /// The created session. public static async Task CreateSessionWithCredentialsAsync( string url, string appId, PSCredential credentials, bool ignoreSsl = false) { var uri = $"{url}/api/{appId}/user"; var auth = Convert.ToBase64String( Encoding.UTF8.GetBytes($"{credentials.UserName}:{GetPasswordString(credentials)}")); using var client = CreateHttpClient(ignoreSsl); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", auth); var response = await client.PostAsync(uri, null); var content = await response.Content.ReadAsStringAsync(); var jsonResponse = JsonConvert.DeserializeObject(content); if (jsonResponse?.success != true) { throw new InvalidOperationException( jsonResponse?.error?.ToString() ?? "Failed to create session"); } var token = jsonResponse.data.token.ToString(); var expires = DateTime.Parse(jsonResponse.data.expires.ToString()); _currentSession = new Session( AuthType.Credentials, token, appId, url, expires, credentials ); return _currentSession; } /// /// Creates a new session using a static API token. /// /// The phpIPAM server URL. /// The API application ID. /// The API token. /// The created session. public static Session CreateSessionWithToken(string url, string appId, string token) { _currentSession = new Session( AuthType.Token, token, appId, url, null, null ); return _currentSession; } /// /// Closes the current session and clears session data. /// public static void CloseSession() { _currentSession = null; } /// /// Creates an HttpClient with optional SSL bypass. /// /// Whether to ignore SSL certificate errors. /// Optional custom message handler for testing. /// A configured HttpClient instance. public static HttpClient CreateHttpClient(bool ignoreSsl = false, HttpMessageHandler? handler = null) { if (handler != null) { return new HttpClient(handler); } if (ignoreSsl) { var sslHandler = new HttpClientHandler { ServerCertificateCustomValidationCallback = (_, _, _, _) => true }; return new HttpClient(sslHandler); } return new HttpClient(); } /// /// Extracts the plain text password from a PSCredential object. /// private static string GetPasswordString(PSCredential credential) { var ptr = Marshal.SecureStringToBSTR(credential.Password); try { return Marshal.PtrToStringBSTR(ptr); } finally { Marshal.ZeroFreeBSTR(ptr); } } }