diff --git a/dotnetcore.csproj b/dotnetcore.csproj new file mode 100644 index 0000000..120e38c --- /dev/null +++ b/dotnetcore.csproj @@ -0,0 +1,8 @@ + + + + Exe + net7.0 + + + diff --git a/insight.sln b/insight.sln index 85085b4..c6e0266 100644 --- a/insight.sln +++ b/insight.sln @@ -27,19 +27,15 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Api", "Api", "{35BA5DCB-BEC EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Insight.Api", "src\Api\Insight.Api\Insight.Api.csproj", "{EF3188D7-338D-43DA-BF6B-D26E5BDAC3A6}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Insight.Server", "src\Server\Insight.Server\Insight.Server.csproj", "{1E75F7E9-E6AA-44E7-A2F3-DB4CA85E0118}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Insight.Updater", "src\Updater\Insight.Updater\Insight.Updater.csproj", "{4875D70F-A96B-4EBA-99BE-218886D29BEB}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Insight.Web.Assets", "src\Web\Insight.Web.Assets\Insight.Web.Assets.csproj", "{EBB8A2A8-453B-4867-A8E2-072530391DD0}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Insight.Agent", "src\Agent\Insight.Agent\Insight.Agent.csproj", "{2A391CA2-F96B-4DB7-80AA-0668A5141640}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Remote", "Remote", "{D4D7BF4A-B2E3-470A-A14C-FC658FF7461D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Insight.Remote.Shared", "src\Remote\Insight.Remote.Shared\Insight.Remote.Shared.csproj", "{5C4697BD-BC97-484F-9DB1-CA87E2BEAA4B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Insight.Remote.Windows", "src\Remote\Insight.Remote.Windows\Insight.Remote.Windows.csproj", "{AF313B47-3079-407F-91D1-9989C1E1AF2A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Insight.Infrastructure.Web", "src\Core\Insight.Infrastructure.Web\Insight.Infrastructure.Web.csproj", "{39B81A0D-A88C-44D3-9624-1A19C78A4310}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Insight.Server", "src\Server\Insight.Server\Insight.Server.csproj", "{FCAE9C42-1DCE-4C2E-BAE0-251C147903B4}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Insight.Agent.Assets", "src\Agent\Insight.Agent.Assets\Insight.Agent.Assets.csproj", "{4C2B66EA-4EE1-47BF-BAEE-DDBAF6FCB324}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -67,30 +63,26 @@ Global {EF3188D7-338D-43DA-BF6B-D26E5BDAC3A6}.Debug|Any CPU.Build.0 = Debug|Any CPU {EF3188D7-338D-43DA-BF6B-D26E5BDAC3A6}.Release|Any CPU.ActiveCfg = Release|Any CPU {EF3188D7-338D-43DA-BF6B-D26E5BDAC3A6}.Release|Any CPU.Build.0 = Release|Any CPU + {1E75F7E9-E6AA-44E7-A2F3-DB4CA85E0118}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1E75F7E9-E6AA-44E7-A2F3-DB4CA85E0118}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1E75F7E9-E6AA-44E7-A2F3-DB4CA85E0118}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1E75F7E9-E6AA-44E7-A2F3-DB4CA85E0118}.Release|Any CPU.Build.0 = Release|Any CPU {4875D70F-A96B-4EBA-99BE-218886D29BEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4875D70F-A96B-4EBA-99BE-218886D29BEB}.Debug|Any CPU.Build.0 = Debug|Any CPU {4875D70F-A96B-4EBA-99BE-218886D29BEB}.Release|Any CPU.ActiveCfg = Release|Any CPU {4875D70F-A96B-4EBA-99BE-218886D29BEB}.Release|Any CPU.Build.0 = Release|Any CPU + {EBB8A2A8-453B-4867-A8E2-072530391DD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EBB8A2A8-453B-4867-A8E2-072530391DD0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EBB8A2A8-453B-4867-A8E2-072530391DD0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EBB8A2A8-453B-4867-A8E2-072530391DD0}.Release|Any CPU.Build.0 = Release|Any CPU {2A391CA2-F96B-4DB7-80AA-0668A5141640}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2A391CA2-F96B-4DB7-80AA-0668A5141640}.Debug|Any CPU.Build.0 = Debug|Any CPU {2A391CA2-F96B-4DB7-80AA-0668A5141640}.Release|Any CPU.ActiveCfg = Release|Any CPU {2A391CA2-F96B-4DB7-80AA-0668A5141640}.Release|Any CPU.Build.0 = Release|Any CPU - {5C4697BD-BC97-484F-9DB1-CA87E2BEAA4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5C4697BD-BC97-484F-9DB1-CA87E2BEAA4B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5C4697BD-BC97-484F-9DB1-CA87E2BEAA4B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5C4697BD-BC97-484F-9DB1-CA87E2BEAA4B}.Release|Any CPU.Build.0 = Release|Any CPU - {AF313B47-3079-407F-91D1-9989C1E1AF2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AF313B47-3079-407F-91D1-9989C1E1AF2A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AF313B47-3079-407F-91D1-9989C1E1AF2A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AF313B47-3079-407F-91D1-9989C1E1AF2A}.Release|Any CPU.Build.0 = Release|Any CPU - {39B81A0D-A88C-44D3-9624-1A19C78A4310}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {39B81A0D-A88C-44D3-9624-1A19C78A4310}.Debug|Any CPU.Build.0 = Debug|Any CPU - {39B81A0D-A88C-44D3-9624-1A19C78A4310}.Release|Any CPU.ActiveCfg = Release|Any CPU - {39B81A0D-A88C-44D3-9624-1A19C78A4310}.Release|Any CPU.Build.0 = Release|Any CPU - {FCAE9C42-1DCE-4C2E-BAE0-251C147903B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FCAE9C42-1DCE-4C2E-BAE0-251C147903B4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FCAE9C42-1DCE-4C2E-BAE0-251C147903B4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FCAE9C42-1DCE-4C2E-BAE0-251C147903B4}.Release|Any CPU.Build.0 = Release|Any CPU + {4C2B66EA-4EE1-47BF-BAEE-DDBAF6FCB324}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4C2B66EA-4EE1-47BF-BAEE-DDBAF6FCB324}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4C2B66EA-4EE1-47BF-BAEE-DDBAF6FCB324}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4C2B66EA-4EE1-47BF-BAEE-DDBAF6FCB324}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -101,12 +93,11 @@ Global {CA99B8CF-520A-4B48-ACCE-0A301C35A7FE} = {15D04093-4974-4B2F-AE8A-F3721F31767A} {375EF474-512A-4410-86CF-46974E07C1F7} = {3F000016-069D-477E-ACA3-F643880B57E8} {EF3188D7-338D-43DA-BF6B-D26E5BDAC3A6} = {35BA5DCB-BECC-4F51-8DD0-694C555D205A} + {1E75F7E9-E6AA-44E7-A2F3-DB4CA85E0118} = {038C3821-E554-496D-B585-A3BC193B7913} {4875D70F-A96B-4EBA-99BE-218886D29BEB} = {F2D241DB-7692-46DB-8A6A-958B365DAAF8} + {EBB8A2A8-453B-4867-A8E2-072530391DD0} = {3F000016-069D-477E-ACA3-F643880B57E8} {2A391CA2-F96B-4DB7-80AA-0668A5141640} = {140F73DD-29D3-4C44-809B-5B470880AA0D} - {5C4697BD-BC97-484F-9DB1-CA87E2BEAA4B} = {D4D7BF4A-B2E3-470A-A14C-FC658FF7461D} - {AF313B47-3079-407F-91D1-9989C1E1AF2A} = {D4D7BF4A-B2E3-470A-A14C-FC658FF7461D} - {39B81A0D-A88C-44D3-9624-1A19C78A4310} = {88B03853-2215-4E52-8986-0E76602E5F21} - {FCAE9C42-1DCE-4C2E-BAE0-251C147903B4} = {038C3821-E554-496D-B585-A3BC193B7913} + {4C2B66EA-4EE1-47BF-BAEE-DDBAF6FCB324} = {140F73DD-29D3-4C44-809B-5B470880AA0D} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {F376A326-7590-4E7E-AB9B-76CED8527AB0} diff --git a/src/Agent/Insight.Agent.Assets/Enums/CategoryEnum.cs b/src/Agent/Insight.Agent.Assets/Enums/CategoryEnum.cs new file mode 100644 index 0000000..5ba8cb9 --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Enums/CategoryEnum.cs @@ -0,0 +1,14 @@ +namespace Insight.Agent.Enums +{ + public enum CategoryEnum + { + Network = 1, + System = 2, + Application = 3, + Security = 4, + Monitoring = 5, + Task = 6, + Printer = 7, + RDP = 8 + } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Enums/DispatchEnum.cs b/src/Agent/Insight.Agent.Assets/Enums/DispatchEnum.cs new file mode 100644 index 0000000..2d824d4 --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Enums/DispatchEnum.cs @@ -0,0 +1,9 @@ +namespace Insight.Agent.Enums +{ + public enum DispatchEnum + { + Pending = 1, + Failure = 2, + Success = 3, + } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Enums/StatusEnum.cs b/src/Agent/Insight.Agent.Assets/Enums/StatusEnum.cs new file mode 100644 index 0000000..49b8e7d --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Enums/StatusEnum.cs @@ -0,0 +1,9 @@ +namespace Insight.Agent.Enums +{ + public enum StatusEnum + { + Information = 1, + Warning = 2, + Error = 3 + } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Insight.Agent.Assets.csproj b/src/Agent/Insight.Agent.Assets/Insight.Agent.Assets.csproj new file mode 100644 index 0000000..26c306e --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Insight.Agent.Assets.csproj @@ -0,0 +1,33 @@ + + + + net7.0 + true + enable + Insight.Agent.Assets + Insight.Agent + Insight + 2025.2.24.0 + 2025.2.24.0 + none + true + + + + none + + + + none + + + + + + + + + + + + diff --git a/src/Agent/Insight.Agent.Assets/Interfaces/IAgentMessageHandler.cs b/src/Agent/Insight.Agent.Assets/Interfaces/IAgentMessageHandler.cs new file mode 100644 index 0000000..a9e69a6 --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Interfaces/IAgentMessageHandler.cs @@ -0,0 +1,9 @@ +using Insight.Agent.Messages; + +namespace Insight.Agent.Interfaces +{ + public partial interface IAgentMessageHandler + { + ValueTask HandleAsync(TSender sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage; + } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Messages/Application/Application.cs b/src/Agent/Insight.Agent.Assets/Messages/Application/Application.cs new file mode 100644 index 0000000..ba3ad5c --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Messages/Application/Application.cs @@ -0,0 +1,41 @@ +using MemoryPack; +using System.Runtime.InteropServices; + +namespace Insight.Agent.Messages +{ + [MemoryPackUnion(120, typeof(Application))] + [MemoryPackUnion(121, typeof(ApplicationList))] + public partial interface IAgentMessage { } + + [MemoryPackable] + public partial class Application : IAgentMessage + { + [MemoryPackOrder(0)] + public string? Name { get; set; } + + [MemoryPackOrder(1)] + public string? Publisher { get; set; } + + [MemoryPackOrder(2)] + public string? Version { get; set; } + + [MemoryPackOrder(3)] + public string? Location { get; set; } + + [MemoryPackOrder(4)] + public string? Source { get; set; } + + [MemoryPackOrder(5)] + public string? Uninstall { get; set; } + + [MemoryPackOrder(6)] + public DateTime? InstallDate { get; set; } + + [MemoryPackOrder(7)] + public Architecture? Architecture { get; set; } + } + + [MemoryPackable(GenerateType.Collection)] + public partial class ApplicationList : List, IAgentMessage { } + +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Messages/Authentication/Authentication.cs b/src/Agent/Insight.Agent.Assets/Messages/Authentication/Authentication.cs new file mode 100644 index 0000000..84406f4 --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Messages/Authentication/Authentication.cs @@ -0,0 +1,34 @@ +using MemoryPack; + +namespace Insight.Agent.Messages +{ + [MemoryPackUnion(1, typeof(Authentication))] + [MemoryPackUnion(2, typeof(AuthenticationRequest))] + public partial interface IAgentMessage { } + + [MemoryPackable] + public partial class Authentication : IAgentMessage + { + [MemoryPackOrder(0)] + public PlatformType? Platform { get; set; } + + [MemoryPackOrder(1)] + public Guid Serial { get; set; } + + [MemoryPackOrder(2)] + public Version? Version { get; set; } + + [MemoryPackOrder(3)] + public string? Hostname { get; set; } + + public enum PlatformType + { + Unknown = 0, + Windows = 1, + Unix = 2 + } + } + + [MemoryPackable] + public partial class AuthenticationRequest : IAgentMessage { } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Messages/Commands/Commands.cs b/src/Agent/Insight.Agent.Assets/Messages/Commands/Commands.cs new file mode 100644 index 0000000..b231232 --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Messages/Commands/Commands.cs @@ -0,0 +1,10 @@ +using MemoryPack; + +namespace Insight.Agent.Messages +{ + [MemoryPackUnion(2000, typeof(GetInventory))] + public partial interface IAgentMessage { } + + [MemoryPackable] + public partial class GetInventory : IAgentMessage { } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Messages/Console/ConsoleQuery.cs b/src/Agent/Insight.Agent.Assets/Messages/Console/ConsoleQuery.cs new file mode 100644 index 0000000..369304c --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Messages/Console/ConsoleQuery.cs @@ -0,0 +1,49 @@ +using MemoryPack; + +namespace Insight.Agent.Messages +{ + [MemoryPackUnion(1000, typeof(ConsoleQuery))] + [MemoryPackUnion(1001, typeof(ConsoleQueryRequest))] + public partial interface IAgentMessage { } + + [MemoryPackable] + public partial class ConsoleQuery : IAgentMessage + { + [MemoryPackOrder(0)] + public string? Id { get; set; } + + [MemoryPackOrder(1)] + public string? HostId { get; set; } + + [MemoryPackOrder(2)] + public string? Query { get; set; } + + [MemoryPackOrder(3)] + public string? Data { get; set; } + + [MemoryPackOrder(4)] + public string? Errors { get; set; } + + [MemoryPackOrder(5)] + public bool IsString { get; set; } + + [MemoryPackOrder(6)] + public bool IsArray { get; set; } + + [MemoryPackOrder(7)] + public bool HadErrors { get; set; } + } + + [MemoryPackable] + public partial class ConsoleQueryRequest : IAgentMessage + { + [MemoryPackOrder(0)] + public string? Id { get; set; } + + [MemoryPackOrder(1)] + public string? HostId { get; set; } + + [MemoryPackOrder(2)] + public string? Query { get; set; } + } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Messages/Drive/Drive.cs b/src/Agent/Insight.Agent.Assets/Messages/Drive/Drive.cs new file mode 100644 index 0000000..5a2f966 --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Messages/Drive/Drive.cs @@ -0,0 +1,103 @@ +using MemoryPack; + +namespace Insight.Agent.Messages +{ + [MemoryPackUnion(50, typeof(Drive))] + [MemoryPackUnion(51, typeof(DriveList))] + public partial interface IAgentMessage { } + + [MemoryPackable] + public partial class Drive : IAgentMessage + { + [MemoryPackOrder(0)] + public uint? Index { get; set; } + + [MemoryPackOrder(1)] + public string? Id { get; set; } + + [MemoryPackOrder(2)] + public string? Name { get; set; } + + [MemoryPackOrder(3)] + public string? Manufacturer { get; set; } + + [MemoryPackOrder(4)] + public string? SerialNumber { get; set; } + + [MemoryPackOrder(5)] + public ulong? Size { get; set; } + + [MemoryPackOrder(6)] + public string? Status { get; set; } + + [MemoryPackOrder(7)] + public string? InterfaceType { get; set; } + + [MemoryPackOrder(8)] + public string? FirmwareRevision { get; set; } + + [MemoryPackOrder(9)] + public string? PNPDeviceID { get; set; } + + [MemoryPackOrder(10)] + public List? Volumes { get; set; } + } + + [MemoryPackable(GenerateType.Collection)] + public partial class DriveList : List, IAgentMessage { } + + [MemoryPackable] + public partial class Volume : IAgentMessage + { + [MemoryPackOrder(0)] + public uint? Index { get; set; } + + [MemoryPackOrder(1)] + public string? Id { get; set; } + + [MemoryPackOrder(2)] + public string? Name { get; set; } + + [MemoryPackOrder(3)] + public string? SerialNumber { get; set; } + + [MemoryPackOrder(4)] + public ulong? Size { get; set; } + + [MemoryPackOrder(5)] + public ulong? FreeSpace { get; set; } + + [MemoryPackOrder(6)] + public string? Type { get; set; } + + [MemoryPackOrder(7)] + public string? FileSystem { get; set; } + + [MemoryPackOrder(8)] + public bool? Compressed { get; set; } + + [MemoryPackOrder(9)] + public bool? Bootable { get; set; } + + [MemoryPackOrder(10)] + public bool? PrimaryPartition { get; set; } + + [MemoryPackOrder(11)] + public bool? BootPartition { get; set; } + + [MemoryPackOrder(12)] + public ulong? BlockSize { get; set; } + + [MemoryPackOrder(13)] + public ulong? NumberOfBlocks { get; set; } + + [MemoryPackOrder(14)] + public ulong? StartingOffset { get; set; } + + [MemoryPackOrder(15)] + public DriveType? DriveType { get; set; } + + [MemoryPackOrder(16)] + public string? ProviderName { get; set; } + } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Messages/Event/Event.cs b/src/Agent/Insight.Agent.Assets/Messages/Event/Event.cs new file mode 100644 index 0000000..edd3b61 --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Messages/Event/Event.cs @@ -0,0 +1,41 @@ +using MemoryPack; + +namespace Insight.Agent.Messages +{ + [MemoryPackUnion(10, typeof(Event))] + public partial interface IAgentMessage { } + + [MemoryPackable] + public partial class Event : IAgentMessage + { + [MemoryPackOrder(0)] + public DateTime? Timestamp { get; set; } + + [MemoryPackOrder(1)] + public StatusType? Status { get; set; } + + [MemoryPackOrder(2)] + public string? Source { get; set; } + + [MemoryPackOrder(3)] + public string? Category { get; set; } + + [MemoryPackOrder(4)] + public int? EventId { get; set; } + + [MemoryPackOrder(5)] + public string? Task { get; set; } + + [MemoryPackOrder(6)] + public string? Message { get; set; } + + public enum StatusType + { + Unknown = 0, + Information = 1, + Warning = 2, + Error = 3, + Critical = 4 + } + } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Messages/IAgentMessage.cs b/src/Agent/Insight.Agent.Assets/Messages/IAgentMessage.cs new file mode 100644 index 0000000..3c3edf0 --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Messages/IAgentMessage.cs @@ -0,0 +1,7 @@ +using MemoryPack; + +namespace Insight.Agent.Messages +{ + [MemoryPackable] + public partial interface IAgentMessage { } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Messages/Interface/Interface.cs b/src/Agent/Insight.Agent.Assets/Messages/Interface/Interface.cs new file mode 100644 index 0000000..1c008c5 --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Messages/Interface/Interface.cs @@ -0,0 +1,195 @@ +using MemoryPack; +using System.Net; +using System.Net.NetworkInformation; +using System.Net.Sockets; + +namespace Insight.Agent.Messages +{ + [MemoryPackUnion(70, typeof(Interface))] + [MemoryPackUnion(71, typeof(InterfaceList))] + public partial interface IAgentMessage { } + + [MemoryPackable] + public partial class Interface : IAgentMessage + { + [MemoryPackOrder(0)] + public uint? Index { get; set; } + + [MemoryPackOrder(1)] + public Guid? Guid { get; set; } + + [MemoryPackOrder(2)] + public string? Mac { get; set; } + + [MemoryPackOrder(3)] + public string? Name { get; set; } + + [MemoryPackOrder(4)] + public string? Description { get; set; } + + [MemoryPackOrder(5)] + public string? Manufacturer { get; set; } + + [MemoryPackOrder(6)] + public string? Suffix { get; set; } + + [MemoryPackOrder(7)] + public bool? Physical { get; set; } + + [MemoryPackOrder(8)] + public NetworkInterfaceType? Type { get; set; } + + [MemoryPackOrder(9)] + public OperationalStatus? Status { get; set; } + + [MemoryPackOrder(10)] + public long? Speed { get; set; } + + [MemoryPackOrder(11)] + public long? Ipv4Mtu { get; set; } + + [MemoryPackOrder(12)] + public bool? Ipv4Dhcp { get; set; } + + [MemoryPackOrder(13)] + public bool? Ipv4Forwarding { get; set; } + + [MemoryPackOrder(14)] + public long? Ipv6Mtu { get; set; } + + [MemoryPackOrder(15)] + public long? Sent { get; set; } + + [MemoryPackOrder(16)] + public long? Received { get; set; } + + [MemoryPackOrder(17)] + public long? IncomingPacketsDiscarded { get; set; } + + [MemoryPackOrder(18)] + public long? IncomingPacketsWithErrors { get; set; } + + [MemoryPackOrder(19)] + public long? IncomingUnknownProtocolPackets { get; set; } + + [MemoryPackOrder(20)] + public long? OutgoingPacketsDiscarded { get; set; } + + [MemoryPackOrder(21)] + public long? OutgoingPacketsWithErrors { get; set; } + + [MemoryPackOrder(22)] + public List? Addresses { get; set; } + + [MemoryPackOrder(23)] + public List? Gateways { get; set; } + + [MemoryPackOrder(24)] + public List? Dns { get; set; } + + [MemoryPackOrder(25)] + public List? Dhcp { get; set; } + + [MemoryPackOrder(26)] + public List? Routes { get; set; } + } + + [MemoryPackable(GenerateType.Collection)] + public partial class InterfaceList : List, IAgentMessage { } + + [MemoryPackable] + public partial class Unicast : IAgentMessage + { + [MemoryPackOrder(0)] + public IPAddress2? IpAddress { get; set; } + + [MemoryPackOrder(1)] + public IPAddress2? Ipv4Mask { get; set; } + + [MemoryPackOrder(2)] + public long? AddressPreferredLifetime { get; set; } + + [MemoryPackOrder(3)] + public long? AddressValidLifetime { get; set; } + + [MemoryPackOrder(4)] + public long? DhcpLeaseLifetime { get; set; } + + [MemoryPackOrder(5)] + public DuplicateAddressDetectionState? DuplicateAddressDetectionState { get; set; } + + [MemoryPackOrder(6)] + public int? PrefixLength { get; set; } + + [MemoryPackOrder(7)] + public PrefixOrigin? PrefixOrigin { get; set; } + + [MemoryPackOrder(8)] + public SuffixOrigin? SuffixOrigin { get; set; } + } + + [MemoryPackable] + public partial class Route : IAgentMessage + { + [MemoryPackOrder(0)] + public uint? InterfaceIndex { get; set; } + + [MemoryPackOrder(1)] + public IPAddress2? Destination { get; set; } + + [MemoryPackOrder(2)] + public IPAddress2? Gateway { get; set; } + + [MemoryPackOrder(3)] + public string? Mask { get; set; } + + [MemoryPackOrder(4)] + public int? Metric { get; set; } + } + + [MemoryPackable] + public partial class IPAddress2 : IAgentMessage + { + [MemoryPackOrder(0)] + public AddressFamily? AddressFamily { get; set; } + + [MemoryPackOrder(1)] + public string? Address { get; set; } + + [MemoryPackOrder(2)] + public bool? IsIPv6Teredo { get; set; } + + [MemoryPackOrder(3)] + public bool? IsIPv6SiteLocal { get; set; } + + [MemoryPackOrder(4)] + public bool? IsIPv6Multicast { get; set; } + + [MemoryPackOrder(5)] + public bool? IsIPv6LinkLocal { get; set; } + + [MemoryPackOrder(6)] + public bool? IsIPv4MappedToIPv6 { get; set; } + + [MemoryPackOrder(7)] + public bool? IsIPv6UniqueLocal { get; set; } + + [MemoryPackConstructor] + public IPAddress2() + { + + } + + public IPAddress2(IPAddress address) + { + AddressFamily = address.AddressFamily; + Address = address.ToString(); + IsIPv4MappedToIPv6 = address.IsIPv4MappedToIPv6; + IsIPv6LinkLocal = address.IsIPv6LinkLocal; + IsIPv6Multicast = address.IsIPv6Multicast; + IsIPv6SiteLocal = address.IsIPv6SiteLocal; + IsIPv6Teredo = address.IsIPv6Teredo; + IsIPv6UniqueLocal = address.IsIPv6UniqueLocal; + } + } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Messages/Keepalive/Keepalive.cs b/src/Agent/Insight.Agent.Assets/Messages/Keepalive/Keepalive.cs new file mode 100644 index 0000000..63588dc --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Messages/Keepalive/Keepalive.cs @@ -0,0 +1,10 @@ +using MemoryPack; + +namespace Insight.Agent.Messages +{ + [MemoryPackUnion(0, typeof(Keepalive))] + public partial interface IAgentMessage { } + + [MemoryPackable] + public partial class Keepalive : IAgentMessage { } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Messages/Mainboard/Mainboard.cs b/src/Agent/Insight.Agent.Assets/Messages/Mainboard/Mainboard.cs new file mode 100644 index 0000000..a86bc5b --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Messages/Mainboard/Mainboard.cs @@ -0,0 +1,29 @@ +using MemoryPack; + +namespace Insight.Agent.Messages +{ + [MemoryPackUnion(20, typeof(Mainboard))] + public partial interface IAgentMessage { } + + [MemoryPackable] + public partial class Mainboard : IAgentMessage + { + [MemoryPackOrder(0)] + public string? Manufacturer { get; set; } + + [MemoryPackOrder(1)] + public string? Model { get; set; } + + [MemoryPackOrder(2)] + public string? Serial { get; set; } + + [MemoryPackOrder(3)] + public string? BiosManufacturer { get; set; } + + [MemoryPackOrder(4)] + public string? BiosVersion { get; set; } + + [MemoryPackOrder(5)] + public DateTime? BiosDate { get; set; } + } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Messages/Memory/Memory.cs b/src/Agent/Insight.Agent.Assets/Messages/Memory/Memory.cs new file mode 100644 index 0000000..bb8e444 --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Messages/Memory/Memory.cs @@ -0,0 +1,67 @@ +using MemoryPack; + +namespace Insight.Agent.Messages +{ + [MemoryPackUnion(40, typeof(Memory))] + [MemoryPackUnion(41, typeof(MemoryList))] + public partial interface IAgentMessage { } + + [MemoryPackable] + public partial class Memory : IAgentMessage + { + [MemoryPackOrder(0)] + public uint? Index { get; set; } + + [MemoryPackOrder(1)] + public string? Tag { get; set; } + + [MemoryPackOrder(2)] + public string? Location { get; set; } + + [MemoryPackOrder(3)] + public string? Manufacturer { get; set; } + + [MemoryPackOrder(4)] + public string? Model { get; set; } + + [MemoryPackOrder(5)] + public string? Serial { get; set; } + + [MemoryPackOrder(6)] + public ulong? Capacity { get; set; } + + [MemoryPackOrder(7)] + public uint? Speed { get; set; } + + [MemoryPackOrder(8)] + public uint? Voltage { get; set; } + + [MemoryPackOrder(9)] + public uint? ConfiguredSpeed { get; set; } + + [MemoryPackOrder(10)] + public uint? ConfiguredVoltage { get; set; } + } + + [MemoryPackable(GenerateType.Collection)] + public partial class MemoryList : List, IAgentMessage { } + + [MemoryPackable] + public partial class MemoryMetric : IAgentMessage + { + [MemoryPackOrder(0)] + public DateTime? Timestamp { get; set; } + + [MemoryPackOrder(1)] + public float? MemoryAvailable { get; set; } + + [MemoryPackOrder(2)] + public float? MemoryAvailablePercentage { get; set; } + + [MemoryPackOrder(3)] + public float? MemoryUsed { get; set; } + + [MemoryPackOrder(4)] + public float? MemoryUsagePercentage { get; set; } + } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Messages/OperationSystem/OperationSystem.cs b/src/Agent/Insight.Agent.Assets/Messages/OperationSystem/OperationSystem.cs new file mode 100644 index 0000000..0fe4ee5 --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Messages/OperationSystem/OperationSystem.cs @@ -0,0 +1,30 @@ +using MemoryPack; +using System.Runtime.InteropServices; + +namespace Insight.Agent.Messages +{ + [MemoryPackUnion(90, typeof(OperationSystem))] + public partial interface IAgentMessage { } + + [MemoryPackable] + public partial class OperationSystem : IAgentMessage + { + [MemoryPackOrder(0)] + public string? Name { get; set; } + + [MemoryPackOrder(1)] + public string? Version { get; set; } + + [MemoryPackOrder(2)] + public string? SerialNumber { get; set; } + + [MemoryPackOrder(3)] + public Architecture? Architecture { get; set; } + + [MemoryPackOrder(4)] + public bool? Virtual { get; set; } + + [MemoryPackOrder(5)] + public DateTime? InstallDate { get; set; } + } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Messages/Printer/Printer.cs b/src/Agent/Insight.Agent.Assets/Messages/Printer/Printer.cs new file mode 100644 index 0000000..0478fc0 --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Messages/Printer/Printer.cs @@ -0,0 +1,30 @@ +using MemoryPack; + +namespace Insight.Agent.Messages +{ + [MemoryPackUnion(140, typeof(Printer))] + [MemoryPackUnion(141, typeof(PrinterList))] + public partial interface IAgentMessage { } + + [MemoryPackable] + public partial class Printer : IAgentMessage + { + [MemoryPackOrder(0)] + public string? Name { get; set; } + + [MemoryPackOrder(1)] + public string? Driver { get; set; } + + [MemoryPackOrder(2)] + public string? Port { get; set; } + + [MemoryPackOrder(3)] + public string? Location { get; set; } + + [MemoryPackOrder(4)] + public string? Comment { get; set; } + } + + [MemoryPackable(GenerateType.Collection)] + public partial class PrinterList : List, IAgentMessage { } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Messages/Processor/Processor.cs b/src/Agent/Insight.Agent.Assets/Messages/Processor/Processor.cs new file mode 100644 index 0000000..edd63af --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Messages/Processor/Processor.cs @@ -0,0 +1,70 @@ +using MemoryPack; + +namespace Insight.Agent.Messages +{ + [MemoryPackUnion(30, typeof(Processor))] + [MemoryPackUnion(31, typeof(ProcessorList))] + public partial interface IAgentMessage { } + + [MemoryPackable] + public partial class Processor : IAgentMessage + { + [MemoryPackOrder(0)] + public uint? Index { get; set; } + + [MemoryPackOrder(1)] + public string? Name { get; set; } + + [MemoryPackOrder(2)] + public string? Manufacturer { get; set; } + + [MemoryPackOrder(3)] + public string? SerialNumber { get; set; } + + [MemoryPackOrder(4)] + public string? Socket { get; set; } + + [MemoryPackOrder(5)] + public string? Version { get; set; } + + [MemoryPackOrder(6)] + public string? DeviceId { get; set; } + + [MemoryPackOrder(7)] + public uint? Cores { get; set; } + + [MemoryPackOrder(8)] + public uint? LogicalCores { get; set; } + + [MemoryPackOrder(9)] + public uint? CurrentSpeed { get; set; } + + [MemoryPackOrder(10)] + public uint? MaxSpeed { get; set; } + + [MemoryPackOrder(11)] + public uint? L1Size { get; set; } + + [MemoryPackOrder(12)] + public uint? L2Size { get; set; } + + [MemoryPackOrder(13)] + public uint? L3Size { get; set; } + + [MemoryPackOrder(14)] + public bool? Virtualization { get; set; } + } + + [MemoryPackable(GenerateType.Collection)] + public partial class ProcessorList : List, IAgentMessage { } + + [MemoryPackable] + public partial class ProcessorMetric : IAgentMessage + { + [MemoryPackOrder(0)] + public DateTime? Timestamp { get; set; } + + [MemoryPackOrder(1)] + public float? ProcessorUsagePercentage { get; set; } + } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Messages/Service/Service.cs b/src/Agent/Insight.Agent.Assets/Messages/Service/Service.cs new file mode 100644 index 0000000..61aa86d --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Messages/Service/Service.cs @@ -0,0 +1,64 @@ +using MemoryPack; + +namespace Insight.Agent.Messages +{ + [MemoryPackUnion(130, typeof(Service))] + [MemoryPackUnion(131, typeof(ServiceList))] + public partial interface IAgentMessage { } + + [MemoryPackable] + public partial class Service : IAgentMessage + { + [MemoryPackOrder(0)] + public uint? ProcessId { get; set; } + + [MemoryPackOrder(1)] + public string? Name { get; set; } + + [MemoryPackOrder(2)] + public string? Display { get; set; } + + [MemoryPackOrder(3)] + public string? Description { get; set; } + + [MemoryPackOrder(4)] + public string? PathName { get; set; } + + [MemoryPackOrder(5)] + public string? Account { get; set; } + + [MemoryPackOrder(6)] + public bool? Delay { get; set; } + + [MemoryPackOrder(7)] + public ServiceStatus? Status { get; set; } + + [MemoryPackOrder(8)] + public ServiceMode? StartMode { get; set; } + + public enum ServiceStatus + { + Unknown = -1, + Stopped = 1, + StartPending = 2, + StopPending = 3, + Running = 4, + ContinuePending = 5, + PausePending = 6, + Paused = 7 + } + + public enum ServiceMode + { + Unknown = -1, + Boot = 0, + System = 1, + Automatic = 2, + Manual = 3, + Disabled = 4 + } + } + + [MemoryPackable(GenerateType.Collection)] + public partial class ServiceList : List, IAgentMessage { } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Messages/Session/Session.cs b/src/Agent/Insight.Agent.Assets/Messages/Session/Session.cs new file mode 100644 index 0000000..625c4ef --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Messages/Session/Session.cs @@ -0,0 +1,30 @@ +using MemoryPack; + +namespace Insight.Agent.Messages +{ + [MemoryPackUnion(110, typeof(Session))] + [MemoryPackUnion(111, typeof(SessionList))] + public partial interface IAgentMessage { } + + [MemoryPackable] + public partial class Session : IAgentMessage + { + [MemoryPackOrder(0)] + public string? Sid { get; set; } + + [MemoryPackOrder(1)] + public string? User { get; set; } + + [MemoryPackOrder(2)] + public string? Type { get; set; } + + [MemoryPackOrder(3)] + public string? Status { get; set; } + + [MemoryPackOrder(4)] + public string? Remote { get; set; } + } + + [MemoryPackable(GenerateType.Collection)] + public partial class SessionList : List, IAgentMessage { } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Messages/Status/Status.cs b/src/Agent/Insight.Agent.Assets/Messages/Status/Status.cs new file mode 100644 index 0000000..de31591 --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Messages/Status/Status.cs @@ -0,0 +1,17 @@ +using MemoryPack; + +namespace Insight.Agent.Messages +{ + [MemoryPackUnion(3, typeof(Status))] + public partial interface IAgentMessage { } + + [MemoryPackable] + public partial class Status : IAgentMessage + { + [MemoryPackOrder(0)] + public DateTime Timestamp { get; } = DateTime.Now; + + [MemoryPackOrder(1)] + public TimeSpan Uptime { get; set; } + } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Messages/StoragePool/StoragePool.cs b/src/Agent/Insight.Agent.Assets/Messages/StoragePool/StoragePool.cs new file mode 100644 index 0000000..6148979 --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Messages/StoragePool/StoragePool.cs @@ -0,0 +1,302 @@ +using MemoryPack; + +namespace Insight.Agent.Messages +{ + [MemoryPackUnion(160, typeof(StoragePool))] + [MemoryPackUnion(161, typeof(StoragePoolList))] + public partial interface IAgentMessage { } + + [MemoryPackable] + public partial class StoragePool : IAgentMessage + { + [MemoryPackOrder(0)] + public string? UniqueId { get; set; } + + [MemoryPackOrder(1)] + public string? Name { get; set; } + + [MemoryPackOrder(2)] + public string? FriendlyName { get; set; } + + [MemoryPackOrder(3)] + public List? States { get; set; } + + [MemoryPackOrder(4)] + public HealthState? Health { get; set; } + + [MemoryPackOrder(5)] + public RetireMissingPhysicalDisksEnum? RetireMissingPhysicalDisks { get; set; } + + [MemoryPackOrder(6)] + public string? Resiliency { get; set; } + + [MemoryPackOrder(7)] + public bool? IsPrimordial { get; set; } + + [MemoryPackOrder(8)] + public bool? IsReadOnly { get; set; } + + [MemoryPackOrder(9)] + public bool? IsClustered { get; set; } + + [MemoryPackOrder(10)] + public ulong? Size { get; set; } + + [MemoryPackOrder(11)] + public ulong? AllocatedSize { get; set; } + + [MemoryPackOrder(12)] + public ulong? SectorSize { get; set; } + + [MemoryPackOrder(13)] + public List? PhysicalDisks { get; set; } + + [MemoryPackOrder(14)] + public List? VirtualDisks { get; set; } + + public enum OperationalState + { + Unknown = 0, + Other = 1, + OK = 2, + Degraded = 3, + Stressed = 4, + Predictive_Failure = 5, + Error = 6, + Non_Recoverable_Error = 7, + Starting = 8, + Stopping = 9, + Stopped = 10, + In_Service = 11, + No_Contact = 12, + Lost_Communication = 13, + Aborted = 14, + Dormant = 15, + Supporting_Entity_In_Error = 16, + Completed = 17, + Power_Mode = 18, + Relocating = 19 + } + + public enum HealthState + { + Healthy = 0, + Warning = 1, + Unhealthy = 2, + Unknown = 3 + } + + public enum RetireMissingPhysicalDisksEnum + { + Auto = 1, + Always = 2, + Never = 3 + } + } + + [MemoryPackable(GenerateType.Collection)] + public partial class StoragePoolList : List, IAgentMessage { } + + [MemoryPackable] + public partial class PhysicalDisk : IAgentMessage + { + [MemoryPackOrder(0)] + public string? UniqueId { get; set; } + + [MemoryPackOrder(1)] + public string? DeviceId { get; set; } + + [MemoryPackOrder(2)] + public string? FriendlyName { get; set; } + + [MemoryPackOrder(3)] + public string? Manufacturer { get; set; } + + [MemoryPackOrder(4)] + public string? Model { get; set; } + + [MemoryPackOrder(5)] + public ushort? MediaType { get; set; } + + [MemoryPackOrder(6)] + public ushort? BusType { get; set; } + + [MemoryPackOrder(7)] + public List? States { get; set; } + + [MemoryPackOrder(8)] + public HealthState? Health { get; set; } + + [MemoryPackOrder(9)] + public List? SupportedUsages { get; set; } + + [MemoryPackOrder(10)] + public ushort? Usage { get; set; } + + [MemoryPackOrder(11)] + public string? PhysicalLocation { get; set; } + + [MemoryPackOrder(12)] + public string? SerialNumber { get; set; } + + [MemoryPackOrder(13)] + public string? FirmwareVersion { get; set; } + + [MemoryPackOrder(14)] + public ulong? Size { get; set; } + + [MemoryPackOrder(15)] + public ulong? AllocatedSize { get; set; } + + [MemoryPackOrder(16)] + public ulong? LogicalSectorSize { get; set; } + + [MemoryPackOrder(17)] + public ulong? PhysicalSectorSize { get; set; } + + [MemoryPackOrder(18)] + public ulong? VirtualDiskFootprint { get; set; } + + public enum OperationalState + { + Unknown = 0, + Other = 1, + OK = 2, + Degraded = 3, + Stressed = 4, + Predictive_Failure = 5, + Error = 6, + Non_Recoverable_Error = 7, + Starting = 8, + Stopping = 9, + Stopped = 10, + In_Service = 11, + No_Contact = 12, + Lost_Communication = 13, + Aborted = 14, + Dormant = 15, + Supporting_Entity_In_Error = 16, + Completed = 17, + Power_Mode = 18, + Relocating = 19 + } + + public enum HealthState + { + Healthy = 0, + Warning = 1, + Unhealthy = 2, + Unknown = 3 + } + + public enum SupportedUsagesEnum + { + Unknown = 0, + Auto_Select = 1, + Manual_Select = 2, + Hot_Spare = 3, + Retired = 4, + Journal = 5 + } + } + + [MemoryPackable] + public partial class VirtualDisk : IAgentMessage + { + [MemoryPackOrder(0)] + public string? UniqueId { get; set; } + + [MemoryPackOrder(1)] + public string? Name { get; set; } + + [MemoryPackOrder(2)] + public string? FriendlyName { get; set; } + + [MemoryPackOrder(3)] + public List? States { get; set; } + + [MemoryPackOrder(4)] + public HealthState? Health { get; set; } + + [MemoryPackOrder(5)] + public AccessTypeEnum? AccessType { get; set; } + + [MemoryPackOrder(6)] + public ProvisioningTypeEnum? ProvisioningType { get; set; } + + [MemoryPackOrder(7)] + public ushort? PhysicalDiskRedundancy { get; set; } + + [MemoryPackOrder(8)] + public string? ResiliencySettingName { get; set; } + + [MemoryPackOrder(9)] + public bool? Deduplication { get; set; } + + [MemoryPackOrder(10)] + public bool? IsSnapshot { get; set; } + + [MemoryPackOrder(11)] + public ulong? Size { get; set; } + + [MemoryPackOrder(12)] + public ulong? AllocatedSize { get; set; } + + [MemoryPackOrder(13)] + public ulong? FootprintOnPool { get; set; } + + [MemoryPackOrder(14)] + public ulong? ReadCacheSize { get; set; } + + [MemoryPackOrder(15)] + public ulong? WriteCacheSize { get; set; } + + public enum OperationalState + { + Unknown = 0, + Other = 1, + OK = 2, + Degraded = 3, + Stressed = 4, + Predictive_Failure = 5, + Error = 6, + Non_Recoverable_Error = 7, + Starting = 8, + Stopping = 9, + Stopped = 10, + In_Service = 11, + No_Contact = 12, + Lost_Communication = 13, + Aborted = 14, + Dormant = 15, + Supporting_Entity_In_Error = 16, + Completed = 17, + Power_Mode = 18, + Relocating = 19 + } + + public enum HealthState + { + Healthy = 0, + Warning = 1, + Unhealthy = 2, + Unknown = 3 + } + + public enum AccessTypeEnum + { + Unknown = 0, + Readable = 1, + Writeable = 2, + Read_Write = 3, + Write_Once = 4 + } + + public enum ProvisioningTypeEnum + { + Unknown = 0, + Thin = 1, + Fixed = 2 + } + } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Messages/SystemInfo/SystemInfo.cs b/src/Agent/Insight.Agent.Assets/Messages/SystemInfo/SystemInfo.cs new file mode 100644 index 0000000..8ec0441 --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Messages/SystemInfo/SystemInfo.cs @@ -0,0 +1,23 @@ +using MemoryPack; + +namespace Insight.Agent.Messages +{ + [MemoryPackUnion(80, typeof(SystemInfo))] + public partial interface IAgentMessage { } + + [MemoryPackable] + public partial class SystemInfo : IAgentMessage + { + [MemoryPackOrder(0)] + public DateTime? LastBootUpTime { get; set; } + + [MemoryPackOrder(1)] + public DateTime? LocalDateTime { get; set; } + + [MemoryPackOrder(2)] + public uint? Processes { get; set; } + + [MemoryPackOrder(3)] + public string? License { get; set; } + } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Messages/Trap/Trap.cs b/src/Agent/Insight.Agent.Assets/Messages/Trap/Trap.cs new file mode 100644 index 0000000..d0a66db --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Messages/Trap/Trap.cs @@ -0,0 +1,29 @@ +using MemoryPack; + +namespace Insight.Agent.Messages +{ + [MemoryPackUnion(11, typeof(Trap))] + public partial interface IAgentMessage { } + + [MemoryPackable] + public partial class Trap : IAgentMessage + { + [MemoryPackOrder(0)] + public DateTime? Timestamp { get; set; } + + [MemoryPackOrder(1)] + public string? Endpoint { get; set; } + + [MemoryPackOrder(2)] + public string? Hostname { get; set; } + + [MemoryPackOrder(3)] + public string? Version { get; set; } + + [MemoryPackOrder(4)] + public string? Community { get; set; } + + [MemoryPackOrder(5)] + public List>? Data { get; set; } + } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Messages/Update/Update.cs b/src/Agent/Insight.Agent.Assets/Messages/Update/Update.cs new file mode 100644 index 0000000..ecc84c1 --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Messages/Update/Update.cs @@ -0,0 +1,83 @@ +using MemoryPack; + +namespace Insight.Agent.Messages +{ + [MemoryPackUnion(100, typeof(Update))] + [MemoryPackUnion(101, typeof(UpdateList))] + public partial interface IAgentMessage { } + + [MemoryPackable] + public partial class Update : IAgentMessage + { + [MemoryPackOrder(0)] + public string? Id { get; set; } + + [MemoryPackOrder(1)] + public DateTime? Date { get; set; } + + [MemoryPackOrder(2)] + public string? Name { get; set; } + + [MemoryPackOrder(3)] + public string? Description { get; set; } + + [MemoryPackOrder(4)] + public string? SupportUrl { get; set; } + + [MemoryPackOrder(5)] + public string? Hotfix { get; set; } + + // if installed + [MemoryPackOrder(6)] + public OsUpdateResultCodeEnum? Result { get; set; } + + // if pending + [MemoryPackOrder(7)] + public OsUpdateTypeEnum? Type { get; set; } + + [MemoryPackOrder(8)] + public decimal? Size { get; set; } + + [MemoryPackOrder(9)] + public bool? IsDownloaded { get; set; } + + [MemoryPackOrder(10)] + public bool? CanRequestUserInput { get; set; } + + [MemoryPackOrder(11)] + public OsUpdateRebootBehaviorEnum? RebootBehavior { get; set; } + + public enum OsUpdateRebootBehaviorEnum + { + NeverReboots = 1, + AlwaysRequiresReboot = 2, + CanRequestReboot = 3 + } + + public enum OsUpdateResultCodeEnum + { + NotStarted = 1, + InProgress = 2, + Succeeded = 3, + SucceededWithErrors = 4, + Failed = 5, + Aborted = 6 + } + + public enum OsUpdateTypeEnum + { + Software = 1, + Driver = 2 + } + } + + [MemoryPackable] + public partial class UpdateList : IAgentMessage + { + [MemoryPackOrder(0)] + public List? Installed { get; set; } + + [MemoryPackOrder(1)] + public List? Pending { get; set; } + } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Messages/User/User.cs b/src/Agent/Insight.Agent.Assets/Messages/User/User.cs new file mode 100644 index 0000000..968c4bb --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Messages/User/User.cs @@ -0,0 +1,73 @@ +using MemoryPack; + +namespace Insight.Agent.Messages +{ + [MemoryPackUnion(150, typeof(User))] + [MemoryPackUnion(151, typeof(UserList))] + public partial interface IAgentMessage { } + + [MemoryPackable] + public partial class User : IAgentMessage + { + [MemoryPackOrder(0)] + public string? Sid { get; set; } + + [MemoryPackOrder(1)] + public string? Domain { get; set; } + + [MemoryPackOrder(2)] + public string? Name { get; set; } + + [MemoryPackOrder(3)] + public string? FullName { get; set; } + + [MemoryPackOrder(4)] + public string? Description { get; set; } + + [MemoryPackOrder(5)] + public string? Status { get; set; } + + [MemoryPackOrder(6)] + public bool? LocalAccount { get; set; } + + [MemoryPackOrder(7)] + public bool? Disabled { get; set; } + + [MemoryPackOrder(8)] + public bool? Lockout { get; set; } + + [MemoryPackOrder(9)] + public bool? PasswordChangeable { get; set; } + + [MemoryPackOrder(10)] + public bool? PasswordExpires { get; set; } + + [MemoryPackOrder(11)] + public bool? PasswordRequired { get; set; } + + [MemoryPackOrder(12)] + public List? Groups { get; set; } + } + + [MemoryPackable(GenerateType.Collection)] + public partial class UserList : List, IAgentMessage { } + + [MemoryPackable] + public partial class Group : IAgentMessage + { + [MemoryPackOrder(0)] + public string? Sid { get; set; } + + [MemoryPackOrder(1)] + public string? Domain { get; set; } + + [MemoryPackOrder(2)] + public string? Name { get; set; } + + [MemoryPackOrder(3)] + public string? Description { get; set; } + + [MemoryPackOrder(4)] + public bool? LocalAccount { get; set; } + } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Messages/Videocard/Videocard.cs b/src/Agent/Insight.Agent.Assets/Messages/Videocard/Videocard.cs new file mode 100644 index 0000000..151d441 --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Messages/Videocard/Videocard.cs @@ -0,0 +1,30 @@ +using MemoryPack; + +namespace Insight.Agent.Messages +{ + [MemoryPackUnion(60, typeof(Videocard))] + [MemoryPackUnion(61, typeof(VideocardList))] + public partial interface IAgentMessage { } + + [MemoryPackable] + public partial class Videocard : IAgentMessage + { + [MemoryPackOrder(0)] + public string? DeviceId { get; set; } + + [MemoryPackOrder(1)] + public string? Model { get; set; } + + [MemoryPackOrder(2)] + public ulong Memory { get; set; } + + [MemoryPackOrder(3)] + public DateTime DriverDate { get; set; } + + [MemoryPackOrder(4)] + public string? DriverVersion { get; set; } + } + + [MemoryPackable(GenerateType.Collection)] + public partial class VideocardList : List, IAgentMessage { } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Messages/VirtualMaschine/VirtualMaschine.cs b/src/Agent/Insight.Agent.Assets/Messages/VirtualMaschine/VirtualMaschine.cs new file mode 100644 index 0000000..a91dc44 --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Messages/VirtualMaschine/VirtualMaschine.cs @@ -0,0 +1,265 @@ +using MemoryPack; + +namespace Insight.Agent.Messages +{ + [MemoryPackUnion(170, typeof(VirtualMaschine))] + [MemoryPackUnion(171, typeof(VirtualMaschineList))] + public partial interface IAgentMessage { } + + [MemoryPackable] + public partial class VirtualMaschine : IAgentMessage + { + [MemoryPackOrder(0)] + public Guid? Id { get; set; } + + [MemoryPackOrder(1)] + public uint? ProcessId { get; set; } + + [MemoryPackOrder(2)] + public string? Caption { get; set; } + + [MemoryPackOrder(3)] + public string? Name { get; set; } + + [MemoryPackOrder(4)] + public string? Notes { get; set; } + + [MemoryPackOrder(5)] + public EnabledEnum? Enabled { get; set; } + + [MemoryPackOrder(6)] + public EnabledDefaultEnum? EnabledDefault { get; set; } + + [MemoryPackOrder(7)] + public HealthStatusEnum? HealthState { get; set; } + + [MemoryPackOrder(8)] + public string? Status { get; set; } + + [MemoryPackOrder(9)] + public ulong? OnTime { get; set; } + + [MemoryPackOrder(10)] + public uint? ReplicationMode { get; set; } + + [MemoryPackOrder(11)] + public ReplicationStateEnum? ReplicationState { get; set; } + + [MemoryPackOrder(12)] + public ReplicationHealthEnum? ReplicationHealth { get; set; } + + [MemoryPackOrder(13)] + public string? ConfigurationVersion { get; set; } + + [MemoryPackOrder(14)] + public IntegrationServicesVersionStateEnum? IntegrationServicesVersionState { get; set; } + + [MemoryPackOrder(15)] + public uint? NumberOfProcessors { get; set; } + + [MemoryPackOrder(16)] + public uint? ProcessorLoad { get; set; } + + [MemoryPackOrder(17)] + public int? MemoryAvailable { get; set; } + + [MemoryPackOrder(18)] + public ulong? MemoryUsage { get; set; } + + [MemoryPackOrder(19)] + public DateTime? InstallDate { get; set; } + + [MemoryPackOrder(20)] + public DateTime? TimeOfLastConfigurationChange { get; set; } + + [MemoryPackOrder(21)] + public DateTime? TimeOfLastStateChange { get; set; } + + [MemoryPackOrder(22)] + public DateTime? LastReplicationTime { get; set; } + + [MemoryPackOrder(23)] + public string? GuestOperatingSystem { get; set; } + + [MemoryPackOrder(24)] + public List? Configurations { get; set; } + + public enum EnabledEnum + { + Unbekannt = 0, + Andere = 1, + Aktiviert = 2, + Deaktiviert = 3, + Herunterfahren = 4, + Nicht_Verfügbar = 5, + Aktiviert_Offline = 6, + In_Test = 7, + Latent = 8, + Eingeschränkt = 9, + Wird_gestartet = 10 + } + + public enum EnabledDefaultEnum + { + Aktiviert = 2, + Deaktiviert = 3, + Aktiviert_Offline = 6 + } + + public enum HealthStatusEnum + { + OK = 5, + Hauptfehler = 20, + Kritischer_Fehler = 25 + } + + public enum ReplicationStateEnum + { + Deaktiviert = 0, + Bereit = 1, + Warten_auf_Erstreplikation = 2, + Replikat = 3, + Synchronisierte_Replication_abgeschlossen = 4, + Wiederhergestellt = 5, + Commit = 6, + Angehalten = 7, + Kritisch = 8, + Warten_auf_die_Neusynchronisierung = 9, + Resynchronisierung = 10, + Resynchronisierung_angehalten = 11, + Failover_in_Bearbeitung = 12, + Failback_in_Fortschritt = 13, + Failback_abgeschlossen = 14, + Datenträgerupdate_in_Bearbeitung = 15, + Datenträgeraktualisierung_kritisch = 16, + Unbekannt = 17, + Repurpose_Replikation_in_Bearbeitung = 18, + Vorbereitet_für_die_Synchronisierungsreplikation = 19, + Vorbereitet_für_die_Umgekehrte_Replikation_der_Gruppe = 20, + Failover_in_Fortschritt = 21 + } + + public enum ReplicationHealthEnum + { + OK = 1, + Warnung = 2, + Kritisch = 3 + } + + public enum IntegrationServicesVersionStateEnum + { + Unknown = 0, + UpToDate = 1, + Mismatch = 2 + } + } + + [MemoryPackable(GenerateType.Collection)] + public partial class VirtualMaschineList : List, IAgentMessage { } + + [MemoryPackable] + public partial class VirtualMaschineConfiguration : IAgentMessage + { + [MemoryPackOrder(0)] + public string? Id { get; set; } + + [MemoryPackOrder(1)] + public string? ParentId { get; set; } + + [MemoryPackOrder(2)] + public string? Type { get; set; } + + [MemoryPackOrder(3)] + public string? Name { get; set; } + + [MemoryPackOrder(4)] + public DateTime? CreationTime { get; set; } + + [MemoryPackOrder(5)] + public string? Generation { get; set; } + + [MemoryPackOrder(6)] + public string? Architecture { get; set; } + + [MemoryPackOrder(7)] + public AutomaticStartupActionEnum? AutomaticStartupAction { get; set; } + //public DateTime? AutomaticStartupActionDelay { get; set; } + + [MemoryPackOrder(8)] + public AutomaticShutdownActionEnum? AutomaticShutdownAction { get; set; } + + [MemoryPackOrder(9)] + public AutomaticRecoveryActionEnum? AutomaticRecoveryAction { get; set; } + + [MemoryPackOrder(10)] + public bool? AutomaticSnapshotsEnabled { get; set; } + + [MemoryPackOrder(11)] + public string? BaseBoardSerialNumber { get; set; } + + [MemoryPackOrder(12)] + public string? BIOSGUID { get; set; } + + [MemoryPackOrder(13)] + public string? BIOSSerialNumber { get; set; } + + [MemoryPackOrder(14)] + public ushort[]? BootOrder { get; set; } + + [MemoryPackOrder(15)] + public string? ConfigurationDataRoot { get; set; } + + [MemoryPackOrder(16)] + public string? ConfigurationFile { get; set; } + + [MemoryPackOrder(17)] + public string? GuestStateDataRoot { get; set; } + + [MemoryPackOrder(18)] + public string? GuestStateFile { get; set; } + + [MemoryPackOrder(19)] + public string? SnapshotDataRoot { get; set; } + + [MemoryPackOrder(20)] + public string? SuspendDataRoot { get; set; } + + [MemoryPackOrder(21)] + public string? SwapFileDataRoot { get; set; } + + [MemoryPackOrder(22)] + public bool? SecureBootEnabled { get; set; } + + [MemoryPackOrder(23)] + public bool? IsAutomaticSnapshot { get; set; } + + [MemoryPackOrder(24)] + public string[]? Notes { get; set; } + + [MemoryPackOrder(25)] + public List? Childs { get; set; } + + //public string[]? HostResource { get; set; } + + public enum AutomaticStartupActionEnum + { + Nothing = 2, + RestartIfLastStateActive = 3, + Alway = 4 + } + + public enum AutomaticShutdownActionEnum + { + Ausschalten = 2, + Speichern = 3, + Herunterfahren = 4 + } + + public enum AutomaticRecoveryActionEnum + { + Keine = 2, + Neustart = 3, + Rollback = 4 + } + } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent.Assets/Models/Config.cs b/src/Agent/Insight.Agent.Assets/Models/Config.cs new file mode 100644 index 0000000..4be9391 --- /dev/null +++ b/src/Agent/Insight.Agent.Assets/Models/Config.cs @@ -0,0 +1,7 @@ +namespace Insight.Agent.Models +{ + public class Config + { + public Guid? Serial { get; set; } + } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Constants/Appsettings.cs b/src/Agent/Insight.Agent/Constants/Appsettings.cs index 074d6b8..9a45fe7 100644 --- a/src/Agent/Insight.Agent/Constants/Appsettings.cs +++ b/src/Agent/Insight.Agent/Constants/Appsettings.cs @@ -1,9 +1,10 @@ -namespace Insight.Agent; - -public static class Appsettings +namespace Insight.Agent { - public const string Api = "api"; - public const string ServerHost = "server.host"; - public const string ServerPort = "server.port"; - public const string TrapPort = "trap.port"; + public static class Appsettings + { + public const string Api = "api"; + public const string ServerHost = "server.host"; + public const string ServerPort = "server.port"; + public const string TrapPort = "trap.port"; + } } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Constants/Deploy.cs b/src/Agent/Insight.Agent/Constants/Deploy.cs index ded093c..35aa19b 100644 --- a/src/Agent/Insight.Agent/Constants/Deploy.cs +++ b/src/Agent/Insight.Agent/Constants/Deploy.cs @@ -1,20 +1,21 @@ -namespace Insight.Agent.Constants; - -public static class Deploy +namespace Insight.Agent.Constants { - public static class Updater + public static class Deploy { - public const string Name = "Updater"; - public const string ServiceName = "insight_updater"; - public const string Description = "Insight Updater"; + public static class Updater + { + public const string Name = "Updater"; + public const string ServiceName = "insight_updater"; + public const string Description = "Insight Updater"; + } + + public static DirectoryInfo GetAppDirectory(string appName) + => new($"{Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)}/Webmatic/Insight/{appName}"); + + public static FileInfo GetAppExecutable(string appName) + => new($"{GetAppDirectory(appName).FullName}/{appName.ToLower()}.exe"); + + public static Uri GetUpdateHref(Uri api, string appName) + => new($"{api.AbsoluteUri}/update/{appName.ToLower()}/windows"); } - - public static DirectoryInfo GetAppDirectory(string appName) - => new($"{Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)}/Webmatic/Insight/{appName}"); - - public static FileInfo GetAppExecutable(string appName) - => new($"{GetAppDirectory(appName).FullName}/{appName.ToLower()}.exe"); - - public static Uri GetUpdateHref(Uri api, string appName) - => new($"{api.AbsoluteUri}/update/{appName.ToLower()}/windows"); } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Extensions/Configuration.cs b/src/Agent/Insight.Agent/Extensions/Configuration.cs new file mode 100644 index 0000000..c5df5da --- /dev/null +++ b/src/Agent/Insight.Agent/Extensions/Configuration.cs @@ -0,0 +1,14 @@ +using Microsoft.Extensions.Configuration; + +namespace Insight.Agent.Extensions +{ + public static class ConfigurationExtensions + { + public static IConfigurationBuilder Defaults(this IConfigurationBuilder configuration) + { + configuration.Sources.Clear(); + configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true); + return configuration.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true, reloadOnChange: true); + } + } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Extensions/Linux.cs b/src/Agent/Insight.Agent/Extensions/Linux.cs new file mode 100644 index 0000000..da4f85a --- /dev/null +++ b/src/Agent/Insight.Agent/Extensions/Linux.cs @@ -0,0 +1,32 @@ +using System.Diagnostics; +using System.Runtime.Versioning; + +namespace Insight.Agent.Extensions +{ + public static class Linux + { + [SupportedOSPlatform("linux")] + public static string Bash(this string cmd) + { + var escaped = cmd.Replace("\"", "\\\""); + + using var proc = new Process() + { + StartInfo = new ProcessStartInfo + { + FileName = "/bin/bash", + Arguments = $"-c \"{escaped}\"", + RedirectStandardOutput = true, + UseShellExecute = false, + CreateNoWindow = true, + } + }; + + proc.Start(); + var result = proc.StandardOutput.ReadToEnd(); + proc.WaitForExit(); + + return result; + } + } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Extensions/ServiceExtensions.cs b/src/Agent/Insight.Agent/Extensions/ServiceExtensions.cs deleted file mode 100644 index a6d644e..0000000 --- a/src/Agent/Insight.Agent/Extensions/ServiceExtensions.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Insight.Agent.Network; -using Insight.Agent.Network.Handlers; -using Insight.Domain.Interfaces; -using Microsoft.Extensions.DependencyInjection; -using System.Runtime.Versioning; - -namespace Insight.Agent.Extensions; - -internal static class ServiceExtensions -{ - [SupportedOSPlatform("windows")] - internal static IServiceCollection InjectWindowsHandler(this IServiceCollection services) - { - services.AddSingleton, DriveHandler>(); - services.AddSingleton, InterfaceHandler>(); - services.AddSingleton, MainboardHandler>(); - services.AddSingleton, MemoryHandler>(); - services.AddSingleton, OperationSystemHandler>(); - services.AddSingleton, PrinterHandler>(); - services.AddSingleton, ProcessorHandler>(); - services.AddSingleton, ServiceHandler>(); - services.AddSingleton, SessionHandler>(); - services.AddSingleton, SoftwareHandler>(); - services.AddSingleton, StoragePoolHandler>(); - services.AddSingleton, SystemInfoHandler>(); - services.AddSingleton, UpdateHandler>(); - services.AddSingleton, UserHandler>(); - services.AddSingleton, VideocardHandler>(); - services.AddSingleton, VirtualMaschineHandler>(); - - return services; - } -} \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Insight.Agent.csproj b/src/Agent/Insight.Agent/Insight.Agent.csproj index becf45f..59caaa1 100644 --- a/src/Agent/Insight.Agent/Insight.Agent.csproj +++ b/src/Agent/Insight.Agent/Insight.Agent.csproj @@ -2,12 +2,13 @@ Exe - net8.0 + net7.0 latest Insight.Agent Insight agent - 2023.12.14.0 + 2025.2.24.0 + 2025.2.24.0 enable enable none @@ -15,7 +16,7 @@ - none + none @@ -23,17 +24,17 @@ - - - + + + - - - + + + - + diff --git a/src/Agent/Insight.Agent/Internal/Config.cs b/src/Agent/Insight.Agent/Internal/Config.cs deleted file mode 100644 index f79bdff..0000000 --- a/src/Agent/Insight.Agent/Internal/Config.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Insight.Agent; - -internal sealed class Config -{ - public Guid? Serial { get; set; } -} \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Internal/Extensions.cs b/src/Agent/Insight.Agent/Internal/Extensions.cs deleted file mode 100644 index a9380f8..0000000 --- a/src/Agent/Insight.Agent/Internal/Extensions.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System.Management; -using System.Runtime.Versioning; - -namespace Insight.Agent; - -public static class ManagmentExtensions -{ - [SupportedOSPlatform("windows")] - public static HashSet GetPropertyHashes(this ManagementBaseObject @object) - { - var properties = new HashSet(); - - foreach (var property in @object.Properties) - { - properties.Add(property.Name); - } - - return properties; - } - - [SupportedOSPlatform("windows")] - internal static bool TryGet(this ManagementObjectSearcher searcher, out ManagementObjectCollection collection) - { - collection = searcher.Get(); - - try - { - _ = collection.Count; - return true; - } - catch (ManagementException) - { - collection.Dispose(); - return false; - } - } - - [SupportedOSPlatform("windows")] - internal static T? GetValue(this ManagementObject @object, HashSet properties, string key) - { - if (@object is null || properties is null || key is null) return default; - if (properties.Contains(key, StringComparer.OrdinalIgnoreCase) is false) return default; - - if (@object[key] is not T obj) - { - return default; - } - - return obj; - } - - [SupportedOSPlatform("windows")] - internal static bool TryGetValue(this ManagementBaseObject @object, HashSet properties, string key, out T? value) - { - value = default; - - if (@object is null || properties is null || key is null) return default; - if (properties.Contains(key, StringComparer.OrdinalIgnoreCase) is false) return false; - - if (@object[key] is not T obj) - { - return false; - } - - value = obj; - return true; - } -} \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Internal/Helpers.cs b/src/Agent/Insight.Agent/Internal/Helpers.cs deleted file mode 100644 index e0a0a23..0000000 --- a/src/Agent/Insight.Agent/Internal/Helpers.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Runtime.Versioning; -using System.ServiceProcess; -using System.Text; - -namespace Insight.Agent; - -internal class Helpers -{ - internal static string? EscapeWql(string text) - { - if (text == null) return null; - - var sb = new StringBuilder(text.Length); - foreach (var c in text) - { - if (c == '\\' || c == '\'' || c == '"') - { - sb.Append('\\'); - } - sb.Append(c); - } - return sb.ToString(); - } - - [SupportedOSPlatform("windows")] - internal static bool ForceWinRmStart() - { - var winRm = ServiceController - .GetServices() - .First(x => x.ServiceName - .ToLower() - .Equals("winrm", StringComparison.Ordinal)); - - if (winRm.Status is not ServiceControllerStatus.Running) - { - winRm.Start(); - winRm.WaitForStatus(ServiceControllerStatus.Running); - } - - if (winRm.Status != ServiceControllerStatus.Running) return false; - return true; - } -} \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Internals/Extensions.cs b/src/Agent/Insight.Agent/Internals/Extensions.cs new file mode 100644 index 0000000..9699249 --- /dev/null +++ b/src/Agent/Insight.Agent/Internals/Extensions.cs @@ -0,0 +1,69 @@ +using System.Management; +using System.Runtime.Versioning; + +namespace Insight.Agent +{ + public static class ManagmentExtensions + { + [SupportedOSPlatform("windows")] + public static HashSet GetPropertyHashes(this ManagementBaseObject @object) + { + var properties = new HashSet(); + + foreach (var property in @object.Properties) + { + properties.Add(property.Name); + } + + return properties; + } + + [SupportedOSPlatform("windows")] + internal static bool TryGet(this ManagementObjectSearcher searcher, out ManagementObjectCollection collection) + { + collection = searcher.Get(); + + try + { + _ = collection.Count; + return true; + } + catch (ManagementException) + { + collection.Dispose(); + return false; + } + } + + [SupportedOSPlatform("windows")] + internal static T? GetValue(this ManagementObject @object, HashSet properties, string key) + { + if (@object is null || properties is null || key is null) return default; + if (properties.Contains(key, StringComparer.OrdinalIgnoreCase) is false) return default; + + if (@object[key] is not T obj) + { + return default; + } + + return obj; + } + + [SupportedOSPlatform("windows")] + internal static bool TryGetValue(this ManagementBaseObject @object, HashSet properties, string key, out T? value) + { + value = default; + + if (@object is null || properties is null || key is null) return default; + if (properties.Contains(key, StringComparer.OrdinalIgnoreCase) is false) return false; + + if (@object[key] is not T obj) + { + return false; + } + + value = obj; + return true; + } + } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Internals/Helpers.cs b/src/Agent/Insight.Agent/Internals/Helpers.cs new file mode 100644 index 0000000..93d7e62 --- /dev/null +++ b/src/Agent/Insight.Agent/Internals/Helpers.cs @@ -0,0 +1,44 @@ +using System.Runtime.Versioning; +using System.ServiceProcess; +using System.Text; + +namespace Insight.Agent +{ + internal class Helpers + { + internal static string? EscapeWql(string text) + { + if (text == null) return null; + + var sb = new StringBuilder(text.Length); + foreach (var c in text) + { + if (c == '\\' || c == '\'' || c == '"') + { + sb.Append('\\'); + } + sb.Append(c); + } + return sb.ToString(); + } + + [SupportedOSPlatform("windows")] + internal static bool ForceWinRmStart() + { + var winRm = ServiceController + .GetServices() + .First(x => x.ServiceName + .ToLower() + .Equals("winrm", StringComparison.Ordinal)); + + if (winRm.Status is not ServiceControllerStatus.Running) + { + winRm.Start(); + winRm.WaitForStatus(ServiceControllerStatus.Running); + } + + if (winRm.Status != ServiceControllerStatus.Running) return false; + return true; + } + } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Network/AgentSession.cs b/src/Agent/Insight.Agent/Network/AgentSession.cs index 7e6ed26..4b17ea0 100644 --- a/src/Agent/Insight.Agent/Network/AgentSession.cs +++ b/src/Agent/Insight.Agent/Network/AgentSession.cs @@ -1,49 +1,25 @@ -using Insight.Agent.Services; -using Insight.Domain.Constants; -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; using Microsoft.Extensions.Logging; +using System.Net.Sockets; using Vaitr.Network; namespace Insight.Agent.Network; -public class AgentSession(IEnumerable> handlers, ISerializer serializer, ILogger logger) - : TcpSession(serializer, logger) +public class AgentSession(IEnumerable> handlers, Socket socket, Stream stream, TcpConnectionOptions options, MemPackSerializer serializer, ILogger logger) + : TcpSession(socket, stream, options, serializer, logger) { - private readonly IEnumerable> _handlers = handlers; + private readonly IEnumerable> _handlers = handlers; - protected override ValueTask OnConnectedAsync(CancellationToken cancellationToken) - { - _logger.LogInformation("Agent ({ep?}) connected", RemoteEndPoint); - return default; - } - - protected override ValueTask OnDisconnectedAsync(CancellationToken cancellationToken) - { - _logger.LogInformation("Agent ({ep?}) disconnected", RemoteEndPoint); - return default; - } - - protected override ValueTask OnSentAsync(IPacketContext context, CancellationToken cancellationToken) - { - return base.OnSentAsync(context, cancellationToken); - } - - protected override async ValueTask OnReceivedAsync(IPacketContext context, CancellationToken cancellationToken) + protected override async ValueTask OnReceivedAsync(PacketContext context, CancellationToken cancellationToken) { await base.OnReceivedAsync(context, cancellationToken); - // catch authentication request - if (context.Packet is AuthenticationRequest) - await OnAuthenticationAsync(cancellationToken); - - // pass message to handlers foreach (var handler in _handlers) { try { - await handler.HandleAsync(this, context.Packet, cancellationToken); + await handler.HandleAsync(this, context.Data, cancellationToken); } catch (Exception ex) { @@ -51,37 +27,4 @@ public class AgentSession(IEnumerable> handlers, I } } } - - protected override ValueTask OnHeartbeatAsync(CancellationToken cancellationToken) - { - _logger.LogInformation("Agent ({ep?}) Heartbeat", RemoteEndPoint); - return default; - } - - private async ValueTask OnAuthenticationAsync(CancellationToken cancellationToken) - { - Config? config = null; - - try - { - config = await Configurator.ReadAsync(Configuration.DefaultConfig, cancellationToken).ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.LogError("Config ({config}) read error ({exception})", Configuration.DefaultConfig, ex); - } - - if (config is null) - { - config = new Config { Serial = Guid.NewGuid() }; - await Configurator.WriteAsync(config, Configuration.DefaultConfig, cancellationToken).ConfigureAwait(false); - } - - await SendAsync(new AuthenticationResponse - { - Serial = config.Serial ?? throw new InvalidDataException(nameof(config.Serial)), - Version = Configuration.Version, - Hostname = Configuration.Hostname - }, cancellationToken).ConfigureAwait(false); - } } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Network/Handlers/AuthenticationHandler.cs b/src/Agent/Insight.Agent/Network/Handlers/AuthenticationHandler.cs new file mode 100644 index 0000000..4247693 --- /dev/null +++ b/src/Agent/Insight.Agent/Network/Handlers/AuthenticationHandler.cs @@ -0,0 +1,38 @@ +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; +using Insight.Agent.Models; +using Insight.Agent.Services; +using Insight.Domain.Constants; + +namespace Insight.Agent.Network.Handlers +{ + public class AuthenticationHandler : IAgentMessageHandler + { + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage + { + if (message is AuthenticationRequest) + { + Config? config = null; + + try + { + config = await Configurator.ReadAsync(Configuration.DefaultConfig, cancellationToken).ConfigureAwait(false); + } + catch (Exception) { } + + if (config is null) + { + config = new Config { Serial = Guid.NewGuid() }; + await Configurator.WriteAsync(config, Configuration.DefaultConfig, cancellationToken).ConfigureAwait(false); + } + + await sender.SendAsync(new Authentication + { + Serial = config.Serial ?? throw new InvalidDataException(nameof(config.Serial)), + Version = Configuration.Version, + Hostname = Configuration.Hostname + }, cancellationToken); + } + } + } +} \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Services/ScriptService.cs b/src/Agent/Insight.Agent/Network/Handlers/ConsoleHandler.cs similarity index 64% rename from src/Agent/Insight.Agent/Services/ScriptService.cs rename to src/Agent/Insight.Agent/Network/Handlers/ConsoleHandler.cs index f77c3c4..267bb5d 100644 --- a/src/Agent/Insight.Agent/Services/ScriptService.cs +++ b/src/Agent/Insight.Agent/Network/Handlers/ConsoleHandler.cs @@ -1,17 +1,37 @@ -using Microsoft.Extensions.Logging; +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; using System.Management.Automation; using System.Management.Automation.Runspaces; -namespace Insight.Agent.Services; +namespace Insight.Agent.Network.Handlers; -public class ScriptService(ILogger logger) +public class ConsoleHandler : IAgentMessageHandler { - private readonly ILogger _logger = logger; - - public async Task QueryAsync(string query) + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage { - _logger.LogDebug("QueryAsync ({query})", query); + if (message is ConsoleQueryRequest consoleQueryRequest) + { + await OnConsoleQueryRequestAsync(sender, consoleQueryRequest, cancellationToken); + } + } + private async ValueTask OnConsoleQueryRequestAsync(AgentSession sender, ConsoleQueryRequest consoleQueryRequest, CancellationToken cancellationToken) + { + var result = await QueryScriptAsync(consoleQueryRequest.Query); + + await sender.SendAsync(new ConsoleQuery + { + Id = consoleQueryRequest.Id, + HostId = consoleQueryRequest.HostId, + Query = consoleQueryRequest.Query, + Data = result.Data, + Errors = result.Errors, + HadErrors = result.HadErrors + }, cancellationToken); + } + + private static async Task QueryScriptAsync(string query) + { var result = new QueryResult(); var errors = new List(); @@ -24,7 +44,7 @@ public class ScriptService(ILogger logger) using var ps = PowerShell.Create(runspace); ps.AddScript("Set-ExecutionPolicy unrestricted -Scope Process"); ps.AddScript(query); - //ps.AddCommand("ConvertTo-Json"); // -Depth 10 + ps.AddCommand("ConvertTo-Json"); // -Depth 10 result.Query = query; @@ -37,15 +57,7 @@ public class ScriptService(ILogger logger) } else { - var newLine = false; - - foreach (var data in queryResult) - { - if (newLine) result.Data += "\n"; - else newLine = true; - - result.Data += data.ToString(); - } + result.Data = queryResult[0].ToString(); //if (string.IsNullOrWhiteSpace(jsonString)) return result; @@ -88,12 +100,12 @@ public class ScriptService(ILogger logger) result.Errors = string.Join("\n", errors); return result; } +} - public class QueryResult - { - public bool HadErrors { get; set; } - public string? Query { get; set; } - public string? Data { get; set; } - public string? Errors { get; set; } - } +public class QueryResult +{ + public bool HadErrors { get; set; } + public string? Query { get; set; } + public string? Data { get; set; } + public string? Errors { get; set; } } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Network/Handlers/CustomHandler.cs b/src/Agent/Insight.Agent/Network/Handlers/CustomHandler.cs deleted file mode 100644 index 46e6a1a..0000000 --- a/src/Agent/Insight.Agent/Network/Handlers/CustomHandler.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Insight.Agent.Services; -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; - -namespace Insight.Agent.Network.Handlers; - -public class CustomHandler(ScriptService scriptService) : IMessageHandler -{ - private readonly ScriptService _scriptService = scriptService; - - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage - { - switch (message) - { - case Request request: - await OnRequestAsync(sender, request, cancellationToken); - break; - } - } - - private async ValueTask OnRequestAsync(AgentSession sender, Request request, CancellationToken cancellationToken) - { - if (request.RequestData is null) return; - var result = await _scriptService.QueryAsync(request.RequestData); - - await sender.SendAsync(new Response(request) - { - ResponseData = result.HadErrors ? result.Errors : result.Data, - ResponseError = result.HadErrors - }, cancellationToken); - } -} \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Network/Handlers/DriveHandler.cs b/src/Agent/Insight.Agent/Network/Handlers/DriveHandler.cs index 75b7670..13fafe8 100644 --- a/src/Agent/Insight.Agent/Network/Handlers/DriveHandler.cs +++ b/src/Agent/Insight.Agent/Network/Handlers/DriveHandler.cs @@ -1,182 +1,178 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; using System.Management; using System.Runtime.Versioning; -namespace Insight.Agent.Network.Handlers; - -[SupportedOSPlatform("windows")] -public class DriveHandler : IMessageHandler +namespace Insight.Agent.Network.Handlers { - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage + [SupportedOSPlatform("windows")] + public class DriveHandler : IAgentMessageHandler { - switch (message) + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage { - case InventoryRequest: - { - var result = new Collection(); - result.AddRange(GetDrives()); - - await sender.SendAsync(result, cancellationToken); - break; - } - } - } - - private static List GetDrives() - { - using var searcher = new ManagementObjectSearcher - { - Scope = new ManagementScope(@"root\cimv2"), - Query = new ObjectQuery("select index, name, caption, model, manufacturer, serialNumber, size, status, interfacetype, firmwarerevision, deviceid, pnpdeviceid from win32_diskdrive") - }; - - if (searcher.TryGet(out var collection) is false) - { - searcher.Query = new ObjectQuery("select * from win32_diskdrive"); - - if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); - } - - var drives = new List(); - - using (collection) - { - foreach (ManagementObject @object in collection.Cast()) + if (message is GetInventory) { - var drive = new Drive(); + var result = new DriveList(); + result.AddRange(GetDrives()); - var properties = @object.GetPropertyHashes(); - - drive.Index = @object.GetValue(properties, "index"); - drive.Id = @object.GetValue(properties, "deviceid")?.Trim(); - drive.Name = @object.GetValue(properties, "model")?.Trim(); - drive.Manufacturer = @object.GetValue(properties, "manufacturer")?.Trim(); - drive.SerialNumber = @object.GetValue(properties, "serialnumber")?.Trim(); - drive.Size = @object.GetValue(properties, "size"); - drive.Status = @object.GetValue(properties, "status")?.Trim(); - drive.InterfaceType = @object.GetValue(properties, "interfacetype")?.Trim(); - drive.FirmwareRevision = @object.GetValue(properties, "firmwarerevision")?.Trim(); - drive.PNPDeviceID = @object.GetValue(properties, "pnpdeviceid")?.Trim(); - drive.Volumes = []; - - var diskpartition = @object.GetRelated("win32_diskpartition"); - using (diskpartition) - { - foreach (ManagementObject dp in diskpartition.Cast()) - { - var volume = new Volume(); - var dpProperties = dp.GetPropertyHashes(); - - volume.NumberOfBlocks = dp.GetValue(dpProperties, "numberofblocks"); - volume.BootPartition = dp.GetValue(dpProperties, "bootpartition"); - volume.PrimaryPartition = dp.GetValue(dpProperties, "primarypartition"); - volume.Size = dp.GetValue(dpProperties, "size"); - volume.Index = dp.GetValue(dpProperties, "index"); - volume.Type = dp.GetValue(dpProperties, "type")?.Trim(); - volume.Bootable = dp.GetValue(dpProperties, "bootable"); - volume.BlockSize = dp.GetValue(dpProperties, "blocksize"); - volume.StartingOffset = dp.GetValue(dpProperties, "startingoffset"); - - var logicaldisk = dp.GetRelated("win32_logicaldisk"); - using (logicaldisk) - { - foreach (ManagementObject ld in logicaldisk.Cast()) - { - var ldProperties = ld.GetPropertyHashes(); - - volume.Id = ld.GetValue(ldProperties, "deviceid")?.Trim(); - volume.Name = ld.GetValue(ldProperties, "volumename")?.Trim(); - volume.SerialNumber = ld.GetValue(ldProperties, "volumeserialnumber")?.Trim(); - volume.DriveType = (DriveType)ld.GetValue(ldProperties, "drivetype"); - volume.FileSystem = ld.GetValue(ldProperties, "filesystem")?.Trim(); - volume.Compressed = ld.GetValue(ldProperties, "compressed"); - volume.Size = ld.GetValue(ldProperties, "size"); - volume.FreeSpace = ld.GetValue(ldProperties, "freespace"); - volume.ProviderName = ld.GetValue(ldProperties, "providername")?.Trim(); - } - } - - drive.Volumes.Add(volume); - } - } - - drives.Add(drive); + await sender.SendAsync(result, cancellationToken); } } - return drives; - } - - private static List GetVolumes() - { - using var searcher = new ManagementObjectSearcher + private static List GetDrives() { - Scope = new ManagementScope(@"root\cimv2"), - Query = new ObjectQuery("select deviceid, volumename, volumeserialnumber, drivetype, filesystem, compressed, size, freeSpace, providername from win32_logicaldisk") - }; + using var searcher = new ManagementObjectSearcher + { + Scope = new ManagementScope(@"root\cimv2"), + Query = new ObjectQuery("select index, name, caption, model, manufacturer, serialNumber, size, status, interfacetype, firmwarerevision, deviceid, pnpdeviceid from win32_diskdrive") + }; - // per device query - // "ASSOCIATORS OF {Win32_DiskDrive.DeviceID='" + driveDeviceId + "'} WHERE AssocClass=Win32_DiskDriveToDiskPartition" + if (searcher.TryGet(out var collection) is false) + { + searcher.Query = new ObjectQuery("select * from win32_diskdrive"); - if (searcher.TryGet(out var collection) is false) - { - searcher.Query = new ObjectQuery("select * from win32_logicaldisk"); + if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); + } - if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); + var drives = new List(); + + using (collection) + { + foreach (ManagementObject @object in collection.Cast()) + { + var drive = new Drive(); + + var properties = @object.GetPropertyHashes(); + + drive.Index = @object.GetValue(properties, "index"); + drive.Id = @object.GetValue(properties, "deviceid")?.Trim(); + drive.Name = @object.GetValue(properties, "model")?.Trim(); + drive.Manufacturer = @object.GetValue(properties, "manufacturer")?.Trim(); + drive.SerialNumber = @object.GetValue(properties, "serialnumber")?.Trim(); + drive.Size = @object.GetValue(properties, "size"); + drive.Status = @object.GetValue(properties, "status")?.Trim(); + drive.InterfaceType = @object.GetValue(properties, "interfacetype")?.Trim(); + drive.FirmwareRevision = @object.GetValue(properties, "firmwarerevision")?.Trim(); + drive.PNPDeviceID = @object.GetValue(properties, "pnpdeviceid")?.Trim(); + drive.Volumes = new List(); + + var diskpartition = @object.GetRelated("win32_diskpartition"); + using (diskpartition) + { + foreach (ManagementObject dp in diskpartition.Cast()) + { + var volume = new Volume(); + var dpProperties = dp.GetPropertyHashes(); + + volume.NumberOfBlocks = dp.GetValue(dpProperties, "numberofblocks"); + volume.BootPartition = dp.GetValue(dpProperties, "bootpartition"); + volume.PrimaryPartition = dp.GetValue(dpProperties, "primarypartition"); + volume.Size = dp.GetValue(dpProperties, "size"); + volume.Index = dp.GetValue(dpProperties, "index"); + volume.Type = dp.GetValue(dpProperties, "type")?.Trim(); + volume.Bootable = dp.GetValue(dpProperties, "bootable"); + volume.BlockSize = dp.GetValue(dpProperties, "blocksize"); + volume.StartingOffset = dp.GetValue(dpProperties, "startingoffset"); + + var logicaldisk = dp.GetRelated("win32_logicaldisk"); + using (logicaldisk) + { + foreach (ManagementObject ld in logicaldisk.Cast()) + { + var ldProperties = ld.GetPropertyHashes(); + + volume.Id = ld.GetValue(ldProperties, "deviceid")?.Trim(); + volume.Name = ld.GetValue(ldProperties, "volumename")?.Trim(); + volume.SerialNumber = ld.GetValue(ldProperties, "volumeserialnumber")?.Trim(); + volume.DriveType = (DriveType)ld.GetValue(ldProperties, "drivetype"); + volume.FileSystem = ld.GetValue(ldProperties, "filesystem")?.Trim(); + volume.Compressed = ld.GetValue(ldProperties, "compressed"); + volume.Size = ld.GetValue(ldProperties, "size"); + volume.FreeSpace = ld.GetValue(ldProperties, "freespace"); + volume.ProviderName = ld.GetValue(ldProperties, "providername")?.Trim(); + } + } + + drive.Volumes.Add(volume); + } + } + + drives.Add(drive); + } + } + + return drives; } - var volumes = new List(); - - using (collection) + private static List GetVolumes() { - foreach (ManagementObject @object in collection.Cast()) + using var searcher = new ManagementObjectSearcher { - var volume = new Volume(); + Scope = new ManagementScope(@"root\cimv2"), + Query = new ObjectQuery("select deviceid, volumename, volumeserialnumber, drivetype, filesystem, compressed, size, freeSpace, providername from win32_logicaldisk") + }; - var properties = @object.GetPropertyHashes(); + // per device query + // "ASSOCIATORS OF {Win32_DiskDrive.DeviceID='" + driveDeviceId + "'} WHERE AssocClass=Win32_DiskDriveToDiskPartition" - //volume.DeviceId = @object.GetValue(properties, "deviceid")?.Trim(); - //volume.VolumeName = @object.GetValue(properties, "volumename")?.Trim(); - //volume.VolumeSerialNumber = @object.GetValue(properties, "volumeserialnumber")?.Trim(); - volume.DriveType = (DriveType)@object.GetValue(properties, "drivetype"); - volume.FileSystem = @object.GetValue(properties, "filesystem")?.Trim(); - volume.Compressed = @object.GetValue(properties, "compressed"); - volume.Size = @object.GetValue(properties, "size"); - volume.FreeSpace = @object.GetValue(properties, "freespace"); - volume.ProviderName = @object.GetValue(properties, "providername")?.Trim(); + if (searcher.TryGet(out var collection) is false) + { + searcher.Query = new ObjectQuery("select * from win32_logicaldisk"); - if (volume.Id is not null) + if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); + } + + var volumes = new List(); + + using (collection) + { + foreach (ManagementObject @object in collection.Cast()) { - searcher.Query = new ObjectQuery("associators of {win32_logicaldisk.deviceid='" + volume.Id + "'} where assocclass=win32_logicaldisktopartition"); + var volume = new Volume(); - if (searcher.TryGet(out var collection2)) + var properties = @object.GetPropertyHashes(); + + //volume.DeviceId = @object.GetValue(properties, "deviceid")?.Trim(); + //volume.VolumeName = @object.GetValue(properties, "volumename")?.Trim(); + //volume.VolumeSerialNumber = @object.GetValue(properties, "volumeserialnumber")?.Trim(); + volume.DriveType = (DriveType)@object.GetValue(properties, "drivetype"); + volume.FileSystem = @object.GetValue(properties, "filesystem")?.Trim(); + volume.Compressed = @object.GetValue(properties, "compressed"); + volume.Size = @object.GetValue(properties, "size"); + volume.FreeSpace = @object.GetValue(properties, "freespace"); + volume.ProviderName = @object.GetValue(properties, "providername")?.Trim(); + + if (volume.Id is not null) { - using (collection2) - { - foreach (ManagementObject @object2 in collection2.Cast()) - { - var properties2 = @object2.GetPropertyHashes(); + searcher.Query = new ObjectQuery("associators of {win32_logicaldisk.deviceid='" + volume.Id + "'} where assocclass=win32_logicaldisktopartition"); - volume.Index = @object2.GetValue(properties2, "index"); - //volume.DiskIndex = @object2.GetValue(properties2, "diskindex"); - volume.Type = @object2.GetValue(properties2, "type")?.Trim(); - volume.Bootable = @object2.GetValue(properties2, "bootable"); - volume.PrimaryPartition = @object2.GetValue(properties2, "primarypartition"); - volume.BootPartition = @object2.GetValue(properties2, "bootpartition"); - volume.BlockSize = @object2.GetValue(properties2, "blocksize"); - volume.NumberOfBlocks = @object2.GetValue(properties2, "numberofblocks"); - volume.StartingOffset = @object2.GetValue(properties2, "startingoffset"); + if (searcher.TryGet(out var collection2)) + { + using (collection2) + { + foreach (ManagementObject @object2 in collection2) + { + var properties2 = @object2.GetPropertyHashes(); + + volume.Index = @object2.GetValue(properties2, "index"); + //volume.DiskIndex = @object2.GetValue(properties2, "diskindex"); + volume.Type = @object2.GetValue(properties2, "type")?.Trim(); + volume.Bootable = @object2.GetValue(properties2, "bootable"); + volume.PrimaryPartition = @object2.GetValue(properties2, "primarypartition"); + volume.BootPartition = @object2.GetValue(properties2, "bootpartition"); + volume.BlockSize = @object2.GetValue(properties2, "blocksize"); + volume.NumberOfBlocks = @object2.GetValue(properties2, "numberofblocks"); + volume.StartingOffset = @object2.GetValue(properties2, "startingoffset"); + } } } } + + volumes.Add(volume); } - - volumes.Add(volume); } - } - return volumes; + return volumes; + } } } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Network/Handlers/InterfaceHandler.cs b/src/Agent/Insight.Agent/Network/Handlers/InterfaceHandler.cs index 92402ca..2d6e294 100644 --- a/src/Agent/Insight.Agent/Network/Handlers/InterfaceHandler.cs +++ b/src/Agent/Insight.Agent/Network/Handlers/InterfaceHandler.cs @@ -1,277 +1,274 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; using System.Management; using System.Net; using System.Net.NetworkInformation; using System.Runtime.InteropServices; using System.Runtime.Versioning; +using Route = Insight.Agent.Messages.Route; -namespace Insight.Agent.Network.Handlers; - -[SupportedOSPlatform("windows")] -public class InterfaceHandler : IMessageHandler +namespace Insight.Agent.Network.Handlers { - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage + [SupportedOSPlatform("windows")] + public class InterfaceHandler : IAgentMessageHandler { - switch (message) + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage { - case InventoryRequest: - { - var result = new Collection(); - if (GetInterfaces() is List interfaces) result.AddRange(interfaces); - - await sender.SendAsync(result, cancellationToken); - break; - } - } - } - - private static List? GetInterfaces() - { - if (NetworkInterface.GetIsNetworkAvailable() is false) return null; - if (NetworkInterface.GetAllNetworkInterfaces().Length == 0) return null; - - var interfaces = new List(); - - foreach (var ni in NetworkInterface.GetAllNetworkInterfaces()) - { - var ipProperties = ni.GetIPProperties(); - var ipStatistics = ni.GetIPStatistics(); - - var @interface = new Interface + if (message is GetInventory) { - Mac = ni.GetPhysicalAddress().ToString(), - Name = ni.Name, - Description = ni.Description, - Type = ni.NetworkInterfaceType, - Speed = ni.Speed, - Status = ni.OperationalStatus, - Suffix = ipProperties.DnsSuffix, - Sent = ipStatistics.BytesSent, - Received = ipStatistics.BytesReceived, - IncomingPacketsDiscarded = ipStatistics.IncomingPacketsDiscarded, - IncomingPacketsWithErrors = ipStatistics.IncomingPacketsWithErrors, - IncomingUnknownProtocolPackets = ipStatistics.IncomingUnknownProtocolPackets, - OutgoingPacketsDiscarded = ipStatistics.OutgoingPacketsDiscarded, - OutgoingPacketsWithErrors = ipStatistics.OutgoingPacketsWithErrors + var result = new InterfaceList(); + result.AddRange(GetInterfaces()); + + await sender.SendAsync(result, cancellationToken); + } + } + + private static List GetInterfaces() + { + if (NetworkInterface.GetIsNetworkAvailable() is false) return null; + if (NetworkInterface.GetAllNetworkInterfaces().Any() is false) return null; + + var interfaces = new List(); + + foreach (var ni in NetworkInterface.GetAllNetworkInterfaces()) + { + var ipProperties = ni.GetIPProperties(); + var ipStatistics = ni.GetIPStatistics(); + + var @interface = new Interface + { + Mac = ni.GetPhysicalAddress().ToString(), + Name = ni.Name, + Description = ni.Description, + Type = ni.NetworkInterfaceType, + Speed = ni.Speed, + Status = ni.OperationalStatus, + Suffix = ipProperties.DnsSuffix, + Sent = ipStatistics.BytesSent, + Received = ipStatistics.BytesReceived, + IncomingPacketsDiscarded = ipStatistics.IncomingPacketsDiscarded, + IncomingPacketsWithErrors = ipStatistics.IncomingPacketsWithErrors, + IncomingUnknownProtocolPackets = ipStatistics.IncomingUnknownProtocolPackets, + OutgoingPacketsDiscarded = ipStatistics.OutgoingPacketsDiscarded, + OutgoingPacketsWithErrors = ipStatistics.OutgoingPacketsWithErrors + }; + + try + { + var propertiesV4 = ipProperties.GetIPv4Properties(); + @interface.Index = uint.Parse(propertiesV4.Index.ToString()); + @interface.Ipv4Mtu = propertiesV4.Mtu; + @interface.Ipv4Dhcp = propertiesV4.IsDhcpEnabled; + @interface.Ipv4Forwarding = propertiesV4.IsForwardingEnabled; + } + catch (Exception) { } + + try + { + var propertiesV6 = ipProperties.GetIPv6Properties(); + @interface.Index = uint.Parse(propertiesV6.Index.ToString()); + @interface.Ipv6Mtu = propertiesV6.Mtu; + } + catch (Exception) { } + + @interface.Gateways = GetAddresses(ipProperties.GatewayAddresses); + @interface.Addresses = GetAddresses(ipProperties.UnicastAddresses); + @interface.Dns = GetAddresses(ipProperties.DnsAddresses); + @interface.Dhcp = GetAddresses(ipProperties.DhcpServerAddresses); + + if (@interface.Index.HasValue) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + using var searcher = new ManagementObjectSearcher + { + Scope = new ManagementScope(@"root\cimv2"), + Query = new ObjectQuery($"select interfaceindex, guid, physicaladapter, manufacturer from win32_networkadapter where interfaceindex = {@interface.Index}") + }; + + if (searcher.TryGet(out var collection) is false) + { + searcher.Query = new ObjectQuery($"select * from win32_networkadapter where interfaceindex = {@interface.Index}"); + + if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); + } + + using (collection) + { + foreach (ManagementObject @object in collection) + { + var properties = @object.GetPropertyHashes(); + + @interface.Manufacturer = @object.GetValue(properties, "manufacturer")?.Trim(); + @interface.Guid = @object.GetValue(properties, "guid"); + @interface.Physical = @object.GetValue(properties, "physicaladapter"); + + break; + } + } + + @interface.Routes = QueryInterfaceRoutes(@interface.Index.Value); + } + } + + interfaces.Add(@interface); + } + + return interfaces; + } + + private static List QueryInterfaceRoutes(uint interfaceIndex) + { + using var searcher = new ManagementObjectSearcher + { + Scope = new ManagementScope(@"root\standardcimv2"), + Query = new ObjectQuery($"select addressFamily, state, interfaceindex, routemetric, nexthop, destinationprefix from msft_netroute where interfaceindex = {interfaceIndex}") }; - try + if (searcher.TryGet(out var collection) is false) { - var propertiesV4 = ipProperties.GetIPv4Properties(); - @interface.Index = uint.Parse(propertiesV4.Index.ToString()); - @interface.Ipv4Mtu = propertiesV4.Mtu; - @interface.Ipv4Dhcp = propertiesV4.IsDhcpEnabled; - @interface.Ipv4Forwarding = propertiesV4.IsForwardingEnabled; + searcher.Query = new ObjectQuery($"select * from msft_netroute where interfaceindex = {interfaceIndex}"); + + if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); } - catch (Exception) { } - try + var routes = new List(); + + using (collection) { - var propertiesV6 = ipProperties.GetIPv6Properties(); - @interface.Index = uint.Parse(propertiesV6.Index.ToString()); - @interface.Ipv6Mtu = propertiesV6.Mtu; - } - catch (Exception) { } - - @interface.Gateways = GetAddresses(ipProperties.GatewayAddresses); - @interface.Addresses = GetAddresses(ipProperties.UnicastAddresses); - @interface.Dns = GetAddresses(ipProperties.DnsAddresses); - @interface.Dhcp = GetAddresses(ipProperties.DhcpServerAddresses); - - if (@interface.Index.HasValue) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + foreach (var @object in collection) { - using var searcher = new ManagementObjectSearcher + var route = new Route { - Scope = new ManagementScope(@"root\cimv2"), - Query = new ObjectQuery($"select interfaceindex, guid, physicaladapter, manufacturer from win32_networkadapter where interfaceindex = {@interface.Index}") + InterfaceIndex = interfaceIndex }; - if (searcher.TryGet(out var collection) is false) - { - searcher.Query = new ObjectQuery($"select * from win32_networkadapter where interfaceindex = {@interface.Index}"); + var properties = @object.GetPropertyHashes(); - if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); + if (@object.TryGetValue(properties, "routemetric", out var routemetric)) + { + if (int.TryParse(routemetric?.ToString(), out var metric)) route.Metric = metric; } - using (collection) + if (@object.TryGetValue(properties, "nexthop", out var nexthop)) { - foreach (ManagementObject @object in collection.Cast()) + if (IPAddress.TryParse(nexthop?.ToString(), out var gateway)) route.Gateway = new IPAddress2(gateway); + } + + if (@object.TryGetValue(properties, "destinationprefix", out var destinationprefix)) + { + var split = destinationprefix?.ToString()?.Split('/'); + var cidrData = split?[1]; + + if (IPAddress.TryParse(split?[0], out var destination)) + route.Destination = new IPAddress2(destination); + + if (int.TryParse(cidrData, out var cidr)) { - var properties = @object.GetPropertyHashes(); - - @interface.Manufacturer = @object.GetValue(properties, "manufacturer")?.Trim(); - @interface.Guid = @object.GetValue(properties, "guid"); - @interface.Physical = @object.GetValue(properties, "physicaladapter"); - - break; + var mask = ConvertCidr(cidr); + route.Mask = mask; } } - @interface.Routes = QueryInterfaceRoutes(@interface.Index.Value); + routes.Add(route); } } - interfaces.Add(@interface); + return routes; } - return interfaces; - } - - private static List QueryInterfaceRoutes(uint interfaceIndex) - { - using var searcher = new ManagementObjectSearcher + private static List GetAddresses(UnicastIPAddressInformationCollection unicastCollection) { - Scope = new ManagementScope(@"root\standardcimv2"), - Query = new ObjectQuery($"select addressFamily, state, interfaceindex, routemetric, nexthop, destinationprefix from msft_netroute where interfaceindex = {interfaceIndex}") - }; + var addresses = new List(); - if (searcher.TryGet(out var collection) is false) - { - searcher.Query = new ObjectQuery($"select * from msft_netroute where interfaceindex = {interfaceIndex}"); + if (unicastCollection.Any() is false) return addresses; - if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); - } - - var routes = new List(); - - using (collection) - { - foreach (var @object in collection) + foreach (var unicast in unicastCollection) { - var route = new Route + addresses.Add(new Unicast { - InterfaceIndex = interfaceIndex - }; - - var properties = @object.GetPropertyHashes(); - - if (@object.TryGetValue(properties, "routemetric", out var routemetric)) - { - if (int.TryParse(routemetric?.ToString(), out var metric)) route.Metric = metric; - } - - if (@object.TryGetValue(properties, "nexthop", out var nexthop)) - { - if (IPAddress.TryParse(nexthop?.ToString(), out var gateway)) route.Gateway = new IPAddress2(gateway); - } - - if (@object.TryGetValue(properties, "destinationprefix", out var destinationprefix)) - { - var split = destinationprefix?.ToString()?.Split('/'); - var cidrData = split?[1]; - - if (IPAddress.TryParse(split?[0], out var destination)) - route.Destination = new IPAddress2(destination); - - if (int.TryParse(cidrData, out var cidr)) - { - var mask = ConvertCidr(cidr); - route.Mask = mask; - } - } - - routes.Add(route); + IpAddress = new IPAddress2(unicast.Address), + AddressPreferredLifetime = unicast.AddressPreferredLifetime, + AddressValidLifetime = unicast.AddressValidLifetime, + DuplicateAddressDetectionState = unicast.DuplicateAddressDetectionState, + Ipv4Mask = new IPAddress2(unicast.IPv4Mask), + PrefixLength = unicast.PrefixLength, + PrefixOrigin = unicast.PrefixOrigin, + SuffixOrigin = unicast.SuffixOrigin, + DhcpLeaseLifetime = unicast.DhcpLeaseLifetime, + }); } + + return addresses; } - return routes; - } - - private static List GetAddresses(UnicastIPAddressInformationCollection unicastCollection) - { - var addresses = new List(); - - if (unicastCollection.Count == 0) return addresses; - - foreach (var unicast in unicastCollection) + private static List GetAddresses(IPAddressCollection addressCollection) { - addresses.Add(new Unicast + var addresses = new List(); + + if (addressCollection.Any() is false) return addresses; + + foreach (var address in addressCollection) { - IpAddress = new IPAddress2(unicast.Address), - AddressPreferredLifetime = unicast.AddressPreferredLifetime, - AddressValidLifetime = unicast.AddressValidLifetime, - DuplicateAddressDetectionState = unicast.DuplicateAddressDetectionState, - Ipv4Mask = new IPAddress2(unicast.IPv4Mask), - PrefixLength = unicast.PrefixLength, - PrefixOrigin = unicast.PrefixOrigin, - SuffixOrigin = unicast.SuffixOrigin, - DhcpLeaseLifetime = unicast.DhcpLeaseLifetime, - }); + addresses.Add(new IPAddress2(address)); + } + + return addresses; } - return addresses; - } - - private static List GetAddresses(IPAddressCollection addressCollection) - { - var addresses = new List(); - - if (addressCollection.Count == 0) return addresses; - - foreach (var address in addressCollection) + private static List GetAddresses(GatewayIPAddressInformationCollection addressCollection) { - addresses.Add(new IPAddress2(address)); + var addresses = new List(); + + if (addressCollection.Any() is false) return addresses; + + foreach (var address in addressCollection) + { + addresses.Add(new IPAddress2(address.Address)); + } + + return addresses; } - return addresses; - } - - private static List GetAddresses(GatewayIPAddressInformationCollection addressCollection) - { - var addresses = new List(); - - if (addressCollection.Count == 0) return addresses; - - foreach (var address in addressCollection) + private static string? ConvertCidr(int cidr) { - addresses.Add(new IPAddress2(address.Address)); + return cidr switch + { + 0 => "0.0.0.0", + 1 => "128.0.0.0", + 2 => "192.0.0.0", + 3 => "224.0.0.0", + 4 => "240.0.0.0", + 5 => "248.0.0.0", + 6 => "252.0.0.0", + 7 => "254.0.0.0", + 8 => "255.0.0.0", + 9 => "255.128.0.0", + 10 => "255.192.0.0", + 11 => "255.224.0.0", + 12 => "255.240.0.0", + 13 => "255.248.0.0", + 14 => "255.252.0.0", + 15 => "255.254.0.0", + 16 => "255.255.0.0", + 17 => "255.255.128.0", + 18 => "255.255.192.0", + 19 => "255.255.224.0", + 20 => "255.255.240.0", + 21 => "255.255.248.0", + 22 => "255.255.252.0", + 23 => "255.255.254.0", + 24 => "255.255.255.0", + 25 => "255.255.255.128", + 26 => "255.255.255.192", + 27 => "255.255.255.224", + 28 => "255.255.255.240", + 29 => "255.255.255.248", + 30 => "255.255.255.252", + 31 => "255.255.255.254", + 32 => "255.255.255.255", + _ => null, + }; } - - return addresses; - } - - private static string? ConvertCidr(int cidr) - { - return cidr switch - { - 0 => "0.0.0.0", - 1 => "128.0.0.0", - 2 => "192.0.0.0", - 3 => "224.0.0.0", - 4 => "240.0.0.0", - 5 => "248.0.0.0", - 6 => "252.0.0.0", - 7 => "254.0.0.0", - 8 => "255.0.0.0", - 9 => "255.128.0.0", - 10 => "255.192.0.0", - 11 => "255.224.0.0", - 12 => "255.240.0.0", - 13 => "255.248.0.0", - 14 => "255.252.0.0", - 15 => "255.254.0.0", - 16 => "255.255.0.0", - 17 => "255.255.128.0", - 18 => "255.255.192.0", - 19 => "255.255.224.0", - 20 => "255.255.240.0", - 21 => "255.255.248.0", - 22 => "255.255.252.0", - 23 => "255.255.254.0", - 24 => "255.255.255.0", - 25 => "255.255.255.128", - 26 => "255.255.255.192", - 27 => "255.255.255.224", - 28 => "255.255.255.240", - 29 => "255.255.255.248", - 30 => "255.255.255.252", - 31 => "255.255.255.254", - 32 => "255.255.255.255", - _ => null, - }; } } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Network/Handlers/MainboardHandler.cs b/src/Agent/Insight.Agent/Network/Handlers/MainboardHandler.cs index 324a357..43f210b 100644 --- a/src/Agent/Insight.Agent/Network/Handlers/MainboardHandler.cs +++ b/src/Agent/Insight.Agent/Network/Handlers/MainboardHandler.cs @@ -1,88 +1,86 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; using System.Management; using System.Runtime.Versioning; -namespace Insight.Agent.Network.Handlers; - -[SupportedOSPlatform("windows")] -public class MainboardHandler : IMessageHandler +namespace Insight.Agent.Network.Handlers { - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage + [SupportedOSPlatform("windows")] + public class MainboardHandler : IAgentMessageHandler { - switch (message) + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage { - case InventoryRequest: - if (GetMainboard() is Mainboard mainboard) await sender.SendAsync(mainboard, cancellationToken); - break; - } - } - - private static Mainboard? GetMainboard() - { - using var searcher = new ManagementObjectSearcher - { - Scope = new ManagementScope(@"root\cimv2"), - Query = new ObjectQuery("select manufacturer, product, serialnumber from win32_baseboard") - }; - - if (searcher.TryGet(out var collection) is false) - { - searcher.Query = new ObjectQuery("select * from win32_baseboard"); - - if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); - } - - var mainboard = new Mainboard(); - - using (collection) - { - foreach (ManagementObject @object in collection.Cast()) + if (message is GetInventory) { - var properties = @object.GetPropertyHashes(); - - mainboard.Manufacturer = @object.GetValue(properties, "manufacturer")?.Trim(); - mainboard.Model = @object.GetValue(properties, "product")?.Trim(); - mainboard.Serial = @object.GetValue(properties, "serialnumber")?.Trim(); - - break; + await sender.SendAsync(GetMainboard(), cancellationToken); } } - searcher.Query = new ObjectQuery("select manufacturer, serialnumber, smbiosbiosversion, releasedate from win32_bios"); - - if (searcher.TryGet(out var collection2) is false) + private static Mainboard GetMainboard() { - searcher.Query = new ObjectQuery("select * from win32_bios"); - - if (searcher.TryGet(out collection2) is false) return null; - } - - using (collection2) - { - foreach (ManagementObject @object in collection2.Cast()) + using var searcher = new ManagementObjectSearcher { - var properties = @object.GetPropertyHashes(); + Scope = new ManagementScope(@"root\cimv2"), + Query = new ObjectQuery("select manufacturer, product, serialnumber from win32_baseboard") + }; - mainboard.BiosManufacturer = @object.GetValue(properties, "manufacturer")?.Trim(); - mainboard.Serial = @object.GetValue(properties, "serialnumber")?.Trim(); - mainboard.BiosVersion = @object.GetValue(properties, "smbiosbiosversion")?.Trim(); + if (searcher.TryGet(out var collection) is false) + { + searcher.Query = new ObjectQuery("select * from win32_baseboard"); - if (@object.TryGetValue(properties, "releasedate", out var releasedate)) + if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); + } + + var mainboard = new Mainboard(); + + using (collection) + { + foreach (ManagementObject @object in collection.Cast()) { - mainboard.BiosDate = ManagementDateTimeConverter.ToDateTime(releasedate?.ToString()); + var properties = @object.GetPropertyHashes(); + + mainboard.Manufacturer = @object.GetValue(properties, "manufacturer")?.Trim(); + mainboard.Model = @object.GetValue(properties, "product")?.Trim(); + mainboard.Serial = @object.GetValue(properties, "serialnumber")?.Trim(); + + break; } - - break; } + + searcher.Query = new ObjectQuery("select manufacturer, serialnumber, smbiosbiosversion, releasedate from win32_bios"); + + if (searcher.TryGet(out var collection2) is false) + { + searcher.Query = new ObjectQuery("select * from win32_bios"); + + if (searcher.TryGet(out collection2) is false) return null; + } + + using (collection2) + { + foreach (ManagementObject @object in collection2.Cast()) + { + var properties = @object.GetPropertyHashes(); + + mainboard.BiosManufacturer = @object.GetValue(properties, "manufacturer")?.Trim(); + mainboard.Serial = @object.GetValue(properties, "serialnumber")?.Trim(); + mainboard.BiosVersion = @object.GetValue(properties, "smbiosbiosversion")?.Trim(); + + if (@object.TryGetValue(properties, "releasedate", out var releasedate)) + { + mainboard.BiosDate = ManagementDateTimeConverter.ToDateTime(releasedate?.ToString()); + } + + break; + } + } + + //Logger.LogWarning(JsonSerializer.Serialize(mainboard, new JsonSerializerOptions + //{ + // WriteIndented= true + //})); + + return mainboard; } - - //Logger.LogWarning(JsonSerializer.Serialize(mainboard, new JsonSerializerOptions - //{ - // WriteIndented= true - //})); - - return mainboard; } } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Network/Handlers/MemoryHandler.cs b/src/Agent/Insight.Agent/Network/Handlers/MemoryHandler.cs index aea3bce..11ef77f 100644 --- a/src/Agent/Insight.Agent/Network/Handlers/MemoryHandler.cs +++ b/src/Agent/Insight.Agent/Network/Handlers/MemoryHandler.cs @@ -1,127 +1,123 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; using System.Management; using System.Runtime.Versioning; -namespace Insight.Agent.Network.Handlers; - -[SupportedOSPlatform("windows")] -public class MemoryHandler : IMessageHandler +namespace Insight.Agent.Network.Handlers { - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage + [SupportedOSPlatform("windows")] + public class MemoryHandler : IAgentMessageHandler { - switch (message) + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage { - case InventoryRequest: - { - var result = new Collection(); - result.AddRange(GetMemory()); - - await sender.SendAsync(result, cancellationToken); - break; - } - } - } - - private static List GetMemory() - { - using var searcher = new ManagementObjectSearcher - { - Scope = new ManagementScope(@"root\cimv2"), - Query = new ObjectQuery("select tag, devicelocator, manufacturer, partnumber, serialnumber, capacity, speed, maxvoltage, configuredclockspeed, configuredvoltage from win32_physicalmemory") - }; - - if (searcher.TryGet(out var collection) is false) - { - searcher.Query = new ObjectQuery("select * from win32_physicalmemory"); - - if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); - } - - var memorysticks = new List(); - - using (collection) - { - uint index = 0; - - foreach (ManagementObject @object in collection.Cast()) + if (message is GetInventory) { - var @memory = new Memory(); + var result = new MemoryList(); + result.AddRange(GetMemory()); - var properties = @object.GetPropertyHashes(); - - @memory.Index = index; - @memory.Tag = @object.GetValue(properties, "tag")?.Trim(); - @memory.Location = @object.GetValue(properties, "devicelocator")?.Trim(); - @memory.Manufacturer = @object.GetValue(properties, "manufacturer")?.Trim(); - @memory.Model = @object.GetValue(properties, "partnumber")?.Trim(); - @memory.Serial = @object.GetValue(properties, "serialnumber")?.Trim(); - @memory.Capacity = @object.GetValue(properties, "capacity"); - @memory.Speed = @object.GetValue(properties, "speed"); - @memory.Voltage = @object.GetValue(properties, "maxvoltage"); - @memory.ConfiguredSpeed = @object.GetValue(properties, "configuredclockspeed"); - @memory.ConfiguredVoltage = @object.GetValue(properties, "configuredvoltage"); - - memorysticks.Add(@memory); - index++; + await sender.SendAsync(result, cancellationToken); } } - return memorysticks; + private static List GetMemory() + { + using var searcher = new ManagementObjectSearcher + { + Scope = new ManagementScope(@"root\cimv2"), + Query = new ObjectQuery("select tag, devicelocator, manufacturer, partnumber, serialnumber, capacity, speed, maxvoltage, configuredclockspeed, configuredvoltage from win32_physicalmemory") + }; + + if (searcher.TryGet(out var collection) is false) + { + searcher.Query = new ObjectQuery("select * from win32_physicalmemory"); + + if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); + } + + var memorysticks = new List(); + + using (collection) + { + uint index = 0; + + foreach (ManagementObject @object in collection.Cast()) + { + var @memory = new Memory(); + + var properties = @object.GetPropertyHashes(); + + @memory.Index = index; + @memory.Tag = @object.GetValue(properties, "tag")?.Trim(); + @memory.Location = @object.GetValue(properties, "devicelocator")?.Trim(); + @memory.Manufacturer = @object.GetValue(properties, "manufacturer")?.Trim(); + @memory.Model = @object.GetValue(properties, "partnumber")?.Trim(); + @memory.Serial = @object.GetValue(properties, "serialnumber")?.Trim(); + @memory.Capacity = @object.GetValue(properties, "capacity"); + @memory.Speed = @object.GetValue(properties, "speed"); + @memory.Voltage = @object.GetValue(properties, "maxvoltage"); + @memory.ConfiguredSpeed = @object.GetValue(properties, "configuredclockspeed"); + @memory.ConfiguredVoltage = @object.GetValue(properties, "configuredvoltage"); + + memorysticks.Add(@memory); + index++; + } + } + + return memorysticks; + } + + //private async ValueTask GetMemoryMetricAsync(CancellationToken cancellationToken) + //{ + // var metric = new Memory.Metric(); + + // using var searcher = new ManagementObjectSearcher + // { + // Scope = new ManagementScope(@"root\cimv2"), + // Query = new ObjectQuery("select totalphysicalmemory from win32_computersystem") + // }; + + // if (searcher.TryGet(out var collection) is false) + // { + // searcher.Query = new ObjectQuery("select * from win32_computersystem"); + + // if (searcher.TryGet(out collection) is false) return metric; + // } + + // ulong capacity = 0; + + // using (collection) + // { + // foreach (var @object in collection) + // { + // var properties = @object.GetPropertyHashes(); + + // if (@object.TryGetValue(properties, "totalphysicalmemory", out capacity)) + // { + // capacity = capacity / 1024 / 1024; + // } + + // break; + // } + // } + + // if (MemoryAvailableCounter is null) + // { + // MemoryAvailableCounter = new PerformanceCounter + // { + // CategoryName = "Memory", + // CounterName = "Available MBytes" + // }; + + // metric.MemoryAvailable = MemoryAvailableCounter.NextValue(); + // await Task.Delay(1000, cancellationToken).ConfigureAwait(false); + // } + + // metric.Timestamp = DateTime.Now; + // metric.MemoryAvailable = MemoryAvailableCounter.NextValue(); + // metric.MemoryUsed = capacity - metric.MemoryAvailable; + // metric.MemoryUsagePercentage = metric.MemoryUsed / capacity * 100; + // metric.MemoryAvailablePercentage = 100 - metric.MemoryUsagePercentage; + // return metric; + //} } - - //private async ValueTask GetMemoryMetricAsync(CancellationToken cancellationToken) - //{ - // var metric = new Memory.Metric(); - - // using var searcher = new ManagementObjectSearcher - // { - // Scope = new ManagementScope(@"root\cimv2"), - // Query = new ObjectQuery("select totalphysicalmemory from win32_computersystem") - // }; - - // if (searcher.TryGet(out var collection) is false) - // { - // searcher.Query = new ObjectQuery("select * from win32_computersystem"); - - // if (searcher.TryGet(out collection) is false) return metric; - // } - - // ulong capacity = 0; - - // using (collection) - // { - // foreach (var @object in collection) - // { - // var properties = @object.GetPropertyHashes(); - - // if (@object.TryGetValue(properties, "totalphysicalmemory", out capacity)) - // { - // capacity = capacity / 1024 / 1024; - // } - - // break; - // } - // } - - // if (MemoryAvailableCounter is null) - // { - // MemoryAvailableCounter = new PerformanceCounter - // { - // CategoryName = "Memory", - // CounterName = "Available MBytes" - // }; - - // metric.MemoryAvailable = MemoryAvailableCounter.NextValue(); - // await Task.Delay(1000, cancellationToken).ConfigureAwait(false); - // } - - // metric.Timestamp = DateTime.Now; - // metric.MemoryAvailable = MemoryAvailableCounter.NextValue(); - // metric.MemoryUsed = capacity - metric.MemoryAvailable; - // metric.MemoryUsagePercentage = metric.MemoryUsed / capacity * 100; - // metric.MemoryAvailablePercentage = 100 - metric.MemoryUsagePercentage; - // return metric; - //} } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Network/Handlers/OperationSystemHandler.cs b/src/Agent/Insight.Agent/Network/Handlers/OperationSystemHandler.cs index 3f3dabe..0a36aad 100644 --- a/src/Agent/Insight.Agent/Network/Handlers/OperationSystemHandler.cs +++ b/src/Agent/Insight.Agent/Network/Handlers/OperationSystemHandler.cs @@ -1,94 +1,91 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; using Microsoft.Win32; using System.Management; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security.AccessControl; -namespace Insight.Agent.Network.Handlers; - -[SupportedOSPlatform("windows")] -public class OperationSystemHandler : IMessageHandler +namespace Insight.Agent.Network.Handlers { - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage + [SupportedOSPlatform("windows")] + public class OperationSystemHandler : IAgentMessageHandler { - switch (message) + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage { - case InventoryRequest: - await sender.SendAsync(GetOperatingSystem(), cancellationToken); - break; - } - } - - private static OperationSystem GetOperatingSystem() - { - using var searcher = new ManagementObjectSearcher - { - Scope = new ManagementScope(@"root\cimv2"), - Query = new ObjectQuery("select caption, version, serialnumber, osarchitecture, installdate from win32_operatingsystem") - }; - - if (searcher.TryGet(out var collection) is false) - { - searcher.Query = new ObjectQuery("select * from win32_operatingsystem"); - - if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); - } - - var os = new OperationSystem(); - - using (collection) - { - foreach (ManagementObject @object in collection.Cast()) + if (message is GetInventory) { - var properties = @object.GetPropertyHashes(); - - os.Name = @object.GetValue(properties, "caption")?.Trim(); - os.Version = @object.GetValue(properties, "version")?.Trim(); - os.SerialNumber = @object.GetValue(properties, "serialnumber")?.Trim(); - - if (@object.TryGetValue(properties, "osarchitecture", out var architecture)) - { - if (architecture is not null && architecture.Contains("64", StringComparison.CurrentCultureIgnoreCase)) - os.Architecture = Architecture.X64; - } - else - { - os.Architecture = Architecture.X86; - } - - if (@object.TryGetValue(properties, "installdate", out var installdate)) - { - os.InstallDate = ManagementDateTimeConverter.ToDateTime(installdate?.ToString()); - } - - break; + await sender.SendAsync(GetOperatingSystem(), cancellationToken); } } - using var registry = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Default); - using var key = registry.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion", RegistryKeyPermissionCheck.ReadSubTree, RegistryRights.ReadKey); - - if (key is not null && key?.GetValue("UBR")?.ToString() is string buildNumber) + private static OperationSystem GetOperatingSystem() { - os.Version = $"{os.Version}.{buildNumber}"; + using var searcher = new ManagementObjectSearcher + { + Scope = new ManagementScope(@"root\cimv2"), + Query = new ObjectQuery("select caption, version, serialnumber, osarchitecture, installdate from win32_operatingsystem") + }; + + if (searcher.TryGet(out var collection) is false) + { + searcher.Query = new ObjectQuery("select * from win32_operatingsystem"); + + if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); + } + + var os = new OperationSystem(); + + using (collection) + { + foreach (ManagementObject @object in collection) + { + var properties = @object.GetPropertyHashes(); + + os.Name = @object.GetValue(properties, "caption")?.Trim(); + os.Version = @object.GetValue(properties, "version")?.Trim(); + os.SerialNumber = @object.GetValue(properties, "serialnumber")?.Trim(); + + if (@object.TryGetValue(properties, "osarchitecture", out var architecture)) + { + if (architecture is not null && architecture.ToLower().Contains("64")) os.Architecture = Architecture.X64; + } + else + { + os.Architecture = Architecture.X86; + } + + if (@object.TryGetValue(properties, "installdate", out var installdate)) + { + os.InstallDate = ManagementDateTimeConverter.ToDateTime(installdate?.ToString()); + } + + break; + } + } + + using var registry = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Default); + using var key = registry.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion", RegistryKeyPermissionCheck.ReadSubTree, RegistryRights.ReadKey); + + if (key is not null && key?.GetValue("UBR")?.ToString() is string buildNumber) + { + os.Version = $"{os.Version}.{buildNumber}"; + } + + searcher.Query = new ObjectQuery("select * from win32_portconnector"); + + if (searcher.TryGet(out var collection2) is false) + { + os.Virtual = true; + } + else + { + os.Virtual = false; + } + + collection2.Dispose(); + + return os; } - - searcher.Query = new ObjectQuery("select * from win32_portconnector"); - - if (searcher.TryGet(out var collection2) is false) - { - os.Virtual = true; - } - else - { - os.Virtual = false; - } - - collection2.Dispose(); - - return os; } } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Network/Handlers/PrinterHandler.cs b/src/Agent/Insight.Agent/Network/Handlers/PrinterHandler.cs index 0b241e6..f52c60d 100644 --- a/src/Agent/Insight.Agent/Network/Handlers/PrinterHandler.cs +++ b/src/Agent/Insight.Agent/Network/Handlers/PrinterHandler.cs @@ -1,64 +1,60 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; using System.Management; using System.Runtime.Versioning; -namespace Insight.Agent.Network.Handlers; - -[SupportedOSPlatform("windows")] -public class PrinterHandler : IMessageHandler +namespace Insight.Agent.Network.Handlers { - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage + [SupportedOSPlatform("windows")] + public class PrinterHandler : IAgentMessageHandler { - switch (message) + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage { - case InventoryRequest: - { - var result = new Collection(); - result.AddRange(GetPrinters()); - - await sender.SendAsync(result, cancellationToken); - break; - } - } - } - - private static List GetPrinters() - { - using var searcher = new ManagementObjectSearcher - { - Scope = new ManagementScope(@"root\cimv2"), - Query = new ObjectQuery("select drivername, name, portname, location, comment from win32_printer") - }; - - if (searcher.TryGet(out var collection) is false) - { - searcher.Query = new ObjectQuery("select * from win32_printer"); - - if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); - } - - var printers = new List(); - - using (collection) - { - foreach (ManagementObject @object in collection.Cast()) + if (message is GetInventory) { - var printer = new Printer(); + var result = new PrinterList(); + result.AddRange(GetPrinters()); - var properties = @object.GetPropertyHashes(); - - printer.Driver = @object.GetValue(properties, "drivername")?.Trim(); - printer.Name = @object.GetValue(properties, "name")?.Trim(); - printer.Port = @object.GetValue(properties, "portname")?.Trim(); - printer.Location = @object.GetValue(properties, "location")?.Trim(); - printer.Comment = @object.GetValue(properties, "comment")?.Trim(); - - printers.Add(printer); + await sender.SendAsync(result, cancellationToken); } } - return printers; + private static List GetPrinters() + { + using var searcher = new ManagementObjectSearcher + { + Scope = new ManagementScope(@"root\cimv2"), + Query = new ObjectQuery("select drivername, name, portname, location, comment from win32_printer") + }; + + if (searcher.TryGet(out var collection) is false) + { + searcher.Query = new ObjectQuery("select * from win32_printer"); + + if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); + } + + var printers = new List(); + + using (collection) + { + foreach (ManagementObject @object in collection.Cast()) + { + var printer = new Printer(); + + var properties = @object.GetPropertyHashes(); + + printer.Driver = @object.GetValue(properties, "drivername")?.Trim(); + printer.Name = @object.GetValue(properties, "name")?.Trim(); + printer.Port = @object.GetValue(properties, "portname")?.Trim(); + printer.Location = @object.GetValue(properties, "location")?.Trim(); + printer.Comment = @object.GetValue(properties, "comment")?.Trim(); + + printers.Add(printer); + } + } + + return printers; + } } } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Network/Handlers/ProcessorHandler.cs b/src/Agent/Insight.Agent/Network/Handlers/ProcessorHandler.cs index 7953846..47052cc 100644 --- a/src/Agent/Insight.Agent/Network/Handlers/ProcessorHandler.cs +++ b/src/Agent/Insight.Agent/Network/Handlers/ProcessorHandler.cs @@ -1,147 +1,143 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; using System.Management; using System.Runtime.Versioning; -namespace Insight.Agent.Network.Handlers; - -[SupportedOSPlatform("windows")] -public class ProcessorHandler : IMessageHandler +namespace Insight.Agent.Network.Handlers { - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage + [SupportedOSPlatform("windows")] + public class ProcessorHandler : IAgentMessageHandler { - switch (message) + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage { - case InventoryRequest: - { - var result = new Collection(); - result.AddRange(GetProcessors()); - - await sender.SendAsync(result, cancellationToken); - break; - } - } - } - - private static List GetProcessors() - { - using var searcher = new ManagementObjectSearcher - { - Scope = new ManagementScope(@"root\cimv2"), - Query = new ObjectQuery("select deviceid, name, manufacturer, socketdesignation, version, processorid, l2cachesize, l3cachesize, currentclockspeed, maxclockspeed, numberofcores, numberoflogicalprocessors, virtualizationfirmwareenabled from win32_processor") - }; - - if (searcher.TryGet(out var collection) is false) - { - searcher.Query = new ObjectQuery("select * from win32_processor"); - - if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); - } - - var processors = new List(); - - using (collection) - { - uint index = 0; - - foreach (ManagementObject @object in collection.Cast()) + if (message is GetInventory) { - var processor = new Processor(); + var result = new ProcessorList(); + result.AddRange(GetProcessors()); - var properties = @object.GetPropertyHashes(); - - processor.Index = index; - processor.DeviceId = @object.GetValue(properties, "deviceid")?.Trim(); - processor.Name = @object.GetValue(properties, "name")?.Trim(); - processor.Manufacturer = @object.GetValue(properties, "manufacturer")?.Trim(); - processor.Socket = @object.GetValue(properties, "socketdesignation")?.Trim(); - processor.Version = @object.GetValue(properties, "version")?.Trim(); - processor.SerialNumber = @object.GetValue(properties, "processorid")?.Trim(); - processor.CurrentSpeed = @object.GetValue(properties, "currentclockspeed"); - processor.MaxSpeed = @object.GetValue(properties, "maxclockspeed"); - processor.Cores = @object.GetValue(properties, "numberofcores"); - processor.LogicalCores = @object.GetValue(properties, "numberoflogicalprocessors"); - processor.Virtualization = @object.GetValue(properties, "virtualizationfirmwareenabled"); - - searcher.Query = new ObjectQuery("select level, maxcachesize from win32_cachememory"); - - if (searcher.TryGet(out var collection2) is false) - { - searcher.Query = new ObjectQuery("select * from win32_cachememory"); - - if (searcher.TryGet(out collection2) is false) throw new InvalidOperationException("WMI Collection NULL"); - } - - using (collection2) - { - foreach (ManagementObject @object2 in collection2.Cast()) - { - var properties2 = @object2.GetPropertyHashes(); - - ProcessorCacheLevelEnum? cacheLevel = null; - - cacheLevel = (ProcessorCacheLevelEnum?)@object2.GetValue(properties2, "level"); - - if (cacheLevel is null) continue; - - var installedSize = @object2.GetValue(properties2, "maxcachesize"); - - switch (cacheLevel) - { - case ProcessorCacheLevelEnum.L1: - { - processor.L1Size = installedSize; - break; - } - case ProcessorCacheLevelEnum.L2: - { - processor.L2Size = installedSize; - break; - } - case ProcessorCacheLevelEnum.L3: - { - processor.L3Size = installedSize; - break; - } - } - } - } - - processors.Add(processor); - index++; + await sender.SendAsync(result, cancellationToken); } } - return processors; + private static List GetProcessors() + { + using var searcher = new ManagementObjectSearcher + { + Scope = new ManagementScope(@"root\cimv2"), + Query = new ObjectQuery("select deviceid, name, manufacturer, socketdesignation, version, processorid, l2cachesize, l3cachesize, currentclockspeed, maxclockspeed, numberofcores, numberoflogicalprocessors, virtualizationfirmwareenabled from win32_processor") + }; + + if (searcher.TryGet(out var collection) is false) + { + searcher.Query = new ObjectQuery("select * from win32_processor"); + + if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); + } + + var processors = new List(); + + using (collection) + { + uint index = 0; + + foreach (ManagementObject @object in collection.Cast()) + { + var processor = new Processor(); + + var properties = @object.GetPropertyHashes(); + + processor.Index = index; + processor.DeviceId = @object.GetValue(properties, "deviceid")?.Trim(); + processor.Name = @object.GetValue(properties, "name")?.Trim(); + processor.Manufacturer = @object.GetValue(properties, "manufacturer")?.Trim(); + processor.Socket = @object.GetValue(properties, "socketdesignation")?.Trim(); + processor.Version = @object.GetValue(properties, "version")?.Trim(); + processor.SerialNumber = @object.GetValue(properties, "processorid")?.Trim(); + processor.CurrentSpeed = @object.GetValue(properties, "currentclockspeed"); + processor.MaxSpeed = @object.GetValue(properties, "maxclockspeed"); + processor.Cores = @object.GetValue(properties, "numberofcores"); + processor.LogicalCores = @object.GetValue(properties, "numberoflogicalprocessors"); + processor.Virtualization = @object.GetValue(properties, "virtualizationfirmwareenabled"); + + searcher.Query = new ObjectQuery("select level, maxcachesize from win32_cachememory"); + + if (searcher.TryGet(out var collection2) is false) + { + searcher.Query = new ObjectQuery("select * from win32_cachememory"); + + if (searcher.TryGet(out collection2) is false) throw new InvalidOperationException("WMI Collection NULL"); + } + + using (collection2) + { + foreach (ManagementObject @object2 in collection2.Cast()) + { + var properties2 = @object2.GetPropertyHashes(); + + ProcessorCacheLevelEnum? cacheLevel = null; + + cacheLevel = (ProcessorCacheLevelEnum?)@object2.GetValue(properties2, "level"); + + if (cacheLevel is null) continue; + + var installedSize = @object2.GetValue(properties2, "maxcachesize"); + + switch (cacheLevel) + { + case ProcessorCacheLevelEnum.L1: + { + processor.L1Size = installedSize; + break; + } + case ProcessorCacheLevelEnum.L2: + { + processor.L2Size = installedSize; + break; + } + case ProcessorCacheLevelEnum.L3: + { + processor.L3Size = installedSize; + break; + } + } + } + } + + processors.Add(processor); + index++; + } + } + + return processors; + } + + private enum ProcessorCacheLevelEnum + { + L1 = 3, + L2 = 4, + L3 = 5, + } + + //private async ValueTask GetProcessorMetricAsync(CancellationToken cancellationToken) + //{ + // var metric = new Processor.Metric(); + + // if (ProcessorTimeCounter is null) + // { + // ProcessorTimeCounter = new PerformanceCounter + // { + // CategoryName = "Processor", + // CounterName = "% Processor Time", + // InstanceName = "_Total" + // }; + + // metric.ProcessorUsagePercentage = ProcessorTimeCounter.NextValue(); + // await Task.Delay(1000, cancellationToken).ConfigureAwait(false); + // } + + // metric.Timestamp = DateTime.Now; + // metric.ProcessorUsagePercentage = ProcessorTimeCounter?.NextValue(); + // return metric; + //} } - - private enum ProcessorCacheLevelEnum - { - L1 = 3, - L2 = 4, - L3 = 5, - } - - //private async ValueTask GetProcessorMetricAsync(CancellationToken cancellationToken) - //{ - // var metric = new Processor.Metric(); - - // if (ProcessorTimeCounter is null) - // { - // ProcessorTimeCounter = new PerformanceCounter - // { - // CategoryName = "Processor", - // CounterName = "% Processor Time", - // InstanceName = "_Total" - // }; - - // metric.ProcessorUsagePercentage = ProcessorTimeCounter.NextValue(); - // await Task.Delay(1000, cancellationToken).ConfigureAwait(false); - // } - - // metric.Timestamp = DateTime.Now; - // metric.ProcessorUsagePercentage = ProcessorTimeCounter?.NextValue(); - // return metric; - //} } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Network/Handlers/ProxyHandler.cs b/src/Agent/Insight.Agent/Network/Handlers/ProxyHandler.cs deleted file mode 100644 index 22956b3..0000000 --- a/src/Agent/Insight.Agent/Network/Handlers/ProxyHandler.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Insight.Agent.Services; -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; - -namespace Insight.Agent.Network.Handlers; - -public class ProxyHandler(ScriptService scriptService) : IMessageHandler -{ - private readonly ScriptService _scriptService = scriptService; - - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage - { - switch (message) - { - case Proxy proxyRequest: - await OnProxyRequestAsync(sender, proxyRequest, cancellationToken); - break; - } - } - - private async ValueTask OnProxyRequestAsync(AgentSession sender, Proxy proxyRequest, CancellationToken cancellationToken) - { - if (proxyRequest.Message?.RequestData is null) return; - var result = await _scriptService.QueryAsync(proxyRequest.Message.RequestData); - - await sender.SendAsync(new Proxy() - { - ProxyId = proxyRequest.ProxyId, - Message = new Response(proxyRequest.Message) - { - ResponseData = result.HadErrors ? result.Errors : result.Data, - ResponseError = result.HadErrors - } - }, cancellationToken); - } -} \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Network/Handlers/ServiceHandler.cs b/src/Agent/Insight.Agent/Network/Handlers/ServiceHandler.cs index acb5755..db3fb34 100644 --- a/src/Agent/Insight.Agent/Network/Handlers/ServiceHandler.cs +++ b/src/Agent/Insight.Agent/Network/Handlers/ServiceHandler.cs @@ -1,122 +1,118 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; using System.Management; using System.Runtime.Versioning; using System.ServiceProcess; -namespace Insight.Agent.Network.Handlers; - -[SupportedOSPlatform("windows")] -public class ServiceHandler : IMessageHandler +namespace Insight.Agent.Network.Handlers { - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage + [SupportedOSPlatform("windows")] + public class ServiceHandler : IAgentMessageHandler { - switch (message) + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage { - case InventoryRequest: - { - var result = new Collection(); - result.AddRange(GetServices()); - - await sender.SendAsync(result, cancellationToken); - break; - } - } - } - - private static List GetServices() - { - var services = new List(); - - var serviceControllers = ServiceController.GetServices()?.OrderBy(s => s.DisplayName)?.ToList(); - if (serviceControllers is null || serviceControllers.Count == 0) throw new InvalidOperationException("SERVICE Collection NULL"); - - foreach (var sc in serviceControllers) - { - var status = sc.Status switch + if (message is GetInventory) { - ServiceControllerStatus.Stopped => Service.ServiceStatus.Stopped, - ServiceControllerStatus.StartPending => Service.ServiceStatus.StartPending, - ServiceControllerStatus.StopPending => Service.ServiceStatus.StopPending, - ServiceControllerStatus.Running => Service.ServiceStatus.Running, - ServiceControllerStatus.ContinuePending => Service.ServiceStatus.ContinuePending, - ServiceControllerStatus.PausePending => Service.ServiceStatus.PausePending, - ServiceControllerStatus.Paused => Service.ServiceStatus.Paused, - _ => Service.ServiceStatus.Unknown - }; + var result = new ServiceList(); + result.AddRange(GetServices()); - var mode = sc.StartType switch - { - ServiceStartMode.Boot => Service.ServiceMode.Boot, - ServiceStartMode.System => Service.ServiceMode.System, - ServiceStartMode.Automatic => Service.ServiceMode.Automatic, - ServiceStartMode.Manual => Service.ServiceMode.Manual, - ServiceStartMode.Disabled => Service.ServiceMode.Disabled, - _ => Service.ServiceMode.Unknown, - }; - - var service = new Service - { - Name = sc.ServiceName?.Trim(), - Display = sc.DisplayName?.Trim(), - Status = status, - StartMode = mode - }; - - services.Add(service); - } - - // additional infos - using var searcher = new ManagementObjectSearcher - { - Scope = new ManagementScope(@"root\cimv2"), - Query = new ObjectQuery("SELECT processid, name, description, pathname, startname, delayedautostart from win32_service") - }; - - if (searcher.TryGet(out var collection) is false) - { - searcher.Query = new ObjectQuery("select * from win32_service"); - - if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); - } - - var services2 = new List(); - - using (collection) - { - foreach (ManagementObject @object in collection.Cast()) - { - var service2 = new Service(); - - var properties = @object.GetPropertyHashes(); - - service2.Name = @object.GetValue(properties, "name")?.Trim(); - service2.ProcessId = @object.GetValue(properties, "processid"); - service2.Description = @object.GetValue(properties, "description")?.Trim(); - service2.PathName = @object.GetValue(properties, "pathname")?.Trim(); - service2.Account = @object.GetValue(properties, "startname")?.Trim(); - service2.Delay = @object.GetValue(properties, "delayedautostart"); - - services2.Add(service2); + await sender.SendAsync(result, cancellationToken); } } - if (services2.Count == 0) return services; - - foreach (var svc in services) + private static List GetServices() { - var map = services2.Where(p => p.Name == svc.Name).FirstOrDefault(); + var services = new List(); - if (map is null) continue; + var serviceControllers = ServiceController.GetServices()?.OrderBy(s => s.DisplayName)?.ToList(); + if (serviceControllers is null || serviceControllers.Any() is false) throw new InvalidOperationException("SERVICE Collection NULL"); - svc.ProcessId = map.ProcessId; - svc.Description = map.Description; - svc.PathName = map.PathName; - svc.Account = map.Account; - svc.Delay = map.Delay; + foreach (var sc in serviceControllers) + { + var status = sc.Status switch + { + ServiceControllerStatus.Stopped => Service.ServiceStatus.Stopped, + ServiceControllerStatus.StartPending => Service.ServiceStatus.StartPending, + ServiceControllerStatus.StopPending => Service.ServiceStatus.StopPending, + ServiceControllerStatus.Running => Service.ServiceStatus.Running, + ServiceControllerStatus.ContinuePending => Service.ServiceStatus.ContinuePending, + ServiceControllerStatus.PausePending => Service.ServiceStatus.PausePending, + ServiceControllerStatus.Paused => Service.ServiceStatus.Paused, + _ => Service.ServiceStatus.Unknown + }; + + var mode = sc.StartType switch + { + ServiceStartMode.Boot => Service.ServiceMode.Boot, + ServiceStartMode.System => Service.ServiceMode.System, + ServiceStartMode.Automatic => Service.ServiceMode.Automatic, + ServiceStartMode.Manual => Service.ServiceMode.Manual, + ServiceStartMode.Disabled => Service.ServiceMode.Disabled, + _ => Service.ServiceMode.Unknown, + }; + + var service = new Service + { + Name = sc.ServiceName?.Trim(), + Display = sc.DisplayName?.Trim(), + Status = status, + StartMode = mode + }; + + services.Add(service); + } + + // additional infos + using var searcher = new ManagementObjectSearcher + { + Scope = new ManagementScope(@"root\cimv2"), + Query = new ObjectQuery("SELECT processid, name, description, pathname, startname, delayedautostart from win32_service") + }; + + if (searcher.TryGet(out var collection) is false) + { + searcher.Query = new ObjectQuery("select * from win32_service"); + + if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); + } + + var services2 = new List(); + + using (collection) + { + foreach (ManagementObject @object in collection.Cast()) + { + var service2 = new Service(); + + var properties = @object.GetPropertyHashes(); + + service2.Name = @object.GetValue(properties, "name")?.Trim(); + service2.ProcessId = @object.GetValue(properties, "processid"); + service2.Description = @object.GetValue(properties, "description")?.Trim(); + service2.PathName = @object.GetValue(properties, "pathname")?.Trim(); + service2.Account = @object.GetValue(properties, "startname")?.Trim(); + service2.Delay = @object.GetValue(properties, "delayedautostart"); + + services2.Add(service2); + } + } + + if (services2.Any() is false) return services; + + foreach (var svc in services) + { + var map = services2.Where(p => p.Name == svc.Name).FirstOrDefault(); + + if (map is null) continue; + + svc.ProcessId = map.ProcessId; + svc.Description = map.Description; + svc.PathName = map.PathName; + svc.Account = map.Account; + svc.Delay = map.Delay; + } + + return services.OrderBy(x => x.Name).ToList(); } - - return [.. services.OrderBy(x => x.Name)]; } } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Network/Handlers/SessionHandler.cs b/src/Agent/Insight.Agent/Network/Handlers/SessionHandler.cs index 886a062..c857127 100644 --- a/src/Agent/Insight.Agent/Network/Handlers/SessionHandler.cs +++ b/src/Agent/Insight.Agent/Network/Handlers/SessionHandler.cs @@ -1,254 +1,252 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; using System.Runtime.InteropServices; using System.Runtime.Versioning; -namespace Insight.Agent.Network.Handlers; - -[SupportedOSPlatform("windows")] -public class SessionHandler : IMessageHandler +namespace Insight.Agent.Network.Handlers { - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage + [SupportedOSPlatform("windows")] + public class SessionHandler : IAgentMessageHandler { - switch (message) + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage { - case InventoryRequest: - { - var result = new Collection(); - result.AddRange(GetSessions()); - - await sender.SendAsync(result, cancellationToken); - break; - } - } - } - - private static List GetSessions() - { - var sessions = new List(); - - foreach (var s in NativeMethods.GetSessions()) - { - sessions.Add(new Session + if (message is GetInventory) { - Sid = s.SessionId.ToString(), - User = s.Username, - Type = s.Workstation, - Status = s.State.ToString(), - Remote = s.IPAddress - }); - } + var result = new SessionList(); + result.AddRange(GetSessions()); - return sessions; - } - - private static partial class NativeMethods - { - //public const int WTS_CURRENT_SESSION = -1; - - [DllImport("wtsapi32.dll")] - private static extern int WTSEnumerateSessions( - nint pServer, - [MarshalAs(UnmanagedType.U4)] int iReserved, - [MarshalAs(UnmanagedType.U4)] int iVersion, - ref nint pSessionInfo, - [MarshalAs(UnmanagedType.U4)] ref int iCount); - - [DllImport("Wtsapi32.dll")] - private static extern bool WTSQuerySessionInformation( - nint pServer, - int iSessionID, - WTS_INFO_CLASS oInfoClass, - out nint pBuffer, - out uint iBytesReturned); - - [DllImport("wtsapi32.dll")] - private static extern void WTSFreeMemory( - nint pMemory); - - [StructLayout(LayoutKind.Sequential)] - private struct WTS_CLIENT_ADDRESS - { - public int iAddressFamily; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] - public byte[] bAddress; - } - - [StructLayout(LayoutKind.Sequential)] - private struct WTS_SESSION_INFO - { - public int iSessionID; - [MarshalAs(UnmanagedType.LPStr)] - public string sWinsWorkstationName; - public WTS_CONNECTSTATE_CLASS oState; - } - - [StructLayout(LayoutKind.Sequential)] - private struct WTS_CLIENT_DISPLAY - { - public int iHorizontalResolution; - public int iVerticalResolution; - //1 = The display uses 4 bits per pixel for a maximum of 16 colors. - //2 = The display uses 8 bits per pixel for a maximum of 256 colors. - //4 = The display uses 16 bits per pixel for a maximum of 2^16 colors. - //8 = The display uses 3-byte RGB values for a maximum of 2^24 colors. - //16 = The display uses 15 bits per pixel for a maximum of 2^15 colors. - public int iColorDepth; - } - - public enum WTS_CONNECTSTATE_CLASS - { - WTSActive, - WTSConnected, - WTSConnectQuery, - WTSShadow, - WTSDisconnected, - WTSIdle, - WTSListen, - WTSReset, - WTSDown, - WTSInit - } - - public enum WTS_INFO_CLASS - { - WTSInitialProgram, - WTSApplicationName, - WTSWorkingDirectory, - WTSOEMId, - WTSSessionId, - WTSUserName, - WTSWinStationName, - WTSDomainName, - WTSConnectState, - WTSClientBuildNumber, - WTSClientName, - WTSClientDirectory, - WTSClientProductId, - WTSClientHardwareId, - WTSClientAddress, - WTSClientDisplay, - WTSClientProtocolType, - WTSIdleTime, - WTSLogonTime, - WTSIncomingBytes, - WTSOutgoingBytes, - WTSIncomingFrames, - WTSOutgoingFrames, - WTSClientInfo, - WTSSessionInfo, - WTSConfigInfo, - WTSValidationInfo, - WTSSessionAddressV4, - WTSIsRemoteSession - } - - public class WTSSession - { - public int SessionId { get; set; } - public WTS_CONNECTSTATE_CLASS State { get; set; } - public string? Workstation { get; set; } - public string? IPAddress { get; set; } - public string? Username { get; set; } - public int HorizontalResolution { get; set; } - public int VerticalResolution { get; set; } - public int ColorDepth { get; set; } - public string? ClientApplicationDirectory { get; set; } - } - - public static IEnumerable GetSessions() - { - var sessions = new List(); - - var pServer = nint.Zero; - var pSessionInfo = nint.Zero; - - try - { - var count = 0; - var sessionCount = WTSEnumerateSessions(pServer, 0, 1, ref pSessionInfo, ref count); - var dataSize = (long)Marshal.SizeOf(typeof(WTS_SESSION_INFO)); - var current = (long)pSessionInfo; - - if (sessionCount <= 0) - return sessions; - - for (int i = 0; i < count; i++) - { - if (Marshal.PtrToStructure((nint)current, typeof(WTS_SESSION_INFO)) is not object sessionStructure) - continue; - - var sessionInfo = (WTS_SESSION_INFO)sessionStructure; - current += dataSize; - - var session = new WTSSession - { - SessionId = sessionInfo.iSessionID, - State = sessionInfo.oState, - Workstation = sessionInfo.sWinsWorkstationName, - }; - - var returned = (uint)0; - - // get terminal user address - var address = nint.Zero; - var clientAddress = new WTS_CLIENT_ADDRESS(); - - if (WTSQuerySessionInformation(pServer, sessionInfo.iSessionID, WTS_INFO_CLASS.WTSClientAddress, out address, out returned) == true) - { - if (Marshal.PtrToStructure(address, clientAddress.GetType()) is not object addressStructure) - break; - - clientAddress = (WTS_CLIENT_ADDRESS)addressStructure; - session.IPAddress = clientAddress.bAddress[2] + "." + clientAddress.bAddress[3] + "." + clientAddress.bAddress[4] + "." + clientAddress.bAddress[5]; - } - - // get terminal user name - if (WTSQuerySessionInformation(pServer, sessionInfo.iSessionID, WTS_INFO_CLASS.WTSUserName, out address, out returned) == true) - { - session.Username = Marshal.PtrToStringAnsi(address); - } - - // get terminal user domain name - if (WTSQuerySessionInformation(pServer, sessionInfo.iSessionID, WTS_INFO_CLASS.WTSDomainName, out address, out returned) == true) - { - session.Username = Marshal.PtrToStringAnsi(address) + @"\" + session.Username; - } - - // get terminal user display informations - var clientDisplay = new WTS_CLIENT_DISPLAY(); - - if (WTSQuerySessionInformation(pServer, sessionInfo.iSessionID, WTS_INFO_CLASS.WTSClientDisplay, out address, out returned) == true) - { - if (Marshal.PtrToStructure(address, clientDisplay.GetType()) is not object displayStructure) - break; - - clientDisplay = (WTS_CLIENT_DISPLAY)displayStructure; - session.HorizontalResolution = clientDisplay.iHorizontalResolution; - session.VerticalResolution = clientDisplay.iVerticalResolution; - session.ColorDepth = clientDisplay.iColorDepth; - } - - // get terminal user application directory - if (WTSQuerySessionInformation(pServer, sessionInfo.iSessionID, WTS_INFO_CLASS.WTSClientDirectory, out address, out returned) == true) - { - session.ClientApplicationDirectory = Marshal.PtrToStringAnsi(address); - } - - sessions.Add(session); - } + await sender.SendAsync(result, cancellationToken); } - catch (Exception) + } + + private static List GetSessions() + { + var query = NativeMethods.GetSessions(); + + var sessions = new List(); + + foreach (var s in NativeMethods.GetSessions()) { - throw; - } - finally - { - WTSFreeMemory(pSessionInfo); + sessions.Add(new Session + { + Sid = s.SessionId.ToString(), + User = s.Username, + Type = s.Workstation, + Status = s.State.ToString(), + Remote = s.IPAddress + }); } return sessions; } + + private static partial class NativeMethods + { + //public const int WTS_CURRENT_SESSION = -1; + + [DllImport("wtsapi32.dll")] + static extern int WTSEnumerateSessions( + nint pServer, + [MarshalAs(UnmanagedType.U4)] int iReserved, + [MarshalAs(UnmanagedType.U4)] int iVersion, + ref nint pSessionInfo, + [MarshalAs(UnmanagedType.U4)] ref int iCount); + + [DllImport("Wtsapi32.dll")] + private static extern bool WTSQuerySessionInformation( + nint pServer, + int iSessionID, + WTS_INFO_CLASS oInfoClass, + out nint pBuffer, + out uint iBytesReturned); + + [DllImport("wtsapi32.dll")] + static extern void WTSFreeMemory( + nint pMemory); + + [StructLayout(LayoutKind.Sequential)] + private struct WTS_CLIENT_ADDRESS + { + public int iAddressFamily; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] + public byte[] bAddress; + } + + [StructLayout(LayoutKind.Sequential)] + private struct WTS_SESSION_INFO + { + public int iSessionID; + [MarshalAs(UnmanagedType.LPStr)] + public string sWinsWorkstationName; + public WTS_CONNECTSTATE_CLASS oState; + } + + [StructLayout(LayoutKind.Sequential)] + private struct WTS_CLIENT_DISPLAY + { + public int iHorizontalResolution; + public int iVerticalResolution; + //1 = The display uses 4 bits per pixel for a maximum of 16 colors. + //2 = The display uses 8 bits per pixel for a maximum of 256 colors. + //4 = The display uses 16 bits per pixel for a maximum of 2^16 colors. + //8 = The display uses 3-byte RGB values for a maximum of 2^24 colors. + //16 = The display uses 15 bits per pixel for a maximum of 2^15 colors. + public int iColorDepth; + } + + public enum WTS_CONNECTSTATE_CLASS + { + WTSActive, + WTSConnected, + WTSConnectQuery, + WTSShadow, + WTSDisconnected, + WTSIdle, + WTSListen, + WTSReset, + WTSDown, + WTSInit + } + + public enum WTS_INFO_CLASS + { + WTSInitialProgram, + WTSApplicationName, + WTSWorkingDirectory, + WTSOEMId, + WTSSessionId, + WTSUserName, + WTSWinStationName, + WTSDomainName, + WTSConnectState, + WTSClientBuildNumber, + WTSClientName, + WTSClientDirectory, + WTSClientProductId, + WTSClientHardwareId, + WTSClientAddress, + WTSClientDisplay, + WTSClientProtocolType, + WTSIdleTime, + WTSLogonTime, + WTSIncomingBytes, + WTSOutgoingBytes, + WTSIncomingFrames, + WTSOutgoingFrames, + WTSClientInfo, + WTSSessionInfo, + WTSConfigInfo, + WTSValidationInfo, + WTSSessionAddressV4, + WTSIsRemoteSession + } + + public class WTSSession + { + public int SessionId { get; set; } + public WTS_CONNECTSTATE_CLASS State { get; set; } + public string? Workstation { get; set; } + public string? IPAddress { get; set; } + public string? Username { get; set; } + public int HorizontalResolution { get; set; } + public int VerticalResolution { get; set; } + public int ColorDepth { get; set; } + public string? ClientApplicationDirectory { get; set; } + } + + public static IEnumerable GetSessions() + { + var sessions = new List(); + + var pServer = nint.Zero; + var pSessionInfo = nint.Zero; + + try + { + var count = 0; + var sessionCount = WTSEnumerateSessions(pServer, 0, 1, ref pSessionInfo, ref count); + var dataSize = (long)Marshal.SizeOf(typeof(WTS_SESSION_INFO)); + var current = (long)pSessionInfo; + + if (sessionCount <= 0) + return sessions; + + for (int i = 0; i < count; i++) + { + if (Marshal.PtrToStructure((nint)current, typeof(WTS_SESSION_INFO)) is not object sessionStructure) + continue; + + var sessionInfo = (WTS_SESSION_INFO)sessionStructure; + current += dataSize; + + var session = new WTSSession + { + SessionId = sessionInfo.iSessionID, + State = sessionInfo.oState, + Workstation = sessionInfo.sWinsWorkstationName, + }; + + var returned = (uint)0; + + // get terminal user address + var address = nint.Zero; + var clientAddress = new WTS_CLIENT_ADDRESS(); + + if (WTSQuerySessionInformation(pServer, sessionInfo.iSessionID, WTS_INFO_CLASS.WTSClientAddress, out address, out returned) == true) + { + if (Marshal.PtrToStructure(address, clientAddress.GetType()) is not object addressStructure) + break; + + clientAddress = (WTS_CLIENT_ADDRESS)addressStructure; + session.IPAddress = clientAddress.bAddress[2] + "." + clientAddress.bAddress[3] + "." + clientAddress.bAddress[4] + "." + clientAddress.bAddress[5]; + } + + // get terminal user name + if (WTSQuerySessionInformation(pServer, sessionInfo.iSessionID, WTS_INFO_CLASS.WTSUserName, out address, out returned) == true) + { + session.Username = Marshal.PtrToStringAnsi(address); + } + + // get terminal user domain name + if (WTSQuerySessionInformation(pServer, sessionInfo.iSessionID, WTS_INFO_CLASS.WTSDomainName, out address, out returned) == true) + { + session.Username = Marshal.PtrToStringAnsi(address) + @"\" + session.Username; + } + + // get terminal user display informations + var clientDisplay = new WTS_CLIENT_DISPLAY(); + + if (WTSQuerySessionInformation(pServer, sessionInfo.iSessionID, WTS_INFO_CLASS.WTSClientDisplay, out address, out returned) == true) + { + if (Marshal.PtrToStructure(address, clientDisplay.GetType()) is not object displayStructure) + break; + + clientDisplay = (WTS_CLIENT_DISPLAY)displayStructure; + session.HorizontalResolution = clientDisplay.iHorizontalResolution; + session.VerticalResolution = clientDisplay.iVerticalResolution; + session.ColorDepth = clientDisplay.iColorDepth; + } + + // get terminal user application directory + if (WTSQuerySessionInformation(pServer, sessionInfo.iSessionID, WTS_INFO_CLASS.WTSClientDirectory, out address, out returned) == true) + { + session.ClientApplicationDirectory = Marshal.PtrToStringAnsi(address); + } + + sessions.Add(session); + } + } + catch (Exception) + { + throw; + } + finally + { + WTSFreeMemory(pSessionInfo); + } + + return sessions; + } + } } } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Network/Handlers/SoftwareHandler.cs b/src/Agent/Insight.Agent/Network/Handlers/SoftwareHandler.cs index e2c04ca..806c2d4 100644 --- a/src/Agent/Insight.Agent/Network/Handlers/SoftwareHandler.cs +++ b/src/Agent/Insight.Agent/Network/Handlers/SoftwareHandler.cs @@ -1,123 +1,119 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; using Microsoft.Win32; using System.Globalization; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security.AccessControl; -namespace Insight.Agent.Network.Handlers; - -[SupportedOSPlatform("windows")] -internal class SoftwareHandler : IMessageHandler +namespace Insight.Agent.Network.Handlers { - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage + [SupportedOSPlatform("windows")] + internal class SoftwareHandler : IAgentMessageHandler { - switch (message) + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage { - case InventoryRequest: - { - var x64 = Task.Run(() => ApplicationRegistryQuery(RegistryView.Registry64), cancellationToken); - var x86 = Task.Run(() => ApplicationRegistryQuery(RegistryView.Registry32), cancellationToken); - - await Task.WhenAll(x64, x86).ConfigureAwait(false); - - var result = new Collection(); - result.AddRange(x64.Result); - result.AddRange(x86.Result.Where(p => result.All(app => p.Name != app.Name && p.Version != app.Version))); - - await sender.SendAsync(result, cancellationToken); - break; - } - } - } - - private static IEnumerable ApplicationRegistryQuery(RegistryView registryView) - { - using var registry = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, registryView); - - using var key = registry.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\", RegistryKeyPermissionCheck.ReadSubTree, RegistryRights.ReadKey); - if (key is null) throw new NullReferenceException(nameof(key)); - - var apps = new List(); - - var architecture = registryView switch - { - RegistryView.Registry32 => Architecture.X86, - _ => Architecture.X64 - }; - - foreach (string name in key.GetSubKeyNames()) - { - using var query = key.OpenSubKey(name); - if (query is null) continue; - - var app = new Application + if (message is GetInventory) { - Architecture = architecture + var x64 = Task.Run(() => ApplicationRegistryQuery(RegistryView.Registry64), cancellationToken); + var x86 = Task.Run(() => ApplicationRegistryQuery(RegistryView.Registry32), cancellationToken); + + await Task.WhenAll(x64, x86).ConfigureAwait(false); + + var result = new ApplicationList(); + result.AddRange(x64.Result); + result.AddRange(x86.Result.Where(p => result.All(app => p.Name != app.Name && p.Version != app.Version))); + + await sender.SendAsync(result, cancellationToken); + } + } + + private static IEnumerable ApplicationRegistryQuery(RegistryView registryView) + { + using var registry = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, registryView); + + using var key = registry.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\", RegistryKeyPermissionCheck.ReadSubTree, RegistryRights.ReadKey); + if (key is null) throw new NullReferenceException(nameof(key)); + + var apps = new List(); + + var architecture = registryView switch + { + RegistryView.Registry32 => Architecture.X86, + _ => Architecture.X64 }; - if (query.GetValue("DisplayName")?.ToString()?.Trim() is string displayName && string.IsNullOrWhiteSpace(displayName) is false) + foreach (string name in key.GetSubKeyNames()) { - app.Name = displayName; - } + using var query = key.OpenSubKey(name); + if (query is null) continue; - if (query.GetValue("Publisher")?.ToString()?.Trim() is string publisher && string.IsNullOrWhiteSpace(publisher) is false) - { - app.Publisher = publisher; - } - - if (query.GetValue("DisplayVersion")?.ToString()?.Trim() is string version && string.IsNullOrWhiteSpace(version) is false) - { - app.Version = version; - } - - if (query.GetValue("InstallLocation")?.ToString()?.Trim() is string location && string.IsNullOrWhiteSpace(location) is false) - { - app.Location = location; - } - - if (query.GetValue("InstallSource")?.ToString()?.Trim() is string source && string.IsNullOrWhiteSpace(source) is false) - { - app.Source = source; - } - - if (query.GetValue("UninstallString")?.ToString()?.Trim() is string uninstall && string.IsNullOrWhiteSpace(uninstall) is false) - { - app.Uninstall = uninstall; - } - - if (app.Uninstall is null) - { - if (query.GetValue("UninstallString_Hidden")?.ToString()?.Trim() is string uninstall2 && string.IsNullOrWhiteSpace(uninstall2) is false) + var app = new Application { - app.Uninstall = uninstall2; - } - } + Architecture = architecture + }; - if (query.GetValue("InstallDate")?.ToString()?.Trim() is string installDate) - { - if (DateTime.TryParseExact(installDate, "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime valid)) + if (query.GetValue("DisplayName")?.ToString()?.Trim() is string displayName && string.IsNullOrWhiteSpace(displayName) is false) { - app.InstallDate = valid; + app.Name = displayName; } - if (app.InstallDate is null) + if (query.GetValue("Publisher")?.ToString()?.Trim() is string publisher && string.IsNullOrWhiteSpace(publisher) is false) { - if (DateTime.TryParseExact(installDate, "dd.MM.yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime valid2)) + app.Publisher = publisher; + } + + if (query.GetValue("DisplayVersion")?.ToString()?.Trim() is string version && string.IsNullOrWhiteSpace(version) is false) + { + app.Version = version; + } + + if (query.GetValue("InstallLocation")?.ToString()?.Trim() is string location && string.IsNullOrWhiteSpace(location) is false) + { + app.Location = location; + } + + if (query.GetValue("InstallSource")?.ToString()?.Trim() is string source && string.IsNullOrWhiteSpace(source) is false) + { + app.Source = source; + } + + if (query.GetValue("UninstallString")?.ToString()?.Trim() is string uninstall && string.IsNullOrWhiteSpace(uninstall) is false) + { + app.Uninstall = uninstall; + } + + if (app.Uninstall is null) + { + if (query.GetValue("UninstallString_Hidden")?.ToString()?.Trim() is string uninstall2 && string.IsNullOrWhiteSpace(uninstall2) is false) { - app.InstallDate = valid2; + app.Uninstall = uninstall2; } } + + if (query.GetValue("InstallDate")?.ToString()?.Trim() is string installDate) + { + if (DateTime.TryParseExact(installDate, "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime valid)) + { + app.InstallDate = valid; + } + + if (app.InstallDate is null) + { + if (DateTime.TryParseExact(installDate, "dd.MM.yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime valid2)) + { + app.InstallDate = valid2; + } + } + } + + if (app.Name is not null) + { + apps.Add(app); + } } - if (app.Name is not null) - { - apps.Add(app); - } + return apps; } - - return apps; } } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Network/Handlers/StoragePoolHandler.cs b/src/Agent/Insight.Agent/Network/Handlers/StoragePoolHandler.cs index 7f71a64..84b5506 100644 --- a/src/Agent/Insight.Agent/Network/Handlers/StoragePoolHandler.cs +++ b/src/Agent/Insight.Agent/Network/Handlers/StoragePoolHandler.cs @@ -1,197 +1,308 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; using System.Management; using System.Runtime.Versioning; -using static Insight.Domain.Network.Agent.Messages.PhysicalDisk; -using static Insight.Domain.Network.Agent.Messages.StoragePool; -using static Insight.Domain.Network.Agent.Messages.VirtualDisk; +using static Insight.Agent.Messages.PhysicalDisk; +using static Insight.Agent.Messages.StoragePool; +using static Insight.Agent.Messages.VirtualDisk; -namespace Insight.Agent.Network.Handlers; - -[SupportedOSPlatform("windows")] -public class StoragePoolHandler : IMessageHandler +namespace Insight.Agent.Network.Handlers { - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage + [SupportedOSPlatform("windows")] + public class StoragePoolHandler : IAgentMessageHandler { - switch (message) + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage { - case InventoryRequest: - { - var result = new Collection(); - result.AddRange(GetStoragePool()); - - await sender.SendAsync(result, cancellationToken); - break; - } - } - } - - private static List GetStoragePool() - { - if (Environment.OSVersion.Version.Major < 6 || Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor < 2) - { - throw new PlatformNotSupportedException(); - } - - using var searcher = new ManagementObjectSearcher - { - Scope = new ManagementScope(@"root\microsoft\windows\storage"), - Query = new ObjectQuery("select objectid, uniqueid, name, friendlyname, resiliencysettingnamedefault, isprimordial, isreadonly, isclustered, size, allocatedsize, logicalsectorsize, operationalstatus, healthstatus from msft_storagepool") - }; - - if (searcher.TryGet(out var collection) is false) - { - searcher.Query = new ObjectQuery("select * from msft_storagepool"); - - if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); - } - - var pools = new List(); - - using (collection) - { - foreach (ManagementObject @object in collection.Cast()) + if (message is GetInventory) { - var pool = new StoragePool(); + var result = new StoragePoolList(); + result.AddRange(GetStoragePool()); - var properties = @object.GetPropertyHashes(); - - pool.UniqueId = @object.GetValue(properties, "uniqueid")?.Trim(); - pool.Name = @object.GetValue(properties, "name")?.Trim(); - pool.FriendlyName = @object.GetValue(properties, "friendlyname")?.Trim(); - - if (@object.TryGetValue(properties, "operationalstatus", out var operationals) && operationals is not null) - { - pool.States = operationals.Select(p => (StoragePool.OperationalState)p).ToList(); - } - - pool.Health = (StoragePool.HealthState)@object.GetValue(properties, "healthstatus"); - pool.RetireMissingPhysicalDisks = (RetireMissingPhysicalDisksEnum)@object.GetValue(properties, "retiremissingphysicaldisks"); - pool.Resiliency = @object.GetValue(properties, "resiliencysettingnamedefault")?.Trim(); - pool.IsPrimordial = @object.GetValue(properties, "isprimordial"); - pool.IsReadOnly = @object.GetValue(properties, "isreadonly"); - pool.IsClustered = @object.GetValue(properties, "isclustered"); - pool.Size = @object.GetValue(properties, "size"); - pool.AllocatedSize = @object.GetValue(properties, "allocatedsize"); - pool.SectorSize = @object.GetValue(properties, "logicalsectorsize"); - - if (@object.GetValue(properties, "objectid") is string objectId) - { - pool.PhysicalDisks = QueryPhysicalDisksByStoragePool(objectId); - pool.VirtualDisks = QueryVirtualDisksByStoragePool(objectId); - } - - pools.Add(pool); + await sender.SendAsync(result, cancellationToken); } } - return pools; - } - - private static List QueryPhysicalDisksByStoragePool(string storagePoolObjectId) - { - using var searcher = new ManagementObjectSearcher + private static List GetStoragePool() { - Scope = new ManagementScope(@"root\microsoft\windows\storage"), - Query = new ObjectQuery("ASSOCIATORS OF {MSFT_StoragePool.ObjectId=\"" + Helpers.EscapeWql(storagePoolObjectId) + "\"} WHERE AssocClass = MSFT_StoragePoolToPhysicalDisk") - }; - - if (searcher.TryGet(out var collection) is false) throw new InvalidOperationException("WMI Collection NULL"); - - var disks = new List(); - - using (collection) - { - foreach (ManagementObject @object in collection.Cast()) + if (Environment.OSVersion.Version.Major < 6 || Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor < 2) { - var disk = new PhysicalDisk(); - - var properties = @object.GetPropertyHashes(); - - disk.UniqueId = @object.GetValue(properties, "uniqueid")?.Trim(); - disk.DeviceId = @object.GetValue(properties, "deviceid")?.Trim(); - disk.FriendlyName = @object.GetValue(properties, "friendlyname")?.Trim(); - disk.Manufacturer = @object.GetValue(properties, "manufacturer")?.Trim(); - disk.Model = @object.GetValue(properties, "model")?.Trim(); - disk.MediaType = @object.GetValue(properties, "mediatype"); - disk.BusType = @object.GetValue(properties, "bustype"); - - if (@object.TryGetValue(properties, "operationalstatus", out var operationals) && operationals is not null) - { - disk.States = operationals.Select(p => (PhysicalDisk.OperationalState)p).ToList(); - } - - disk.Health = (PhysicalDisk.HealthState)@object.GetValue(properties, "healthstatus"); - - if (@object.TryGetValue(properties, "supportedusages", out var supportedusages) && supportedusages is not null) - { - disk.SupportedUsages = supportedusages.Select(p => (SupportedUsagesEnum)p).ToList(); - } - - disk.Usage = @object.GetValue(properties, "usage"); - disk.PhysicalLocation = @object.GetValue(properties, "physicallocation")?.Trim(); - disk.SerialNumber = @object.GetValue(properties, "serialnumber")?.Trim(); - disk.FirmwareVersion = @object.GetValue(properties, "firmwareversion")?.Trim(); - disk.Size = @object.GetValue(properties, "size"); - disk.AllocatedSize = @object.GetValue(properties, "allocatedsize"); - disk.LogicalSectorSize = @object.GetValue(properties, "logicalsectorsize"); - disk.PhysicalSectorSize = @object.GetValue(properties, "physicalsectorsize"); - disk.VirtualDiskFootprint = @object.GetValue(properties, "virtualdiskfootprint"); - - disks.Add(disk); + throw new PlatformNotSupportedException(); } + + using var searcher = new ManagementObjectSearcher + { + Scope = new ManagementScope(@"root\microsoft\windows\storage"), + Query = new ObjectQuery("select objectid, uniqueid, name, friendlyname, resiliencysettingnamedefault, isprimordial, isreadonly, isclustered, size, allocatedsize, logicalsectorsize, operationalstatus, healthstatus from msft_storagepool") + }; + + if (searcher.TryGet(out var collection) is false) + { + searcher.Query = new ObjectQuery("select * from msft_storagepool"); + + if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); + } + + var pools = new List(); + + using (collection) + { + foreach (ManagementObject @object in collection.Cast()) + { + var pool = new StoragePool(); + + var properties = @object.GetPropertyHashes(); + + pool.UniqueId = @object.GetValue(properties, "uniqueid")?.Trim(); + pool.Name = @object.GetValue(properties, "name")?.Trim(); + pool.FriendlyName = @object.GetValue(properties, "friendlyname")?.Trim(); + + if (@object.TryGetValue(properties, "operationalstatus", out var operationals) && operationals is not null) + { + pool.States = operationals.Select(p => (StoragePool.OperationalState)p).ToList(); + } + + pool.Health = (StoragePool.HealthState)@object.GetValue(properties, "healthstatus"); + pool.RetireMissingPhysicalDisks = (RetireMissingPhysicalDisksEnum)@object.GetValue(properties, "retiremissingphysicaldisks"); + pool.Resiliency = @object.GetValue(properties, "resiliencysettingnamedefault")?.Trim(); + pool.IsPrimordial = @object.GetValue(properties, "isprimordial"); + pool.IsReadOnly = @object.GetValue(properties, "isreadonly"); + pool.IsClustered = @object.GetValue(properties, "isclustered"); + pool.Size = @object.GetValue(properties, "size"); + pool.AllocatedSize = @object.GetValue(properties, "allocatedsize"); + pool.SectorSize = @object.GetValue(properties, "logicalsectorsize"); + + if (@object.GetValue(properties, "objectid") is string objectId) + { + pool.PhysicalDisks = QueryPhysicalDisksByStoragePool(objectId); + pool.VirtualDisks = QueryVirtualDisksByStoragePool(objectId); + } + + pools.Add(pool); + } + } + + return pools; } - return disks; - } - - private static List QueryVirtualDisksByStoragePool(string storagePoolObjectId) - { - using var searcher = new ManagementObjectSearcher + private static List GetPhysicalDisks() { - Scope = new ManagementScope(@"root\microsoft\windows\storage"), - Query = new ObjectQuery("ASSOCIATORS OF {MSFT_StoragePool.ObjectId=\"" + Helpers.EscapeWql(storagePoolObjectId) + "\"} WHERE AssocClass = MSFT_StoragePoolToVirtualDisk") - }; - - if (searcher.TryGet(out var collection) is false) throw new InvalidOperationException("WMI Collection NULL"); - - var disks = new List(); - - using (collection) - { - foreach (ManagementObject @object in collection.Cast()) + using var searcher = new ManagementObjectSearcher { - var disk = new VirtualDisk(); + Scope = new ManagementScope(@"root\microsoft\windows\storage"), + Query = new ObjectQuery("select objectid, uniqueid, name, friendlyname from msft_physicaldisk") + }; - var properties = @object.GetPropertyHashes(); + if (searcher.TryGet(out var collection) is false) + { + searcher.Query = new ObjectQuery("select * from msft_physicaldisk"); - disk.UniqueId = @object.GetValue(properties, "uniqueid")?.Trim(); - disk.Name = @object.GetValue(properties, "name")?.Trim(); - disk.FriendlyName = @object.GetValue(properties, "friendlyname")?.Trim(); - disk.AccessType = (AccessTypeEnum)@object.GetValue(properties, "access"); - disk.ProvisioningType = (ProvisioningTypeEnum)@object.GetValue(properties, "provisioningtype"); - disk.PhysicalDiskRedundancy = @object.GetValue(properties, "physicaldiskredundancy"); - disk.ResiliencySettingName = @object.GetValue(properties, "resiliencysettingname")?.Trim(); - disk.Deduplication = @object.GetValue(properties, "isdeduplicationenabled"); - disk.IsSnapshot = @object.GetValue(properties, "issnapshot"); - - if (@object.TryGetValue(properties, "operationalstatus", out var operationals) && operationals is not null) - { - disk.States = operationals.Select(p => (VirtualDisk.OperationalState)p).ToList(); - } - - disk.Health = (VirtualDisk.HealthState)@object.GetValue(properties, "healthstatus"); - disk.Size = @object.GetValue(properties, "size"); - disk.AllocatedSize = @object.GetValue(properties, "allocatedsize"); - disk.FootprintOnPool = @object.GetValue(properties, "footprintonpool"); - disk.ReadCacheSize = @object.GetValue(properties, "readcachesize"); - disk.WriteCacheSize = @object.GetValue(properties, "writecachesize"); - - disks.Add(disk); + if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); } + + var disks = new List(); + + using (collection) + { + foreach (ManagementObject @object in collection.Cast()) + { + var disk = new PhysicalDisk(); + + var properties = @object.GetPropertyHashes(); + + disk.UniqueId = @object.GetValue(properties, "uniqueid")?.Trim(); + disk.FriendlyName = @object.GetValue(properties, "friendlyname")?.Trim(); + disk.Manufacturer = @object.GetValue(properties, "manufacturer")?.Trim(); + disk.Model = @object.GetValue(properties, "model")?.Trim(); + disk.MediaType = @object.GetValue(properties, "mediatype"); + disk.BusType = @object.GetValue(properties, "bustype"); + + if (@object.TryGetValue(properties, "operationalstatus", out var operationals) && operationals is not null) + { + disk.States = operationals.Select(p => (PhysicalDisk.OperationalState)p).ToList(); + } + + disk.Health = (PhysicalDisk.HealthState)@object.GetValue(properties, "healthstatus"); + + if (@object.TryGetValue(properties, "supportedusages", out var supportedusages) && supportedusages is not null) + { + disk.SupportedUsages = supportedusages.Select(p => (SupportedUsagesEnum)p).ToList(); + } + + disk.Usage = @object.GetValue(properties, "usage"); + disk.PhysicalLocation = @object.GetValue(properties, "physicallocation")?.Trim(); + disk.SerialNumber = @object.GetValue(properties, "serialnumber")?.Trim(); + disk.FirmwareVersion = @object.GetValue(properties, "firmwareversion")?.Trim(); + disk.Size = @object.GetValue(properties, "size"); + disk.AllocatedSize = @object.GetValue(properties, "allocatedsize"); + disk.LogicalSectorSize = @object.GetValue(properties, "logicalsectorsize"); + disk.PhysicalSectorSize = @object.GetValue(properties, "physicalsectorsize"); + disk.VirtualDiskFootprint = @object.GetValue(properties, "virtualdiskfootprint"); + + disks.Add(disk); + } + } + + return disks; } - return disks; + private static List GetVirtualDisks() + { + using var searcher = new ManagementObjectSearcher + { + Scope = new ManagementScope(@"root\microsoft\windows\storage"), + Query = new ObjectQuery("select objectid, uniqueid, name, friendlyname, access, provisioningtype, physicaldiskredundancy, resiliencysettingname, isdeduplicationenabled, issnapshot, operationalstatus, healthstatus, size, allocatedsize, footprintonpool, readcachesize, writecachesize from msft_virtualdisk") + }; + + if (searcher.TryGet(out var collection) is false) + { + searcher.Query = new ObjectQuery("select * from msft_virtualdisk"); + + if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); + } + + var disks = new List(); + + using (collection) + { + foreach (ManagementObject @object in collection.Cast()) + { + var disk = new VirtualDisk(); + + var properties = @object.GetPropertyHashes(); + + disk.UniqueId = @object.GetValue(properties, "uniqueid")?.Trim(); + disk.Name = @object.GetValue(properties, "name")?.Trim(); + disk.FriendlyName = @object.GetValue(properties, "friendlyname")?.Trim(); + disk.AccessType = (AccessTypeEnum)@object.GetValue(properties, "access"); + disk.ProvisioningType = (ProvisioningTypeEnum)@object.GetValue(properties, "provisioningtype"); + disk.PhysicalDiskRedundancy = @object.GetValue(properties, "physicaldiskredundancy"); + disk.ResiliencySettingName = @object.GetValue(properties, "resiliencysettingname")?.Trim(); + disk.Deduplication = @object.GetValue(properties, "isdeduplicationenabled"); + disk.IsSnapshot = @object.GetValue(properties, "issnapshot"); + + if (@object.TryGetValue(properties, "operationalstatus", out var operationals) && operationals is not null) + { + disk.States = operationals.Select(p => (VirtualDisk.OperationalState)p).ToList(); + } + + disk.Health = (VirtualDisk.HealthState)@object.GetValue(properties, "healthstatus"); + disk.Size = @object.GetValue(properties, "size"); + disk.AllocatedSize = @object.GetValue(properties, "allocatedsize"); + disk.FootprintOnPool = @object.GetValue(properties, "footprintonpool"); + disk.ReadCacheSize = @object.GetValue(properties, "readcachesize"); + disk.WriteCacheSize = @object.GetValue(properties, "writecachesize"); + + disks.Add(disk); + } + } + + return disks; + } + + private static List QueryPhysicalDisksByStoragePool(string storagePoolObjectId) + { + using var searcher = new ManagementObjectSearcher + { + Scope = new ManagementScope(@"root\microsoft\windows\storage"), + Query = new ObjectQuery("ASSOCIATORS OF {MSFT_StoragePool.ObjectId=\"" + Helpers.EscapeWql(storagePoolObjectId) + "\"} WHERE AssocClass = MSFT_StoragePoolToPhysicalDisk") + }; + + if (searcher.TryGet(out var collection) is false) throw new InvalidOperationException("WMI Collection NULL"); + + var disks = new List(); + + using (collection) + { + foreach (ManagementObject @object in collection) + { + var disk = new PhysicalDisk(); + + var properties = @object.GetPropertyHashes(); + + disk.UniqueId = @object.GetValue(properties, "uniqueid")?.Trim(); + disk.DeviceId = @object.GetValue(properties, "deviceid")?.Trim(); + disk.FriendlyName = @object.GetValue(properties, "friendlyname")?.Trim(); + disk.Manufacturer = @object.GetValue(properties, "manufacturer")?.Trim(); + disk.Model = @object.GetValue(properties, "model")?.Trim(); + disk.MediaType = @object.GetValue(properties, "mediatype"); + disk.BusType = @object.GetValue(properties, "bustype"); + + if (@object.TryGetValue(properties, "operationalstatus", out var operationals) && operationals is not null) + { + disk.States = operationals.Select(p => (PhysicalDisk.OperationalState)p).ToList(); + } + + disk.Health = (PhysicalDisk.HealthState)@object.GetValue(properties, "healthstatus"); + + if (@object.TryGetValue(properties, "supportedusages", out var supportedusages) && supportedusages is not null) + { + disk.SupportedUsages = supportedusages.Select(p => (SupportedUsagesEnum)p).ToList(); + } + + disk.Usage = @object.GetValue(properties, "usage"); + disk.PhysicalLocation = @object.GetValue(properties, "physicallocation")?.Trim(); + disk.SerialNumber = @object.GetValue(properties, "serialnumber")?.Trim(); + disk.FirmwareVersion = @object.GetValue(properties, "firmwareversion")?.Trim(); + disk.Size = @object.GetValue(properties, "size"); + disk.AllocatedSize = @object.GetValue(properties, "allocatedsize"); + disk.LogicalSectorSize = @object.GetValue(properties, "logicalsectorsize"); + disk.PhysicalSectorSize = @object.GetValue(properties, "physicalsectorsize"); + disk.VirtualDiskFootprint = @object.GetValue(properties, "virtualdiskfootprint"); + + disks.Add(disk); + } + } + + return disks; + } + + private static List QueryVirtualDisksByStoragePool(string storagePoolObjectId) + { + using var searcher = new ManagementObjectSearcher + { + Scope = new ManagementScope(@"root\microsoft\windows\storage"), + Query = new ObjectQuery("ASSOCIATORS OF {MSFT_StoragePool.ObjectId=\"" + Helpers.EscapeWql(storagePoolObjectId) + "\"} WHERE AssocClass = MSFT_StoragePoolToVirtualDisk") + }; + + if (searcher.TryGet(out var collection) is false) throw new InvalidOperationException("WMI Collection NULL"); + + var disks = new List(); + + using (collection) + { + foreach (ManagementObject @object in collection) + { + var disk = new VirtualDisk(); + + var properties = @object.GetPropertyHashes(); + + disk.UniqueId = @object.GetValue(properties, "uniqueid")?.Trim(); + disk.Name = @object.GetValue(properties, "name")?.Trim(); + disk.FriendlyName = @object.GetValue(properties, "friendlyname")?.Trim(); + disk.AccessType = (AccessTypeEnum)@object.GetValue(properties, "access"); + disk.ProvisioningType = (ProvisioningTypeEnum)@object.GetValue(properties, "provisioningtype"); + disk.PhysicalDiskRedundancy = @object.GetValue(properties, "physicaldiskredundancy"); + disk.ResiliencySettingName = @object.GetValue(properties, "resiliencysettingname")?.Trim(); + disk.Deduplication = @object.GetValue(properties, "isdeduplicationenabled"); + disk.IsSnapshot = @object.GetValue(properties, "issnapshot"); + + if (@object.TryGetValue(properties, "operationalstatus", out var operationals) && operationals is not null) + { + disk.States = operationals.Select(p => (VirtualDisk.OperationalState)p).ToList(); + } + + disk.Health = (VirtualDisk.HealthState)@object.GetValue(properties, "healthstatus"); + disk.Size = @object.GetValue(properties, "size"); + disk.AllocatedSize = @object.GetValue(properties, "allocatedsize"); + disk.FootprintOnPool = @object.GetValue(properties, "footprintonpool"); + disk.ReadCacheSize = @object.GetValue(properties, "readcachesize"); + disk.WriteCacheSize = @object.GetValue(properties, "writecachesize"); + + disks.Add(disk); + } + } + + return disks; + } } } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Network/Handlers/SystemInfoHandler.cs b/src/Agent/Insight.Agent/Network/Handlers/SystemInfoHandler.cs index 0a7e7d4..6f9ee19 100644 --- a/src/Agent/Insight.Agent/Network/Handlers/SystemInfoHandler.cs +++ b/src/Agent/Insight.Agent/Network/Handlers/SystemInfoHandler.cs @@ -1,176 +1,175 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; using Microsoft.Win32; using System.Collections; using System.Management; using System.Runtime.Versioning; -namespace Insight.Agent.Network.Handlers; - -[SupportedOSPlatform("windows")] -public class SystemInfoHandler : IMessageHandler +namespace Insight.Agent.Network.Handlers { - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage + [SupportedOSPlatform("windows")] + public class SystemInfoHandler : IAgentMessageHandler { - switch (message) + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage { - case InventoryRequest: + if (message is GetInventory) + { await sender.SendAsync(GetSystem(), cancellationToken); - break; - } - } - - private static SystemInfo GetSystem() - { - using var searcher = new ManagementObjectSearcher - { - Scope = new ManagementScope(@"root\cimv2"), - Query = new ObjectQuery("select lastbootuptime, localdatetime, numberofprocesses from win32_operatingsystem") - }; - - if (searcher.TryGet(out var collection) is false) - { - searcher.Query = new ObjectQuery("select * from win32_operatingsystem"); - - if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); - } - - var system = new SystemInfo(); - - using (collection) - { - foreach (ManagementObject @object in collection.Cast()) - { - var properties = @object.GetPropertyHashes(); - - if (@object.TryGetValue(properties, "lastbootuptime", out var lastbootuptime)) - { - system.LastBootUpTime = ManagementDateTimeConverter.ToDateTime(lastbootuptime?.ToString()); - } - - if (@object.TryGetValue(properties, "localdatetime", out var localdatetime)) - { - system.LocalDateTime = ManagementDateTimeConverter.ToDateTime(localdatetime?.ToString()); - } - - system.Processes = @object.GetValue(properties, "numberofprocesses"); - - break; } } - system.License = GetWindowsProductKeyFromRegistry(); - - return system; - } - - private static string GetWindowsProductKeyFromRegistry() - { - var localKey = - RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, Environment.Is64BitOperatingSystem - ? RegistryView.Registry64 - : RegistryView.Registry32); - - var registryKeyValue = localKey.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion")?.GetValue("DigitalProductId"); - if (registryKeyValue == null) - return "Failed to get DigitalProductId from registry"; - var digitalProductId = (byte[])registryKeyValue; - localKey.Close(); - var isWin8OrUp = - Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor >= 2 - || - Environment.OSVersion.Version.Major > 6; - return GetWindowsProductKeyFromDigitalProductId(digitalProductId, - isWin8OrUp ? DigitalProductIdVersion.Windows8AndUp : DigitalProductIdVersion.UpToWindows7); - } - - private static string GetWindowsProductKeyFromDigitalProductId(byte[] digitalProductId, DigitalProductIdVersion digitalProductIdVersion) - { - var productKey = digitalProductIdVersion == DigitalProductIdVersion.Windows8AndUp - ? DecodeProductKeyWin8AndUp(digitalProductId) - : DecodeProductKey(digitalProductId); - return productKey; - } - - private static string DecodeProductKey(byte[] digitalProductId) - { - const int keyStartIndex = 52; - const int keyEndIndex = keyStartIndex + 15; - var digits = new[] + private static SystemInfo GetSystem() { - 'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'M', 'P', 'Q', 'R', - 'T', 'V', 'W', 'X', 'Y', '2', '3', '4', '6', '7', '8', '9', - }; - const int decodeLength = 29; - const int decodeStringLength = 15; - var decodedChars = new char[decodeLength]; - var hexPid = new ArrayList(); - for (var i = keyStartIndex; i <= keyEndIndex; i++) - { - hexPid.Add(digitalProductId[i]); - } - for (var i = decodeLength - 1; i >= 0; i--) - { - // Every sixth char is a separator. - if ((i + 1) % 6 == 0) + using var searcher = new ManagementObjectSearcher { - decodedChars[i] = '-'; + Scope = new ManagementScope(@"root\cimv2"), + Query = new ObjectQuery("select lastbootuptime, localdatetime, numberofprocesses from win32_operatingsystem") + }; + + if (searcher.TryGet(out var collection) is false) + { + searcher.Query = new ObjectQuery("select * from win32_operatingsystem"); + + if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); } - else + + var system = new SystemInfo(); + + using (collection) { - // Do the actual decoding. - var digitMapIndex = 0; - for (var j = decodeStringLength - 1; j >= 0; j--) + foreach (ManagementObject @object in collection.Cast()) { - var byteValue = digitMapIndex << 8 | (byte)hexPid[j]!; - hexPid[j] = (byte)(byteValue / 24); - digitMapIndex = byteValue % 24; - decodedChars[i] = digits[digitMapIndex]; + var properties = @object.GetPropertyHashes(); + + if (@object.TryGetValue(properties, "lastbootuptime", out var lastbootuptime)) + { + system.LastBootUpTime = ManagementDateTimeConverter.ToDateTime(lastbootuptime?.ToString()); + } + + if (@object.TryGetValue(properties, "localdatetime", out var localdatetime)) + { + system.LocalDateTime = ManagementDateTimeConverter.ToDateTime(localdatetime?.ToString()); + } + + system.Processes = @object.GetValue(properties, "numberofprocesses"); + + break; } } + + system.License = GetWindowsProductKeyFromRegistry(); + + return system; } - return new string(decodedChars); - } - private static string DecodeProductKeyWin8AndUp(byte[] digitalProductId) - { - var key = string.Empty; - const int keyOffset = 52; - var isWin8 = (byte)(digitalProductId[66] / 6 & 1); - digitalProductId[66] = (byte)(digitalProductId[66] & 0xf7 | (isWin8 & 2) * 4); - - const string digits = "BCDFGHJKMPQRTVWXY2346789"; - var last = 0; - for (var i = 24; i >= 0; i--) + private static string GetWindowsProductKeyFromRegistry() { - var current = 0; - for (var j = 14; j >= 0; j--) + var localKey = + RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, Environment.Is64BitOperatingSystem + ? RegistryView.Registry64 + : RegistryView.Registry32); + + var registryKeyValue = localKey.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion")?.GetValue("DigitalProductId"); + if (registryKeyValue == null) + return "Failed to get DigitalProductId from registry"; + var digitalProductId = (byte[])registryKeyValue; + localKey.Close(); + var isWin8OrUp = + Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor >= 2 + || + Environment.OSVersion.Version.Major > 6; + return GetWindowsProductKeyFromDigitalProductId(digitalProductId, + isWin8OrUp ? DigitalProductIdVersion.Windows8AndUp : DigitalProductIdVersion.UpToWindows7); + } + + private static string GetWindowsProductKeyFromDigitalProductId(byte[] digitalProductId, DigitalProductIdVersion digitalProductIdVersion) + { + + var productKey = digitalProductIdVersion == DigitalProductIdVersion.Windows8AndUp + ? DecodeProductKeyWin8AndUp(digitalProductId) + : DecodeProductKey(digitalProductId); + return productKey; + } + + private static string DecodeProductKey(byte[] digitalProductId) + { + const int keyStartIndex = 52; + const int keyEndIndex = keyStartIndex + 15; + var digits = new[] { - current *= 256; - current = digitalProductId[j + keyOffset] + current; - digitalProductId[j + keyOffset] = (byte)(current / 24); - current %= 24; - last = current; + 'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'M', 'P', 'Q', 'R', + 'T', 'V', 'W', 'X', 'Y', '2', '3', '4', '6', '7', '8', '9', + }; + const int decodeLength = 29; + const int decodeStringLength = 15; + var decodedChars = new char[decodeLength]; + var hexPid = new ArrayList(); + for (var i = keyStartIndex; i <= keyEndIndex; i++) + { + hexPid.Add(digitalProductId[i]); } - key = digits[current] + key; + for (var i = decodeLength - 1; i >= 0; i--) + { + // Every sixth char is a separator. + if ((i + 1) % 6 == 0) + { + decodedChars[i] = '-'; + } + else + { + // Do the actual decoding. + var digitMapIndex = 0; + for (var j = decodeStringLength - 1; j >= 0; j--) + { + var byteValue = digitMapIndex << 8 | (byte)hexPid[j]; + hexPid[j] = (byte)(byteValue / 24); + digitMapIndex = byteValue % 24; + decodedChars[i] = digits[digitMapIndex]; + } + } + } + return new string(decodedChars); } - var keypart1 = key.Substring(1, last); - var keypart2 = key[(last + 1)..]; - key = keypart1 + "N" + keypart2; - - for (var i = 5; i < key.Length; i += 6) + private static string DecodeProductKeyWin8AndUp(byte[] digitalProductId) { - key = key.Insert(i, "-"); + var key = string.Empty; + const int keyOffset = 52; + var isWin8 = (byte)(digitalProductId[66] / 6 & 1); + digitalProductId[66] = (byte)(digitalProductId[66] & 0xf7 | (isWin8 & 2) * 4); + + const string digits = "BCDFGHJKMPQRTVWXY2346789"; + var last = 0; + for (var i = 24; i >= 0; i--) + { + var current = 0; + for (var j = 14; j >= 0; j--) + { + current = current * 256; + current = digitalProductId[j + keyOffset] + current; + digitalProductId[j + keyOffset] = (byte)(current / 24); + current = current % 24; + last = current; + } + key = digits[current] + key; + } + + var keypart1 = key.Substring(1, last); + var keypart2 = key.Substring(last + 1, key.Length - (last + 1)); + key = keypart1 + "N" + keypart2; + + for (var i = 5; i < key.Length; i += 6) + { + key = key.Insert(i, "-"); + } + + return key; } - return key; - } - - private enum DigitalProductIdVersion - { - UpToWindows7, - Windows8AndUp + private enum DigitalProductIdVersion + { + UpToWindows7, + Windows8AndUp + } } } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Network/Handlers/UpdateHandler.cs b/src/Agent/Insight.Agent/Network/Handlers/UpdateHandler.cs index 1679d7e..287c181 100644 --- a/src/Agent/Insight.Agent/Network/Handlers/UpdateHandler.cs +++ b/src/Agent/Insight.Agent/Network/Handlers/UpdateHandler.cs @@ -1,131 +1,130 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; using System.Runtime.Versioning; using System.Text.RegularExpressions; using WUApiLib; -using static Insight.Domain.Network.Agent.Messages.Update; -using UpdateCollection = Insight.Domain.Network.Agent.Messages.UpdateCollection; +using static Insight.Agent.Messages.Update; -namespace Insight.Agent.Network.Handlers; - -[SupportedOSPlatform("windows")] -public partial class UpdateHandler : IMessageHandler +namespace Insight.Agent.Network.Handlers { - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage + [SupportedOSPlatform("windows")] + public class UpdateHandler : IAgentMessageHandler { - switch (message) + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage { - case InventoryRequest: - await sender.SendAsync(new UpdateCollection - { - Installed = QueryInstalledUpdates(), - Pending = QueryPendingUpdates() - }, cancellationToken); - break; - } - } - - private static List QueryInstalledUpdates() - { - var updates = new List(); - - var session = new UpdateSessionClass(); - var searcher = session.CreateUpdateSearcher(); - searcher.Online = false; - - var count = searcher.GetTotalHistoryCount(); - var result = searcher.QueryHistory(0, count); - - foreach (IUpdateHistoryEntry wupdate in result) - { - var update = new Update + if (message is GetInventory) { - Id = wupdate.UpdateIdentity.UpdateID, - Date = wupdate.Date, - Name = wupdate.Title, - Description = wupdate.Description, - Result = wupdate.ResultCode switch - { - OperationResultCode.orcNotStarted => OsUpdateResultCodeEnum.NotStarted, - OperationResultCode.orcInProgress => OsUpdateResultCodeEnum.InProgress, - OperationResultCode.orcSucceeded => OsUpdateResultCodeEnum.Succeeded, - OperationResultCode.orcSucceededWithErrors => OsUpdateResultCodeEnum.SucceededWithErrors, - OperationResultCode.orcFailed => OsUpdateResultCodeEnum.Failed, - OperationResultCode.orcAborted => OsUpdateResultCodeEnum.Aborted, - _ => null - }, - SupportUrl = wupdate.SupportUrl, - }; - - try - { - var rx = KnowledgeBaseRegex(); - update.Hotfix = rx.Match(wupdate.Title).Value; + await sender.SendAsync(GetUpdates(), cancellationToken); } - catch (Exception) - { - - } - - updates.Add(update); } - return updates; - } - - private static List QueryPendingUpdates() - { - var updates = new List(); - - var session = new UpdateSessionClass(); - var searcher = session.CreateUpdateSearcher(); - searcher.Online = true; - - var result = searcher.Search("IsInstalled=0"); - - foreach (IUpdate wupdate in result.Updates) + private static UpdateList GetUpdates() { - var update = new Update + return new UpdateList { - Id = wupdate.Identity.UpdateID, - Type = wupdate.Type switch - { - UpdateType.utSoftware => OsUpdateTypeEnum.Software, - UpdateType.utDriver => OsUpdateTypeEnum.Driver, - _ => null - }, - Date = wupdate.LastDeploymentChangeTime, - Name = wupdate.Title, - Description = wupdate.Description, - SupportUrl = wupdate.SupportUrl, - Size = wupdate.MaxDownloadSize, - IsDownloaded = wupdate.IsDownloaded, - CanRequestUserInput = wupdate.InstallationBehavior.CanRequestUserInput, - RebootBehavior = wupdate.InstallationBehavior.RebootBehavior switch - { - InstallationRebootBehavior.irbNeverReboots => OsUpdateRebootBehaviorEnum.NeverReboots, - InstallationRebootBehavior.irbAlwaysRequiresReboot => OsUpdateRebootBehaviorEnum.AlwaysRequiresReboot, - InstallationRebootBehavior.irbCanRequestReboot => OsUpdateRebootBehaviorEnum.CanRequestReboot, - _ => null - }, + Installed = QueryInstalledUpdates(), + Pending = QueryPendingUpdates() }; + } - if (wupdate.KBArticleIDs.Count > 0) + private static List QueryInstalledUpdates() + { + var updates = new List(); + + var session = new UpdateSessionClass(); + var searcher = session.CreateUpdateSearcher(); + searcher.Online = false; + + var count = searcher.GetTotalHistoryCount(); + var result = searcher.QueryHistory(0, count); + + foreach (IUpdateHistoryEntry wupdate in result) { - foreach (var id in wupdate.KBArticleIDs) + var update = new Update { - update.Hotfix = $"KB{id}"; - break; + Id = wupdate.UpdateIdentity.UpdateID, + Date = wupdate.Date, + Name = wupdate.Title, + Description = wupdate.Description, + Result = wupdate.ResultCode switch + { + OperationResultCode.orcNotStarted => OsUpdateResultCodeEnum.NotStarted, + OperationResultCode.orcInProgress => OsUpdateResultCodeEnum.InProgress, + OperationResultCode.orcSucceeded => OsUpdateResultCodeEnum.Succeeded, + OperationResultCode.orcSucceededWithErrors => OsUpdateResultCodeEnum.SucceededWithErrors, + OperationResultCode.orcFailed => OsUpdateResultCodeEnum.Failed, + OperationResultCode.orcAborted => OsUpdateResultCodeEnum.Aborted, + _ => null + }, + SupportUrl = wupdate.SupportUrl, + }; + + try + { + var rx = new Regex(@"KB(\d+)"); + update.Hotfix = rx.Match(wupdate.Title).Value; } + catch (Exception) + { + + } + + updates.Add(update); } - updates.Add(update); + return updates; } - return updates; - } + private static List QueryPendingUpdates() + { + var updates = new List(); - [GeneratedRegex(@"KB(\d+)")] - private static partial Regex KnowledgeBaseRegex(); + var session = new UpdateSessionClass(); + var searcher = session.CreateUpdateSearcher(); + searcher.Online = true; + + var result = searcher.Search("IsInstalled=0"); + + foreach (IUpdate wupdate in result.Updates) + { + var update = new Update + { + Id = wupdate.Identity.UpdateID, + Type = wupdate.Type switch + { + UpdateType.utSoftware => OsUpdateTypeEnum.Software, + UpdateType.utDriver => OsUpdateTypeEnum.Driver, + _ => null + }, + Date = wupdate.LastDeploymentChangeTime, + Name = wupdate.Title, + Description = wupdate.Description, + SupportUrl = wupdate.SupportUrl, + Size = wupdate.MaxDownloadSize, + IsDownloaded = wupdate.IsDownloaded, + CanRequestUserInput = wupdate.InstallationBehavior.CanRequestUserInput, + RebootBehavior = wupdate.InstallationBehavior.RebootBehavior switch + { + InstallationRebootBehavior.irbNeverReboots => OsUpdateRebootBehaviorEnum.NeverReboots, + InstallationRebootBehavior.irbAlwaysRequiresReboot => OsUpdateRebootBehaviorEnum.AlwaysRequiresReboot, + InstallationRebootBehavior.irbCanRequestReboot => OsUpdateRebootBehaviorEnum.CanRequestReboot, + _ => null + }, + }; + + if (wupdate.KBArticleIDs.Count > 0) + { + foreach (var id in wupdate.KBArticleIDs) + { + update.Hotfix = $"KB{id}"; + break; + } + } + + updates.Add(update); + } + + return updates; + } + } } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Network/Handlers/UserHandler.cs b/src/Agent/Insight.Agent/Network/Handlers/UserHandler.cs index e681b8e..b232e3a 100644 --- a/src/Agent/Insight.Agent/Network/Handlers/UserHandler.cs +++ b/src/Agent/Insight.Agent/Network/Handlers/UserHandler.cs @@ -1,192 +1,188 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; using System.Management; using System.Runtime.Versioning; -namespace Insight.Agent.Network.Handlers; - -[SupportedOSPlatform("windows")] -public class UserHandler : IMessageHandler +namespace Insight.Agent.Network.Handlers { - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage + [SupportedOSPlatform("windows")] + public class UserHandler : IAgentMessageHandler { - switch (message) + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage { - case InventoryRequest: - { - var result = new Collection(); - result.AddRange(GetUsers()); - - await sender.SendAsync(result, cancellationToken); - break; - } - } - } - - private static List GetUsers() - { - var users = QueryUsers(); - var groups = GetGroups(); - var usergrouping = QueryUserGroupMaps(); - - foreach (var u in users) - { - u.Groups = []; - - foreach (var ug in usergrouping.Where(ug => ug.UserDomain == u.Domain && ug.UserName == u.Name)) + if (message is GetInventory) { - var grps = groups.Where(g => g.Domain == ug.GroupDomain && g.Name == ug.GroupName); + var result = new UserList(); + result.AddRange(GetUsers()); - if (grps is not null) - { - u.Groups.AddRange(grps); - } + await sender.SendAsync(result, cancellationToken); } } - return users; - } - - private static List GetGroups() - { - using var searcher = new ManagementObjectSearcher + private static List GetUsers() { - Scope = new ManagementScope(@"root\cimv2"), - Query = new ObjectQuery("select sid, domain, name, description, localaccount from win32_group") - }; + var users = QueryUsers(); + var groups = GetGroups(); + var usergrouping = QueryUserGroupMaps(); - if (searcher.TryGet(out var collection) is false) - { - searcher.Query = new ObjectQuery("select * from win32_group"); - - if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); - } - - var groups = new List(); - - using (collection) - { - foreach (ManagementObject @object in collection.Cast()) + foreach (var u in users) { - var group = new Group(); + u.Groups = new List(); - var properties = @object.GetPropertyHashes(); - - group.Sid = @object.GetValue(properties, "sid")?.Trim(); - group.Domain = @object.GetValue(properties, "domain")?.Trim(); - group.Name = @object.GetValue(properties, "name")?.Trim(); - group.Description = @object.GetValue(properties, "description")?.Trim(); - group.LocalAccount = @object.GetValue(properties, "localaccount"); - - groups.Add(group); - } - } - - return [.. groups.OrderBy(x => x.Name)]; - } - - private static List QueryUsers() - { - using var searcher = new ManagementObjectSearcher - { - Scope = new ManagementScope(@"root\cimv2"), - Query = new ObjectQuery("select sid, name, fullname, description, domain, localaccount, disabled, lockout, status, passwordchangeable, passwordexpires, passwordrequired from win32_useraccount") - }; - - if (searcher.TryGet(out var collection) is false) - { - searcher.Query = new ObjectQuery("select * from win32_useraccount"); - - if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); - } - - var users = new List(); - - using (collection) - { - foreach (ManagementObject @object in collection.Cast()) - { - var user = new User(); - - var properties = @object.GetPropertyHashes(); - - user.Sid = @object.GetValue(properties, "sid")?.Trim(); - user.Name = @object.GetValue(properties, "name")?.Trim(); - user.FullName = @object.GetValue(properties, "fullname")?.Trim(); - user.Description = @object.GetValue(properties, "description")?.Trim(); - user.Domain = @object.GetValue(properties, "domain")?.Trim(); - user.LocalAccount = @object.GetValue(properties, "localaccount"); - user.Disabled = @object.GetValue(properties, "disabled"); - user.Lockout = @object.GetValue(properties, "lockout"); - user.Status = @object.GetValue(properties, "status")?.Trim(); - user.PasswordChangeable = @object.GetValue(properties, "passwordchangeable"); - user.PasswordExpires = @object.GetValue(properties, "passwordexpires"); - user.PasswordRequired = @object.GetValue(properties, "passwordrequired"); - - users.Add(user); - } - } - - return users; - } - - private static List QueryUserGroupMaps() - { - using var searcher = new ManagementObjectSearcher - { - Scope = new ManagementScope(@"root\cimv2"), - Query = new ObjectQuery("select groupcomponent, partcomponent from win32_groupuser") - }; - - if (searcher.TryGet(out var collection) is false) - { - searcher.Query = new ObjectQuery("select * from win32_groupuser"); - - if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); - } - - var usergroups = new List(); - - using (collection) - { - foreach (ManagementObject @object in collection.Cast()) - { - var usergroup = new UserGroupMap(); - - var properties = @object.GetPropertyHashes(); - - var raw = @object.GetValue(properties, "groupcomponent"); - var split = raw?.Split(".Domain=")[1]?.Split(",Name="); - - if (split is not null && split.Length > 1) + foreach (var ug in usergrouping.Where(ug => ug.UserDomain == u.Domain && ug.UserName == u.Name)) { - usergroup.GroupDomain = split[0].TrimStart('"').TrimEnd('"'); - usergroup.GroupName = split[1].TrimStart('"').TrimEnd('"'); + var grps = groups.Where(g => g.Domain == ug.GroupDomain && g.Name == ug.GroupName); + + if (grps is not null) + { + u.Groups.AddRange(grps); + } } - - raw = @object.GetValue(properties, "partcomponent"); - split = raw?.Split(".Domain=")[1]?.Split(",Name="); - - if (split is not null && split.Length > 1) - { - usergroup.UserDomain = split[0].TrimStart('"').TrimEnd('"'); - usergroup.UserName = split[1].TrimStart('"').TrimEnd('"'); - } - - usergroups.Add(usergroup); } + + return users; } - return usergroups; - } + private static List GetGroups() + { + using var searcher = new ManagementObjectSearcher + { + Scope = new ManagementScope(@"root\cimv2"), + Query = new ObjectQuery("select sid, domain, name, description, localaccount from win32_group") + }; - private class UserGroupMap - { - public string? GroupDomain { get; set; } - public string? GroupName { get; set; } + if (searcher.TryGet(out var collection) is false) + { + searcher.Query = new ObjectQuery("select * from win32_group"); - public string? UserDomain { get; set; } - public string? UserName { get; set; } + if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); + } + + var groups = new List(); + + using (collection) + { + foreach (ManagementObject @object in collection) + { + var group = new Group(); + + var properties = @object.GetPropertyHashes(); + + group.Sid = @object.GetValue(properties, "sid")?.Trim(); + group.Domain = @object.GetValue(properties, "domain")?.Trim(); + group.Name = @object.GetValue(properties, "name")?.Trim(); + group.Description = @object.GetValue(properties, "description")?.Trim(); + group.LocalAccount = @object.GetValue(properties, "localaccount"); + + groups.Add(group); + } + } + + return groups.OrderBy(x => x.Name)?.ToList(); + } + + private static List QueryUsers() + { + using var searcher = new ManagementObjectSearcher + { + Scope = new ManagementScope(@"root\cimv2"), + Query = new ObjectQuery("select sid, name, fullname, description, domain, localaccount, disabled, lockout, status, passwordchangeable, passwordexpires, passwordrequired from win32_useraccount") + }; + + if (searcher.TryGet(out var collection) is false) + { + searcher.Query = new ObjectQuery("select * from win32_useraccount"); + + if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); + } + + var users = new List(); + + using (collection) + { + foreach (ManagementObject @object in collection) + { + var user = new User(); + + var properties = @object.GetPropertyHashes(); + + user.Sid = @object.GetValue(properties, "sid")?.Trim(); + user.Name = @object.GetValue(properties, "name")?.Trim(); + user.FullName = @object.GetValue(properties, "fullname")?.Trim(); + user.Description = @object.GetValue(properties, "description")?.Trim(); + user.Domain = @object.GetValue(properties, "domain")?.Trim(); + user.LocalAccount = @object.GetValue(properties, "localaccount"); + user.Disabled = @object.GetValue(properties, "disabled"); + user.Lockout = @object.GetValue(properties, "lockout"); + user.Status = @object.GetValue(properties, "status")?.Trim(); + user.PasswordChangeable = @object.GetValue(properties, "passwordchangeable"); + user.PasswordExpires = @object.GetValue(properties, "passwordexpires"); + user.PasswordRequired = @object.GetValue(properties, "passwordrequired"); + + users.Add(user); + } + } + + return users; + } + + private static List QueryUserGroupMaps() + { + using var searcher = new ManagementObjectSearcher + { + Scope = new ManagementScope(@"root\cimv2"), + Query = new ObjectQuery("select groupcomponent, partcomponent from win32_groupuser") + }; + + if (searcher.TryGet(out var collection) is false) + { + searcher.Query = new ObjectQuery("select * from win32_groupuser"); + + if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); + } + + var usergroups = new List(); + + using (collection) + { + foreach (ManagementObject @object in collection) + { + var usergroup = new UserGroupMap(); + + var properties = @object.GetPropertyHashes(); + + var raw = @object.GetValue(properties, "groupcomponent"); + var split = raw?.Split(".Domain=")[1]?.Split(",Name="); + + if (split is not null && split.Length > 1) + { + usergroup.GroupDomain = split[0].TrimStart('"').TrimEnd('"'); + usergroup.GroupName = split[1].TrimStart('"').TrimEnd('"'); + } + + raw = @object.GetValue(properties, "partcomponent"); + split = raw?.Split(".Domain=")[1]?.Split(",Name="); + + if (split is not null && split.Length > 1) + { + usergroup.UserDomain = split[0].TrimStart('"').TrimEnd('"'); + usergroup.UserName = split[1].TrimStart('"').TrimEnd('"'); + } + + usergroups.Add(usergroup); + } + } + + return usergroups; + } + + private class UserGroupMap + { + public string? GroupDomain { get; set; } + public string? GroupName { get; set; } + + public string? UserDomain { get; set; } + public string? UserName { get; set; } + } } } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Network/Handlers/VideocardHandler.cs b/src/Agent/Insight.Agent/Network/Handlers/VideocardHandler.cs index 078c36a..0e8f1bb 100644 --- a/src/Agent/Insight.Agent/Network/Handlers/VideocardHandler.cs +++ b/src/Agent/Insight.Agent/Network/Handlers/VideocardHandler.cs @@ -1,68 +1,64 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; using System.Management; using System.Runtime.Versioning; -namespace Insight.Agent.Network.Handlers; - -[SupportedOSPlatform("windows")] -public class VideocardHandler : IMessageHandler +namespace Insight.Agent.Network.Handlers { - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage + [SupportedOSPlatform("windows")] + public class VideocardHandler : IAgentMessageHandler { - switch (message) + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage { - case InventoryRequest: - { - var result = new Collection(); - result.AddRange(GetVideocards()); - - await sender.SendAsync(result, cancellationToken); - break; - } - } - } - - private static List GetVideocards() - { - using var searcher = new ManagementObjectSearcher - { - Scope = new ManagementScope(@"root\cimv2"), - Query = new ObjectQuery("select deviceid, name, adapterram, driverdate, driverversion from win32_videocontroller") - }; - - if (searcher.TryGet(out var collection) is false) - { - searcher.Query = new ObjectQuery("select * from win32_videocontroller"); - - if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); - } - - var videocards = new List(); - - using (collection) - { - foreach (ManagementObject @object in collection.Cast()) + if (message is GetInventory) { - var videocard = new Videocard(); + var result = new VideocardList(); + result.AddRange(GetVideocards()); - var properties = @object.GetPropertyHashes(); - - videocard.DeviceId = @object.GetValue(properties, "deviceid")?.Trim(); - videocard.Model = @object.GetValue(properties, "name")?.Trim(); - - if (@object.TryGetValue(properties, "driverdate", out var driverdate)) - { - videocard.DriverDate = ManagementDateTimeConverter.ToDateTime(driverdate?.ToString()); - } - - videocard.DriverVersion = @object.GetValue(properties, "driverversion")?.Trim(); - - videocards.Add(videocard); + await sender.SendAsync(result, cancellationToken); } } - return videocards; + private static List GetVideocards() + { + using var searcher = new ManagementObjectSearcher + { + Scope = new ManagementScope(@"root\cimv2"), + Query = new ObjectQuery("select deviceid, name, adapterram, driverdate, driverversion from win32_videocontroller") + }; + + if (searcher.TryGet(out var collection) is false) + { + searcher.Query = new ObjectQuery("select * from win32_videocontroller"); + + if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL"); + } + + var videocards = new List(); + + using (collection) + { + foreach (ManagementObject @object in collection.Cast()) + { + var videocard = new Videocard(); + + var properties = @object.GetPropertyHashes(); + + videocard.DeviceId = @object.GetValue(properties, "deviceid")?.Trim(); + videocard.Model = @object.GetValue(properties, "name")?.Trim(); + + if (@object.TryGetValue(properties, "driverdate", out var driverdate)) + { + videocard.DriverDate = ManagementDateTimeConverter.ToDateTime(driverdate?.ToString()); + } + + videocard.DriverVersion = @object.GetValue(properties, "driverversion")?.Trim(); + + videocards.Add(videocard); + } + } + + return videocards; + } } } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Network/Handlers/VirtualMaschineHandler.cs b/src/Agent/Insight.Agent/Network/Handlers/VirtualMaschineHandler.cs index 793ae19..a6cc0ff 100644 --- a/src/Agent/Insight.Agent/Network/Handlers/VirtualMaschineHandler.cs +++ b/src/Agent/Insight.Agent/Network/Handlers/VirtualMaschineHandler.cs @@ -1,363 +1,359 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; using System.Management; using System.Runtime.Versioning; -using static Insight.Domain.Network.Agent.Messages.VirtualMaschine; -using static Insight.Domain.Network.Agent.Messages.VirtualMaschineConfiguration; +using static Insight.Agent.Messages.VirtualMaschine; +using static Insight.Agent.Messages.VirtualMaschineConfiguration; -namespace Insight.Agent.Network.Handlers; - -[SupportedOSPlatform("windows")] -public class VirtualMaschineHandler : IMessageHandler +namespace Insight.Agent.Network.Handlers { - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage + [SupportedOSPlatform("windows")] + public class VirtualMaschineHandler : IAgentMessageHandler { - switch (message) + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage { - case InventoryRequest: - { - var result = new Collection(); - result.AddRange(GetVirtualMaschines()); - - await sender.SendAsync(result, cancellationToken); - break; - } - } - } - - private static List GetVirtualMaschines() - { - using var searcher = new ManagementObjectSearcher - { - Scope = new ManagementScope(@"root\virtualization\v2"), - Query = new ObjectQuery("select * msvm_computersystem") - }; - - if (searcher.TryGet(out var computersystems) is false) - { - searcher.Query = new ObjectQuery("select * from msvm_computersystem"); - - if (searcher.TryGet(out computersystems) is false) throw new InvalidOperationException("WMI Collection NULL"); - } - - var vms = new List(); - - using (computersystems) - { - foreach (ManagementObject cs in computersystems.Cast()) + if (message is GetInventory) { - var vm = new VirtualMaschine(); + var result = new VirtualMaschineList(); + result.AddRange(GetVirtualMaschines()); - var csProperties = cs.GetPropertyHashes(); - - var vmId = cs.GetValue(csProperties, "name")?.Trim(); - - if (Guid.TryParse(vmId, out var vmGuid) is false) continue; - - vm.Id = vmGuid; - vm.ProcessId = cs.GetValue(csProperties, "processid"); - vm.Caption = cs.GetValue(csProperties, "caption")?.Trim(); - vm.Name = cs.GetValue(csProperties, "elementname")?.Trim(); - vm.Enabled = (EnabledEnum)cs.GetValue(csProperties, "enabledstate"); - vm.EnabledDefault = (EnabledDefaultEnum)cs.GetValue(csProperties, "enableddefault"); - vm.HealthState = (HealthStatusEnum)cs.GetValue(csProperties, "healthstate"); - vm.Status = cs.GetValue(csProperties, "status")?.Trim(); - vm.OnTime = cs.GetValue(csProperties, "ontimeinmilliseconds"); - vm.ReplicationMode = cs.GetValue(csProperties, "replicationmode"); - vm.ReplicationState = (ReplicationStateEnum)cs.GetValue(csProperties, "replicationstate"); - vm.ReplicationHealth = (ReplicationHealthEnum)cs.GetValue(csProperties, "replicationhealth"); - - if (cs.TryGetValue(csProperties, "installdate", out var installdate)) - { - vm.InstallDate = ManagementDateTimeConverter.ToDateTime(installdate?.ToString()); - } - - if (cs.TryGetValue(csProperties, "timeoflastconfigurationchange", out var timeoflastconfigurationchange)) - { - vm.TimeOfLastConfigurationChange = ManagementDateTimeConverter.ToDateTime(timeoflastconfigurationchange?.ToString()); - } - - if (cs.TryGetValue(csProperties, "timeoflaststatechange", out var timeoflaststatechange)) - { - vm.TimeOfLastStateChange = ManagementDateTimeConverter.ToDateTime(timeoflaststatechange?.ToString()); - } - - if (cs.TryGetValue(csProperties, "lastreplicationtime", out var lastreplicationtime)) - { - vm.LastReplicationTime = ManagementDateTimeConverter.ToDateTime(lastreplicationtime?.ToString()); - } - - var summaryinformation = cs.GetRelated("msvm_summaryinformation"); - using (summaryinformation) - { - foreach (ManagementObject si in summaryinformation.Cast()) - { - var siProperties = si.GetPropertyHashes(); - - vm.Notes = si.GetValue(siProperties, "Notes"); - vm.ConfigurationVersion = si.GetValue(siProperties, "Version"); - vm.IntegrationServicesVersionState = (IntegrationServicesVersionStateEnum)si.GetValue(siProperties, "IntegrationServicesVersionState"); - vm.GuestOperatingSystem = si.GetValue(siProperties, "GuestOperatingSystem"); - vm.NumberOfProcessors = si.GetValue(siProperties, "NumberOfProcessors"); - vm.ProcessorLoad = si.GetValue(siProperties, "ProcessorLoad"); - vm.MemoryAvailable = si.GetValue(siProperties, "MemoryAvailable"); - vm.MemoryUsage = si.GetValue(siProperties, "MemoryUsage"); - } - } - - var virtualSystemSettingData = cs.GetRelated("Msvm_VirtualSystemSettingData"); - using (virtualSystemSettingData) - { - var configs = new List(); - - foreach (ManagementObject vssd in virtualSystemSettingData.Cast()) - { - var vmc = new VirtualMaschineConfiguration(); - - var vssdProperties = vssd.GetPropertyHashes(); - - var vmcId = vssd.GetValue(vssdProperties, "ConfigurationID")?.Trim(); - - if (Guid.TryParse(vmcId, out var vmcGuid) is false) continue; - - vmc.Id = vmcGuid.ToString(); - - vmc.Type = vssd.GetValue(vssdProperties, "VirtualSystemType"); - vmc.Name = vssd.GetValue(vssdProperties, "ElementName"); - - if (vssd.TryGetValue(vssdProperties, "CreationTime", out var creationtime)) - { - vmc.CreationTime = ManagementDateTimeConverter.ToDateTime(creationtime?.ToString()); - } - - vmc.Generation = vssd.GetValue(vssdProperties, "VirtualSystemSubType"); - vmc.Architecture = vssd.GetValue(vssdProperties, "Architecture"); - vmc.AutomaticStartupAction = (AutomaticStartupActionEnum)vssd.GetValue(vssdProperties, "AutomaticStartupAction"); - vmc.AutomaticShutdownAction = (AutomaticShutdownActionEnum)vssd.GetValue(vssdProperties, "AutomaticShutdownAction"); - vmc.AutomaticRecoveryAction = (AutomaticRecoveryActionEnum)vssd.GetValue(vssdProperties, "AutomaticRecoveryAction"); - vmc.AutomaticSnapshotsEnabled = vssd.GetValue(vssdProperties, "AutomaticSnapshotsEnabled"); - - //if (vssd.TryGetValue(vssdProperties, "AutomaticStartupActionDelay", out var automaticstartupactiondelay)) - //{ - // vmc.CreationTime = ManagementDateTimeConverter.ToDateTime(automaticstartupactiondelay?.ToString()); - //} - - vmc.BaseBoardSerialNumber = vssd.GetValue(vssdProperties, "BaseBoardSerialNumber"); - vmc.BIOSGUID = vssd.GetValue(vssdProperties, "BIOSGUID"); - vmc.BIOSSerialNumber = vssd.GetValue(vssdProperties, "BIOSSerialNumber"); - vmc.BootOrder = vssd.GetValue(vssdProperties, "BootOrder"); - vmc.ConfigurationDataRoot = vssd.GetValue(vssdProperties, "ConfigurationDataRoot"); - vmc.ConfigurationFile = vssd.GetValue(vssdProperties, "ConfigurationFile"); - vmc.GuestStateDataRoot = vssd.GetValue(vssdProperties, "GuestStateDataRoot"); - vmc.GuestStateFile = vssd.GetValue(vssdProperties, "GuestStateFile"); - vmc.SnapshotDataRoot = vssd.GetValue(vssdProperties, "SnapshotDataRoot"); - vmc.SuspendDataRoot = vssd.GetValue(vssdProperties, "SuspendDataRoot"); - vmc.SwapFileDataRoot = vssd.GetValue(vssdProperties, "SwapFileDataRoot"); - vmc.SecureBootEnabled = vssd.GetValue(vssdProperties, "SecureBootEnabled"); - vmc.IsAutomaticSnapshot = vssd.GetValue(vssdProperties, "IsAutomaticSnapshot"); - vmc.Notes = vssd.GetValue(vssdProperties, "Notes"); - - if (vssd.GetValue(vssdProperties, "Parent") is string parent) - { - using var vmcp = new ManagementObject(parent); - vmcp.Get(); - - if (Guid.TryParse(vmcp["ConfigurationID"]?.ToString(), out var parentGuid) is false) continue; - vmc.ParentId = parentGuid.ToString(); - } - - //var storageallocationsettingdata = cs.GetRelated("Msvm_StorageAllocationSettingData"); - //using (storageallocationsettingdata) - //{ - - //} - - configs.Add(vmc); - } - - vm.Configurations = configs.GroupBy(p => p.Id).Select(p => p.First()).ToList(); - } - - vms.Add(vm); + await sender.SendAsync(result, cancellationToken); } } - return vms; - } - - private static List QueryVirtualMaschines0() - { - using var searcher = new ManagementObjectSearcher + private static List GetVirtualMaschines() { - Scope = new ManagementScope(@"root\virtualization\v2"), - Query = new ObjectQuery("select * msvm_computersystem") - }; - - if (searcher.TryGet(out var computersystems) is false) - { - searcher.Query = new ObjectQuery("select * from msvm_computersystem"); - - if (searcher.TryGet(out computersystems) is false) throw new InvalidOperationException("WMI Collection NULL"); - } - - var vms = new List(); - - using (computersystems) - { - foreach (ManagementObject cs in computersystems.Cast()) + using var searcher = new ManagementObjectSearcher { - var vm = new VirtualMaschine(); + Scope = new ManagementScope(@"root\virtualization\v2"), + Query = new ObjectQuery("select * msvm_computersystem") + }; - var csProperties = cs.GetPropertyHashes(); + if (searcher.TryGet(out var computersystems) is false) + { + searcher.Query = new ObjectQuery("select * from msvm_computersystem"); - var vmId = cs.GetValue(csProperties, "name")?.Trim(); - - if (Guid.TryParse(vmId, out var vmGuid) is false) continue; - - vm.Id = vmGuid; - vm.ProcessId = cs.GetValue(csProperties, "processid"); - vm.Caption = cs.GetValue(csProperties, "caption")?.Trim(); - vm.Name = cs.GetValue(csProperties, "elementname")?.Trim(); - vm.Enabled = (EnabledEnum)cs.GetValue(csProperties, "enabledstate"); - vm.EnabledDefault = (EnabledDefaultEnum)cs.GetValue(csProperties, "enableddefault"); - vm.HealthState = (HealthStatusEnum)cs.GetValue(csProperties, "healthstate"); - vm.Status = cs.GetValue(csProperties, "status")?.Trim(); - vm.OnTime = cs.GetValue(csProperties, "ontimeinmilliseconds"); - vm.ReplicationMode = cs.GetValue(csProperties, "replicationmode"); - vm.ReplicationState = (ReplicationStateEnum)cs.GetValue(csProperties, "replicationstate"); - vm.ReplicationHealth = (ReplicationHealthEnum)cs.GetValue(csProperties, "replicationhealth"); - - if (cs.TryGetValue(csProperties, "installdate", out var installdate)) - { - vm.InstallDate = ManagementDateTimeConverter.ToDateTime(installdate?.ToString()); - } - - if (cs.TryGetValue(csProperties, "timeoflastconfigurationchange", out var timeoflastconfigurationchange)) - { - vm.TimeOfLastConfigurationChange = ManagementDateTimeConverter.ToDateTime(timeoflastconfigurationchange?.ToString()); - } - - if (cs.TryGetValue(csProperties, "timeoflaststatechange", out var timeoflaststatechange)) - { - vm.TimeOfLastStateChange = ManagementDateTimeConverter.ToDateTime(timeoflaststatechange?.ToString()); - } - - if (cs.TryGetValue(csProperties, "lastreplicationtime", out var lastreplicationtime)) - { - vm.LastReplicationTime = ManagementDateTimeConverter.ToDateTime(lastreplicationtime?.ToString()); - } - - var summaryinformation = cs.GetRelated("msvm_summaryinformation"); - using (summaryinformation) - { - foreach (ManagementObject si in summaryinformation.Cast()) - { - var siProperties = si.GetPropertyHashes(); - - vm.Notes = si.GetValue(siProperties, "Notes"); - vm.ConfigurationVersion = si.GetValue(siProperties, "Version"); - vm.IntegrationServicesVersionState = (IntegrationServicesVersionStateEnum)si.GetValue(siProperties, "IntegrationServicesVersionState"); - vm.GuestOperatingSystem = si.GetValue(siProperties, "GuestOperatingSystem"); - vm.NumberOfProcessors = si.GetValue(siProperties, "NumberOfProcessors"); - vm.ProcessorLoad = si.GetValue(siProperties, "ProcessorLoad"); - vm.MemoryAvailable = si.GetValue(siProperties, "MemoryAvailable"); - vm.MemoryUsage = si.GetValue(siProperties, "MemoryUsage"); - } - } - - var virtualSystemSettingData = cs.GetRelated("Msvm_VirtualSystemSettingData"); - using (virtualSystemSettingData) - { - var configs = new List(); - - foreach (ManagementObject vssd in virtualSystemSettingData.Cast()) - { - var vmc = new VirtualMaschineConfiguration(); - - var vssdProperties = vssd.GetPropertyHashes(); - - var vmcId = vssd.GetValue(vssdProperties, "ConfigurationID")?.Trim(); - - if (Guid.TryParse(vmcId, out var vmcGuid) is false) continue; - - vmc.Id = vmcGuid.ToString(); - - vmc.Type = vssd.GetValue(vssdProperties, "VirtualSystemType"); - vmc.Name = vssd.GetValue(vssdProperties, "ElementName"); - - if (vssd.TryGetValue(vssdProperties, "CreationTime", out var creationtime)) - { - vmc.CreationTime = ManagementDateTimeConverter.ToDateTime(creationtime?.ToString()); - } - - vmc.Generation = vssd.GetValue(vssdProperties, "VirtualSystemSubType"); - vmc.Architecture = vssd.GetValue(vssdProperties, "Architecture"); - vmc.AutomaticStartupAction = (AutomaticStartupActionEnum)vssd.GetValue(vssdProperties, "AutomaticStartupAction"); - - //if (vssd.TryGetValue(vssdProperties, "AutomaticStartupActionDelay", out var automaticstartupactiondelay)) - //{ - // vmc.CreationTime = ManagementDateTimeConverter.ToDateTime(automaticstartupactiondelay?.ToString()); - //} - - vmc.AutomaticShutdownAction = (AutomaticShutdownActionEnum)vssd.GetValue(vssdProperties, "AutomaticShutdownAction"); - vmc.AutomaticRecoveryAction = (AutomaticRecoveryActionEnum)vssd.GetValue(vssdProperties, "AutomaticRecoveryAction"); - vmc.AutomaticSnapshotsEnabled = vssd.GetValue(vssdProperties, "AutomaticSnapshotsEnabled"); - - vmc.BaseBoardSerialNumber = vssd.GetValue(vssdProperties, "BaseBoardSerialNumber"); - vmc.BIOSGUID = vssd.GetValue(vssdProperties, "BIOSGUID"); - vmc.BIOSSerialNumber = vssd.GetValue(vssdProperties, "BIOSSerialNumber"); - vmc.BootOrder = vssd.GetValue(vssdProperties, "BootOrder"); - vmc.ConfigurationDataRoot = vssd.GetValue(vssdProperties, "ConfigurationDataRoot"); - vmc.ConfigurationFile = vssd.GetValue(vssdProperties, "ConfigurationFile"); - vmc.GuestStateDataRoot = vssd.GetValue(vssdProperties, "GuestStateDataRoot"); - vmc.GuestStateFile = vssd.GetValue(vssdProperties, "GuestStateFile"); - vmc.SnapshotDataRoot = vssd.GetValue(vssdProperties, "SnapshotDataRoot"); - vmc.SuspendDataRoot = vssd.GetValue(vssdProperties, "SuspendDataRoot"); - vmc.SwapFileDataRoot = vssd.GetValue(vssdProperties, "SwapFileDataRoot"); - vmc.SecureBootEnabled = vssd.GetValue(vssdProperties, "SecureBootEnabled"); - vmc.IsAutomaticSnapshot = vssd.GetValue(vssdProperties, "IsAutomaticSnapshot"); - vmc.Notes = vssd.GetValue(vssdProperties, "Notes"); - vmc.ParentId = vssd.GetValue(vssdProperties, "Parent"); - - var storageallocationsettingdata = cs.GetRelated("Msvm_StorageAllocationSettingData"); - using (storageallocationsettingdata) - { - - } - - configs.Add(vmc); - } - - configs = configs.GroupBy(p => p.Id).Select(p => p.First()).ToList(); - if (configs.Any(p => p.ParentId is not null)) - { - foreach (var conf in configs.Where(p => p.ParentId is not null)) - { - using var parent = new ManagementObject(conf.ParentId); - parent.Get(); - - if (Guid.TryParse(parent["ConfigurationID"]?.ToString(), out var parentGuid) && configs.FirstOrDefault(p => p.Id == parentGuid.ToString()) is VirtualMaschineConfiguration parentConfig) - { - conf.ParentId = parentGuid.ToString(); - - parentConfig.Childs ??= []; - parentConfig.Childs.Add(conf); - } - else - { - conf.ParentId = null; - } - } - } - - vm.Configurations = configs.Where(p => p.ParentId is null).ToList(); - } - - vms.Add(vm); + if (searcher.TryGet(out computersystems) is false) throw new InvalidOperationException("WMI Collection NULL"); } + + var vms = new List(); + + using (computersystems) + { + foreach (ManagementObject cs in computersystems.Cast()) + { + var vm = new VirtualMaschine(); + + var csProperties = cs.GetPropertyHashes(); + + var vmId = cs.GetValue(csProperties, "name")?.Trim(); + + if (Guid.TryParse(vmId, out var vmGuid) is false) continue; + + vm.Id = vmGuid; + vm.ProcessId = cs.GetValue(csProperties, "processid"); + vm.Caption = cs.GetValue(csProperties, "caption")?.Trim(); + vm.Name = cs.GetValue(csProperties, "elementname")?.Trim(); + vm.Enabled = (EnabledEnum)cs.GetValue(csProperties, "enabledstate"); + vm.EnabledDefault = (EnabledDefaultEnum)cs.GetValue(csProperties, "enableddefault"); + vm.HealthState = (HealthStatusEnum)cs.GetValue(csProperties, "healthstate"); + vm.Status = cs.GetValue(csProperties, "status")?.Trim(); + vm.OnTime = cs.GetValue(csProperties, "ontimeinmilliseconds"); + vm.ReplicationMode = cs.GetValue(csProperties, "replicationmode"); + vm.ReplicationState = (ReplicationStateEnum)cs.GetValue(csProperties, "replicationstate"); + vm.ReplicationHealth = (ReplicationHealthEnum)cs.GetValue(csProperties, "replicationhealth"); + + if (cs.TryGetValue(csProperties, "installdate", out var installdate)) + { + vm.InstallDate = ManagementDateTimeConverter.ToDateTime(installdate?.ToString()); + } + + if (cs.TryGetValue(csProperties, "timeoflastconfigurationchange", out var timeoflastconfigurationchange)) + { + vm.TimeOfLastConfigurationChange = ManagementDateTimeConverter.ToDateTime(timeoflastconfigurationchange?.ToString()); + } + + if (cs.TryGetValue(csProperties, "timeoflaststatechange", out var timeoflaststatechange)) + { + vm.TimeOfLastStateChange = ManagementDateTimeConverter.ToDateTime(timeoflaststatechange?.ToString()); + } + + if (cs.TryGetValue(csProperties, "lastreplicationtime", out var lastreplicationtime)) + { + vm.LastReplicationTime = ManagementDateTimeConverter.ToDateTime(lastreplicationtime?.ToString()); + } + + var summaryinformation = cs.GetRelated("msvm_summaryinformation"); + using (summaryinformation) + { + foreach (ManagementObject si in summaryinformation.Cast()) + { + var siProperties = si.GetPropertyHashes(); + + vm.Notes = si.GetValue(siProperties, "Notes"); + vm.ConfigurationVersion = si.GetValue(siProperties, "Version"); + vm.IntegrationServicesVersionState = (IntegrationServicesVersionStateEnum)si.GetValue(siProperties, "IntegrationServicesVersionState"); + vm.GuestOperatingSystem = si.GetValue(siProperties, "GuestOperatingSystem"); + vm.NumberOfProcessors = si.GetValue(siProperties, "NumberOfProcessors"); + vm.ProcessorLoad = si.GetValue(siProperties, "ProcessorLoad"); + vm.MemoryAvailable = si.GetValue(siProperties, "MemoryAvailable"); + vm.MemoryUsage = si.GetValue(siProperties, "MemoryUsage"); + } + } + + var virtualSystemSettingData = cs.GetRelated("Msvm_VirtualSystemSettingData"); + using (virtualSystemSettingData) + { + var configs = new List(); + + foreach (ManagementObject vssd in virtualSystemSettingData.Cast()) + { + var vmc = new VirtualMaschineConfiguration(); + + var vssdProperties = vssd.GetPropertyHashes(); + + var vmcId = vssd.GetValue(vssdProperties, "ConfigurationID")?.Trim(); + + if (Guid.TryParse(vmcId, out var vmcGuid) is false) continue; + + vmc.Id = vmcGuid.ToString(); + + vmc.Type = vssd.GetValue(vssdProperties, "VirtualSystemType"); + vmc.Name = vssd.GetValue(vssdProperties, "ElementName"); + + if (vssd.TryGetValue(vssdProperties, "CreationTime", out var creationtime)) + { + vmc.CreationTime = ManagementDateTimeConverter.ToDateTime(creationtime?.ToString()); + } + + vmc.Generation = vssd.GetValue(vssdProperties, "VirtualSystemSubType"); + vmc.Architecture = vssd.GetValue(vssdProperties, "Architecture"); + vmc.AutomaticStartupAction = (AutomaticStartupActionEnum)vssd.GetValue(vssdProperties, "AutomaticStartupAction"); + vmc.AutomaticShutdownAction = (AutomaticShutdownActionEnum)vssd.GetValue(vssdProperties, "AutomaticShutdownAction"); + vmc.AutomaticRecoveryAction = (AutomaticRecoveryActionEnum)vssd.GetValue(vssdProperties, "AutomaticRecoveryAction"); + vmc.AutomaticSnapshotsEnabled = vssd.GetValue(vssdProperties, "AutomaticSnapshotsEnabled"); + + //if (vssd.TryGetValue(vssdProperties, "AutomaticStartupActionDelay", out var automaticstartupactiondelay)) + //{ + // vmc.CreationTime = ManagementDateTimeConverter.ToDateTime(automaticstartupactiondelay?.ToString()); + //} + + vmc.BaseBoardSerialNumber = vssd.GetValue(vssdProperties, "BaseBoardSerialNumber"); + vmc.BIOSGUID = vssd.GetValue(vssdProperties, "BIOSGUID"); + vmc.BIOSSerialNumber = vssd.GetValue(vssdProperties, "BIOSSerialNumber"); + vmc.BootOrder = vssd.GetValue(vssdProperties, "BootOrder"); + vmc.ConfigurationDataRoot = vssd.GetValue(vssdProperties, "ConfigurationDataRoot"); + vmc.ConfigurationFile = vssd.GetValue(vssdProperties, "ConfigurationFile"); + vmc.GuestStateDataRoot = vssd.GetValue(vssdProperties, "GuestStateDataRoot"); + vmc.GuestStateFile = vssd.GetValue(vssdProperties, "GuestStateFile"); + vmc.SnapshotDataRoot = vssd.GetValue(vssdProperties, "SnapshotDataRoot"); + vmc.SuspendDataRoot = vssd.GetValue(vssdProperties, "SuspendDataRoot"); + vmc.SwapFileDataRoot = vssd.GetValue(vssdProperties, "SwapFileDataRoot"); + vmc.SecureBootEnabled = vssd.GetValue(vssdProperties, "SecureBootEnabled"); + vmc.IsAutomaticSnapshot = vssd.GetValue(vssdProperties, "IsAutomaticSnapshot"); + vmc.Notes = vssd.GetValue(vssdProperties, "Notes"); + + if (vssd.GetValue(vssdProperties, "Parent") is string parent) + { + using var vmcp = new ManagementObject(parent); + vmcp.Get(); + + if (Guid.TryParse(vmcp["ConfigurationID"]?.ToString(), out var parentGuid) is false) continue; + vmc.ParentId = parentGuid.ToString(); + } + + //var storageallocationsettingdata = cs.GetRelated("Msvm_StorageAllocationSettingData"); + //using (storageallocationsettingdata) + //{ + + //} + + configs.Add(vmc); + } + + vm.Configurations = configs.GroupBy(p => p.Id).Select(p => p.First()).ToList(); + } + + vms.Add(vm); + } + } + + return vms; } - return vms; + private static List QueryVirtualMaschines0() + { + using var searcher = new ManagementObjectSearcher + { + Scope = new ManagementScope(@"root\virtualization\v2"), + Query = new ObjectQuery("select * msvm_computersystem") + }; + + if (searcher.TryGet(out var computersystems) is false) + { + searcher.Query = new ObjectQuery("select * from msvm_computersystem"); + + if (searcher.TryGet(out computersystems) is false) throw new InvalidOperationException("WMI Collection NULL"); + } + + var vms = new List(); + + using (computersystems) + { + foreach (ManagementObject cs in computersystems.Cast()) + { + var vm = new VirtualMaschine(); + + var csProperties = cs.GetPropertyHashes(); + + var vmId = cs.GetValue(csProperties, "name")?.Trim(); + + if (Guid.TryParse(vmId, out var vmGuid) is false) continue; + + vm.Id = vmGuid; + vm.ProcessId = cs.GetValue(csProperties, "processid"); + vm.Caption = cs.GetValue(csProperties, "caption")?.Trim(); + vm.Name = cs.GetValue(csProperties, "elementname")?.Trim(); + vm.Enabled = (EnabledEnum)cs.GetValue(csProperties, "enabledstate"); + vm.EnabledDefault = (EnabledDefaultEnum)cs.GetValue(csProperties, "enableddefault"); + vm.HealthState = (HealthStatusEnum)cs.GetValue(csProperties, "healthstate"); + vm.Status = cs.GetValue(csProperties, "status")?.Trim(); + vm.OnTime = cs.GetValue(csProperties, "ontimeinmilliseconds"); + vm.ReplicationMode = cs.GetValue(csProperties, "replicationmode"); + vm.ReplicationState = (ReplicationStateEnum)cs.GetValue(csProperties, "replicationstate"); + vm.ReplicationHealth = (ReplicationHealthEnum)cs.GetValue(csProperties, "replicationhealth"); + + if (cs.TryGetValue(csProperties, "installdate", out var installdate)) + { + vm.InstallDate = ManagementDateTimeConverter.ToDateTime(installdate?.ToString()); + } + + if (cs.TryGetValue(csProperties, "timeoflastconfigurationchange", out var timeoflastconfigurationchange)) + { + vm.TimeOfLastConfigurationChange = ManagementDateTimeConverter.ToDateTime(timeoflastconfigurationchange?.ToString()); + } + + if (cs.TryGetValue(csProperties, "timeoflaststatechange", out var timeoflaststatechange)) + { + vm.TimeOfLastStateChange = ManagementDateTimeConverter.ToDateTime(timeoflaststatechange?.ToString()); + } + + if (cs.TryGetValue(csProperties, "lastreplicationtime", out var lastreplicationtime)) + { + vm.LastReplicationTime = ManagementDateTimeConverter.ToDateTime(lastreplicationtime?.ToString()); + } + + var summaryinformation = cs.GetRelated("msvm_summaryinformation"); + using (summaryinformation) + { + foreach (ManagementObject si in summaryinformation.Cast()) + { + var siProperties = si.GetPropertyHashes(); + + vm.Notes = si.GetValue(siProperties, "Notes"); + vm.ConfigurationVersion = si.GetValue(siProperties, "Version"); + vm.IntegrationServicesVersionState = (IntegrationServicesVersionStateEnum)si.GetValue(siProperties, "IntegrationServicesVersionState"); + vm.GuestOperatingSystem = si.GetValue(siProperties, "GuestOperatingSystem"); + vm.NumberOfProcessors = si.GetValue(siProperties, "NumberOfProcessors"); + vm.ProcessorLoad = si.GetValue(siProperties, "ProcessorLoad"); + vm.MemoryAvailable = si.GetValue(siProperties, "MemoryAvailable"); + vm.MemoryUsage = si.GetValue(siProperties, "MemoryUsage"); + } + } + + var virtualSystemSettingData = cs.GetRelated("Msvm_VirtualSystemSettingData"); + using (virtualSystemSettingData) + { + var configs = new List(); + + foreach (ManagementObject vssd in virtualSystemSettingData.Cast()) + { + var vmc = new VirtualMaschineConfiguration(); + + var vssdProperties = vssd.GetPropertyHashes(); + + var vmcId = vssd.GetValue(vssdProperties, "ConfigurationID")?.Trim(); + + if (Guid.TryParse(vmcId, out var vmcGuid) is false) continue; + + vmc.Id = vmcGuid.ToString(); + + vmc.Type = vssd.GetValue(vssdProperties, "VirtualSystemType"); + vmc.Name = vssd.GetValue(vssdProperties, "ElementName"); + + if (vssd.TryGetValue(vssdProperties, "CreationTime", out var creationtime)) + { + vmc.CreationTime = ManagementDateTimeConverter.ToDateTime(creationtime?.ToString()); + } + + vmc.Generation = vssd.GetValue(vssdProperties, "VirtualSystemSubType"); + vmc.Architecture = vssd.GetValue(vssdProperties, "Architecture"); + vmc.AutomaticStartupAction = (AutomaticStartupActionEnum)vssd.GetValue(vssdProperties, "AutomaticStartupAction"); + + //if (vssd.TryGetValue(vssdProperties, "AutomaticStartupActionDelay", out var automaticstartupactiondelay)) + //{ + // vmc.CreationTime = ManagementDateTimeConverter.ToDateTime(automaticstartupactiondelay?.ToString()); + //} + + vmc.AutomaticShutdownAction = (AutomaticShutdownActionEnum)vssd.GetValue(vssdProperties, "AutomaticShutdownAction"); + vmc.AutomaticRecoveryAction = (AutomaticRecoveryActionEnum)vssd.GetValue(vssdProperties, "AutomaticRecoveryAction"); + vmc.AutomaticSnapshotsEnabled = vssd.GetValue(vssdProperties, "AutomaticSnapshotsEnabled"); + + vmc.BaseBoardSerialNumber = vssd.GetValue(vssdProperties, "BaseBoardSerialNumber"); + vmc.BIOSGUID = vssd.GetValue(vssdProperties, "BIOSGUID"); + vmc.BIOSSerialNumber = vssd.GetValue(vssdProperties, "BIOSSerialNumber"); + vmc.BootOrder = vssd.GetValue(vssdProperties, "BootOrder"); + vmc.ConfigurationDataRoot = vssd.GetValue(vssdProperties, "ConfigurationDataRoot"); + vmc.ConfigurationFile = vssd.GetValue(vssdProperties, "ConfigurationFile"); + vmc.GuestStateDataRoot = vssd.GetValue(vssdProperties, "GuestStateDataRoot"); + vmc.GuestStateFile = vssd.GetValue(vssdProperties, "GuestStateFile"); + vmc.SnapshotDataRoot = vssd.GetValue(vssdProperties, "SnapshotDataRoot"); + vmc.SuspendDataRoot = vssd.GetValue(vssdProperties, "SuspendDataRoot"); + vmc.SwapFileDataRoot = vssd.GetValue(vssdProperties, "SwapFileDataRoot"); + vmc.SecureBootEnabled = vssd.GetValue(vssdProperties, "SecureBootEnabled"); + vmc.IsAutomaticSnapshot = vssd.GetValue(vssdProperties, "IsAutomaticSnapshot"); + vmc.Notes = vssd.GetValue(vssdProperties, "Notes"); + vmc.ParentId = vssd.GetValue(vssdProperties, "Parent"); + + var storageallocationsettingdata = cs.GetRelated("Msvm_StorageAllocationSettingData"); + using (storageallocationsettingdata) + { + + } + + configs.Add(vmc); + } + + configs = configs.GroupBy(p => p.Id).Select(p => p.First()).ToList(); + if (configs.Any(p => p.ParentId is not null)) + { + foreach (var conf in configs.Where(p => p.ParentId is not null)) + { + using var parent = new ManagementObject(conf.ParentId); + parent.Get(); + + if (Guid.TryParse(parent["ConfigurationID"]?.ToString(), out var parentGuid) && configs.FirstOrDefault(p => p.Id == parentGuid.ToString()) is VirtualMaschineConfiguration parentConfig) + { + conf.ParentId = parentGuid.ToString(); + + parentConfig.Childs ??= new List(); + parentConfig.Childs.Add(conf); + } + else + { + conf.ParentId = null; + } + } + } + + vm.Configurations = configs.Where(p => p.ParentId is null).ToList(); + } + + vms.Add(vm); + } + } + + return vms; + } } } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Program.cs b/src/Agent/Insight.Agent/Program.cs index 6671d77..15ed188 100644 --- a/src/Agent/Insight.Agent/Program.cs +++ b/src/Agent/Insight.Agent/Program.cs @@ -1,86 +1,101 @@ using Insight.Agent.Extensions; +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; using Insight.Agent.Network; using Insight.Agent.Network.Handlers; using Insight.Agent.Services; using Insight.Domain.Constants; -using Insight.Domain.Extensions; -using Insight.Domain.Interfaces; -using Insight.Domain.Network; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using System.Diagnostics; using Vaitr.Network; -using Vaitr.Network.Hosting; -namespace Insight.Agent.Windows; - -internal class Program +namespace Insight.Agent.Windows { - public static async Task Main(string[] args) + internal class Program { - var builder = Host.CreateDefaultBuilder(args); - builder.UseWindowsService(); - builder.UseSystemd(); - - builder.ConfigureAppConfiguration(config => + public static async Task Main(string[] args) { - config.Defaults(); - }); + var builder = Host.CreateDefaultBuilder(args); + builder.UseWindowsService(); + builder.UseSystemd(); - builder.ConfigureLogging(options => - { - options.ClearProviders(); - options.SetMinimumLevel(LogLevel.Trace); - - options.AddSimpleConsole(options => + builder.ConfigureAppConfiguration(config => { - options.IncludeScopes = true; - options.SingleLine = true; - options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff "; - }); - options.AddFile(Configuration.AppDirectory?.FullName + "/logs/" + Process.GetCurrentProcess().ProcessName + "_{Date}.log", LogLevel.Trace, fileSizeLimitBytes: 104857600, retainedFileCountLimit: 10, outputTemplate: "{Timestamp:o} [{Level:u3}] {Message} {NewLine}{Exception}"); - }); - - builder.ConfigureServices((host, services) => - { - // HOST-SERVICES - services.AddHostedService(); - services.AddHostedService(); - - // SERVICES (WINDOWS) - if (OperatingSystem.IsWindows()) services.AddHostedService(); - if (OperatingSystem.IsWindows()) services.AddSingleton(); - - // AGENT NETWORKING - services.UseHostedClient(options => - { - options.Host = host.Configuration.GetValue(Appsettings.ServerHost) ?? throw new Exception($"{Appsettings.ServerHost} value not set (appsettings)"); - options.Port = host.Configuration.GetValue(Appsettings.ServerPort) ?? throw new Exception($"{Appsettings.ServerPort} value not set (appsettings)"); - options.Keepalive = 10000; - options.Timeout = 30000; - - options.Compression = true; - options.Encryption = Encryption.Tls12; - - options.UseSerializer>(); + config.Defaults(); }); - services.AddSingleton, ProxyHandler>(); - services.AddSingleton, CustomHandler>(); - - if (OperatingSystem.IsWindows()) ServiceExtensions.InjectWindowsHandler(services); - - // GLOBAL DEPENDENCIES - services.AddTransient(provider => new HttpClient(new HttpClientHandler + builder.ConfigureLogging(options => { - ClientCertificateOptions = ClientCertificateOption.Manual, - ServerCertificateCustomValidationCallback = (httpRequestMessage, cert, cetChain, policyErrors) => true - })); - }); + options.ClearProviders(); + options.SetMinimumLevel(LogLevel.Trace); - var host = builder.Build(); - await host.RunAsync().ConfigureAwait(false); + options.AddSimpleConsole(options => + { + options.IncludeScopes = true; + options.SingleLine = true; + options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff "; + }); + + options.AddFile($"{Configuration.AppDirectory?.FullName}/" + "logs/agent_{Date}.log", LogLevel.Trace, fileSizeLimitBytes: 104857600, retainedFileCountLimit: 10, outputTemplate: "{Timestamp:o} [{Level:u3}] {Message} {NewLine}{Exception}"); + }); + + builder.ConfigureServices((host, services) => + { + // SERVICES + services.AddHostedService(); + services.AddHostedService(); + + // SERVICES (WINDOWS) + if (OperatingSystem.IsWindows()) services.AddHostedService(); + + // AGENT NETWORKING + services.UseHostedTcpClient(options => + { + options.Host = host.Configuration.GetValue(Appsettings.ServerHost) ?? throw new Exception($"{Appsettings.ServerHost} value not set (appsettings)"); + options.Port = host.Configuration.GetValue(Appsettings.ServerPort) ?? throw new Exception($"{Appsettings.ServerPort} value not set (appsettings)"); + options.Buffer = 1024 * 1024; + options.KeepAlive = 10000; + options.Timeout = 30000; + options.Parallelism = 0; + options.Compression = Compression.None; + options.Encryption = Encryption.Tls12; + options.SslPolicy = SslPolicy.None; + + //options.InputRateLimit = 1024 * 1024 * 100; + //options.OutputRateLimit = 1024 * 1024 * 100; + }); + + services.AddSingleton, AuthenticationHandler>(); + services.AddSingleton, DriveHandler>(); + services.AddSingleton, InterfaceHandler>(); + services.AddSingleton, MainboardHandler>(); + services.AddSingleton, MemoryHandler>(); + services.AddSingleton, OperationSystemHandler>(); + services.AddSingleton, PrinterHandler>(); + services.AddSingleton, ProcessorHandler>(); + services.AddSingleton, ServiceHandler>(); + services.AddSingleton, SessionHandler>(); + services.AddSingleton, SoftwareHandler>(); + services.AddSingleton, StoragePoolHandler>(); + services.AddSingleton, SystemInfoHandler>(); + services.AddSingleton, UpdateHandler>(); + services.AddSingleton, UserHandler>(); + services.AddSingleton, VideocardHandler>(); + services.AddSingleton, VirtualMaschineHandler>(); + services.AddSingleton, ConsoleHandler>(); + + // GLOBAL DEPENDENCIES + services.AddTransient(provider => new HttpClient(new HttpClientHandler + { + ClientCertificateOptions = ClientCertificateOption.Manual, + ServerCertificateCustomValidationCallback = (httpRequestMessage, cert, cetChain, policyErrors) => true + })); + }); + + var host = builder.Build(); + await host.RunAsync().ConfigureAwait(false); + } } } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Services/CollectorService.cs b/src/Agent/Insight.Agent/Services/CollectorService.cs index 2058aeb..6b8d224 100644 --- a/src/Agent/Insight.Agent/Services/CollectorService.cs +++ b/src/Agent/Insight.Agent/Services/CollectorService.cs @@ -2,10 +2,16 @@ using Microsoft.Extensions.Logging.Abstractions; using System.Runtime.Versioning; -namespace Insight.Agent.Services; - -[SupportedOSPlatform("linux")] -public partial class CollectorService(ILogger? logger = null) +namespace Insight.Agent.Services { - public ILogger Logger { get; } = logger ?? NullLogger.Instance; + [SupportedOSPlatform("linux")] + public partial class CollectorService + { + public ILogger Logger { get; } + + public CollectorService(ILogger? logger = null) + { + Logger = logger ?? NullLogger.Instance; + } + } } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Services/Configurator.cs b/src/Agent/Insight.Agent/Services/Configurator.cs index 44fbace..0778ac2 100644 --- a/src/Agent/Insight.Agent/Services/Configurator.cs +++ b/src/Agent/Insight.Agent/Services/Configurator.cs @@ -1,98 +1,97 @@ using System.Text.Json; -namespace Insight.Agent.Services; - -public static class Configurator +namespace Insight.Agent.Services { - private static readonly JsonSerializerOptions _serializerOptions = new() { PropertyNameCaseInsensitive = true, WriteIndented = true }; - - public static async ValueTask ReadAsync(string file, CancellationToken cancellationToken = default) - where TConfig : class + public static class Configurator { - var json = await File.ReadAllTextAsync(file, cancellationToken); - - if (JsonSerializer.Deserialize(json, _serializerOptions) is not TConfig config) + public static async ValueTask ReadAsync(string file, CancellationToken cancellationToken = default) + where TConfig : class { - throw new InvalidDataException($"Failed to deserialize ({file})"); + var json = await File.ReadAllTextAsync(file, cancellationToken); + + if (JsonSerializer.Deserialize(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true, WriteIndented = true }) is not TConfig config) + { + throw new InvalidDataException($"Failed to deserialize ({file})"); + } + + return config; + } + public static async ValueTask ReadJsonAsync(string file, CancellationToken cancellationToken = default) + { + var json = await File.ReadAllTextAsync(file, cancellationToken); + + if (JsonDocument.Parse(json) is not JsonDocument doc) + { + throw new InvalidDataException($"Failed to deserialize ({file})"); + } + + return doc; + } + public static async ValueTask> ReadDictionaryAsync(string file, CancellationToken cancellationToken = default) + { + var json = await File.ReadAllTextAsync(file, cancellationToken); + + if (JsonSerializer.Deserialize>(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true, WriteIndented = true }) is not IDictionary config) + { + throw new InvalidDataException($"Failed to deserialize ({file})"); + } + + return config; } - return config; - } - public static async ValueTask ReadJsonAsync(string file, CancellationToken cancellationToken = default) - { - var json = await File.ReadAllTextAsync(file, cancellationToken); - - if (JsonDocument.Parse(json) is not JsonDocument doc) + public static async ValueTask WriteAsync(TConfig config, string file, CancellationToken cancellationToken) where TConfig : class { - throw new InvalidDataException($"Failed to deserialize ({file})"); + await WriteToFileAsync(config, file, cancellationToken); + } + public static async ValueTask WriteAsync(JsonDocument config, string file, CancellationToken cancellationToken) + { + await WriteToFileAsync(config, file, cancellationToken); + } + public static async ValueTask WriteAsync(IDictionary config, string file, CancellationToken cancellationToken) + { + await WriteToFileAsync(config, file, cancellationToken); } - return doc; - } - public static async ValueTask> ReadDictionaryAsync(string file, CancellationToken cancellationToken = default) - { - var json = await File.ReadAllTextAsync(file, cancellationToken); - - if (JsonSerializer.Deserialize>(json, _serializerOptions) is not IDictionary config) + public static async ValueTask AddOrUpdateAsync(KeyValuePair data, string file, CancellationToken cancellationToken) { - throw new InvalidDataException($"Failed to deserialize ({file})"); + var readData = await ReadDictionaryAsync(file, cancellationToken); + + var key = readData.Keys.FirstOrDefault(dic => string.Compare(dic, data.Key, StringComparison.OrdinalIgnoreCase) == 0); + + if (key is null) + { + readData.Add(data.Key, data.Value); + } + else + { + readData[key] = data.Value; + } + + await WriteToFileAsync(readData, file, cancellationToken); + } + public static async ValueTask RemoveAsync(string data, string file, CancellationToken cancellationToken) + { + var readData = await ReadDictionaryAsync(file, cancellationToken); + + var key = readData.Keys.FirstOrDefault(dic => string.Compare(dic, data, StringComparison.OrdinalIgnoreCase) == 0); + + if (key is null) + { + return; + } + else + { + readData.Remove(key); + } + + await WriteToFileAsync(readData, file, cancellationToken); } - return config; - } - - public static async ValueTask WriteAsync(TConfig config, string file, CancellationToken cancellationToken) where TConfig : class - { - await WriteToFileAsync(config, file, cancellationToken); - } - public static async ValueTask WriteAsync(JsonDocument config, string file, CancellationToken cancellationToken) - { - await WriteToFileAsync(config, file, cancellationToken); - } - public static async ValueTask WriteAsync(IDictionary config, string file, CancellationToken cancellationToken) - { - await WriteToFileAsync(config, file, cancellationToken); - } - - public static async ValueTask AddOrUpdateAsync(KeyValuePair data, string file, CancellationToken cancellationToken) - { - var readData = await ReadDictionaryAsync(file, cancellationToken); - - var key = readData.Keys.FirstOrDefault(dic => string.Compare(dic, data.Key, StringComparison.OrdinalIgnoreCase) == 0); - - if (key is null) + private static async ValueTask WriteToFileAsync(TData data, string file, CancellationToken cancellationToken) { - readData.Add(data.Key, data.Value); + var json = JsonSerializer.Serialize(data, new JsonSerializerOptions { WriteIndented = true }); + + await File.WriteAllTextAsync(file, json, cancellationToken); } - else - { - readData[key] = data.Value; - } - - await WriteToFileAsync(readData, file, cancellationToken); - } - public static async ValueTask RemoveAsync(string data, string file, CancellationToken cancellationToken) - { - var readData = await ReadDictionaryAsync(file, cancellationToken); - - var key = readData.Keys.FirstOrDefault(dic => string.Compare(dic, data, StringComparison.OrdinalIgnoreCase) == 0); - - if (key is null) - { - return; - } - else - { - readData.Remove(key); - } - - await WriteToFileAsync(readData, file, cancellationToken); - } - - private static async ValueTask WriteToFileAsync(TData data, string file, CancellationToken cancellationToken) - { - var json = JsonSerializer.Serialize(data, _serializerOptions); - - await File.WriteAllTextAsync(file, json, cancellationToken); } } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Services/EventService.cs b/src/Agent/Insight.Agent/Services/EventService.cs index e14d8da..2400023 100644 --- a/src/Agent/Insight.Agent/Services/EventService.cs +++ b/src/Agent/Insight.Agent/Services/EventService.cs @@ -1,170 +1,170 @@ -using Insight.Agent.Network; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; +using Insight.Agent.Messages; +using Insight.Agent.Network; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using System.Diagnostics.Eventing.Reader; using System.Runtime.Versioning; using System.Threading.Channels; using Vaitr.Network; -using static Insight.Domain.Network.Agent.Messages.Event; +using static Insight.Agent.Messages.Event; using EventLevel = System.Diagnostics.Tracing.EventLevel; -namespace Insight.Agent.Services; - -[SupportedOSPlatform("windows")] -internal class EventService : BackgroundService +namespace Insight.Agent.Services { - private readonly Channel _queue; - private readonly ISessionPool _pool; - private readonly ILogger _logger; - - public EventService(ISessionPool pool, ILogger logger) + [SupportedOSPlatform("windows")] + internal class EventService : BackgroundService { - _pool = pool; - _logger = logger; + private readonly Channel _queue; + private readonly TcpSessionPool _pool; + private readonly ILogger _logger; - _queue = Channel.CreateBounded(new BoundedChannelOptions(1000) + public EventService(TcpSessionPool pool, ILogger logger) { - SingleReader = true, - SingleWriter = true, - AllowSynchronousContinuations = false, - FullMode = BoundedChannelFullMode.DropOldest - }); - } + _pool = pool; + _logger = logger; - protected override async Task ExecuteAsync(CancellationToken cancellationToken) - { - _logger.LogTrace("ExecuteAsync"); - - while (cancellationToken.IsCancellationRequested is false) - { - try + _queue = Channel.CreateBounded(new BoundedChannelOptions(1000) { - var tasks = new List + SingleReader = true, + SingleWriter = true, + AllowSynchronousContinuations = false, + FullMode = BoundedChannelFullMode.DropOldest + }); + } + + protected override async Task ExecuteAsync(CancellationToken cancellationToken) + { + _logger.LogTrace("ExecuteAsync"); + + while (cancellationToken.IsCancellationRequested is false) + { + try { - HandleQueueAsync(cancellationToken), - WatchAsync("Application", "*", cancellationToken), - WatchAsync("Security", "*", cancellationToken), - WatchAsync("System", "*", cancellationToken), - WatchAsync("Microsoft-Windows-PrintService/Admin", "*", cancellationToken), - WatchAsync("Microsoft-Windows-TaskScheduler/Operational", "*", cancellationToken), - WatchAsync("Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational", "*", cancellationToken), - WatchAsync("Microsoft-Windows-TerminalServices-LocalSessionManager/Operational", "*", cancellationToken), - WatchAsync("Microsoft-Windows-TerminalServices-RDPClient/Operational", "*", cancellationToken), - WatchAsync("Microsoft-Windows-SmbClient/Connectivity", "*", cancellationToken), - WatchAsync("Microsoft-Windows-SmbClient/Security", "*", cancellationToken), - WatchAsync("Microsoft-Windows-SMBServer/Security", "*", cancellationToken), - WatchAsync("Microsoft-Windows-StorageSpaces-Driver/Operational", "*", cancellationToken), - WatchAsync("Microsoft-Windows-Diagnostics-Performance/Operational", "*", cancellationToken) - }; + var tasks = new List + { + HandleQueueAsync(cancellationToken), + WatchAsync("Application", "*", cancellationToken), + WatchAsync("Security", "*", cancellationToken), + WatchAsync("System", "*", cancellationToken), + WatchAsync("Microsoft-Windows-PrintService/Admin", "*", cancellationToken), + WatchAsync("Microsoft-Windows-TaskScheduler/Operational", "*", cancellationToken), + WatchAsync("Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational", "*", cancellationToken), + WatchAsync("Microsoft-Windows-TerminalServices-LocalSessionManager/Operational", "*", cancellationToken), + WatchAsync("Microsoft-Windows-TerminalServices-RDPClient/Operational", "*", cancellationToken), + WatchAsync("Microsoft-Windows-SmbClient/Connectivity", "*", cancellationToken), + WatchAsync("Microsoft-Windows-SmbClient/Security", "*", cancellationToken), + WatchAsync("Microsoft-Windows-SMBServer/Security", "*", cancellationToken), + WatchAsync("Microsoft-Windows-StorageSpaces-Driver/Operational", "*", cancellationToken), + WatchAsync("Microsoft-Windows-Diagnostics-Performance/Operational", "*", cancellationToken) + }; - await Task.WhenAll(tasks); + await Task.WhenAll(tasks); + } + catch (OperationCanceledException) { } + catch (Exception ex) + { + _logger.LogError("{ex}", ex); + } } - catch (OperationCanceledException) { } - catch (Exception ex) + } + + private async Task WatchAsync(string path, string query, CancellationToken cancellationToken) + { + var config = new EventLogConfiguration(path); + if (config is null) return; + + if (config.IsEnabled is false) { - _logger.LogError("{ex}", ex); + config.IsEnabled = true; + config.SaveChanges(); } - } - } - private async Task WatchAsync(string path, string query, CancellationToken cancellationToken) - { - var config = new EventLogConfiguration(path); - if (config is null) return; - - if (config.IsEnabled is false) - { - config.IsEnabled = true; - config.SaveChanges(); - } - - var watcher = new EventLogWatcher(new EventLogQuery(path, PathType.LogName, query) - { - TolerateQueryErrors = true, - Session = EventLogSession.GlobalSession - }); - - try - { - watcher.EventRecordWritten += new EventHandler(OnEvent); - watcher.Enabled = true; - - using var semaphore = new SemaphoreSlim(0, 1); - await semaphore.WaitAsync(cancellationToken); - } - catch (Exception) { } - finally - { - watcher.EventRecordWritten -= new EventHandler(OnEvent); - watcher.Enabled = false; - - watcher?.Dispose(); - } - } - - private async Task HandleQueueAsync(CancellationToken cancellationToken) - { - while (await _queue.Reader.WaitToReadAsync(cancellationToken)) - { - var session = _pool.FirstOrDefault(); - - if (session.Value is null) + var watcher = new EventLogWatcher(new EventLogQuery(path, PathType.LogName, query) { - await Task.Delay(10000, cancellationToken); - continue; - } - - if (_queue.Reader.TryRead(out var item) is false) - { - await Task.Delay(1000, cancellationToken); - continue; - } + TolerateQueryErrors = true, + Session = EventLogSession.GlobalSession + }); try { - await session.Value.SendAsync(item, cancellationToken); + watcher.EventRecordWritten += new EventHandler(OnEvent); + watcher.Enabled = true; + + using var semaphore = new SemaphoreSlim(0, 1); + await semaphore.WaitAsync(cancellationToken); } - catch (OperationCanceledException) { } - catch (Exception ex) + catch (Exception) { } + finally { - _logger.LogError("{ex}", ex); - await Task.Delay(10000, cancellationToken); + watcher.EventRecordWritten -= new EventHandler(OnEvent); + watcher.Enabled = false; + + watcher?.Dispose(); } } - } - private void OnEvent(object? sender, EventRecordWrittenEventArgs e) - { - if (e is null || e.EventRecord is null) return; - - try + private async Task HandleQueueAsync(CancellationToken cancellationToken) { - var @event = new Event + while (await _queue.Reader.WaitToReadAsync(cancellationToken)) { - Timestamp = e?.EventRecord?.TimeCreated, - EventId = e?.EventRecord?.Id, - Source = e?.EventRecord?.ProviderName, - Category = e?.EventRecord?.LogName, - Task = e?.EventRecord?.TaskDisplayName, - Message = e?.EventRecord?.FormatDescription(), - }; + var session = _pool.FirstOrDefault(); - if (e?.EventRecord?.Level is not null) - { - @event.Status = (EventLevel)Convert.ToInt32(e?.EventRecord?.Level) switch + if (session.Value is null) { - EventLevel.Informational => StatusType.Information, - EventLevel.Warning => StatusType.Warning, - EventLevel.Error => StatusType.Error, - EventLevel.Critical => StatusType.Critical, - _ => StatusType.Information, - }; - } + await Task.Delay(10000, cancellationToken); + continue; + } - _ = _queue.Writer.WriteAsync(@event, default); + if (_queue.Reader.TryRead(out var item) is false) + { + await Task.Delay(1000, cancellationToken); + continue; + } + + try + { + await session.Value.SendAsync(item, cancellationToken); + } + catch (OperationCanceledException) { } + catch (Exception ex) + { + _logger.LogError("{ex}", ex); + await Task.Delay(10000, cancellationToken); + } + } + } + + private void OnEvent(object? sender, EventRecordWrittenEventArgs e) + { + if (e is null || e.EventRecord is null) return; + + try + { + var @event = new Event + { + Timestamp = e?.EventRecord?.TimeCreated, + EventId = e?.EventRecord?.Id, + Source = e?.EventRecord?.ProviderName, + Category = e?.EventRecord?.LogName, + Task = e?.EventRecord?.TaskDisplayName, + Message = e?.EventRecord?.FormatDescription(), + }; + + if (e?.EventRecord?.Level is not null) + { + @event.Status = (EventLevel)Convert.ToInt32(e?.EventRecord?.Level) switch + { + EventLevel.Informational => StatusType.Information, + EventLevel.Warning => StatusType.Warning, + EventLevel.Error => StatusType.Error, + EventLevel.Critical => StatusType.Critical, + _ => StatusType.Information, + }; + } + + _queue.Writer.WriteAsync(@event, default); + } + catch (Exception) { } // app crash } - catch (Exception) { } // app crash } } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Services/TrapService.cs b/src/Agent/Insight.Agent/Services/TrapService.cs index cd1a1a9..13051d5 100644 --- a/src/Agent/Insight.Agent/Services/TrapService.cs +++ b/src/Agent/Insight.Agent/Services/TrapService.cs @@ -1,6 +1,5 @@ -using Insight.Agent.Network; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; +using Insight.Agent.Messages; +using Insight.Agent.Network; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; @@ -10,190 +9,192 @@ using System.Net.Sockets; using System.Threading.Channels; using Vaitr.Network; -namespace Insight.Agent.Services; - -public class TrapService : BackgroundService +namespace Insight.Agent.Services { - private static IPEndPoint EndpointCache { get; } = new(IPAddress.Any, 0); - private readonly Channel _queue; - - private readonly int _port; - private readonly ISessionPool _pool; - private readonly ILogger _logger; - - public TrapService(ISessionPool pool, IConfiguration configuration, ILogger logger) + public class TrapService : BackgroundService { - _port = configuration.GetValue(Appsettings.TrapPort) ?? throw new Exception($"{Appsettings.TrapPort} value not set (appsettings)"); - _pool = pool; - _logger = logger; + private static IPEndPoint EndpointCache { get; } = new(IPAddress.Any, 0); + private readonly Channel _queue; - _queue = Channel.CreateBounded(new BoundedChannelOptions(100) + + private readonly int _port; + private readonly TcpSessionPool _pool; + private readonly ILogger _logger; + + public TrapService(TcpSessionPool pool, IConfiguration configuration, ILogger logger) { - SingleReader = false, - SingleWriter = true, - AllowSynchronousContinuations = false, - FullMode = BoundedChannelFullMode.DropOldest - }); - } + _port = configuration.GetValue(Appsettings.TrapPort) ?? throw new Exception($"{Appsettings.TrapPort} value not set (appsettings)"); + _pool = pool; + _logger = logger; - protected override async Task ExecuteAsync(CancellationToken cancellationToken) - { - _logger.LogTrace("ExecuteAsync"); + _queue = Channel.CreateBounded(new BoundedChannelOptions(100) + { + SingleReader = false, + SingleWriter = true, + AllowSynchronousContinuations = false, + FullMode = BoundedChannelFullMode.DropOldest + }); + } - while (cancellationToken.IsCancellationRequested is false) + protected override async Task ExecuteAsync(CancellationToken cancellationToken) { + _logger.LogTrace("ExecuteAsync"); + + while (cancellationToken.IsCancellationRequested is false) + { + try + { + var tasks = new List + { + HandleQueueAsync(cancellationToken), + ListenAsync(cancellationToken) + }; + + await Task.WhenAll(tasks); + } + catch (OperationCanceledException) { } + catch (Exception ex) + { + _logger.LogError("{ex}", ex); + } + } + } + + private async Task HandleQueueAsync(CancellationToken cancellationToken) + { + while (await _queue.Reader.WaitToReadAsync(cancellationToken)) + { + var session = _pool.FirstOrDefault(); + + if (session.Value is null) + { + await Task.Delay(10000, cancellationToken); + continue; + } + + if (_queue.Reader.TryRead(out var item) is false) + { + await Task.Delay(1000, cancellationToken); + continue; + } + + try + { + await session.Value.SendAsync(item, cancellationToken); + } + catch (OperationCanceledException) { } + catch (Exception ex) + { + _logger.LogError("{ex}", ex); + await Task.Delay(10000, cancellationToken); + } + } + } + + private async Task ListenAsync(CancellationToken cancellationToken) + { + using var udpSocket = new Socket(SocketType.Dgram, ProtocolType.Udp); + + cancellationToken.Register(udpSocket.Dispose); + + udpSocket.Bind(new IPEndPoint(IPAddress.Any, _port)); + + var buffer = GC.AllocateArray(length: 65527, pinned: true); + var bufferMem = buffer.AsMemory(); + + while (cancellationToken.IsCancellationRequested is false) + { + try + { + var result = await udpSocket.ReceiveFromAsync(bufferMem, SocketFlags.None, EndpointCache, cancellationToken); + + if (result.ReceivedBytes == 0) continue; + + var actualBytes = bufferMem[..result.ReceivedBytes].ToArray(); + + var ep = (IPEndPoint)result.RemoteEndPoint; + + await ProcessAsync(ep, actualBytes, cancellationToken); + } + catch (SocketException) { continue; } + catch (IOException) { continue; } + catch (Exception) { continue; } + } + } + + private async ValueTask ProcessAsync(IPEndPoint endpoint, byte[] buffer, CancellationToken cancellationToken) + { + var trap = new Trap + { + Timestamp = DateTime.Now, + Endpoint = endpoint.ToString(), + }; + try { - var tasks = new List - { - HandleQueueAsync(cancellationToken), - ListenAsync(cancellationToken) - }; + var protocol = (SnmpVersion)SnmpPacket.GetProtocolVersion(buffer, buffer.Length); - await Task.WhenAll(tasks); + trap.Version = protocol.ToString(); + trap.Hostname = Dns.GetHostEntry(endpoint.Address)?.HostName; + + if (protocol == SnmpVersion.Ver1) + { + var packet = new SnmpV1TrapPacket(); + packet.decode(buffer, buffer.Length); + + trap.Community = packet?.Community?.ToString(); + + if (packet?.Pdu?.VbList is not null) + { + trap.Data = ConvertVbs(packet.Pdu.VbList); + } + } + + if (protocol == SnmpVersion.Ver2) + { + var packet = new SnmpV2Packet(); + packet.decode(buffer, buffer.Length); + + trap.Community = packet?.Community?.ToString(); + + if (packet?.Pdu?.VbList is not null) + { + trap.Data = ConvertVbs(packet.Pdu.VbList); + } + } + + if (protocol == SnmpVersion.Ver3) + { + var packet = new SnmpV3Packet(); + } } - catch (OperationCanceledException) { } catch (Exception ex) { _logger.LogError("{ex}", ex); } + + await _queue.Writer.WriteAsync(trap, cancellationToken); } - } - private async Task HandleQueueAsync(CancellationToken cancellationToken) - { - while (await _queue.Reader.WaitToReadAsync(cancellationToken)) + private List>? ConvertVbs(VbCollection vbs) { - var session = _pool.FirstOrDefault(); - - if (session.Value is null) - { - await Task.Delay(10000, cancellationToken); - continue; - } - - if (_queue.Reader.TryRead(out var item) is false) - { - await Task.Delay(1000, cancellationToken); - continue; - } + var data = new List>(); try { - await session.Value.SendAsync(item, cancellationToken); + foreach (var item in vbs) + { + if (item.Oid is null) continue; + + data.Add(new KeyValuePair(item.Oid.ToString(), item?.Value?.ToString())); + } } - catch (OperationCanceledException) { } catch (Exception ex) { _logger.LogError("{ex}", ex); - await Task.Delay(10000, cancellationToken); - } - } - } - - private async Task ListenAsync(CancellationToken cancellationToken) - { - using var udpSocket = new Socket(SocketType.Dgram, ProtocolType.Udp); - - cancellationToken.Register(udpSocket.Dispose); - - udpSocket.Bind(new IPEndPoint(IPAddress.Any, _port)); - - var buffer = GC.AllocateArray(length: 65527, pinned: true); - var bufferMem = buffer.AsMemory(); - - while (cancellationToken.IsCancellationRequested is false) - { - try - { - var result = await udpSocket.ReceiveFromAsync(bufferMem, SocketFlags.None, EndpointCache, cancellationToken); - - if (result.ReceivedBytes == 0) continue; - - var actualBytes = bufferMem[..result.ReceivedBytes].ToArray(); - - var ep = (IPEndPoint)result.RemoteEndPoint; - - await ProcessAsync(ep, actualBytes, cancellationToken); - } - catch (SocketException) { continue; } - catch (IOException) { continue; } - catch (Exception) { continue; } - } - } - - private async ValueTask ProcessAsync(IPEndPoint endpoint, byte[] buffer, CancellationToken cancellationToken) - { - var trap = new Trap - { - Timestamp = DateTime.Now, - Endpoint = endpoint.ToString(), - }; - - try - { - var protocol = (SnmpVersion)SnmpPacket.GetProtocolVersion(buffer, buffer.Length); - - trap.Version = protocol.ToString(); - trap.Hostname = Dns.GetHostEntry(endpoint.Address)?.HostName; - - if (protocol == SnmpVersion.Ver1) - { - var packet = new SnmpV1TrapPacket(); - packet.decode(buffer, buffer.Length); - - trap.Community = packet?.Community?.ToString(); - - if (packet?.Pdu?.VbList is not null) - { - trap.Data = ConvertVbs(packet.Pdu.VbList); - } } - if (protocol == SnmpVersion.Ver2) - { - var packet = new SnmpV2Packet(); - packet.decode(buffer, buffer.Length); - - trap.Community = packet?.Community?.ToString(); - - if (packet?.Pdu?.VbList is not null) - { - trap.Data = ConvertVbs(packet.Pdu.VbList); - } - } - - if (protocol == SnmpVersion.Ver3) - { - var packet = new SnmpV3Packet(); - } + return data; } - catch (Exception ex) - { - _logger.LogError("{ex}", ex); - } - - await _queue.Writer.WriteAsync(trap, cancellationToken); - } - - private List>? ConvertVbs(VbCollection vbs) - { - var data = new List>(); - - try - { - foreach (var item in vbs) - { - if (item.Oid is null) continue; - - data.Add(new KeyValuePair(item.Oid.ToString(), item?.Value?.ToString())); - } - } - catch (Exception ex) - { - _logger.LogError("{ex}", ex); - } - - return data; } } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Services/UpdateService.cs b/src/Agent/Insight.Agent/Services/UpdateService.cs index 18df6fe..6869d58 100644 --- a/src/Agent/Insight.Agent/Services/UpdateService.cs +++ b/src/Agent/Insight.Agent/Services/UpdateService.cs @@ -10,343 +10,351 @@ using System.Runtime.Versioning; using System.ServiceProcess; using System.Text.Json; -namespace Insight.Agent.Services; - -internal class UpdateService(HttpClient httpClient, IConfiguration configuration, ILogger logger) : BackgroundService +namespace Insight.Agent.Services { - private readonly Uri _uri = configuration.GetValue("api") ?? throw new Exception($"api value not set (appsettings)"); - - private readonly HttpClient _httpClient = httpClient; - private readonly ILogger _logger = logger; - - protected override async Task ExecuteAsync(CancellationToken cancellationToken) + internal class UpdateService : BackgroundService { - _logger.LogTrace("ExecuteAsync"); + private readonly Uri _uri; - while (cancellationToken.IsCancellationRequested is false) + private readonly HttpClient _httpClient; + private readonly ILogger _logger; + + public UpdateService(HttpClient httpClient, IConfiguration configuration, ILogger logger) { - try - { - UpdateResult? result = null; - - if (OperatingSystem.IsWindows()) result = await WindowsUpdateAsync(cancellationToken); - if (OperatingSystem.IsLinux()) result = await LinuxUpdateAsync(cancellationToken); - - _logger.LogInformation("Update Result: {result}", result?.Success); - if (result?.UpdateErrors is not null) - { - _logger.LogError("Update Errors: {errors}", string.Concat(result.UpdateErrors)); - } - } - catch (OperationCanceledException) { } - catch (Exception ex) // may inform via client / api about errors - { - _logger.LogError("{ex}", ex.Message); - } - finally - { - await Task.Delay(TimeSpan.FromMinutes(1), cancellationToken); - } + _httpClient = httpClient; + _uri = configuration.GetValue("api") ?? throw new Exception($"api value not set (appsettings)"); + _logger = logger; } - } - [SupportedOSPlatform("windows")] - private async ValueTask WindowsUpdateAsync(CancellationToken cancellationToken) - { - return await Windows.Service.UpdateAsync( - _httpClient, - Deploy.GetUpdateHref(_uri, Deploy.Updater.Name), - Deploy.GetAppExecutable(Deploy.Updater.Name), - Deploy.Updater.ServiceName, - cancellationToken); - } - - [SupportedOSPlatform("linux")] - private ValueTask LinuxUpdateAsync(CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } - - [SupportedOSPlatform("windows")] - private static class Windows - { - public static class Service + protected override async Task ExecuteAsync(CancellationToken cancellationToken) { - public static bool ServiceExistence(string serviceName) + _logger.LogTrace("ExecuteAsync"); + + while (cancellationToken.IsCancellationRequested is false) { try { - if (ServiceController.GetServices().Any(s => s.ServiceName.Equals(serviceName, StringComparison.InvariantCultureIgnoreCase))) return true; + UpdateResult? result = null; + + if (OperatingSystem.IsWindows()) result = await WindowsUpdateAsync(cancellationToken); + if (OperatingSystem.IsLinux()) result = await LinuxUpdateAsync(cancellationToken); + + _logger.LogInformation("Update Result: {result}", result?.Success); + if (result?.UpdateErrors is not null) + { + _logger.LogError("Update Errors: {errors}", string.Concat(result?.UpdateErrors)); + } + } + catch (OperationCanceledException) { } + catch (Exception ex) // may inform via client / api about errors + { + _logger.LogError("{ex}", ex.Message); + } + finally + { + await Task.Delay(TimeSpan.FromMinutes(1), cancellationToken); + } + } + } + + [SupportedOSPlatform("windows")] + private async ValueTask WindowsUpdateAsync(CancellationToken cancellationToken) + { + return await Windows.Service.UpdateAsync( + _httpClient, + Deploy.GetUpdateHref(_uri, Deploy.Updater.Name), + Deploy.GetAppExecutable(Deploy.Updater.Name), + Deploy.Updater.ServiceName, + cancellationToken); + } + + [SupportedOSPlatform("linux")] + private ValueTask LinuxUpdateAsync(CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + [SupportedOSPlatform("windows")] + private static class Windows + { + public static class Service + { + public static bool ServiceExistence(string serviceName) + { + try + { + if (ServiceController.GetServices().Any(s => s.ServiceName.Equals(serviceName, StringComparison.InvariantCultureIgnoreCase))) return true; + return false; + } + catch (Exception) { } + return false; } - catch (Exception) { } - return false; - } - - public static bool SetServiceState(string app, ServiceControllerStatus status, TimeSpan timeout) - { - try + public static bool SetServiceState(string app, ServiceControllerStatus status, TimeSpan timeout) { - using var sc = ServiceController.GetServices().FirstOrDefault(s => s.ServiceName.Equals(app, StringComparison.InvariantCultureIgnoreCase)); - if (sc is null) return false; - - if (sc.Status != status) + try { - switch (status) - { - case ServiceControllerStatus.Running: - sc.Start(); - break; + using var sc = ServiceController.GetServices().FirstOrDefault(s => s.ServiceName.Equals(app, StringComparison.InvariantCultureIgnoreCase)); + if (sc is null) return false; - case ServiceControllerStatus.Stopped: - sc.Stop(); - break; + if (sc.Status != status) + { + switch (status) + { + case ServiceControllerStatus.Running: + sc.Start(); + break; + + case ServiceControllerStatus.Stopped: + sc.Stop(); + break; + } + + sc.WaitForStatus(status, timeout); } - sc.WaitForStatus(status, timeout); + return true; } + catch (Exception) { } - return true; + return false; } - catch (Exception) { } - return false; - } - - public static async ValueTask UpdateAsync(HttpClient httpClient, Uri api, FileInfo bin, string serviceName, CancellationToken cancellationToken) - { - var result = new UpdateResult + public static async ValueTask UpdateAsync(HttpClient httpClient, Uri api, FileInfo bin, string serviceName, CancellationToken cancellationToken) { - Api = api?.ToString(), - SourceDirectory = bin.Directory?.FullName, - App = bin.Name, - ServiceName = serviceName - }; - - try - { - // check if service exists - if (ServiceExistence(serviceName) is false) + var result = new UpdateResult { - result.UpdateErrors.Add("service not found"); - return result; - } + Api = api?.ToString(), + SourceDirectory = bin.Directory?.FullName, + App = bin.Name, + ServiceName = serviceName + }; - // get service update details - var response = await httpClient.GetFromJsonAsync(api, cancellationToken); - if (response is null) + try { - result.ApiErrors.Add("not available / response null"); - return result; - } + // check if service exists + if (ServiceExistence(serviceName) is false) + { + result.UpdateErrors.Add("service not found"); + return result; + } - result.ApiAvailable = true; + // get service update details + var response = await httpClient.GetFromJsonAsync(api, cancellationToken); + if (response is null) + { + result.ApiErrors.Add("not available / response null"); + return result; + } - // check if local binary exists - if (bin is null) - { - result.UpdateErrors.Add("source binary not found"); - return result; - } + result.ApiAvailable = true; - // get local file binary version - if (FileVersionInfo.GetVersionInfo(bin.FullName).FileVersion is not string binVersionString) - { - result.UpdateErrors.Add("source binary fileversion not valid"); - return result; - } + // check if local binary exists + if (bin is null) + { + result.UpdateErrors.Add("source binary not found"); + return result; + } + + // get local file binary version + if (FileVersionInfo.GetVersionInfo(bin.FullName).FileVersion is not string binVersionString) + { + result.UpdateErrors.Add("source binary fileversion not valid"); + return result; + } + + // compare local against update version, skip lower or equal update version + var actualVersion = Version.Parse(binVersionString); + if (actualVersion >= response.Version) + { + result.Success = true; + return result; + } + else + { + result.UpdateAvailable = true; + } + + // get update file (bytes) to memory + using var update = await httpClient.GetAsync(response.Uri, cancellationToken); + if (update is null) + { + result.ApiErrors.Add("update source not available"); + return result; + } + + // stop service + if (SetServiceState(serviceName, ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(10)) is false) + { + result.UpdateErrors.Add("service control failed / failed to stop service"); + return result; + } + + // read update archive to temp (overwrite) + var temp = Directory.CreateTempSubdirectory(); + var updateFile = new FileInfo($@"{temp.FullName}/{bin.Name}.zip"); + + await File.WriteAllBytesAsync(updateFile.FullName, await update.Content.ReadAsByteArrayAsync(cancellationToken), cancellationToken); + + // extract update archive from temp to app dir (overwrite) + ZipFile.ExtractToDirectory(updateFile.FullName, bin.Directory?.FullName, true); + + // delete temp folder + if (temp.Exists) temp.Delete(true); + + // start updateds service + if (SetServiceState(serviceName, ServiceControllerStatus.Running, TimeSpan.FromSeconds(10)) is false) + { + result.UpdateErrors.Add("service control failed / failed to start service"); + return result; + } - // compare local against update version, skip lower or equal update version - var actualVersion = Version.Parse(binVersionString); - if (actualVersion >= response.Version) - { result.Success = true; - return result; } - else + catch (Exception ex) { - result.UpdateAvailable = true; + result.UpdateErrors.Add(ex.Message); } - // get update file (bytes) to memory - using var update = await httpClient.GetAsync(response.Uri, cancellationToken); - if (update is null) - { - result.ApiErrors.Add("update source not available"); - return result; - } - - // stop service - if (SetServiceState(serviceName, ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(10)) is false) - { - result.UpdateErrors.Add("service control failed / failed to stop service"); - return result; - } - - // read update archive to temp (overwrite) - var temp = Directory.CreateTempSubdirectory(); - var updateFile = new FileInfo($@"{temp.FullName}/{bin.Name}.zip"); - - await File.WriteAllBytesAsync(updateFile.FullName, await update.Content.ReadAsByteArrayAsync(cancellationToken), cancellationToken); - - // extract update archive from temp to app dir (overwrite) - ZipFile.ExtractToDirectory(updateFile.FullName, bin.Directory!.FullName, true); - - // delete temp folder - if (temp.Exists) temp.Delete(true); - - // start updateds service - if (SetServiceState(serviceName, ServiceControllerStatus.Running, TimeSpan.FromSeconds(10)) is false) - { - result.UpdateErrors.Add("service control failed / failed to start service"); - return result; - } - - result.Success = true; + return result; } - catch (Exception ex) - { - result.UpdateErrors.Add(ex.Message); - } - - return result; - } - } - - public static class Process - { - public static bool IsRunning(FileInfo bin) - { - if (bin.Exists is false) return false; - - var matched = System.Diagnostics.Process.GetProcessesByName(bin.FullName); - - if (matched is null || matched.Length == 0) return false; - - if (matched.Any(p => - p.MainModule is not null && - p.MainModule.FileName is not null && - p.MainModule.FileName.Equals(bin.FullName, - StringComparison.InvariantCultureIgnoreCase))) return true; - - return false; } - public static bool Start(FileInfo binary) + public static class Process { - try + public static bool IsRunning(FileInfo bin) { - if (IsRunning(binary) is false) return false; - - using var process = System.Diagnostics.Process.Start(binary.FullName); - return true; - } - catch (Exception) { } - - return false; - } - - public static bool Stop(FileInfo bin, TimeSpan timeout) - { - try - { - if (IsRunning(bin) is false) return false; + if (bin.Exists is false) return false; var matched = System.Diagnostics.Process.GetProcessesByName(bin.FullName); - if (matched is null || matched.Length == 0) return true; + if (matched is null || matched.Any() is false) return false; - foreach (var procsInfo in matched.Where(p => + if (matched.Any(p => p.MainModule is not null && p.MainModule.FileName is not null && - p.MainModule.FileName.Equals(bin.FullName, StringComparison.InvariantCultureIgnoreCase))) + p.MainModule.FileName.Equals(bin.FullName, + StringComparison.InvariantCultureIgnoreCase))) return true; + + return false; + } + + public static bool Start(FileInfo binary) + { + try { - if (procsInfo.CloseMainWindow()) procsInfo.WaitForExit((int)timeout.TotalMilliseconds); - if (procsInfo.HasExited is false) procsInfo.Kill(true); + if (IsRunning(binary) is false) return false; + + using var process = System.Diagnostics.Process.Start(binary.FullName); + return true; } + catch (Exception) { } - return true; + return false; } - catch (Exception) { } - return false; - } - - public static async ValueTask UpdateAsync(HttpClient httpClient, Uri api, FileInfo bin, CancellationToken cancellationToken) - { - if (IsRunning(bin) is false) return false; - - var response = await httpClient.GetFromJsonAsync(api.AbsoluteUri, new JsonSerializerOptions + public static bool Stop(FileInfo bin, TimeSpan timeout) { - IncludeFields = true - }, cancellationToken); + try + { + if (IsRunning(bin) is false) return false; - if (response is null) return false; + var matched = System.Diagnostics.Process.GetProcessesByName(bin.FullName); - Version actualVersion; + if (matched is null || matched.Any() is false) return true; - if (FileVersionInfo.GetVersionInfo(bin.FullName).FileVersion is not string binVersionString) return false; + foreach (var procsInfo in matched.Where(p => + p.MainModule is not null && + p.MainModule.FileName is not null && + p.MainModule.FileName.Equals(bin.FullName, StringComparison.InvariantCultureIgnoreCase))) + { + if (procsInfo.CloseMainWindow()) procsInfo.WaitForExit((int)timeout.TotalMilliseconds); + if (procsInfo.HasExited is false) procsInfo.Kill(true); + } - try - { - actualVersion = Version.Parse(binVersionString); - if (actualVersion >= response.Version) return false; + return true; + } + catch (Exception) { } - using var update = await httpClient.GetAsync(response.Uri, cancellationToken); - if (update is null) return false; - - Stop(bin, TimeSpan.FromSeconds(60)); - - // read update archive to temp (overwrite) - var temp = Directory.CreateTempSubdirectory(); - var updateFile = new FileInfo($@"{temp.FullName}/{bin.Name}.zip"); - - await File.WriteAllBytesAsync(updateFile.FullName, await update.Content.ReadAsByteArrayAsync(cancellationToken), cancellationToken); - - // extract update archive from temp to app dir (overwrite) - ZipFile.ExtractToDirectory(updateFile.FullName, bin.Directory!.FullName, true); - - // delete temp folder - if (temp.Exists) temp.Delete(true); - - // rewrite with options to start user session process - //Start(app, directory, TimeSpan.FromSeconds(60)); - - return true; + return false; } - catch (Exception) { } - return false; - } - - public static bool Delete(FileInfo bin, TimeSpan timeout) - { - try + public static async ValueTask UpdateAsync(HttpClient httpClient, Uri api, FileInfo bin, CancellationToken cancellationToken) { - Stop(bin, timeout); - bin.Delete(); + if (IsRunning(bin) is false) return false; - return true; + var response = await httpClient.GetFromJsonAsync(api.AbsoluteUri, new JsonSerializerOptions + { + IncludeFields = true + }, cancellationToken); + + if (response is null) return false; + + Version actualVersion; + + if (FileVersionInfo.GetVersionInfo(bin.FullName).FileVersion is not string binVersionString) return false; + + try + { + actualVersion = Version.Parse(binVersionString); + if (actualVersion >= response.Version) return false; + + using var update = await httpClient.GetAsync(response.Uri, cancellationToken); + if (update is null) return false; + + Stop(bin, TimeSpan.FromSeconds(60)); + + // read update archive to temp (overwrite) + var temp = Directory.CreateTempSubdirectory(); + var updateFile = new FileInfo($@"{temp.FullName}/{bin.Name}.zip"); + + await File.WriteAllBytesAsync(updateFile.FullName, await update.Content.ReadAsByteArrayAsync(cancellationToken), cancellationToken); + + // extract update archive from temp to app dir (overwrite) + ZipFile.ExtractToDirectory(updateFile.FullName, bin.Directory?.FullName, true); + + // delete temp folder + if (temp.Exists) temp.Delete(true); + + // rewrite with options to start user session process + //Start(app, directory, TimeSpan.FromSeconds(60)); + + return true; + } + catch (Exception) { } + + return false; } - catch (Exception) { } - return false; + public static bool Delete(FileInfo bin, TimeSpan timeout) + { + try + { + Stop(bin, timeout); + bin.Delete(); + + return true; + } + catch (Exception) { } + + return false; + } } } - } - public class UpdateResult - { - public string? Api { get; set; } - public string? SourceDirectory { get; set; } - public string? App { get; set; } - public string? ServiceName { get; set; } + public class UpdateResult + { + public string? Api { get; set; } + public string? SourceDirectory { get; set; } + public string? App { get; set; } + public string? ServiceName { get; set; } - public bool ApiAvailable { get; set; } = false; - public bool UpdateAvailable { get; set; } = false; - public bool Success { get; set; } = false; - public List ApiErrors { get; } = []; - public List UpdateErrors { get; } = []; + public bool ApiAvailable { get; set; } = false; + public bool UpdateAvailable { get; set; } = false; + public bool Success { get; set; } = false; + public List ApiErrors { get; } = new(); + public List UpdateErrors { get; } = new(); + } } } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Services/_Collector/_Os.cs b/src/Agent/Insight.Agent/Services/_Collector/_Os.cs index d1d2daa..7b3eb0e 100644 --- a/src/Agent/Insight.Agent/Services/_Collector/_Os.cs +++ b/src/Agent/Insight.Agent/Services/_Collector/_Os.cs @@ -1,107 +1,106 @@ -using Insight.Domain.Extensions; -using Insight.Domain.Network.Agent.Messages; +using Insight.Agent.Extensions; +using Insight.Agent.Messages; using Microsoft.Extensions.Logging; using System.Text.RegularExpressions; -namespace Insight.Agent.Services; - -public partial class CollectorService +namespace Insight.Agent.Services { - public OperationSystem? GetOperatingSystem() + public partial class CollectorService { - Logger.LogTrace("GetOperatingSystem"); + public OperationSystem? GetOperatingSystem() + { + Logger.LogTrace("GetOperatingSystem"); - var os = new OperationSystem(); + var os = new OperationSystem(); - // get uptime - var output = string.Empty; + // get uptime + var output = string.Empty; - // read file - using var stream = File.OpenText(@"/proc/uptime"); - output = stream.ReadToEnd(); + // read file + using var stream = File.OpenText(@"/proc/uptime"); + output = stream.ReadToEnd(); - // clean output - var clean = CleanRegex().Replace(output - .Trim() - .Replace("\t", " "), " "); - - var elements = clean.Split(Array.Empty(), StringSplitOptions.RemoveEmptyEntries); - - // assign values - //os.Uptime = DateTime.Now - TimeSpan.FromSeconds(double.Parse(elements.ElementAt(0))); - - // request data with process - output = "hostnamectl".Bash(); - - // linebreak list conversion - var lines = new List(output - .Split(separator, StringSplitOptions.RemoveEmptyEntries)) - .Select(l => - { - return CleanRegex().Replace(l + // clean output + var clean = Regex + .Replace(output .Trim() - .Replace("\t", " "), " "); - }) - .ToList(); + .Replace("\t", " "), @"[ ]{2,}", " "); - // assign values - os.Virtual = lines - .Any(l => l - .StartsWith("Virtualization:")) && !string.IsNullOrEmpty(lines - .Where(l => l - .StartsWith("Virtualization:")) - .First() - .Split("Virtualization:")[1] - .Trim()); + var elements = clean.Split(Array.Empty(), StringSplitOptions.RemoveEmptyEntries); - // OS - // request data with process - output = "hostnamectl".Bash(); + // assign values + //os.Uptime = DateTime.Now - TimeSpan.FromSeconds(double.Parse(elements.ElementAt(0))); - // linebreak list conversion - lines = new List(output - .Split(separator, StringSplitOptions.RemoveEmptyEntries)) - .Select(l => - { - return CleanRegex().Replace(l - .Trim() - .Replace("\t", " "), " "); - }) - .ToList(); + // request data with process + output = "hostnamectl".Bash(); - // assign values - os.Name = lines - .Any(l => l - .StartsWith("Operating System:")) ? lines - .Where(l => l - .StartsWith("Operating System:")) - .First() - .Split("Operating System:")[1] - .Trim() : string.Empty; + // linebreak list conversion + var lines = new List(output + .Split(new string[] { "\n", "\r\n" }, StringSplitOptions.RemoveEmptyEntries)) + .Select(l => + { + return Regex + .Replace(l + .Trim() + .Replace("\t", " "), @"[ ]{2,}", " "); + }) + .ToList(); - os.Version = lines - .Any(l => l - .StartsWith("Kernel:")) ? lines - .Where(l => l - .StartsWith("Kernel:")) - .First() - .Split("Kernel:")[1] - .Trim() : string.Empty; + // assign values + os.Virtual = lines + .Any(l => l + .StartsWith("Virtualization:")) && !string.IsNullOrEmpty(lines + .Where(l => l + .StartsWith("Virtualization:")) + .First() + .Split("Virtualization:")[1] + .Trim()); - var architecture = lines - .Any(l => l - .StartsWith("Architecture:")) ? lines - .Where(l => l - .StartsWith("Architecture:")) - .First() - .Split("Architecture:")[1] - .Trim() : string.Empty; + // OS + // request data with process + output = "hostnamectl".Bash(); - return os; + // linebreak list conversion + lines = new List(output + .Split(new string[] { "\n", "\r\n" }, StringSplitOptions.RemoveEmptyEntries)) + .Select(l => + { + return Regex + .Replace(l + .Trim() + .Replace("\t", " "), @"[ ]{2,}", " "); + }) + .ToList(); + + // assign values + os.Name = lines + .Any(l => l + .StartsWith("Operating System:")) ? lines + .Where(l => l + .StartsWith("Operating System:")) + .First() + .Split("Operating System:")[1] + .Trim() : string.Empty; + + os.Version = lines + .Any(l => l + .StartsWith("Kernel:")) ? lines + .Where(l => l + .StartsWith("Kernel:")) + .First() + .Split("Kernel:")[1] + .Trim() : string.Empty; + + var architecture = lines + .Any(l => l + .StartsWith("Architecture:")) ? lines + .Where(l => l + .StartsWith("Architecture:")) + .First() + .Split("Architecture:")[1] + .Trim() : string.Empty; + + return os; + } } - - private static readonly string[] separator = ["\n", "\r\n"]; - - [GeneratedRegex(@"[ ]{2,}")] - private static partial Regex CleanRegex(); } \ No newline at end of file diff --git a/src/Agent/Insight.Agent/Services/_Collector/_Session.cs b/src/Agent/Insight.Agent/Services/_Collector/_Session.cs index 5b98531..3b34213 100644 --- a/src/Agent/Insight.Agent/Services/_Collector/_Session.cs +++ b/src/Agent/Insight.Agent/Services/_Collector/_Session.cs @@ -1,54 +1,50 @@ -using Insight.Domain.Extensions; -using Insight.Domain.Network.Agent.Messages; +using Insight.Agent.Extensions; +using Insight.Agent.Messages; using Microsoft.Extensions.Logging; using System.Text.RegularExpressions; -namespace Insight.Agent.Services; - -public partial class CollectorService +namespace Insight.Agent.Services { - public List? GetSessions() + public partial class CollectorService { - Logger.LogTrace("GetSessions"); - - var sessions = new List(); - - // request data with process - var output = "w".Bash(); - - // linebreak list conversion - var lines = output.Split(separatorArray, StringSplitOptions.RemoveEmptyEntries).ToList(); - - lines = lines.Select(l => + public List? GetSessions() { - return CleanOutputRegex().Replace(l.Trim().Replace("\t", " "), " "); - }).ToList(); + Logger.LogTrace("GetSessions"); - // cleaning - lines.RemoveRange(0, 2); + var sessions = new List(); - // process list elements - foreach (var l in lines) - { - // split into elements - var elements = l.Split(Array.Empty(), StringSplitOptions.RemoveEmptyEntries); + // request data with process + var output = "w".Bash(); - // add user, assign values - sessions.Add(new Session + // linebreak list conversion + var lines = output.Split(new string[] { "\n", "\r\n" }, StringSplitOptions.RemoveEmptyEntries).ToList(); + + lines = lines.Select(l => { - User = elements.ElementAt(0), - //Id = elements.ElementAt(1), - Remote = elements.ElementAt(2), - //Login = elements.ElementAt(3), - //Idle = elements.ElementAt(4) - }); + return Regex.Replace(l.Trim().Replace("\t", " "), @"[ ]{2,}", " "); + }).ToList(); + + // cleaning + lines.RemoveRange(0, 2); + + // process list elements + foreach (var l in lines) + { + // split into elements + var elements = l.Split(Array.Empty(), StringSplitOptions.RemoveEmptyEntries); + + // add user, assign values + sessions.Add(new Session + { + User = elements.ElementAt(0), + //Id = elements.ElementAt(1), + Remote = elements.ElementAt(2), + //Login = elements.ElementAt(3), + //Idle = elements.ElementAt(4) + }); + } + + return sessions; } - - return sessions; } - - private static readonly string[] separatorArray = ["\n", "\r\n"]; - - [GeneratedRegex(@"[ ]{2,}")] - private static partial Regex CleanOutputRegex(); } \ No newline at end of file diff --git a/src/Api/Insight.Api/Constants/Locations.cs b/src/Api/Insight.Api/Constants/Locations.cs index 94d66e7..8db6a8f 100644 --- a/src/Api/Insight.Api/Constants/Locations.cs +++ b/src/Api/Insight.Api/Constants/Locations.cs @@ -1,8 +1,9 @@ using Insight.Domain.Constants; -namespace Insight.Api; - -public static class Locations +namespace Insight.Api { - public static DirectoryInfo UpdatesPath { get; } = new DirectoryInfo($"{Configuration.AppDirectory?.FullName}/files/updates"); + public static class Locations + { + public static DirectoryInfo UpdatesPath { get; } = new DirectoryInfo($"{Configuration.AppDirectory?.FullName}/files/updates"); + } } \ No newline at end of file diff --git a/src/Api/Insight.Api/Controllers/AccountController.cs b/src/Api/Insight.Api/Controllers/AccountController.cs index 4d80252..21756f3 100644 --- a/src/Api/Insight.Api/Controllers/AccountController.cs +++ b/src/Api/Insight.Api/Controllers/AccountController.cs @@ -1,73 +1,76 @@ using Insight.Api.Models; -using Insight.Infrastructure.Entities; using Insight.Infrastructure.Models; using Insight.Infrastructure.Services; -using Insight.Infrastructure.Web; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using MongoDB.Driver; -namespace Insight.Api.Controllers; - -[ApiController, Route("api/accounts")] -public class AccountController(IdentityService identityService, IServiceScopeFactory scopeFactory) : ControllerBase +namespace Insight.Api.Controllers { - private readonly IdentityService _identityService = identityService; - private readonly IServiceScopeFactory _scopeFactory = scopeFactory; - - [HttpGet, Authorize] - public async Task Get([FromQuery] PagedDataRequest request, CancellationToken cancellationToken) + [ApiController, Route("api/accounts")] + public class AccountController : ControllerBase { - using var scope = _scopeFactory.CreateScope(); - var collection = scope.ServiceProvider.GetRequiredService().User(); + private readonly IdentityService _identityService; + private readonly AccountService _accountService; + private readonly ILogger _logger; - try + public AccountController(IdentityService identityService, AccountService accountService, ILogger logger) { - var result = await collection.GetPagedAsync( - offset: request.Offset, - limit: request.Limit, - request: Request, - response: Response, - cancellationToken: cancellationToken).ConfigureAwait(false); - - return Ok(result); - } - catch (UnauthorizedAccessException ex) - { - return Unauthorized(ex.ToString()); - } - catch (Exception ex) - { - return BadRequest(ex.Message); - } - } - - [HttpPost("register"), Authorize] - public async Task Register([FromBody] RegistrationModel model) - { - if (string.IsNullOrWhiteSpace(model.Email)) return BadRequest("Email Required"); - if (string.IsNullOrWhiteSpace(model.Password)) return BadRequest("Password Required"); - if (string.IsNullOrWhiteSpace(model.ConfirmPassword)) return BadRequest("Password Confirmation Required"); - - if (model.Password != model.ConfirmPassword) return BadRequest("Passwords do not match"); - - try - { - var result = await _identityService.CreateUserAsync(model.Email, model.Password).ConfigureAwait(false); - - if (result.Succeeded is false) return BadRequest(result.Errors); - } - catch (UnauthorizedAccessException ex) - { - return Unauthorized(ex.Message); - } - catch (Exception ex) - { - return BadRequest(ex.Message); + _identityService = identityService; + _accountService = accountService; + _logger = logger; } - //await _userManager.AddToRoleAsync(user, "Visitor"); + [HttpGet, Authorize] + public async Task Get([FromQuery] PagedDataRequest request, CancellationToken cancellationToken) + { + try + { + var result = await _accountService.GetAsync( + offset: request.Offset, + limit: request.Limit, + request: Request, + response: Response, + cancellationToken: cancellationToken).ConfigureAwait(false); - return Ok(model.Email); + return Ok(result); + } + catch (UnauthorizedAccessException ex) + { + return Unauthorized(ex.ToString()); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } + } + + [HttpPost("register"), Authorize] + public async Task Register([FromBody] RegistrationModel model) + { + if (string.IsNullOrWhiteSpace(model.Email)) return BadRequest("Email Required"); + if (string.IsNullOrWhiteSpace(model.Password)) return BadRequest("Password Required"); + if (string.IsNullOrWhiteSpace(model.ConfirmPassword)) return BadRequest("Password Confirmation Required"); + + if (model.Password != model.ConfirmPassword) return BadRequest("Passwords do not match"); + + try + { + var result = await _identityService.CreateUserAsync(model.Email, model.Password).ConfigureAwait(false); + + if (result.Succeeded is false) return BadRequest(result.Errors); + } + catch (UnauthorizedAccessException ex) + { + return Unauthorized(ex.Message); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } + + //await _userManager.AddToRoleAsync(user, "Visitor"); + + return Ok(model.Email); + } } } \ No newline at end of file diff --git a/src/Api/Insight.Api/Controllers/AgentController.cs b/src/Api/Insight.Api/Controllers/AgentController.cs index c1d10cc..cc0f6b1 100644 --- a/src/Api/Insight.Api/Controllers/AgentController.cs +++ b/src/Api/Insight.Api/Controllers/AgentController.cs @@ -1,41 +1,44 @@ -using Insight.Infrastructure.Entities; -using Insight.Infrastructure.Models; -using Insight.Infrastructure.Web; +using Insight.Infrastructure.Models; +using Insight.Infrastructure.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using MongoDB.Driver; -namespace Insight.Api.Controllers; - -[ApiController, Route("api/agents")] -public class AgentController(IServiceScopeFactory scopeFactory) : ControllerBase +namespace Insight.Api.Controllers { - private readonly IServiceScopeFactory _scopeFactory = scopeFactory; - - [HttpGet, Authorize] - public async Task Get([FromQuery] PagedDataRequest request, CancellationToken cancellationToken) + [ApiController, Route("api/agents")] + public class AgentController : ControllerBase { - using var scope = _scopeFactory.CreateScope(); - var collection = scope.ServiceProvider.GetRequiredService().Agent(); + private readonly AgentService _agentService; + private readonly ILogger _logger; - try + public AgentController(AgentService agentService, ILogger logger) { - var result = await collection.GetPagedAsync( - offset: request.Offset, - limit: request.Limit, - request: Request, - response: Response, - cancellationToken: cancellationToken).ConfigureAwait(false); + _agentService = agentService; + _logger = logger; + } - return Ok(result); - } - catch (UnauthorizedAccessException ex) + [HttpGet, Authorize] + public async Task Get([FromQuery] PagedDataRequest request, CancellationToken cancellationToken) { - return Unauthorized(ex.ToString()); - } - catch (Exception ex) - { - return BadRequest(ex.Message); + try + { + var result = await _agentService.GetAsync( + offset: request.Offset, + limit: request.Limit, + request: Request, + response: Response, + cancellationToken: cancellationToken).ConfigureAwait(false); + + return Ok(result); + } + catch (UnauthorizedAccessException ex) + { + return Unauthorized(ex.ToString()); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } } } } \ No newline at end of file diff --git a/src/Api/Insight.Api/Controllers/CustomerController.cs b/src/Api/Insight.Api/Controllers/CustomerController.cs index ddc94a2..6733f81 100644 --- a/src/Api/Insight.Api/Controllers/CustomerController.cs +++ b/src/Api/Insight.Api/Controllers/CustomerController.cs @@ -1,41 +1,44 @@ -using Insight.Infrastructure.Entities; -using Insight.Infrastructure.Models; -using Insight.Infrastructure.Web; +using Insight.Infrastructure.Models; +using Insight.Infrastructure.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using MongoDB.Driver; -namespace Insight.Api.Controllers; - -[ApiController, Route("api/customers")] -public class CustomerController(IServiceScopeFactory scopeFactory) : ControllerBase +namespace Insight.Api.Controllers { - private readonly IServiceScopeFactory _scopeFactory = scopeFactory; - - [HttpGet, Authorize] - public async Task Get([FromQuery] PagedDataRequest request, CancellationToken cancellationToken) + [ApiController, Route("api/customers")] + public class CustomerController : ControllerBase { - using var scope = _scopeFactory.CreateScope(); - var collection = scope.ServiceProvider.GetRequiredService().Customer(); + private readonly CustomerService _customerService; + private readonly ILogger _logger; - try + public CustomerController(CustomerService customerService, ILogger logger) { - var result = await collection.GetPagedAsync( - offset: request.Offset, - limit: request.Limit, - request: Request, - response: Response, - cancellationToken: cancellationToken).ConfigureAwait(false); + _customerService = customerService; + _logger = logger; + } - return Ok(result); - } - catch (UnauthorizedAccessException ex) + [HttpGet, Authorize] + public async Task Get([FromQuery] PagedDataRequest request, CancellationToken cancellationToken) { - return Unauthorized(ex.ToString()); - } - catch (Exception ex) - { - return BadRequest(ex.Message); + try + { + var result = await _customerService.GetAsync( + offset: request.Offset, + limit: request.Limit, + request: Request, + response: Response, + cancellationToken: cancellationToken).ConfigureAwait(false); + + return Ok(result); + } + catch (UnauthorizedAccessException ex) + { + return Unauthorized(ex.ToString()); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } } } } \ No newline at end of file diff --git a/src/Api/Insight.Api/Controllers/HostController.cs b/src/Api/Insight.Api/Controllers/HostController.cs index ccd9fea..bd42dac 100644 --- a/src/Api/Insight.Api/Controllers/HostController.cs +++ b/src/Api/Insight.Api/Controllers/HostController.cs @@ -1,41 +1,44 @@ -using Insight.Infrastructure.Entities; -using Insight.Infrastructure.Models; -using Insight.Infrastructure.Web; +using Insight.Infrastructure.Models; +using Insight.Infrastructure.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using MongoDB.Driver; -namespace Insight.Api.Controllers; - -[ApiController, Route("api/hosts")] -public class HostController(IServiceScopeFactory scopeFactory) : ControllerBase +namespace Insight.Api.Controllers { - private readonly IServiceScopeFactory _scopeFactory = scopeFactory; - - [HttpGet, Authorize] - public async Task Get([FromQuery] PagedDataRequest request, CancellationToken cancellationToken) + [ApiController, Route("api/hosts")] + public class HostController : ControllerBase { - using var scope = _scopeFactory.CreateScope(); - var collection = scope.ServiceProvider.GetRequiredService().Host(); + private readonly HostService _hostService; + private readonly ILogger _logger; - try + public HostController(HostService hostService, ILogger logger) { - var result = await collection.GetPagedAsync( - offset: request.Offset, - limit: request.Limit, - request: Request, - response: Response, - cancellationToken: cancellationToken).ConfigureAwait(false); + _hostService = hostService; + _logger = logger; + } - return Ok(result); - } - catch (UnauthorizedAccessException ex) + [HttpGet, Authorize] + public async Task Get([FromQuery] PagedDataRequest request, CancellationToken cancellationToken) { - return Unauthorized(ex.ToString()); - } - catch (Exception ex) - { - return BadRequest(ex.Message); + try + { + var result = await _hostService.GetAsync( + offset: request.Offset, + limit: request.Limit, + request: Request, + response: Response, + cancellationToken: cancellationToken).ConfigureAwait(false); + + return Ok(result); + } + catch (UnauthorizedAccessException ex) + { + return Unauthorized(ex.ToString()); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } } } } \ No newline at end of file diff --git a/src/Api/Insight.Api/Controllers/InventoryController.cs b/src/Api/Insight.Api/Controllers/InventoryController.cs index 14e0e23..2a47dff 100644 --- a/src/Api/Insight.Api/Controllers/InventoryController.cs +++ b/src/Api/Insight.Api/Controllers/InventoryController.cs @@ -1,6 +1,6 @@ using Insight.Infrastructure.Entities; using Insight.Infrastructure.Models; -using Insight.Infrastructure.Web; +using Insight.Infrastructure.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using MongoDB.Bson; @@ -8,61 +8,66 @@ using MongoDB.Driver; using System.Text.Json.Serialization; using System.Text.RegularExpressions; -namespace Insight.Api.Controllers; - -[ApiController, Route("api/inventory")] -public class InventoryController(IServiceScopeFactory scopeFactory) : ControllerBase +namespace Insight.Api.Controllers { - private readonly IServiceScopeFactory _scopeFactory = scopeFactory; - - [HttpGet, Authorize] - public async Task Get([FromQuery] HostApplicationEntity request, [FromQuery] PagedDataRequest meta, CancellationToken cancellationToken) + [ApiController, Route("api/inventory")] + public class InventoryController : ControllerBase { - using var scope = _scopeFactory.CreateScope(); - var collection = scope.ServiceProvider.GetRequiredService().HostApplication(); + private readonly InventoryService _inventoryService; + private readonly ILogger _logger; - try + public InventoryController(InventoryService inventoryService, ILogger logger) { - var filter = Builders.Filter.Empty; - - if (request.Id is not null) - filter &= Builders.Filter.Eq(p => p.Id, request.Id); - - if (request.Host is not null) - filter &= Builders.Filter.Eq(p => p.Host, request.Host); - - if (request.Name is not null) - filter &= Builders.Filter.Regex(p => p.Name, new BsonRegularExpression(new Regex(request.Name, RegexOptions.IgnoreCase))); - - var result = await collection.GetPagedAsync( - filter: filter, - offset: meta.Offset, - limit: meta.Limit, - request: Request, - response: Response, - cancellationToken: cancellationToken).ConfigureAwait(false); - - return Ok(result); + _inventoryService = inventoryService; + _logger = logger; } - catch (UnauthorizedAccessException ex) + + [HttpGet, Authorize] + public async Task Get([FromQuery] HostApplicationEntity request, [FromQuery] PagedDataRequest meta, CancellationToken cancellationToken) { - return Unauthorized(ex.ToString()); + try + { + var filter = Builders.Filter.Empty; + + if (request.Id is not null) + filter &= Builders.Filter.Eq(p => p.Id, request.Id); + + if (request.Host is not null) + filter &= Builders.Filter.Eq(p => p.Host, request.Host); + + if (request.Name is not null) + filter &= Builders.Filter.Regex(p => p.Name, new BsonRegularExpression(new Regex(request.Name, RegexOptions.IgnoreCase))); + + var result = await _inventoryService.GetAsync( + filter: filter, + offset: meta.Offset, + limit: meta.Limit, + request: Request, + response: Response, + cancellationToken: cancellationToken).ConfigureAwait(false); + + return Ok(result); + } + catch (UnauthorizedAccessException ex) + { + return Unauthorized(ex.ToString()); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } } - catch (Exception ex) + + public class ApplicationRequest { - return BadRequest(ex.Message); + [JsonPropertyName("id")] + public string? Id { get; set; } + + [JsonPropertyName("host")] + public string? Host { get; set; } + + [JsonPropertyName("name")] + public string? Name { get; set; } } } - - public class ApplicationRequest - { - [JsonPropertyName("id")] - public string? Id { get; set; } - - [JsonPropertyName("host")] - public string? Host { get; set; } - - [JsonPropertyName("name")] - public string? Name { get; set; } - } } \ No newline at end of file diff --git a/src/Api/Insight.Api/Controllers/SetupController.cs b/src/Api/Insight.Api/Controllers/SetupController.cs index fe03166..913e294 100644 --- a/src/Api/Insight.Api/Controllers/SetupController.cs +++ b/src/Api/Insight.Api/Controllers/SetupController.cs @@ -1,24 +1,30 @@ using Microsoft.AspNetCore.Mvc; -namespace Insight.Server.Controllers; - -[ApiController, Route("api/setup")] -public class SetupController(ILogger logger) : ControllerBase +namespace Insight.Server.Controllers { - private readonly ILogger _logger = logger; - - [HttpGet("windows")] - public async Task GetAsync(CancellationToken cancellationToken) + [ApiController, Route("api/setup")] + public class SetupController : ControllerBase { - _logger.LogInformation("[{method}] {route} => {ep}", Request.Method, Request.HttpContext.Request.Path, Request.HttpContext.Connection.RemoteIpAddress); + private readonly ILogger _logger; - var files = new DirectoryInfo($"{Domain.Constants.Configuration.AppDirectory?.FullName}/files/setup").GetFiles(); - - if (files.Length == 0) + public SetupController(ILogger logger) { - return NotFound(); + _logger = logger; } - return File(await System.IO.File.ReadAllBytesAsync(files.OrderBy(p => p.LastWriteTime).First().FullName, cancellationToken), "application/zip", "setup-win64.zip"); + [HttpGet("windows")] + public async Task GetAsync(CancellationToken cancellationToken) + { + _logger.LogInformation("[{method}] {route} => {ep}", Request.Method, Request.HttpContext.Request.Path, Request.HttpContext.Connection.RemoteIpAddress); + + var files = new DirectoryInfo($"{Domain.Constants.Configuration.AppDirectory?.FullName}/files/setup").GetFiles(); + + if (files.Length == 0) + { + return NotFound(); + } + + return File(await System.IO.File.ReadAllBytesAsync(files.OrderBy(p => p.LastWriteTime).First().FullName, cancellationToken), "application/zip", "setup-win64.zip"); + } } } \ No newline at end of file diff --git a/src/Api/Insight.Api/Controllers/TokenController.cs b/src/Api/Insight.Api/Controllers/TokenController.cs index 12825b1..372a066 100644 --- a/src/Api/Insight.Api/Controllers/TokenController.cs +++ b/src/Api/Insight.Api/Controllers/TokenController.cs @@ -3,80 +3,83 @@ using Insight.Infrastructure.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -namespace Insight.Api.Controllers; - -[ApiController, Route("api/token", Order = 0)] -public class TokenController(TokenService tokenService) : ControllerBase +namespace Insight.Api.Controllers { - private readonly TokenService _tokenService = tokenService; - - /// - /// Access Token Request - /// - [HttpPost, AllowAnonymous] - public async Task Authentication([FromBody] TokenRequest request) + [ApiController, Route("api/token", Order = 0)] + public class TokenController : ControllerBase { - if (request.Username is null) return BadRequest("username is null"); - if (request.Password is null) return BadRequest("password is null"); + private readonly TokenService _tokenService; - try + public TokenController(TokenService tokenService) { - var result = await _tokenService.GetAsync(request.Username, request.Password, request.Code, HttpContext.Connection.RemoteIpAddress).ConfigureAwait(false); - return Ok(result); + _tokenService = tokenService; } - catch (UnauthorizedAccessException ex) - { - return Unauthorized(ex.Message); - } - catch (Exception ex) - { - return BadRequest(ex.Message); - } - } - /// - /// Refresh Token Request - /// - [HttpPost("refresh"), AllowAnonymous] - public async Task Refresh([FromBody] TokenRefreshRequest request) - { - if (string.IsNullOrWhiteSpace(request.Token)) return BadRequest("Refresh Token Required"); + /// + /// Access Token Request + /// + [HttpPost, AllowAnonymous] + public async Task Authentication([FromBody] TokenRequest request) + { + try + { + var result = await _tokenService.GetAsync(request.Username, request.Password, request.Code, HttpContext.Connection.RemoteIpAddress).ConfigureAwait(false); + return Ok(result); + } + catch (UnauthorizedAccessException ex) + { + return Unauthorized(ex.Message); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } + } - try + /// + /// Refresh Token Request + /// + [HttpPost("refresh"), AllowAnonymous] + public async Task Refresh([FromBody] TokenRefreshRequest request) { - var result = await _tokenService.RefreshAsync(request.Token, HttpContext.Connection.RemoteIpAddress).ConfigureAwait(false); - return Ok(result); - } - catch (UnauthorizedAccessException ex) - { - return Unauthorized(ex.Message); - } - catch (Exception ex) - { - return BadRequest(ex.Message); - } - } + if (string.IsNullOrWhiteSpace(request.Token)) return BadRequest("Refresh Token Required"); - /// - /// Revoke Token Request - /// - [HttpPost("revoke"), AllowAnonymous] - public async Task Revoke([FromBody] TokenRevokeRequest request) - { - if (string.IsNullOrWhiteSpace(request.Token)) return BadRequest("Refresh Token Required"); + try + { + var result = await _tokenService.RefreshAsync(request.Token, HttpContext.Connection.RemoteIpAddress).ConfigureAwait(false); + return Ok(result); + } + catch (UnauthorizedAccessException ex) + { + return Unauthorized(ex.Message); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } + } - try + /// + /// Revoke Token Request + /// + [HttpPost("revoke"), AllowAnonymous] + public async Task Revoke([FromBody] TokenRevokeRequest request) { - await _tokenService.RevokeAsync(request.Token, request.Reason ?? "revoked by user", HttpContext.Connection.RemoteIpAddress).ConfigureAwait(false); - return Ok(); - } - catch (UnauthorizedAccessException ex) - { - return Unauthorized(ex.Message); - } - catch (Exception ex) - { - return BadRequest(ex.Message); + if (string.IsNullOrWhiteSpace(request.Token)) return BadRequest("Refresh Token Required"); + + try + { + await _tokenService.RevokeAsync(request.Token, request.Reason ?? "revoked by user", HttpContext.Connection.RemoteIpAddress).ConfigureAwait(false); + return Ok(); + } + catch (UnauthorizedAccessException ex) + { + return Unauthorized(ex.Message); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } } } } \ No newline at end of file diff --git a/src/Api/Insight.Api/Controllers/UpdateController.cs b/src/Api/Insight.Api/Controllers/UpdateController.cs index 712f2fa..6ff09df 100644 --- a/src/Api/Insight.Api/Controllers/UpdateController.cs +++ b/src/Api/Insight.Api/Controllers/UpdateController.cs @@ -2,86 +2,92 @@ using Insight.Domain.Models; using Microsoft.AspNetCore.Mvc; -namespace Insight.Server.Controllers; - -[ApiController, Route("api/update")] -public class UpdateController(ILogger logger) : ControllerBase +namespace Insight.Server.Controllers { - private readonly ILogger _logger = logger; - - [HttpGet("updater/windows")] - public IActionResult UpdaterWindows() + [ApiController, Route("api/update")] + public class UpdateController : ControllerBase { - _logger.LogInformation("[{method}] {route} => {ep}", Request.Method, Request.HttpContext.Request.Path, Request.HttpContext.Connection.RemoteIpAddress); + private readonly ILogger _logger; - var updateDir = new DirectoryInfo($"{Locations.UpdatesPath}/updater/windows"); - - if (updateDir.Exists is false) + public UpdateController(ILogger logger) { - return NotFound(); + _logger = logger; } - var updateLock = new FileInfo($"{updateDir.FullName}/.lock"); - - if (updateLock.Exists) + [HttpGet("updater/windows")] + public IActionResult UpdaterWindows() { - return NotFound("locked"); + _logger.LogInformation("[{method}] {route} => {ep}", Request.Method, Request.HttpContext.Request.Path, Request.HttpContext.Connection.RemoteIpAddress); + + var updateDir = new DirectoryInfo($"{Locations.UpdatesPath}/updater/windows"); + + if (updateDir.Exists is false) + { + return NotFound(); + } + + var updateLock = new FileInfo($"{updateDir.FullName}/.lock"); + + if (updateLock.Exists) + { + return NotFound("locked"); + } + + var versions = updateDir.GetFiles("*.zip", SearchOption.TopDirectoryOnly); + + if (versions is null || versions.Any() is false) return NotFound(); + + var latest = versions.OrderBy(x => x.Name).FirstOrDefault(); + + if (latest is null) return NotFound(); + + var relPath = $"{Path.GetRelativePath($"{Domain.Constants.Configuration.AppDirectory?.FullName}", latest.FullName)}"; + + if (Version.TryParse(Path.GetFileNameWithoutExtension(latest.Name), out var fileversion) is false) return NotFound(); + + return Ok(new UpdateResponse + { + Version = fileversion, + Uri = new Uri($"{Request.Scheme}://{Request.Host}/api/{relPath}") + }); } - var versions = updateDir.GetFiles("*.zip", SearchOption.TopDirectoryOnly); - - if (versions is null || versions.Length == 0) return NotFound(); - - var latest = versions.OrderBy(x => x.Name).FirstOrDefault(); - - if (latest is null) return NotFound(); - - var relPath = $"{Path.GetRelativePath($"{Domain.Constants.Configuration.AppDirectory?.FullName}", latest.FullName)}"; - - if (Version.TryParse(Path.GetFileNameWithoutExtension(latest.Name), out var fileversion) is false) return NotFound(); - - return Ok(new UpdateResponse + [HttpGet("agent/windows")] + public IActionResult AgentWindows() { - Version = fileversion, - Uri = new Uri($"{Request.Scheme}://{Request.Host}/api/{relPath}") - }); - } + _logger.LogInformation("[{method}] {route} => {ep}", Request.Method, Request.HttpContext.Request.Path, Request.HttpContext.Connection.RemoteIpAddress); - [HttpGet("agent/windows")] - public IActionResult AgentWindows() - { - _logger.LogInformation("[{method}] {route} => {ep}", Request.Method, Request.HttpContext.Request.Path, Request.HttpContext.Connection.RemoteIpAddress); + var updateDir = new DirectoryInfo($"{Locations.UpdatesPath}/agent/windows"); - var updateDir = new DirectoryInfo($"{Locations.UpdatesPath}/agent/windows"); + if (updateDir.Exists is false) + { + return NotFound(); + } - if (updateDir.Exists is false) - { - return NotFound(); + var updateLock = new FileInfo($"{updateDir.FullName}/.lock"); + + if (updateLock.Exists) + { + return NotFound("locked"); + } + + var versions = updateDir.GetFiles("*.zip", SearchOption.TopDirectoryOnly); + + if (versions is null || versions.Any() is false) return NotFound(); + + var latest = versions.OrderBy(x => x.Name).FirstOrDefault(); + + if (latest is null) return NotFound(); + + var relPath = $"{Path.GetRelativePath($"{Domain.Constants.Configuration.AppDirectory?.FullName}", latest.FullName)}"; + + if (Version.TryParse(Path.GetFileNameWithoutExtension(latest.Name), out var fileversion) is false) return NotFound(); + + return Ok(new UpdateResponse + { + Version = fileversion, + Uri = new Uri($"{Request.Scheme}://{Request.Host}/api/{relPath}") + }); } - - var updateLock = new FileInfo($"{updateDir.FullName}/.lock"); - - if (updateLock.Exists) - { - return NotFound("locked"); - } - - var versions = updateDir.GetFiles("*.zip", SearchOption.TopDirectoryOnly); - - if (versions is null || versions.Length == 0) return NotFound(); - - var latest = versions.OrderBy(x => x.Name).FirstOrDefault(); - - if (latest is null) return NotFound(); - - var relPath = $"{Path.GetRelativePath($"{Domain.Constants.Configuration.AppDirectory?.FullName}", latest.FullName)}"; - - if (Version.TryParse(Path.GetFileNameWithoutExtension(latest.Name), out var fileversion) is false) return NotFound(); - - return Ok(new UpdateResponse - { - Version = fileversion, - Uri = new Uri($"{Request.Scheme}://{Request.Host}/api/{relPath}") - }); } } \ No newline at end of file diff --git a/src/Api/Insight.Api/Extensions/ServiceExtensions.cs b/src/Api/Insight.Api/Extensions/ServiceExtensions.cs index aa913cf..46b91a7 100644 --- a/src/Api/Insight.Api/Extensions/ServiceExtensions.cs +++ b/src/Api/Insight.Api/Extensions/ServiceExtensions.cs @@ -1,109 +1,59 @@ -using Insight.Infrastructure; -using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.OpenApi.Models; -using OpenTelemetry.Metrics; -using OpenTelemetry.Resources; using System.Reflection; -namespace Insight.Api.Extensions; - -internal static class ServiceExtensions +namespace Insight.Api.Hosting { - internal static WebApplicationBuilder AddMetrics(this WebApplicationBuilder builder) + public static class ServiceExtensions { - builder.Services.AddOpenTelemetry() - .WithMetrics(provider => + internal static IServiceCollection AddSwaggerServices(this IServiceCollection services, IConfiguration configuration) + { + services.AddEndpointsApiExplorer(); + services.AddSwaggerGen(options => { - provider.ConfigureResource(configure => + options.SwaggerDoc("v1", new OpenApiInfo { - configure.Clear(); - configure.AddService(builder.Configuration.GetValue(Appsettings.Influx.Service) ?? throw new Exception($"{Appsettings.Influx.Service} value not set (appsettings)")); - }) - .AddRuntimeInstrumentation() - .AddProcessInstrumentation() - .AddAspNetCoreInstrumentation() - .AddHttpClientInstrumentation() - //.AddMeter("test") - .AddInfluxDBMetricsExporter(configure => - { - configure.Endpoint = builder.Configuration.GetValue(Appsettings.Influx.Endpoint) ?? throw new Exception($"{Appsettings.Influx.Endpoint} value not set (appsettings)"); - configure.Token = builder.Configuration.GetValue(Appsettings.Influx.Token) ?? throw new Exception($"{Appsettings.Influx.Token} value not set (appsettings)"); - configure.Org = builder.Configuration.GetValue(Appsettings.Influx.Organization) ?? throw new Exception($"{Appsettings.Influx.Organization} value not set (appsettings)"); - configure.Bucket = builder.Configuration.GetValue(Appsettings.Influx.Bucket) ?? throw new Exception($"{Appsettings.Influx.Bucket} value not set (appsettings)"); - - configure.MetricExportIntervalMilliseconds = 1000; + Title = "Insight API", + Version = "v1" }); - } - ); - //builder.Services.AddSingleton(); - - return builder; - } - - internal static WebApplicationBuilder AddSwagger(this WebApplicationBuilder builder) - { - builder.Services.AddSwaggerGen(options => - { - options.SwaggerDoc("v1", new OpenApiInfo - { - Title = "Insight API", - Version = "v1" - }); - - options.AddSecurityDefinition(name: "Bearer", securityScheme: new OpenApiSecurityScheme - { - Name = "Authorization", - Description = "Enter the Bearer Authorization string as following: `Bearer Generated-JWT-Token`", - In = ParameterLocation.Header, - Type = SecuritySchemeType.ApiKey, - Scheme = "Bearer", - BearerFormat = "JWT", - - Reference = new OpenApiReference + options.AddSecurityDefinition(name: "Bearer", securityScheme: new OpenApiSecurityScheme { - Id = JwtBearerDefaults.AuthenticationScheme, - Type = ReferenceType.SecurityScheme - } - }); + Name = "Authorization", + Description = "Enter the Bearer Authorization string as following: `Bearer Generated-JWT-Token`", + In = ParameterLocation.Header, + Type = SecuritySchemeType.ApiKey, + Scheme = "Bearer", + BearerFormat = "JWT", - options.AddSecurityRequirement(new OpenApiSecurityRequirement - { - { - new OpenApiSecurityScheme + Reference = new OpenApiReference { - In = ParameterLocation.Header, - Reference = new OpenApiReference + Id = JwtBearerDefaults.AuthenticationScheme, + Type = ReferenceType.SecurityScheme + } + }); + + options.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme { - Id = "Bearer", - Type = ReferenceType.SecurityScheme - } - }, - new List() - } + In = ParameterLocation.Header, + Reference = new OpenApiReference + { + Id = "Bearer", + Type = ReferenceType.SecurityScheme + } + }, + new List() + } + }); + + var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; + options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename)); }); - var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; - options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename)); - }); - - return builder; - } - - internal static WebApplication ConfigureSwagger(this WebApplication app) - { - app.UseSwagger(options => - { - options.RouteTemplate = "api/swagger/{documentName}/swagger.json"; - }); - - app.UseSwaggerUI(options => - { - options.DefaultModelsExpandDepth(-1); - options.SwaggerEndpoint("/api/swagger/v1/swagger.json", "v1"); - options.RoutePrefix = "api/swagger"; - }); - - return app; + return services; + } } } \ No newline at end of file diff --git a/src/Api/Insight.Api/Insight.Api.csproj b/src/Api/Insight.Api/Insight.Api.csproj index 0713355..4d54881 100644 --- a/src/Api/Insight.Api/Insight.Api.csproj +++ b/src/Api/Insight.Api/Insight.Api.csproj @@ -1,42 +1,53 @@  - - - net8.0 - latest - Insight - api - 2023.12.15.0 - Insight.Api - enable - enable - 4ae1d3bf-869e-4963-8a19-35634507d3b3 - false - false - - True - $(NoWarn);1591 - none - true - + + True + $(NoWarn);1591 + + + + none + + + + none + - - - - - - - - - - - + + + + + + + + + + + + + - + - - - \ No newline at end of file + + diff --git a/src/Api/Insight.Api/Models/RegistrationModel.cs b/src/Api/Insight.Api/Models/RegistrationModel.cs index 0794854..206b2dc 100644 --- a/src/Api/Insight.Api/Models/RegistrationModel.cs +++ b/src/Api/Insight.Api/Models/RegistrationModel.cs @@ -1,22 +1,23 @@ using System.ComponentModel.DataAnnotations; -namespace Insight.Api.Models; - -public class RegistrationModel +namespace Insight.Api.Models { - public string? FirstName { get; set; } - public string? LastName { get; set; } + public class RegistrationModel + { + public string? FirstName { get; set; } + public string? LastName { get; set; } - [Required(ErrorMessage = "Email is required")] - [EmailAddress] - public string? Email { get; set; } + [Required(ErrorMessage = "Email is required")] + [EmailAddress] + public string? Email { get; set; } - [Required(ErrorMessage = "Password is required")] - [DataType(DataType.Password)] - public string? Password { get; set; } + [Required(ErrorMessage = "Password is required")] + [DataType(DataType.Password)] + public string? Password { get; set; } - [Required(ErrorMessage = "Password is required")] - [DataType(DataType.Password)] - [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] - public string? ConfirmPassword { get; set; } + [Required(ErrorMessage = "Password is required")] + [DataType(DataType.Password)] + [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] + public string? ConfirmPassword { get; set; } + } } diff --git a/src/Api/Insight.Api/Program.cs b/src/Api/Insight.Api/Program.cs index 9df123f..0c9e95f 100644 --- a/src/Api/Insight.Api/Program.cs +++ b/src/Api/Insight.Api/Program.cs @@ -1,79 +1,99 @@ -using Insight.Api.Extensions; +using Insight.Api.Hosting; using Insight.Domain.Constants; using Insight.Infrastructure; using Microsoft.Extensions.FileProviders; -using System.Diagnostics; -namespace Insight.Api; - -internal class Program +namespace Insight.Api { - public static async Task Main(string[] args) + public class Program { - var builder = WebApplication.CreateBuilder(args); - builder.Host.UseWindowsService(); - builder.Host.UseSystemd(); - - // Configuration - builder.Configuration.Defaults(); - - // Logging - builder.Logging.ClearProviders(); - builder.Logging.SetMinimumLevel(LogLevel.Trace); - builder.Logging.AddFilter("Microsoft.AspNetCore", LogLevel.Warning); - builder.Logging.AddSimpleConsole(options => + public static async Task Main(string[] args) { - options.IncludeScopes = true; - options.SingleLine = true; - options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff "; - }); - builder.Logging.AddFile(Configuration.AppDirectory?.FullName + "/logs/" + Process.GetCurrentProcess().ProcessName + "_{Date}.log", LogLevel.Trace, fileSizeLimitBytes: 104857600, retainedFileCountLimit: 10, outputTemplate: "{Timestamp:o} [{Level:u3}] {Message} {NewLine}{Exception}"); + var builder = WebApplication.CreateBuilder(args); + builder.Host.UseWindowsService(); + builder.Host.UseSystemd(); - // Services - builder.Services.AddDatabase(builder.Configuration); - builder.Services.AddIdentity(builder.Configuration); - builder.Services.AddIdentityServices(); - builder.Services.AddBearerAuthentication(builder.Configuration); - builder.Services.AddTokenServices(builder.Configuration); - builder.Services.AddAuthorization(); + // LOGGER + builder.Logging.ClearProviders(); + builder.Logging.SetMinimumLevel(LogLevel.Trace); + builder.Logging.AddFilter("Microsoft.AspNetCore", LogLevel.Warning); - // Modules - builder.AddDefaults(); - builder.AddApiDefaults(); - builder.AddMetrics(); - builder.AddSwagger(); + builder.Logging.AddSimpleConsole(options => + { + options.IncludeScopes = true; + options.SingleLine = true; + options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff "; + }); - // HTTP Pipeline - var app = builder.Build(); - app.UseForwardedHeaders(); + builder.Logging.AddFile($"{Configuration.AppDirectory?.FullName}/" + "logs/api_{Date}.log", LogLevel.Trace, fileSizeLimitBytes: 104857600, retainedFileCountLimit: 10, outputTemplate: "{Timestamp:o} [{Level:u3}] {Message} {NewLine}{Exception}"); - if (app.Environment.IsDevelopment()) - { + // INFRASTRUCTURE + builder.Services.AddDatabase(builder.Configuration); + builder.Services.AddInfrastructureServices(); + // IDENTITY + builder.Services.AddIdentityServices(builder.Configuration); + builder.Services.AddBearerAuthentication(builder.Configuration); + builder.Services.AddTokenServices(builder.Configuration); + + // SECURITY + builder.Services.AddAuthorization(); + + // WEBSERVICES + builder.Services.AddProxyServices(builder.Configuration); + builder.Services.AddRoutingServices(builder.Configuration); + builder.Services.AddControllers(); + + // SWAGGER + builder.Services.AddSwaggerServices(builder.Configuration); + + //builder.Services.AddControllers(); + //builder.Services.AddEndpointsApiExplorer(); + //builder.Services.AddSwaggerGen(); + + var app = builder.Build(); + + // Configure the HTTP request pipeline. + app.UseForwardedHeaders(); + + if (app.Environment.IsDevelopment()) + { + + } + + app.UseSwagger(options => + { + options.RouteTemplate = "api/swagger/{documentName}/swagger.json"; + }); + + app.UseSwaggerUI(options => + { + options.DefaultModelsExpandDepth(-1); + options.SwaggerEndpoint("/api/swagger/v1/swagger.json", "v1"); + options.RoutePrefix = "api/swagger"; + }); + + app.UseCors(x => x + .AllowAnyOrigin() + .AllowAnyMethod() + .AllowAnyHeader()); + + app.UseAuthorization(); + + app.MapControllers(); + + // STATIC FILES (UPDATES) + var files = new DirectoryInfo($"{Domain.Constants.Configuration.AppDirectory?.FullName}/files"); + files.Create(); + + app.UseStaticFiles(new StaticFileOptions + { + FileProvider = new PhysicalFileProvider(files.FullName), + RequestPath = "/api/files", + ServeUnknownFileTypes = true + }); + + await app.RunAsync(); } - - app.ConfigureSwagger(); - - app.UseCors(x => x - .AllowAnyOrigin() - .AllowAnyMethod() - .AllowAnyHeader()); - - app.UseAuthorization(); - - app.MapControllers(); - - // STATIC FILES (UPDATES) - var files = new DirectoryInfo($"{Domain.Constants.Configuration.AppDirectory?.FullName}/files"); - files.Create(); - - app.UseStaticFiles(new StaticFileOptions - { - FileProvider = new PhysicalFileProvider(files.FullName), - RequestPath = "/api/files", - ServeUnknownFileTypes = true - }); - - await app.RunAsync().ConfigureAwait(false); } } \ No newline at end of file diff --git a/src/Api/Insight.Api/appsettings.Development.json b/src/Api/Insight.Api/appsettings.Development.json index 09790f7..1ccded8 100644 --- a/src/Api/Insight.Api/appsettings.Development.json +++ b/src/Api/Insight.Api/appsettings.Development.json @@ -1,16 +1,7 @@ { "AllowedHosts": "*", "Urls": "http://127.0.0.1:5000", - - // set in env vars - //"influx.endpoint": "http://127.0.0.1:8086", - //"influx.token": "", - "influx.org": "insight", - "influx.bucket": "insight", - "influx.service": "api", - - "mongo.connection": "mongodb://db.insight.local:27017", - + "database": "mongodb://10.22.70.40:32768", "jwt.key": "x5dcaE8fiBmHfgsNrwIEtSWzZkz6gpouzKOIgEiVjxJnW28V1aUnYXF19IcnF5x", "jwt.exp": 3600, "jwt.audience": "http://127.0.0.1:5000", diff --git a/src/Api/Insight.Api/appsettings.json b/src/Api/Insight.Api/appsettings.json index 39a0d2a..84eb581 100644 --- a/src/Api/Insight.Api/appsettings.json +++ b/src/Api/Insight.Api/appsettings.json @@ -1,18 +1,9 @@ { "AllowedHosts": "*", "Urls": "http://127.0.0.1:5000", - - // set in env vars - //"influx.endpoint": "http://127.0.0.1:8086", - //"influx.token": "", - "influx.org": "insight", - "influx.bucket": "insight", - "influx.service": "api", - - "mongo.connection": "mongodb://127.0.0.1:27017", - + "database": "mongodb://127.0.0.1:27017", "jwt.key": "x5dcaE8fiBmHfgsNrwIEtSWzZkz6gpouzKOIgEiVjxJnW28V1aUnYXF19IcnF5x", "jwt.exp": 3600, "jwt.audience": "https://insight.webmatic.de/api", "jwt.issuer": "https://insight.webmatic.de/api" -} \ No newline at end of file +} diff --git a/src/Core/Insight.Domain/Constants/Configuration.cs b/src/Core/Insight.Domain/Constants/Configuration.cs index 0e79218..f0643e2 100644 --- a/src/Core/Insight.Domain/Constants/Configuration.cs +++ b/src/Core/Insight.Domain/Constants/Configuration.cs @@ -1,21 +1,13 @@ -using System.Diagnostics; -using System.Net; +using System.Net; using System.Reflection; -namespace Insight.Domain.Constants; - -public static class Configuration +namespace Insight.Domain.Constants { - public static string Hostname => Dns.GetHostEntry("localhost").HostName; - public static Version Version => Assembly.GetEntryAssembly()?.GetName().Version ?? throw new ArgumentNullException("Version"); - public static DirectoryInfo? AppDirectory => AppDirectoryHelper(); - public static string DefaultConfig => Path.Combine(AppDirectory?.FullName ?? string.Empty, "config.json"); - - private static DirectoryInfo? AppDirectoryHelper() + public static class Configuration { - using var proc = Process.GetCurrentProcess(); - - if (proc?.MainModule?.FileName is null) throw new InvalidOperationException("MainModule not found"); - return new DirectoryInfo(proc.MainModule.FileName).Parent; + public static string Hostname => Dns.GetHostEntry("localhost").HostName; + public static Version Version => Assembly.GetEntryAssembly()?.GetName().Version ?? throw new ArgumentNullException("Version"); + public static DirectoryInfo? AppDirectory => string.IsNullOrWhiteSpace(Environment.ProcessPath) ? null : new DirectoryInfo(Environment.ProcessPath).Parent; + public static string DefaultConfig => Path.Combine(AppDirectory?.FullName ?? string.Empty, "config.json"); } } \ No newline at end of file diff --git a/src/Core/Insight.Domain/Enums/CategoryEnum.cs b/src/Core/Insight.Domain/Enums/CategoryEnum.cs deleted file mode 100644 index 847e096..0000000 --- a/src/Core/Insight.Domain/Enums/CategoryEnum.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Insight.Domain.Enums; - -public enum CategoryEnum -{ - None = 0, - Network = 1, - System = 2, - Application = 3, - Security = 4, - Monitoring = 5, - Task = 6, - Printer = 7, - RDP = 8 -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Enums/DispatchEnum.cs b/src/Core/Insight.Domain/Enums/DispatchEnum.cs deleted file mode 100644 index da38f84..0000000 --- a/src/Core/Insight.Domain/Enums/DispatchEnum.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Insight.Domain.Enums; - -public enum DispatchEnum -{ - Pending = 1, - Failure = 2, - Success = 3, -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Enums/RemoteControlMode.cs b/src/Core/Insight.Domain/Enums/RemoteControlMode.cs deleted file mode 100644 index 2c764e5..0000000 --- a/src/Core/Insight.Domain/Enums/RemoteControlMode.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Insight.Domain.Enums; - -public enum RemoteControlMode -{ - Unknown, - Unattended, - Attended -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Enums/SessionEndReasons.cs b/src/Core/Insight.Domain/Enums/SessionEndReasons.cs deleted file mode 100644 index bf01052..0000000 --- a/src/Core/Insight.Domain/Enums/SessionEndReasons.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Insight.Domain.Enums; - -public enum SessionEndReasons -{ - Logoff = 1, - SystemShutdown = 2 -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Enums/SessionSwitchReason.cs b/src/Core/Insight.Domain/Enums/SessionSwitchReason.cs deleted file mode 100644 index 3785ee9..0000000 --- a/src/Core/Insight.Domain/Enums/SessionSwitchReason.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Insight.Domain.Enums; - -public enum SessionSwitchReason -{ - ConsoleConnect = 1, - ConsoleDisconnect = 2, - RemoteConnect = 3, - RemoteDisconnect = 4, - SessionLogon = 5, - SessionLogoff = 6, - SessionLock = 7, - SessionUnlock = 8, - SessionRemoteControl = 9 -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Enums/StatusEnum.cs b/src/Core/Insight.Domain/Enums/StatusEnum.cs deleted file mode 100644 index 41abd57..0000000 --- a/src/Core/Insight.Domain/Enums/StatusEnum.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Insight.Domain.Enums; - -public enum StatusEnum -{ - Information = 1, - Warning = 2, - Error = 3 -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Extensions/ConfigurationExtensions.cs b/src/Core/Insight.Domain/Extensions/ConfigurationExtensions.cs deleted file mode 100644 index 6d2a378..0000000 --- a/src/Core/Insight.Domain/Extensions/ConfigurationExtensions.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Microsoft.Extensions.Configuration; - -namespace Insight.Domain.Extensions; - -public static class ConfigurationExtensions -{ - public static IConfigurationBuilder Defaults(this IConfigurationBuilder configuration) - { - configuration.Sources.Clear(); - configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true); - configuration.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true, reloadOnChange: true); - configuration.AddEnvironmentVariables(); - - return configuration; - } -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Extensions/Linux.cs b/src/Core/Insight.Domain/Extensions/Linux.cs deleted file mode 100644 index 0cd076b..0000000 --- a/src/Core/Insight.Domain/Extensions/Linux.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Diagnostics; -using System.Runtime.Versioning; - -namespace Insight.Domain.Extensions; - -public static class Linux -{ - [SupportedOSPlatform("linux")] - public static string Bash(this string cmd) - { - var escaped = cmd.Replace("\"", "\\\""); - - using var proc = new Process() - { - StartInfo = new ProcessStartInfo - { - FileName = "/bin/bash", - Arguments = $"-c \"{escaped}\"", - RedirectStandardOutput = true, - UseShellExecute = false, - CreateNoWindow = true, - } - }; - - proc.Start(); - var result = proc.StandardOutput.ReadToEnd(); - proc.WaitForExit(); - - return result; - } -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Insight.Domain.csproj b/src/Core/Insight.Domain/Insight.Domain.csproj index dcfe56d..d3ad1de 100644 --- a/src/Core/Insight.Domain/Insight.Domain.csproj +++ b/src/Core/Insight.Domain/Insight.Domain.csproj @@ -1,25 +1,23 @@  - net8.0 - latest - enable + net7.0 + true enable Insight.Domain Insight - 2023.12.15.0 + 2025.2.24.0 + 2025.2.24.0 none + true - - 9193 + none - - - - - + + none + - \ No newline at end of file + diff --git a/src/Core/Insight.Domain/Interfaces/IMessageHandler.cs b/src/Core/Insight.Domain/Interfaces/IMessageHandler.cs deleted file mode 100644 index 1c0d3cb..0000000 --- a/src/Core/Insight.Domain/Interfaces/IMessageHandler.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Insight.Domain.Network; - -namespace Insight.Domain.Interfaces; - -public partial interface IMessageHandler -{ - ValueTask HandleAsync(TSender sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage; -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Models/Result.cs b/src/Core/Insight.Domain/Models/Result.cs deleted file mode 100644 index 5e07353..0000000 --- a/src/Core/Insight.Domain/Models/Result.cs +++ /dev/null @@ -1,147 +0,0 @@ -using MessagePack; -using System.Runtime.Serialization; -using System.Text.Json.Serialization; - -namespace RemoteControl.Shared; - -/// -/// Describes the success or failure of any kind of operation. -/// -[DataContract] -public class Result -{ - /// - /// For serialization only. - /// - [SerializationConstructor] - [JsonConstructor] - public Result() { } - - public Result(bool isSuccess, string reason = "", Exception? exception = null) - { - if (!isSuccess && exception is null && string.IsNullOrWhiteSpace(reason)) - { - throw new ArgumentException("A reason or exception must be supplied for an unsuccessful result."); - } - - IsSuccess = isSuccess; - Exception = exception; - Reason = reason; - } - - [IgnoreDataMember] - public Exception? Exception { get; set; } - - [IgnoreDataMember] - //[MemberNotNullWhen(true, nameof(Exception))] - public bool HadException => Exception is not null; - - [DataMember] - public bool IsSuccess { get; set; } - - [DataMember] - public string Reason { get; set; } = string.Empty; - - - public static Result Fail(string reason) - { - return new Result(false, reason); - } - - public static Result Fail(Exception ex) - { - return new Result(false, string.Empty, ex); - } - - public static Result Fail(string reason) - { - return new Result(reason); - } - - public static Result Fail(Exception ex) - { - return new Result(ex); - } - - public static Result Ok() - { - return new Result(true); - } - - public static Result Ok(T value) - { - return new Result(value); - } -} - - -/// -/// Describes the success or failure of any kind of operation. -/// -[DataContract] -public class Result -{ - /// - /// Returns a successful result with the given value. - /// - /// - public Result(T value) - { - IsSuccess = true; - Value = value; - } - - /// - /// Returns an unsuccessful result with the given exception. - /// - /// - public Result(Exception exception) - { - IsSuccess = false; - Exception = exception; - Reason = exception.Message; - } - - /// - /// Returns an unsuccessful result with the given reason. - /// - /// - /// - public Result(string reason) - { - IsSuccess = false; - Reason = reason; - } - - /// - /// For serialization only. - /// - [SerializationConstructor] - [JsonConstructor] - public Result() { } - - public Result(Exception? exception, bool isSuccess, string reason, T? value) - { - Exception = exception; - IsSuccess = isSuccess; - Reason = reason; - Value = value; - } - - [IgnoreDataMember] - public Exception? Exception { get; set; } - - [IgnoreDataMember] - //[MemberNotNullWhen(true, nameof(Exception))] - public bool HadException => Exception is not null; - - [DataMember] - //[MemberNotNullWhen(true, nameof(Value))] - public bool IsSuccess { get; set; } - - [DataMember] - public string Reason { get; set; } = string.Empty; - - [DataMember] - public T? Value { get; set; } -} diff --git a/src/Core/Insight.Domain/Models/Token.cs b/src/Core/Insight.Domain/Models/Token.cs index 280373d..66d91bc 100644 --- a/src/Core/Insight.Domain/Models/Token.cs +++ b/src/Core/Insight.Domain/Models/Token.cs @@ -1,43 +1,55 @@ using System.ComponentModel.DataAnnotations; using System.Text.Json.Serialization; -namespace Insight.Domain.Models; - -public class TokenRequest +namespace Insight.Domain.Models { - [JsonPropertyName("username"), EmailAddress, Required] - public string? Username { get; set; } + public class TokenRequest + { + [JsonPropertyName("username"), EmailAddress, Required] + public string Username { get; set; } - [JsonPropertyName("password"), DataType(DataType.Password), Required] - public string? Password { get; set; } + [JsonPropertyName("password"), DataType(DataType.Password), Required] + public string Password { get; set; } - [JsonPropertyName("code"), DataType(DataType.Text)] - public string? Code { get; set; } -} + [JsonPropertyName("code"), DataType(DataType.Text)] + public string? Code { get; set; } + } -public class TokenResponse -{ - [JsonPropertyName("access_token")] - public string? AccessToken { get; set; } + public class TokenResponse + { + [JsonPropertyName("access_token")] + public string AccessToken { get; set; } - [JsonPropertyName("expires_in")] - public int ExpireInSeconds { get; set; } + [JsonPropertyName("expires_in")] + public int ExpireInSeconds { get; set; } - [JsonPropertyName("refresh_token")] - public string? RefreshToken { get; set; } -} + [JsonPropertyName("refresh_token")] + public string RefreshToken { get; set; } + } -public class TokenRevokeRequest(string token, string? reason) -{ - [JsonPropertyName("token"), Required] - public string? Token { get; set; } = token; + public class TokenRevokeRequest + { + [JsonPropertyName("token"), Required] + public string Token { get; set; } - [JsonPropertyName("reason")] - public string? Reason { get; set; } = reason; -} + [JsonPropertyName("reason")] + public string? Reason { get; set; } -public class TokenRefreshRequest(string token) -{ - [JsonPropertyName("token"), Required] - public string? Token { get; set; } = token; + public TokenRevokeRequest(string token, string? reason) + { + Token = token; + Reason = reason; + } + } + + public class TokenRefreshRequest + { + [JsonPropertyName("token"), Required] + public string Token { get; set; } + + public TokenRefreshRequest(string token) + { + Token = token; + } + } } \ No newline at end of file diff --git a/src/Core/Insight.Domain/Models/Update.cs b/src/Core/Insight.Domain/Models/Update.cs index 16258a3..6f0fd0b 100644 --- a/src/Core/Insight.Domain/Models/Update.cs +++ b/src/Core/Insight.Domain/Models/Update.cs @@ -1,7 +1,8 @@ -namespace Insight.Domain.Models; - -public class UpdateResponse +namespace Insight.Domain.Models { - public Version? Version { get; set; } - public Uri? Uri { get; set; } + public class UpdateResponse + { + public Version? Version { get; set; } + public Uri? Uri { get; set; } + } } \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/Agent/Messages/Application.cs b/src/Core/Insight.Domain/Network/Agent/Messages/Application.cs deleted file mode 100644 index fc2db2f..0000000 --- a/src/Core/Insight.Domain/Network/Agent/Messages/Application.cs +++ /dev/null @@ -1,32 +0,0 @@ -using MemoryPack; -using System.Runtime.InteropServices; - -namespace Insight.Domain.Network.Agent.Messages; - -[MemoryPackable] -public partial class Application : IMessage -{ - [MemoryPackOrder(0)] - public string? Name { get; set; } - - [MemoryPackOrder(1)] - public string? Publisher { get; set; } - - [MemoryPackOrder(2)] - public string? Version { get; set; } - - [MemoryPackOrder(3)] - public string? Location { get; set; } - - [MemoryPackOrder(4)] - public string? Source { get; set; } - - [MemoryPackOrder(5)] - public string? Uninstall { get; set; } - - [MemoryPackOrder(6)] - public DateTime? InstallDate { get; set; } - - [MemoryPackOrder(7)] - public Architecture? Architecture { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/Agent/Messages/Authentication.cs b/src/Core/Insight.Domain/Network/Agent/Messages/Authentication.cs deleted file mode 100644 index 566d490..0000000 --- a/src/Core/Insight.Domain/Network/Agent/Messages/Authentication.cs +++ /dev/null @@ -1,29 +0,0 @@ -using MemoryPack; - -namespace Insight.Domain.Network.Agent.Messages; - -[MemoryPackable] -public partial class AuthenticationRequest : IMessage { } - -[MemoryPackable] -public partial class AuthenticationResponse : IMessage -{ - [MemoryPackOrder(0)] - public PlatformType? Platform { get; set; } - - [MemoryPackOrder(1)] - public Guid Serial { get; set; } - - [MemoryPackOrder(2)] - public Version? Version { get; set; } - - [MemoryPackOrder(3)] - public string? Hostname { get; set; } - - public enum PlatformType - { - Unknown = 0, - Windows = 1, - Unix = 2 - } -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/Agent/Messages/Commands.cs b/src/Core/Insight.Domain/Network/Agent/Messages/Commands.cs deleted file mode 100644 index e8b32b6..0000000 --- a/src/Core/Insight.Domain/Network/Agent/Messages/Commands.cs +++ /dev/null @@ -1,6 +0,0 @@ -using MemoryPack; - -namespace Insight.Domain.Network.Agent.Messages; - -[MemoryPackable] -public partial class InventoryRequest : IMessage { } \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/Agent/Messages/Drive.cs b/src/Core/Insight.Domain/Network/Agent/Messages/Drive.cs deleted file mode 100644 index 8d8d556..0000000 --- a/src/Core/Insight.Domain/Network/Agent/Messages/Drive.cs +++ /dev/null @@ -1,95 +0,0 @@ -using MemoryPack; - -namespace Insight.Domain.Network.Agent.Messages; - -[MemoryPackable] -public partial class Drive : IMessage -{ - [MemoryPackOrder(0)] - public uint? Index { get; set; } - - [MemoryPackOrder(1)] - public string? Id { get; set; } - - [MemoryPackOrder(2)] - public string? Name { get; set; } - - [MemoryPackOrder(3)] - public string? Manufacturer { get; set; } - - [MemoryPackOrder(4)] - public string? SerialNumber { get; set; } - - [MemoryPackOrder(5)] - public ulong? Size { get; set; } - - [MemoryPackOrder(6)] - public string? Status { get; set; } - - [MemoryPackOrder(7)] - public string? InterfaceType { get; set; } - - [MemoryPackOrder(8)] - public string? FirmwareRevision { get; set; } - - [MemoryPackOrder(9)] - public string? PNPDeviceID { get; set; } - - [MemoryPackOrder(10)] - public List? Volumes { get; set; } -} - -[MemoryPackable] -public partial class Volume : IMessage -{ - [MemoryPackOrder(0)] - public uint? Index { get; set; } - - [MemoryPackOrder(1)] - public string? Id { get; set; } - - [MemoryPackOrder(2)] - public string? Name { get; set; } - - [MemoryPackOrder(3)] - public string? SerialNumber { get; set; } - - [MemoryPackOrder(4)] - public ulong? Size { get; set; } - - [MemoryPackOrder(5)] - public ulong? FreeSpace { get; set; } - - [MemoryPackOrder(6)] - public string? Type { get; set; } - - [MemoryPackOrder(7)] - public string? FileSystem { get; set; } - - [MemoryPackOrder(8)] - public bool? Compressed { get; set; } - - [MemoryPackOrder(9)] - public bool? Bootable { get; set; } - - [MemoryPackOrder(10)] - public bool? PrimaryPartition { get; set; } - - [MemoryPackOrder(11)] - public bool? BootPartition { get; set; } - - [MemoryPackOrder(12)] - public ulong? BlockSize { get; set; } - - [MemoryPackOrder(13)] - public ulong? NumberOfBlocks { get; set; } - - [MemoryPackOrder(14)] - public ulong? StartingOffset { get; set; } - - [MemoryPackOrder(15)] - public DriveType? DriveType { get; set; } - - [MemoryPackOrder(16)] - public string? ProviderName { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/Agent/Messages/Event.cs b/src/Core/Insight.Domain/Network/Agent/Messages/Event.cs deleted file mode 100644 index 1afb844..0000000 --- a/src/Core/Insight.Domain/Network/Agent/Messages/Event.cs +++ /dev/null @@ -1,37 +0,0 @@ -using MemoryPack; - -namespace Insight.Domain.Network.Agent.Messages; - -[MemoryPackable] -public partial class Event : IMessage -{ - [MemoryPackOrder(0)] - public DateTime? Timestamp { get; set; } - - [MemoryPackOrder(1)] - public StatusType? Status { get; set; } - - [MemoryPackOrder(2)] - public string? Source { get; set; } - - [MemoryPackOrder(3)] - public string? Category { get; set; } - - [MemoryPackOrder(4)] - public int? EventId { get; set; } - - [MemoryPackOrder(5)] - public string? Task { get; set; } - - [MemoryPackOrder(6)] - public string? Message { get; set; } - - public enum StatusType - { - Unknown = 0, - Information = 1, - Warning = 2, - Error = 3, - Critical = 4 - } -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/Agent/Messages/Interface.cs b/src/Core/Insight.Domain/Network/Agent/Messages/Interface.cs deleted file mode 100644 index 241d7da..0000000 --- a/src/Core/Insight.Domain/Network/Agent/Messages/Interface.cs +++ /dev/null @@ -1,187 +0,0 @@ -using MemoryPack; -using System.Net; -using System.Net.NetworkInformation; -using System.Net.Sockets; - -namespace Insight.Domain.Network.Agent.Messages; - -[MemoryPackable] -public partial class Interface : IMessage -{ - [MemoryPackOrder(0)] - public uint? Index { get; set; } - - [MemoryPackOrder(1)] - public Guid? Guid { get; set; } - - [MemoryPackOrder(2)] - public string? Mac { get; set; } - - [MemoryPackOrder(3)] - public string? Name { get; set; } - - [MemoryPackOrder(4)] - public string? Description { get; set; } - - [MemoryPackOrder(5)] - public string? Manufacturer { get; set; } - - [MemoryPackOrder(6)] - public string? Suffix { get; set; } - - [MemoryPackOrder(7)] - public bool? Physical { get; set; } - - [MemoryPackOrder(8)] - public NetworkInterfaceType? Type { get; set; } - - [MemoryPackOrder(9)] - public OperationalStatus? Status { get; set; } - - [MemoryPackOrder(10)] - public long? Speed { get; set; } - - [MemoryPackOrder(11)] - public long? Ipv4Mtu { get; set; } - - [MemoryPackOrder(12)] - public bool? Ipv4Dhcp { get; set; } - - [MemoryPackOrder(13)] - public bool? Ipv4Forwarding { get; set; } - - [MemoryPackOrder(14)] - public long? Ipv6Mtu { get; set; } - - [MemoryPackOrder(15)] - public long? Sent { get; set; } - - [MemoryPackOrder(16)] - public long? Received { get; set; } - - [MemoryPackOrder(17)] - public long? IncomingPacketsDiscarded { get; set; } - - [MemoryPackOrder(18)] - public long? IncomingPacketsWithErrors { get; set; } - - [MemoryPackOrder(19)] - public long? IncomingUnknownProtocolPackets { get; set; } - - [MemoryPackOrder(20)] - public long? OutgoingPacketsDiscarded { get; set; } - - [MemoryPackOrder(21)] - public long? OutgoingPacketsWithErrors { get; set; } - - [MemoryPackOrder(22)] - public List? Addresses { get; set; } - - [MemoryPackOrder(23)] - public List? Gateways { get; set; } - - [MemoryPackOrder(24)] - public List? Dns { get; set; } - - [MemoryPackOrder(25)] - public List? Dhcp { get; set; } - - [MemoryPackOrder(26)] - public List? Routes { get; set; } -} - -[MemoryPackable] -public partial class Unicast : IMessage -{ - [MemoryPackOrder(0)] - public IPAddress2? IpAddress { get; set; } - - [MemoryPackOrder(1)] - public IPAddress2? Ipv4Mask { get; set; } - - [MemoryPackOrder(2)] - public long? AddressPreferredLifetime { get; set; } - - [MemoryPackOrder(3)] - public long? AddressValidLifetime { get; set; } - - [MemoryPackOrder(4)] - public long? DhcpLeaseLifetime { get; set; } - - [MemoryPackOrder(5)] - public DuplicateAddressDetectionState? DuplicateAddressDetectionState { get; set; } - - [MemoryPackOrder(6)] - public int? PrefixLength { get; set; } - - [MemoryPackOrder(7)] - public PrefixOrigin? PrefixOrigin { get; set; } - - [MemoryPackOrder(8)] - public SuffixOrigin? SuffixOrigin { get; set; } -} - -[MemoryPackable] -public partial class Route : IMessage -{ - [MemoryPackOrder(0)] - public uint? InterfaceIndex { get; set; } - - [MemoryPackOrder(1)] - public IPAddress2? Destination { get; set; } - - [MemoryPackOrder(2)] - public IPAddress2? Gateway { get; set; } - - [MemoryPackOrder(3)] - public string? Mask { get; set; } - - [MemoryPackOrder(4)] - public int? Metric { get; set; } -} - -[MemoryPackable] -public partial class IPAddress2 : IMessage -{ - [MemoryPackOrder(0)] - public AddressFamily? AddressFamily { get; set; } - - [MemoryPackOrder(1)] - public string? Address { get; set; } - - [MemoryPackOrder(2)] - public bool? IsIPv6Teredo { get; set; } - - [MemoryPackOrder(3)] - public bool? IsIPv6SiteLocal { get; set; } - - [MemoryPackOrder(4)] - public bool? IsIPv6Multicast { get; set; } - - [MemoryPackOrder(5)] - public bool? IsIPv6LinkLocal { get; set; } - - [MemoryPackOrder(6)] - public bool? IsIPv4MappedToIPv6 { get; set; } - - [MemoryPackOrder(7)] - public bool? IsIPv6UniqueLocal { get; set; } - - [MemoryPackConstructor] - public IPAddress2() - { - - } - - public IPAddress2(IPAddress address) - { - AddressFamily = address.AddressFamily; - Address = address.ToString(); - IsIPv4MappedToIPv6 = address.IsIPv4MappedToIPv6; - IsIPv6LinkLocal = address.IsIPv6LinkLocal; - IsIPv6Multicast = address.IsIPv6Multicast; - IsIPv6SiteLocal = address.IsIPv6SiteLocal; - IsIPv6Teredo = address.IsIPv6Teredo; - //IsIPv6UniqueLocal = address.IsIPv6UniqueLocal; - } -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/Agent/Messages/Mainboard.cs b/src/Core/Insight.Domain/Network/Agent/Messages/Mainboard.cs deleted file mode 100644 index 463c12b..0000000 --- a/src/Core/Insight.Domain/Network/Agent/Messages/Mainboard.cs +++ /dev/null @@ -1,25 +0,0 @@ -using MemoryPack; - -namespace Insight.Domain.Network.Agent.Messages; - -[MemoryPackable] -public partial class Mainboard : IMessage -{ - [MemoryPackOrder(0)] - public string? Manufacturer { get; set; } - - [MemoryPackOrder(1)] - public string? Model { get; set; } - - [MemoryPackOrder(2)] - public string? Serial { get; set; } - - [MemoryPackOrder(3)] - public string? BiosManufacturer { get; set; } - - [MemoryPackOrder(4)] - public string? BiosVersion { get; set; } - - [MemoryPackOrder(5)] - public DateTime? BiosDate { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/Agent/Messages/Memory.cs b/src/Core/Insight.Domain/Network/Agent/Messages/Memory.cs deleted file mode 100644 index d11ddaf..0000000 --- a/src/Core/Insight.Domain/Network/Agent/Messages/Memory.cs +++ /dev/null @@ -1,59 +0,0 @@ -using MemoryPack; - -namespace Insight.Domain.Network.Agent.Messages; - -[MemoryPackable] -public partial class Memory : IMessage -{ - [MemoryPackOrder(0)] - public uint? Index { get; set; } - - [MemoryPackOrder(1)] - public string? Tag { get; set; } - - [MemoryPackOrder(2)] - public string? Location { get; set; } - - [MemoryPackOrder(3)] - public string? Manufacturer { get; set; } - - [MemoryPackOrder(4)] - public string? Model { get; set; } - - [MemoryPackOrder(5)] - public string? Serial { get; set; } - - [MemoryPackOrder(6)] - public ulong? Capacity { get; set; } - - [MemoryPackOrder(7)] - public uint? Speed { get; set; } - - [MemoryPackOrder(8)] - public uint? Voltage { get; set; } - - [MemoryPackOrder(9)] - public uint? ConfiguredSpeed { get; set; } - - [MemoryPackOrder(10)] - public uint? ConfiguredVoltage { get; set; } -} - -[MemoryPackable] -public partial class MemoryMetric : IMessage -{ - [MemoryPackOrder(0)] - public DateTime? Timestamp { get; set; } - - [MemoryPackOrder(1)] - public float? MemoryAvailable { get; set; } - - [MemoryPackOrder(2)] - public float? MemoryAvailablePercentage { get; set; } - - [MemoryPackOrder(3)] - public float? MemoryUsed { get; set; } - - [MemoryPackOrder(4)] - public float? MemoryUsagePercentage { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/Agent/Messages/OperationSystem.cs b/src/Core/Insight.Domain/Network/Agent/Messages/OperationSystem.cs deleted file mode 100644 index 3eb9602..0000000 --- a/src/Core/Insight.Domain/Network/Agent/Messages/OperationSystem.cs +++ /dev/null @@ -1,26 +0,0 @@ -using MemoryPack; -using System.Runtime.InteropServices; - -namespace Insight.Domain.Network.Agent.Messages; - -[MemoryPackable] -public partial class OperationSystem : IMessage -{ - [MemoryPackOrder(0)] - public string? Name { get; set; } - - [MemoryPackOrder(1)] - public string? Version { get; set; } - - [MemoryPackOrder(2)] - public string? SerialNumber { get; set; } - - [MemoryPackOrder(3)] - public Architecture? Architecture { get; set; } - - [MemoryPackOrder(4)] - public bool? Virtual { get; set; } - - [MemoryPackOrder(5)] - public DateTime? InstallDate { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/Agent/Messages/Printer.cs b/src/Core/Insight.Domain/Network/Agent/Messages/Printer.cs deleted file mode 100644 index 743fc2c..0000000 --- a/src/Core/Insight.Domain/Network/Agent/Messages/Printer.cs +++ /dev/null @@ -1,22 +0,0 @@ -using MemoryPack; - -namespace Insight.Domain.Network.Agent.Messages; - -[MemoryPackable] -public partial class Printer : IMessage -{ - [MemoryPackOrder(0)] - public string? Name { get; set; } - - [MemoryPackOrder(1)] - public string? Driver { get; set; } - - [MemoryPackOrder(2)] - public string? Port { get; set; } - - [MemoryPackOrder(3)] - public string? Location { get; set; } - - [MemoryPackOrder(4)] - public string? Comment { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/Agent/Messages/Processor.cs b/src/Core/Insight.Domain/Network/Agent/Messages/Processor.cs deleted file mode 100644 index 94ce8be..0000000 --- a/src/Core/Insight.Domain/Network/Agent/Messages/Processor.cs +++ /dev/null @@ -1,62 +0,0 @@ -using MemoryPack; - -namespace Insight.Domain.Network.Agent.Messages; - -[MemoryPackable] -public partial class Processor : IMessage -{ - [MemoryPackOrder(0)] - public uint? Index { get; set; } - - [MemoryPackOrder(1)] - public string? Name { get; set; } - - [MemoryPackOrder(2)] - public string? Manufacturer { get; set; } - - [MemoryPackOrder(3)] - public string? SerialNumber { get; set; } - - [MemoryPackOrder(4)] - public string? Socket { get; set; } - - [MemoryPackOrder(5)] - public string? Version { get; set; } - - [MemoryPackOrder(6)] - public string? DeviceId { get; set; } - - [MemoryPackOrder(7)] - public uint? Cores { get; set; } - - [MemoryPackOrder(8)] - public uint? LogicalCores { get; set; } - - [MemoryPackOrder(9)] - public uint? CurrentSpeed { get; set; } - - [MemoryPackOrder(10)] - public uint? MaxSpeed { get; set; } - - [MemoryPackOrder(11)] - public uint? L1Size { get; set; } - - [MemoryPackOrder(12)] - public uint? L2Size { get; set; } - - [MemoryPackOrder(13)] - public uint? L3Size { get; set; } - - [MemoryPackOrder(14)] - public bool? Virtualization { get; set; } -} - -[MemoryPackable] -public partial class ProcessorMetric : IMessage -{ - [MemoryPackOrder(0)] - public DateTime? Timestamp { get; set; } - - [MemoryPackOrder(1)] - public float? ProcessorUsagePercentage { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/Agent/Messages/Query.cs b/src/Core/Insight.Domain/Network/Agent/Messages/Query.cs deleted file mode 100644 index 9bd2363..0000000 --- a/src/Core/Insight.Domain/Network/Agent/Messages/Query.cs +++ /dev/null @@ -1,61 +0,0 @@ -using MemoryPack; - -namespace Insight.Domain.Network.Agent.Messages; - -[MemoryPackable] -public partial class Request : IMessage -{ - [MemoryPackOrder(0)] - public string? RequestId { get; set; } - - [MemoryPackOrder(1)] - public string? RequestData { get; set; } -} - -[MemoryPackable] -public partial class Response : IMessage -{ - [MemoryPackOrder(0)] - public string? RequestId { get; set; } - - [MemoryPackOrder(1)] - public string? RequestData { get; set; } - - [MemoryPackOrder(2)] - public string? ResponseId { get; set; } - - [MemoryPackOrder(3)] - public string? ResponseData { get; set; } - - [MemoryPackOrder(4)] - public bool? ResponseError { get; set; } - - [MemoryPackConstructor] - public Response() { } - - public Response(Request request) - { - RequestId = request.RequestId; - RequestData = request.RequestData; - } -} - -//[MemoryPackable] -//public partial class ConsoleQueryRequest : IMessage -//{ -// [MemoryPackOrder(0)] -// public string? Query { get; set; } -//} - -//[MemoryPackable] -//public partial class ConsoleQueryResponse : IMessage -//{ -// [MemoryPackOrder(0)] -// public string? Data { get; set; } - -// [MemoryPackOrder(1)] -// public string? Errors { get; set; } - -// [MemoryPackOrder(2)] -// public bool HadErrors { get; set; } -//} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/Agent/Messages/Service.cs b/src/Core/Insight.Domain/Network/Agent/Messages/Service.cs deleted file mode 100644 index 4d7a51b..0000000 --- a/src/Core/Insight.Domain/Network/Agent/Messages/Service.cs +++ /dev/null @@ -1,56 +0,0 @@ -using MemoryPack; - -namespace Insight.Domain.Network.Agent.Messages; - -[MemoryPackable] -public partial class Service : IMessage -{ - [MemoryPackOrder(0)] - public uint? ProcessId { get; set; } - - [MemoryPackOrder(1)] - public string? Name { get; set; } - - [MemoryPackOrder(2)] - public string? Display { get; set; } - - [MemoryPackOrder(3)] - public string? Description { get; set; } - - [MemoryPackOrder(4)] - public string? PathName { get; set; } - - [MemoryPackOrder(5)] - public string? Account { get; set; } - - [MemoryPackOrder(6)] - public bool? Delay { get; set; } - - [MemoryPackOrder(7)] - public ServiceStatus? Status { get; set; } - - [MemoryPackOrder(8)] - public ServiceMode? StartMode { get; set; } - - public enum ServiceStatus - { - Unknown = -1, - Stopped = 1, - StartPending = 2, - StopPending = 3, - Running = 4, - ContinuePending = 5, - PausePending = 6, - Paused = 7 - } - - public enum ServiceMode - { - Unknown = -1, - Boot = 0, - System = 1, - Automatic = 2, - Manual = 3, - Disabled = 4 - } -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/Agent/Messages/Session.cs b/src/Core/Insight.Domain/Network/Agent/Messages/Session.cs deleted file mode 100644 index 024db30..0000000 --- a/src/Core/Insight.Domain/Network/Agent/Messages/Session.cs +++ /dev/null @@ -1,22 +0,0 @@ -using MemoryPack; - -namespace Insight.Domain.Network.Agent.Messages; - -[MemoryPackable] -public partial class Session : IMessage -{ - [MemoryPackOrder(0)] - public string? Sid { get; set; } - - [MemoryPackOrder(1)] - public string? User { get; set; } - - [MemoryPackOrder(2)] - public string? Type { get; set; } - - [MemoryPackOrder(3)] - public string? Status { get; set; } - - [MemoryPackOrder(4)] - public string? Remote { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/Agent/Messages/Status.cs b/src/Core/Insight.Domain/Network/Agent/Messages/Status.cs deleted file mode 100644 index ec59e1f..0000000 --- a/src/Core/Insight.Domain/Network/Agent/Messages/Status.cs +++ /dev/null @@ -1,13 +0,0 @@ -using MemoryPack; - -namespace Insight.Domain.Network.Agent.Messages; - -[MemoryPackable] -public partial class Status : IMessage -{ - [MemoryPackOrder(0)] - public DateTime Timestamp { get; } = DateTime.Now; - - [MemoryPackOrder(1)] - public TimeSpan Uptime { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/Agent/Messages/StoragePool.cs b/src/Core/Insight.Domain/Network/Agent/Messages/StoragePool.cs deleted file mode 100644 index d2d22da..0000000 --- a/src/Core/Insight.Domain/Network/Agent/Messages/StoragePool.cs +++ /dev/null @@ -1,294 +0,0 @@ -using MemoryPack; - -namespace Insight.Domain.Network.Agent.Messages; - -[MemoryPackable] -public partial class StoragePool : IMessage -{ - [MemoryPackOrder(0)] - public string? UniqueId { get; set; } - - [MemoryPackOrder(1)] - public string? Name { get; set; } - - [MemoryPackOrder(2)] - public string? FriendlyName { get; set; } - - [MemoryPackOrder(3)] - public List? States { get; set; } - - [MemoryPackOrder(4)] - public HealthState? Health { get; set; } - - [MemoryPackOrder(5)] - public RetireMissingPhysicalDisksEnum? RetireMissingPhysicalDisks { get; set; } - - [MemoryPackOrder(6)] - public string? Resiliency { get; set; } - - [MemoryPackOrder(7)] - public bool? IsPrimordial { get; set; } - - [MemoryPackOrder(8)] - public bool? IsReadOnly { get; set; } - - [MemoryPackOrder(9)] - public bool? IsClustered { get; set; } - - [MemoryPackOrder(10)] - public ulong? Size { get; set; } - - [MemoryPackOrder(11)] - public ulong? AllocatedSize { get; set; } - - [MemoryPackOrder(12)] - public ulong? SectorSize { get; set; } - - [MemoryPackOrder(13)] - public List? PhysicalDisks { get; set; } - - [MemoryPackOrder(14)] - public List? VirtualDisks { get; set; } - - public enum OperationalState - { - Unknown = 0, - Other = 1, - OK = 2, - Degraded = 3, - Stressed = 4, - Predictive_Failure = 5, - Error = 6, - Non_Recoverable_Error = 7, - Starting = 8, - Stopping = 9, - Stopped = 10, - In_Service = 11, - No_Contact = 12, - Lost_Communication = 13, - Aborted = 14, - Dormant = 15, - Supporting_Entity_In_Error = 16, - Completed = 17, - Power_Mode = 18, - Relocating = 19 - } - - public enum HealthState - { - Healthy = 0, - Warning = 1, - Unhealthy = 2, - Unknown = 3 - } - - public enum RetireMissingPhysicalDisksEnum - { - Auto = 1, - Always = 2, - Never = 3 - } -} - -[MemoryPackable] -public partial class PhysicalDisk : IMessage -{ - [MemoryPackOrder(0)] - public string? UniqueId { get; set; } - - [MemoryPackOrder(1)] - public string? DeviceId { get; set; } - - [MemoryPackOrder(2)] - public string? FriendlyName { get; set; } - - [MemoryPackOrder(3)] - public string? Manufacturer { get; set; } - - [MemoryPackOrder(4)] - public string? Model { get; set; } - - [MemoryPackOrder(5)] - public ushort? MediaType { get; set; } - - [MemoryPackOrder(6)] - public ushort? BusType { get; set; } - - [MemoryPackOrder(7)] - public List? States { get; set; } - - [MemoryPackOrder(8)] - public HealthState? Health { get; set; } - - [MemoryPackOrder(9)] - public List? SupportedUsages { get; set; } - - [MemoryPackOrder(10)] - public ushort? Usage { get; set; } - - [MemoryPackOrder(11)] - public string? PhysicalLocation { get; set; } - - [MemoryPackOrder(12)] - public string? SerialNumber { get; set; } - - [MemoryPackOrder(13)] - public string? FirmwareVersion { get; set; } - - [MemoryPackOrder(14)] - public ulong? Size { get; set; } - - [MemoryPackOrder(15)] - public ulong? AllocatedSize { get; set; } - - [MemoryPackOrder(16)] - public ulong? LogicalSectorSize { get; set; } - - [MemoryPackOrder(17)] - public ulong? PhysicalSectorSize { get; set; } - - [MemoryPackOrder(18)] - public ulong? VirtualDiskFootprint { get; set; } - - public enum OperationalState - { - Unknown = 0, - Other = 1, - OK = 2, - Degraded = 3, - Stressed = 4, - Predictive_Failure = 5, - Error = 6, - Non_Recoverable_Error = 7, - Starting = 8, - Stopping = 9, - Stopped = 10, - In_Service = 11, - No_Contact = 12, - Lost_Communication = 13, - Aborted = 14, - Dormant = 15, - Supporting_Entity_In_Error = 16, - Completed = 17, - Power_Mode = 18, - Relocating = 19 - } - - public enum HealthState - { - Healthy = 0, - Warning = 1, - Unhealthy = 2, - Unknown = 3 - } - - public enum SupportedUsagesEnum - { - Unknown = 0, - Auto_Select = 1, - Manual_Select = 2, - Hot_Spare = 3, - Retired = 4, - Journal = 5 - } -} - -[MemoryPackable] -public partial class VirtualDisk : IMessage -{ - [MemoryPackOrder(0)] - public string? UniqueId { get; set; } - - [MemoryPackOrder(1)] - public string? Name { get; set; } - - [MemoryPackOrder(2)] - public string? FriendlyName { get; set; } - - [MemoryPackOrder(3)] - public List? States { get; set; } - - [MemoryPackOrder(4)] - public HealthState? Health { get; set; } - - [MemoryPackOrder(5)] - public AccessTypeEnum? AccessType { get; set; } - - [MemoryPackOrder(6)] - public ProvisioningTypeEnum? ProvisioningType { get; set; } - - [MemoryPackOrder(7)] - public ushort? PhysicalDiskRedundancy { get; set; } - - [MemoryPackOrder(8)] - public string? ResiliencySettingName { get; set; } - - [MemoryPackOrder(9)] - public bool? Deduplication { get; set; } - - [MemoryPackOrder(10)] - public bool? IsSnapshot { get; set; } - - [MemoryPackOrder(11)] - public ulong? Size { get; set; } - - [MemoryPackOrder(12)] - public ulong? AllocatedSize { get; set; } - - [MemoryPackOrder(13)] - public ulong? FootprintOnPool { get; set; } - - [MemoryPackOrder(14)] - public ulong? ReadCacheSize { get; set; } - - [MemoryPackOrder(15)] - public ulong? WriteCacheSize { get; set; } - - public enum OperationalState - { - Unknown = 0, - Other = 1, - OK = 2, - Degraded = 3, - Stressed = 4, - Predictive_Failure = 5, - Error = 6, - Non_Recoverable_Error = 7, - Starting = 8, - Stopping = 9, - Stopped = 10, - In_Service = 11, - No_Contact = 12, - Lost_Communication = 13, - Aborted = 14, - Dormant = 15, - Supporting_Entity_In_Error = 16, - Completed = 17, - Power_Mode = 18, - Relocating = 19 - } - - public enum HealthState - { - Healthy = 0, - Warning = 1, - Unhealthy = 2, - Unknown = 3 - } - - public enum AccessTypeEnum - { - Unknown = 0, - Readable = 1, - Writeable = 2, - Read_Write = 3, - Write_Once = 4 - } - - public enum ProvisioningTypeEnum - { - Unknown = 0, - Thin = 1, - Fixed = 2 - } -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/Agent/Messages/SystemInfo.cs b/src/Core/Insight.Domain/Network/Agent/Messages/SystemInfo.cs deleted file mode 100644 index 187abfd..0000000 --- a/src/Core/Insight.Domain/Network/Agent/Messages/SystemInfo.cs +++ /dev/null @@ -1,19 +0,0 @@ -using MemoryPack; - -namespace Insight.Domain.Network.Agent.Messages; - -[MemoryPackable] -public partial class SystemInfo : IMessage -{ - [MemoryPackOrder(0)] - public DateTime? LastBootUpTime { get; set; } - - [MemoryPackOrder(1)] - public DateTime? LocalDateTime { get; set; } - - [MemoryPackOrder(2)] - public uint? Processes { get; set; } - - [MemoryPackOrder(3)] - public string? License { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/Agent/Messages/Trap.cs b/src/Core/Insight.Domain/Network/Agent/Messages/Trap.cs deleted file mode 100644 index e2199ae..0000000 --- a/src/Core/Insight.Domain/Network/Agent/Messages/Trap.cs +++ /dev/null @@ -1,25 +0,0 @@ -using MemoryPack; - -namespace Insight.Domain.Network.Agent.Messages; - -[MemoryPackable] -public partial class Trap : IMessage -{ - [MemoryPackOrder(0)] - public DateTime? Timestamp { get; set; } - - [MemoryPackOrder(1)] - public string? Endpoint { get; set; } - - [MemoryPackOrder(2)] - public string? Hostname { get; set; } - - [MemoryPackOrder(3)] - public string? Version { get; set; } - - [MemoryPackOrder(4)] - public string? Community { get; set; } - - [MemoryPackOrder(5)] - public List>? Data { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/Agent/Messages/Update.cs b/src/Core/Insight.Domain/Network/Agent/Messages/Update.cs deleted file mode 100644 index 5a039cb..0000000 --- a/src/Core/Insight.Domain/Network/Agent/Messages/Update.cs +++ /dev/null @@ -1,78 +0,0 @@ -using MemoryPack; - -namespace Insight.Domain.Network.Agent.Messages; - -[MemoryPackable] -public partial class Update : IMessage -{ - [MemoryPackOrder(0)] - public string? Id { get; set; } - - [MemoryPackOrder(1)] - public DateTime? Date { get; set; } - - [MemoryPackOrder(2)] - public string? Name { get; set; } - - [MemoryPackOrder(3)] - public string? Description { get; set; } - - [MemoryPackOrder(4)] - public string? SupportUrl { get; set; } - - [MemoryPackOrder(5)] - public string? Hotfix { get; set; } - - // if installed - [MemoryPackOrder(6)] - public OsUpdateResultCodeEnum? Result { get; set; } - - // if pending - [MemoryPackOrder(7)] - public OsUpdateTypeEnum? Type { get; set; } - - [MemoryPackOrder(8)] - public decimal? Size { get; set; } - - [MemoryPackOrder(9)] - public bool? IsDownloaded { get; set; } - - [MemoryPackOrder(10)] - public bool? CanRequestUserInput { get; set; } - - [MemoryPackOrder(11)] - public OsUpdateRebootBehaviorEnum? RebootBehavior { get; set; } - - public enum OsUpdateRebootBehaviorEnum - { - NeverReboots = 1, - AlwaysRequiresReboot = 2, - CanRequestReboot = 3 - } - - public enum OsUpdateResultCodeEnum - { - NotStarted = 1, - InProgress = 2, - Succeeded = 3, - SucceededWithErrors = 4, - Failed = 5, - Aborted = 6 - } - - public enum OsUpdateTypeEnum - { - Software = 1, - Driver = 2 - } -} - -[MemoryPackable] -public partial class UpdateCollection : IMessage -{ - [MemoryPackOrder(0)] - public List? Installed { get; set; } - - [MemoryPackOrder(1)] - public List? Pending { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/Agent/Messages/User.cs b/src/Core/Insight.Domain/Network/Agent/Messages/User.cs deleted file mode 100644 index 5417641..0000000 --- a/src/Core/Insight.Domain/Network/Agent/Messages/User.cs +++ /dev/null @@ -1,65 +0,0 @@ -using MemoryPack; - -namespace Insight.Domain.Network.Agent.Messages; - -[MemoryPackable] -public partial class User : IMessage -{ - [MemoryPackOrder(0)] - public string? Sid { get; set; } - - [MemoryPackOrder(1)] - public string? Domain { get; set; } - - [MemoryPackOrder(2)] - public string? Name { get; set; } - - [MemoryPackOrder(3)] - public string? FullName { get; set; } - - [MemoryPackOrder(4)] - public string? Description { get; set; } - - [MemoryPackOrder(5)] - public string? Status { get; set; } - - [MemoryPackOrder(6)] - public bool? LocalAccount { get; set; } - - [MemoryPackOrder(7)] - public bool? Disabled { get; set; } - - [MemoryPackOrder(8)] - public bool? Lockout { get; set; } - - [MemoryPackOrder(9)] - public bool? PasswordChangeable { get; set; } - - [MemoryPackOrder(10)] - public bool? PasswordExpires { get; set; } - - [MemoryPackOrder(11)] - public bool? PasswordRequired { get; set; } - - [MemoryPackOrder(12)] - public List? Groups { get; set; } -} - -[MemoryPackable] -public partial class Group : IMessage -{ - [MemoryPackOrder(0)] - public string? Sid { get; set; } - - [MemoryPackOrder(1)] - public string? Domain { get; set; } - - [MemoryPackOrder(2)] - public string? Name { get; set; } - - [MemoryPackOrder(3)] - public string? Description { get; set; } - - [MemoryPackOrder(4)] - public bool? LocalAccount { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/Agent/Messages/Videocard.cs b/src/Core/Insight.Domain/Network/Agent/Messages/Videocard.cs deleted file mode 100644 index f651294..0000000 --- a/src/Core/Insight.Domain/Network/Agent/Messages/Videocard.cs +++ /dev/null @@ -1,22 +0,0 @@ -using MemoryPack; - -namespace Insight.Domain.Network.Agent.Messages; - -[MemoryPackable] -public partial class Videocard : IMessage -{ - [MemoryPackOrder(0)] - public string? DeviceId { get; set; } - - [MemoryPackOrder(1)] - public string? Model { get; set; } - - [MemoryPackOrder(2)] - public ulong Memory { get; set; } - - [MemoryPackOrder(3)] - public DateTime DriverDate { get; set; } - - [MemoryPackOrder(4)] - public string? DriverVersion { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/Agent/Messages/VirtualMaschine.cs b/src/Core/Insight.Domain/Network/Agent/Messages/VirtualMaschine.cs deleted file mode 100644 index 7e2eef5..0000000 --- a/src/Core/Insight.Domain/Network/Agent/Messages/VirtualMaschine.cs +++ /dev/null @@ -1,257 +0,0 @@ -using MemoryPack; - -namespace Insight.Domain.Network.Agent.Messages; - -[MemoryPackable] -public partial class VirtualMaschine : IMessage -{ - [MemoryPackOrder(0)] - public Guid? Id { get; set; } - - [MemoryPackOrder(1)] - public uint? ProcessId { get; set; } - - [MemoryPackOrder(2)] - public string? Caption { get; set; } - - [MemoryPackOrder(3)] - public string? Name { get; set; } - - [MemoryPackOrder(4)] - public string? Notes { get; set; } - - [MemoryPackOrder(5)] - public EnabledEnum? Enabled { get; set; } - - [MemoryPackOrder(6)] - public EnabledDefaultEnum? EnabledDefault { get; set; } - - [MemoryPackOrder(7)] - public HealthStatusEnum? HealthState { get; set; } - - [MemoryPackOrder(8)] - public string? Status { get; set; } - - [MemoryPackOrder(9)] - public ulong? OnTime { get; set; } - - [MemoryPackOrder(10)] - public uint? ReplicationMode { get; set; } - - [MemoryPackOrder(11)] - public ReplicationStateEnum? ReplicationState { get; set; } - - [MemoryPackOrder(12)] - public ReplicationHealthEnum? ReplicationHealth { get; set; } - - [MemoryPackOrder(13)] - public string? ConfigurationVersion { get; set; } - - [MemoryPackOrder(14)] - public IntegrationServicesVersionStateEnum? IntegrationServicesVersionState { get; set; } - - [MemoryPackOrder(15)] - public uint? NumberOfProcessors { get; set; } - - [MemoryPackOrder(16)] - public uint? ProcessorLoad { get; set; } - - [MemoryPackOrder(17)] - public int? MemoryAvailable { get; set; } - - [MemoryPackOrder(18)] - public ulong? MemoryUsage { get; set; } - - [MemoryPackOrder(19)] - public DateTime? InstallDate { get; set; } - - [MemoryPackOrder(20)] - public DateTime? TimeOfLastConfigurationChange { get; set; } - - [MemoryPackOrder(21)] - public DateTime? TimeOfLastStateChange { get; set; } - - [MemoryPackOrder(22)] - public DateTime? LastReplicationTime { get; set; } - - [MemoryPackOrder(23)] - public string? GuestOperatingSystem { get; set; } - - [MemoryPackOrder(24)] - public List? Configurations { get; set; } - - public enum EnabledEnum - { - Unbekannt = 0, - Andere = 1, - Aktiviert = 2, - Deaktiviert = 3, - Herunterfahren = 4, - Nicht_Verfügbar = 5, - Aktiviert_Offline = 6, - In_Test = 7, - Latent = 8, - Eingeschränkt = 9, - Wird_gestartet = 10 - } - - public enum EnabledDefaultEnum - { - Aktiviert = 2, - Deaktiviert = 3, - Aktiviert_Offline = 6 - } - - public enum HealthStatusEnum - { - OK = 5, - Hauptfehler = 20, - Kritischer_Fehler = 25 - } - - public enum ReplicationStateEnum - { - Deaktiviert = 0, - Bereit = 1, - Warten_auf_Erstreplikation = 2, - Replikat = 3, - Synchronisierte_Replication_abgeschlossen = 4, - Wiederhergestellt = 5, - Commit = 6, - Angehalten = 7, - Kritisch = 8, - Warten_auf_die_Neusynchronisierung = 9, - Resynchronisierung = 10, - Resynchronisierung_angehalten = 11, - Failover_in_Bearbeitung = 12, - Failback_in_Fortschritt = 13, - Failback_abgeschlossen = 14, - Datenträgerupdate_in_Bearbeitung = 15, - Datenträgeraktualisierung_kritisch = 16, - Unbekannt = 17, - Repurpose_Replikation_in_Bearbeitung = 18, - Vorbereitet_für_die_Synchronisierungsreplikation = 19, - Vorbereitet_für_die_Umgekehrte_Replikation_der_Gruppe = 20, - Failover_in_Fortschritt = 21 - } - - public enum ReplicationHealthEnum - { - OK = 1, - Warnung = 2, - Kritisch = 3 - } - - public enum IntegrationServicesVersionStateEnum - { - Unknown = 0, - UpToDate = 1, - Mismatch = 2 - } -} - -[MemoryPackable] -public partial class VirtualMaschineConfiguration : IMessage -{ - [MemoryPackOrder(0)] - public string? Id { get; set; } - - [MemoryPackOrder(1)] - public string? ParentId { get; set; } - - [MemoryPackOrder(2)] - public string? Type { get; set; } - - [MemoryPackOrder(3)] - public string? Name { get; set; } - - [MemoryPackOrder(4)] - public DateTime? CreationTime { get; set; } - - [MemoryPackOrder(5)] - public string? Generation { get; set; } - - [MemoryPackOrder(6)] - public string? Architecture { get; set; } - - [MemoryPackOrder(7)] - public AutomaticStartupActionEnum? AutomaticStartupAction { get; set; } - //public DateTime? AutomaticStartupActionDelay { get; set; } - - [MemoryPackOrder(8)] - public AutomaticShutdownActionEnum? AutomaticShutdownAction { get; set; } - - [MemoryPackOrder(9)] - public AutomaticRecoveryActionEnum? AutomaticRecoveryAction { get; set; } - - [MemoryPackOrder(10)] - public bool? AutomaticSnapshotsEnabled { get; set; } - - [MemoryPackOrder(11)] - public string? BaseBoardSerialNumber { get; set; } - - [MemoryPackOrder(12)] - public string? BIOSGUID { get; set; } - - [MemoryPackOrder(13)] - public string? BIOSSerialNumber { get; set; } - - [MemoryPackOrder(14)] - public ushort[]? BootOrder { get; set; } - - [MemoryPackOrder(15)] - public string? ConfigurationDataRoot { get; set; } - - [MemoryPackOrder(16)] - public string? ConfigurationFile { get; set; } - - [MemoryPackOrder(17)] - public string? GuestStateDataRoot { get; set; } - - [MemoryPackOrder(18)] - public string? GuestStateFile { get; set; } - - [MemoryPackOrder(19)] - public string? SnapshotDataRoot { get; set; } - - [MemoryPackOrder(20)] - public string? SuspendDataRoot { get; set; } - - [MemoryPackOrder(21)] - public string? SwapFileDataRoot { get; set; } - - [MemoryPackOrder(22)] - public bool? SecureBootEnabled { get; set; } - - [MemoryPackOrder(23)] - public bool? IsAutomaticSnapshot { get; set; } - - [MemoryPackOrder(24)] - public string[]? Notes { get; set; } - - [MemoryPackOrder(25)] - public List? Childs { get; set; } - - //public string[]? HostResource { get; set; } - - public enum AutomaticStartupActionEnum - { - Nothing = 2, - RestartIfLastStateActive = 3, - Alway = 4 - } - - public enum AutomaticShutdownActionEnum - { - Ausschalten = 2, - Speichern = 3, - Herunterfahren = 4 - } - - public enum AutomaticRecoveryActionEnum - { - Keine = 2, - Neustart = 3, - Rollback = 4 - } -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/Collection.cs b/src/Core/Insight.Domain/Network/Collection.cs deleted file mode 100644 index 7466c26..0000000 --- a/src/Core/Insight.Domain/Network/Collection.cs +++ /dev/null @@ -1,7 +0,0 @@ -using MemoryPack; - -namespace Insight.Domain.Network; - -[MemoryPackable(GenerateType.Collection)] -public partial class Collection : List, IMessage where TMessage : IMessage -{ } \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/IMessage.cs b/src/Core/Insight.Domain/Network/IMessage.cs deleted file mode 100644 index 35421e8..0000000 --- a/src/Core/Insight.Domain/Network/IMessage.cs +++ /dev/null @@ -1,50 +0,0 @@ -using MemoryPack; - -namespace Insight.Domain.Network; - -// AGENT [0 - 99] -[MemoryPackUnion(0, typeof(Agent.Messages.AuthenticationRequest))] -[MemoryPackUnion(1, typeof(Agent.Messages.AuthenticationResponse))] -[MemoryPackUnion(2, typeof(Agent.Messages.InventoryRequest))] -[MemoryPackUnion(7, typeof(Agent.Messages.Event))] -[MemoryPackUnion(8, typeof(Agent.Messages.Trap))] -[MemoryPackUnion(9, typeof(Agent.Messages.Mainboard))] -[MemoryPackUnion(10, typeof(Agent.Messages.OperationSystem))] -[MemoryPackUnion(11, typeof(Agent.Messages.Status))] -[MemoryPackUnion(12, typeof(Agent.Messages.SystemInfo))] -[MemoryPackUnion(13, typeof(Collection))] -[MemoryPackUnion(14, typeof(Collection))] -[MemoryPackUnion(15, typeof(Collection))] -[MemoryPackUnion(16, typeof(Collection))] -[MemoryPackUnion(17, typeof(Collection))] -[MemoryPackUnion(18, typeof(Collection))] -[MemoryPackUnion(19, typeof(Collection))] -[MemoryPackUnion(20, typeof(Collection))] -[MemoryPackUnion(21, typeof(Collection))] -[MemoryPackUnion(22, typeof(Agent.Messages.UpdateCollection))] -[MemoryPackUnion(23, typeof(Collection))] -[MemoryPackUnion(24, typeof(Collection))] -[MemoryPackUnion(25, typeof(Collection))] - -[MemoryPackUnion(50, typeof(Agent.Messages.Request))] -[MemoryPackUnion(51, typeof(Agent.Messages.Response))] -[MemoryPackUnion(52, typeof(Proxy))] -[MemoryPackUnion(53, typeof(Proxy))] - -// REMOTE [100 - 199] -[MemoryPackUnion(102, typeof(Remote.Messages.RemoteSessionRequest))] -[MemoryPackUnion(103, typeof(Remote.Messages.RemoteSessionResponse))] -[MemoryPackUnion(104, typeof(Remote.Messages.CastRequest))] -[MemoryPackUnion(105, typeof(Remote.Messages.CastRequestResponse))] -[MemoryPackUnion(107, typeof(Remote.Messages.CastAbort))] -[MemoryPackUnion(108, typeof(Remote.Messages.CastMetric))] -[MemoryPackUnion(109, typeof(Remote.Messages.CastDisplay))] -[MemoryPackUnion(110, typeof(Remote.Messages.CastScreen))] -[MemoryPackUnion(111, typeof(Remote.Messages.CastScreenReceived))] -[MemoryPackUnion(112, typeof(Remote.Messages.CastCursor))] -[MemoryPackUnion(113, typeof(Remote.Messages.CastCursorReceived))] -[MemoryPackUnion(114, typeof(Remote.Messages.CastClipboardReceived))] -[MemoryPackUnion(115, typeof(Remote.Messages.CastAudio))] - -[MemoryPackable] -public partial interface IMessage { } \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/Proxy.cs b/src/Core/Insight.Domain/Network/Proxy.cs deleted file mode 100644 index a16fb78..0000000 --- a/src/Core/Insight.Domain/Network/Proxy.cs +++ /dev/null @@ -1,14 +0,0 @@ -using MemoryPack; - -namespace Insight.Domain.Network; - -[MemoryPackable] -public partial class Proxy : IMessage - where TMessage : IMessage -{ - [MemoryPackOrder(0)] - public string? ProxyId { get; set; } - - [MemoryPackOrder(1)] - public TMessage? Message { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/Remote/Messages/Session.cs b/src/Core/Insight.Domain/Network/Remote/Messages/Session.cs deleted file mode 100644 index 1a1ecca..0000000 --- a/src/Core/Insight.Domain/Network/Remote/Messages/Session.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Insight.Domain.Enums; -using MemoryPack; - -namespace Insight.Domain.Network.Remote.Messages; - -[MemoryPackable] -public partial class RemoteSessionRequest : IMessage -{ - [MemoryPackOrder(0)] - public RemoteControlMode Mode { get; set; } - - [MemoryPackOrder(1)] - public string? AccessKey { get; set; } - - [MemoryPackOrder(2)] - public string? Hostname { get; set; } -} - -[MemoryPackable] -public partial class RemoteSessionResponse : IMessage -{ - [MemoryPackOrder(0)] - public string? SessionId { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Domain/Network/Remote/Messages/Stream.cs b/src/Core/Insight.Domain/Network/Remote/Messages/Stream.cs deleted file mode 100644 index e1a9ba0..0000000 --- a/src/Core/Insight.Domain/Network/Remote/Messages/Stream.cs +++ /dev/null @@ -1,185 +0,0 @@ -using Insight.Domain.Enums; -using MemoryPack; - -namespace Insight.Domain.Network.Remote.Messages; - -[MemoryPackable] -public partial class CastRequest : IMessage -{ - [MemoryPackOrder(0)] - public string? Id { get; set; } - - [MemoryPackOrder(1)] - public RemoteControlMode Mode { get; set; } - - [MemoryPackOrder(2)] - public string? RequesterName { get; set; } - - [MemoryPackOrder(3)] - public string? AccessKey { get; set; } -} - -[MemoryPackable] -public partial class CastRequestResponse : IMessage -{ - [MemoryPackOrder(0)] - public string? Id { get; set; } - - [MemoryPackOrder(0)] - public bool Accepted { get; set; } - - [MemoryPackConstructor] - public CastRequestResponse() { } - - public CastRequestResponse(CastRequest request) - { - Id = request.Id; - } -} - -[MemoryPackable] -public partial class CastAbort : IMessage -{ - [MemoryPackOrder(0)] - public string? Id { get; set; } -} - -[MemoryPackable] -public partial class CastMetric : IMessage -{ - [MemoryPackOrder(0)] - public string? Id { get; set; } - - [MemoryPackOrder(1)] - public DateTimeOffset? Timestamp { get; set; } - - [MemoryPackOrder(2)] - public double? Mbps { get; set; } - - [MemoryPackOrder(3)] - public double? Fps { get; set; } - - [MemoryPackOrder(4)] - public double? RTT { get; set; } -} - -[MemoryPackable] -public partial class CastDisplay : IMessage -{ - [MemoryPackOrder(0)] - public string? Id { get; set; } - - [MemoryPackOrder(1)] - public IEnumerable? DisplayNames { get; set; } - - [MemoryPackOrder(2)] - public string? SelectedDisplay { get; set; } - - [MemoryPackOrder(3)] - public int ScreenWidth { get; set; } - - [MemoryPackOrder(4)] - public int ScreenHeight { get; set; } - - [MemoryPackOrder(5)] - public string? MachineName { get; set; } -} - -[MemoryPackable] -public partial class CastScreen : IMessage -{ - [MemoryPackOrder(0)] - public string? Id { get; set; } - - [MemoryPackOrder(1)] - public DateTimeOffset? Timestamp { get; set; } - - [MemoryPackOrder(2)] - public float? ViewWidth { get; set; } - - [MemoryPackOrder(3)] - public float? ViewHeight { get; set; } - - [MemoryPackOrder(4)] - public float? Left { get; set; } - - [MemoryPackOrder(5)] - public float? Top { get; set; } - - [MemoryPackOrder(6)] - public float? Width { get; set; } - - [MemoryPackOrder(7)] - public float? Height { get; set; } - - [MemoryPackOrder(8)] - public byte[]? Image { get; set; } -} - -[MemoryPackable] -public partial class CastScreenReceived : IMessage -{ - [MemoryPackOrder(0)] - public string? Id { get; set; } - - [MemoryPackOrder(1)] - public DateTimeOffset? Timestamp { get; set; } - - [MemoryPackConstructor] - public CastScreenReceived() { } - - public CastScreenReceived(CastScreen screenData) - { - Id = screenData.Id; - Timestamp = screenData.Timestamp; - } -} - -[MemoryPackable] -public partial class CastCursor : IMessage -{ - [MemoryPackOrder(0)] - public string? Id { get; set; } - - [MemoryPackOrder(1)] - public int X { get; set; } - - [MemoryPackOrder(2)] - public int Y { get; set; } - - [MemoryPackOrder(3)] - public byte[]? Icon { get; set; } -} - -[MemoryPackable] -public partial class CastCursorReceived : IMessage -{ - [MemoryPackOrder(0)] - public string? Id { get; set; } - - [MemoryPackOrder(1)] - public int X { get; set; } - - [MemoryPackOrder(2)] - public int Y { get; set; } -} - -[MemoryPackable] -public partial class CastClipboardReceived : IMessage -{ - [MemoryPackOrder(0)] - public string? Id { get; set; } - - [MemoryPackOrder(1)] - public string? Text { get; set; } -} - -[MemoryPackable] -public partial class CastAudio : IMessage -{ - [MemoryPackOrder(0)] - public string? Id { get; set; } - - [MemoryPackOrder(1)] - public byte[]? Buffer { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure.Web/Extensions/HttpRequestExtensions.cs b/src/Core/Insight.Infrastructure.Web/Extensions/HttpRequestExtensions.cs deleted file mode 100644 index a18fca6..0000000 --- a/src/Core/Insight.Infrastructure.Web/Extensions/HttpRequestExtensions.cs +++ /dev/null @@ -1,46 +0,0 @@ -using Insight.Infrastructure.Models; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Extensions; - -namespace Insight.Infrastructure; - -public static partial class HttpRequestExtensions -{ - public static void AddPagination(this HttpRequest request, PagedList pagelist) - { - var builder = new QueryBuilder(); - - foreach (var item in request.Query.Where(p => p.Key.ToLower() != "limit" || p.Key.ToLower() != "offset")) - { - builder.Add(item.Key.ToLower(), item.Value.ToString()); - } - - builder.Add("limit", pagelist.Meta.Limit.ToString()); - - if (pagelist.Meta.Offset > 0) - { - var qb = new QueryBuilder(builder); - - if (pagelist.Meta.Offset > pagelist.Meta.Limit) - { - qb.Add("offset", (pagelist.Meta.Offset - pagelist.Meta.Limit).ToString()); - } - else - { - qb.Add("offset", 0.ToString()); - } - - pagelist.Meta.Previous = $"{request.Scheme}://{request.Host}{request.PathBase}{request.Path}{qb}"; - } - - if ((pagelist.Meta.Offset + pagelist.Meta.Count) < pagelist.Meta.Total) - { - var qb = new QueryBuilder(builder) - { - { "offset", (pagelist.Meta.Offset + pagelist.Meta.Count).ToString() } - }; - - pagelist.Meta.Next = $"{request.Scheme}://{request.Host}{request.PathBase}{request.Path}{qb}"; - } - } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure.Web/Extensions/HttpResponseExtensions.cs b/src/Core/Insight.Infrastructure.Web/Extensions/HttpResponseExtensions.cs deleted file mode 100644 index b449964..0000000 --- a/src/Core/Insight.Infrastructure.Web/Extensions/HttpResponseExtensions.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Insight.Infrastructure.Models; -using Microsoft.AspNetCore.Http; -using System.Text.Json; - -namespace Insight.Infrastructure; - -public static partial class HttpResponseExtensions -{ - private static readonly JsonSerializerOptions _options = new() - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase - }; - - public static void AddPagination(this HttpResponse response, PagedList pagelist) - { - response.Headers.Append("X-Pagination", JsonSerializer.Serialize(pagelist.Meta as PagedHeaderData, _options)); - } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure.Web/Extensions/MongoCollectionExtensions.cs b/src/Core/Insight.Infrastructure.Web/Extensions/MongoCollectionExtensions.cs deleted file mode 100644 index ba9c355..0000000 --- a/src/Core/Insight.Infrastructure.Web/Extensions/MongoCollectionExtensions.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Insight.Infrastructure.Models; -using Microsoft.AspNetCore.Http; -using MongoDB.Bson; -using MongoDB.Driver; - -namespace Insight.Infrastructure.Web; - -public static class MongoCollectionExtensions -{ - public static async Task> GetPagedAsync( - this IMongoCollection collection, - HttpRequest request, - HttpResponse response, - FilterDefinition? filter = null, - SortDefinition? sort = null, - int offset = 0, - int limit = 10, - CancellationToken cancellationToken = default) - { - var result = await Infrastructure.MongoCollectionExtensions.GetPagedAsync(collection, filter, sort, offset, limit, cancellationToken).ConfigureAwait(false); - - request?.AddPagination(result); - response?.AddPagination(result); - - return result; - } - - public static async Task> GetPagedAsync( - this IMongoCollection collection, - HttpRequest request, - HttpResponse response, - IAggregateFluent query, - int offset = 0, - int limit = 10, - CancellationToken cancellationToken = default) - { - var result = await Infrastructure.MongoCollectionExtensions.GetPagedAsync(collection, query, offset, limit, cancellationToken).ConfigureAwait(false); - - request?.AddPagination(result); - response?.AddPagination(result); - - return result; - } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure.Web/Extensions/ServiceExtensions.cs b/src/Core/Insight.Infrastructure.Web/Extensions/ServiceExtensions.cs deleted file mode 100644 index 3333b32..0000000 --- a/src/Core/Insight.Infrastructure.Web/Extensions/ServiceExtensions.cs +++ /dev/null @@ -1,227 +0,0 @@ -using Insight.Infrastructure.Entities; -using Insight.Infrastructure.Services; -using Microsoft.AspNetCore.Authentication.JwtBearer; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.HttpOverrides; -using Microsoft.AspNetCore.Identity; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Primitives; -using Microsoft.IdentityModel.Tokens; -using Microsoft.Net.Http.Headers; -using MongoDB.Bson; -using System.Text; - -namespace Insight.Infrastructure; - -public static partial class ServiceExtensions -{ - public static WebApplicationBuilder AddDefaults(this WebApplicationBuilder builder) - { - builder.Services.Configure(options => - { - options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; - }); - builder.Services.AddRouting(options => - { - options.LowercaseUrls = true; - }); - - return builder; - } - - public static WebApplicationBuilder AddApiDefaults(this WebApplicationBuilder builder) - { - builder.Services.AddControllers(); - builder.Services.AddEndpointsApiExplorer(); - - return builder; - } - - public static IServiceCollection AddIdentity(this IServiceCollection services, IConfiguration configuration) - { - var connectionString = configuration.GetValue(Appsettings.Mongo.ConnectionString) ?? throw new Exception($"{Appsettings.Mongo.ConnectionString} value not set (appsettings)"); - - services.AddIdentity(options => - { - - }) - .AddMongoDbStores(connectionString, Settings.Database) - .AddDefaultTokenProviders() - .AddSignInManager(); - - return services; - } - - public static IServiceCollection AddTokenServices(this IServiceCollection services, IConfiguration configuration) - { - var options = new Models.TokenOptions( - key: configuration.GetValue(Appsettings.Jwt.Key) ?? throw new Exception($"{Appsettings.Jwt.Key} value not set (appsettings)"), - expires: configuration.GetValue(Appsettings.Jwt.Exp) ?? throw new Exception($"{Appsettings.Jwt.Exp} value not set (appsettings)"), - audience: configuration.GetValue(Appsettings.Jwt.Audience) ?? throw new Exception($"{Appsettings.Jwt.Audience} value not set (appsettings)"), - issuer: configuration.GetValue(Appsettings.Jwt.Issuer) ?? throw new Exception($"{Appsettings.Jwt.Issuer} value not set (appsettings)")); - - services.AddSingleton(options); - services.AddTransient(); - - return services; - } - - public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration) - { - // REWRITE TO COOKIE ONLY FOR WEB - - services.AddAuthentication(options => - { - options.DefaultScheme = "Custom"; - options.DefaultChallengeScheme = "Custom"; - }) - .AddCookie("Cookies", options => - { - //options.Cookie.Domain = "insight.webmatic.de"; - options.Cookie.Name = "insight"; - options.LoginPath = "/account/login"; - options.LogoutPath = "/account/logout"; - options.ExpireTimeSpan = TimeSpan.FromHours(1); - options.SlidingExpiration = true; - - options.Events.OnRedirectToLogin = options => - { - if (options.Request.Path.StartsWithSegments("/api") && options.Response.StatusCode == 200) - options.Response.StatusCode = 401; - else - options.Response.Redirect(options.RedirectUri); - - return Task.CompletedTask; - }; - }) - .AddJwtBearer("Bearer", options => - { - options.RequireHttpsMetadata = false; - options.SaveToken = true; - - options.TokenValidationParameters.ValidateActor = false; - - options.TokenValidationParameters.ValidAudience = configuration.GetSection("Jwt:Audience").Value; - options.TokenValidationParameters.ValidateAudience = true; - - options.TokenValidationParameters.ValidIssuer = configuration.GetSection("Jwt:Issuer").Value; - options.TokenValidationParameters.ValidateIssuer = true; - - options.TokenValidationParameters.IssuerSigningKey = new SymmetricSecurityKey( - Encoding.UTF8.GetBytes(configuration.GetSection("Jwt:Key").Value ?? throw new Exception("Configuration for [Jwt:Key] not found")) - ); - - options.TokenValidationParameters.ValidateIssuerSigningKey = true; - options.TokenValidationParameters.ValidateLifetime = true; - }) - .AddPolicyScheme("Custom", "Custom", options => - { - options.ForwardDefaultSelector = context => - { - if (context.Request.Headers[HeaderNames.Authorization] is StringValues auth && auth.ToString().StartsWith("Bearer ")) - return "Bearer"; - else - return "Cookies"; - }; - }); - - return services; - } - - public static IServiceCollection AddBearerAuthentication(this IServiceCollection services, IConfiguration configuration) - { - services.AddAuthentication(options => - { - options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultSignInScheme = JwtBearerDefaults.AuthenticationScheme; - }) - .AddJwtBearer(options => - { - options.RequireHttpsMetadata = false; - options.SaveToken = true; - - options.TokenValidationParameters.ValidateActor = false; - - options.TokenValidationParameters.ValidAudience = configuration.GetValue(Appsettings.Jwt.Audience) ?? throw new Exception($"{Appsettings.Jwt.Audience} value not set (appsettings)"); - options.TokenValidationParameters.ValidateAudience = true; - - options.TokenValidationParameters.ValidIssuer = configuration.GetValue(Appsettings.Jwt.Issuer) ?? throw new Exception($"{Appsettings.Jwt.Issuer} value not set (appsettings)"); - options.TokenValidationParameters.ValidateIssuer = true; - - options.TokenValidationParameters.IssuerSigningKey = new SymmetricSecurityKey( - Encoding.UTF8.GetBytes(configuration.GetValue(Appsettings.Jwt.Key) ?? throw new Exception($"{Appsettings.Jwt.Key} value not set (appsettings)")) - ); - - options.TokenValidationParameters.ValidateIssuerSigningKey = true; - options.TokenValidationParameters.ValidateLifetime = true; - }); - - return services; - } - - //private static IServiceCollection AddIdentityServices2(this IServiceCollection services, IConfiguration configuration) - //{ - // var identityOptions = new MongoDbIdentityConfiguration - // { - // MongoDbSettings = new MongoDbSettings - // { - // ConnectionString = configuration.GetSection("ConnectionStrings:Mongo").Value, - // DatabaseName = "insight" - // }, - // IdentityOptionsAction = options => - // { - // options.User.RequireUniqueEmail = true; - // options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@.-_"; - - // options.Password.RequireDigit = false; - // options.Password.RequiredLength = 8; - // options.Password.RequireNonAlphanumeric = false; - // options.Password.RequireUppercase = false; - // options.Password.RequireLowercase = false; - - // options.SignIn.RequireConfirmedAccount = false; - // options.SignIn.RequireConfirmedEmail = false; - // options.SignIn.RequireConfirmedPhoneNumber = false; - - // options.Lockout.MaxFailedAccessAttempts = 5; - // options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5); - // } - // }; - - // services.ConfigureMongoDbIdentity(identityOptions) - // .AddDefaultTokenProviders() - // .AddSignInManager(); - - // return services; - //} - - //private static IServiceCollection AddIdentityAuthentication(this IServiceCollection services, IConfiguration configuration) - //{ - // services.AddAuthentication(options => - // { - // options.DefaultAuthenticateScheme = - // }); - // cookieBuilder.ApplicationCookie = builder.AddApplicationCookie(); - // cookieBuilder.ExternalCookie = builder.AddExternalCookie(); - // cookieBuilder.TwoFactorRememberMeCookie = builder.AddTwoFactorRememberMeCookie(); - // cookieBuilder.TwoFactorUserIdCookie = builder.AddTwoFactorUserIdCookie(); - // .AddCookie(options => - // { - // options. - // }; - // .AddIdentityCookies(); - // .AddCookie(options => - // { - // // Specify where to redirect un-authenticated users - // options.LoginPath = "/account/login"; - - // // Specify the name of the auth cookie. - // // ASP.NET picks a dumb name by default. - // options.Cookie.Name = "insight"; - // }); - - // return services; - //} -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure.Web/Insight.Infrastructure.Web.csproj b/src/Core/Insight.Infrastructure.Web/Insight.Infrastructure.Web.csproj deleted file mode 100644 index 253b8f2..0000000 --- a/src/Core/Insight.Infrastructure.Web/Insight.Infrastructure.Web.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - net8.0 - latest - enable - enable - Insight.Infrastructure.Web - Insight - 2023.12.15.0 - none - - - - - - - - - - - - - diff --git a/src/Core/Insight.Infrastructure.Web/Models/TokenOptions.cs b/src/Core/Insight.Infrastructure.Web/Models/TokenOptions.cs deleted file mode 100644 index e6d6623..0000000 --- a/src/Core/Insight.Infrastructure.Web/Models/TokenOptions.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Insight.Infrastructure.Models; - -public class TokenOptions(string key, int expires, Uri? audience = null, Uri? issuer = null) -{ - public string Key { get; set; } = key; - public int Expires { get; set; } = expires; - public Uri? Audience { get; set; } = audience; - public Uri? Issuer { get; set; } = issuer; -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure.Web/Services/TokenService.cs b/src/Core/Insight.Infrastructure.Web/Services/TokenService.cs deleted file mode 100644 index 9018b10..0000000 --- a/src/Core/Insight.Infrastructure.Web/Services/TokenService.cs +++ /dev/null @@ -1,141 +0,0 @@ -using Insight.Domain.Models; -using Insight.Infrastructure.Entities; -using Insight.Infrastructure.Models; -using Microsoft.IdentityModel.Tokens; -using MongoDB.Driver; -using System.IdentityModel.Tokens.Jwt; -using System.Net; -using System.Security.Cryptography; -using System.Text; - -namespace Insight.Infrastructure.Services; - -public class TokenService(TokenOptions options, IdentityService identityService, IMongoDatabase database) -{ - private readonly TokenOptions _options = options; - private readonly IdentityService _identityService = identityService; - private readonly IMongoDatabase _database = database; - - public async Task GetAsync(string email, string password, string? code = null, IPAddress? ipa = null) - { - var user = await _identityService.LoginAsync(email, password, code).ConfigureAwait(false); - - var accessToken = await CreateAccessTokenAsync(user).ConfigureAwait(false); - var refreshToken = await CreateRefreshTokenAsync(user, ipa).ConfigureAwait(false); - - return new TokenResponse - { - AccessToken = accessToken.Item1, - ExpireInSeconds = accessToken.Item2, - RefreshToken = refreshToken.Item1 - }; - } - - public async Task RefreshAsync(string refreshToken, IPAddress? ipa = null) - { - if (string.IsNullOrWhiteSpace(refreshToken)) throw new ArgumentNullException(nameof(refreshToken)); - - var user = await _database.User().Find(p => p.RefreshTokens != null && p.RefreshTokens.Any(t => t.Token == refreshToken)).FirstOrDefaultAsync(); - if (user is null || user.RefreshTokens is null) throw new InvalidDataException("Invalid Refresh Token"); - - var token = user.RefreshTokens.First(p => p.Token == refreshToken); - - if (token.IsRevoked) - { - // todo: revoke all descendant tokens in case this token has been compromised - throw new InvalidDataException("Invalid Refresh Token"); - } - - if (token.IsActive is false) - { - throw new InvalidDataException("Invalid Refresh Token"); - } - - // remove actual refresh token - user.RefreshTokens.Remove(token); - - // remove old refresh tokens from user - user.RefreshTokens.RemoveAll(p => p.IsExpired && p.IsRevoked is false); - - // update users refreshTokens - await _database.User().UpdateOneAsync(Builders - .Filter.Eq(p => p.UserName, user.UserName), Builders - .Update.Set(p => p.RefreshTokens, user.RefreshTokens)); - - // create new refresh token - var newRefreshToken = await CreateRefreshTokenAsync(user, ipa).ConfigureAwait(false); - - // create access token - var accessToken = await CreateAccessTokenAsync(user).ConfigureAwait(false); - - return new TokenResponse - { - AccessToken = accessToken.Item1, - ExpireInSeconds = accessToken.Item2, - RefreshToken = newRefreshToken.Item1, - }; - } - - public async Task RevokeAsync(string refreshToken, string reason, IPAddress? ipa = null) - { - if (string.IsNullOrWhiteSpace(refreshToken)) throw new ArgumentNullException(nameof(refreshToken)); - - var user = await _database.User().Find(p => p.RefreshTokens != null && p.RefreshTokens.Any(t => t.Token == refreshToken)).FirstOrDefaultAsync(); - if (user is null || user.RefreshTokens is null) throw new InvalidDataException("Invalid Refresh Token"); - - var token = user.RefreshTokens.First(p => p.Token == refreshToken); - - if (token.IsActive is false) - { - throw new InvalidDataException("Invalid Refresh Token"); - } - - token.Revoked = DateTime.Now; - token.RevokedByIp = ipa?.ToString(); - token.ReasonRevoked = reason; - } - - private async Task<(string, int)> CreateAccessTokenAsync(InsightUser user) - { - var claims = await _identityService.GetClaimsAsync(user).ConfigureAwait(false); - - var key = Encoding.UTF8.GetBytes(_options.Key); - var secret = new SymmetricSecurityKey(key); - var signing = new SigningCredentials(secret, SecurityAlgorithms.HmacSha256); - - var securityToken = new JwtSecurityToken( - _options.Issuer?.ToString(), - _options.Audience?.ToString(), - claims, - DateTime.Now, - DateTime.Now.AddSeconds(Convert.ToDouble(_options.Expires)), - signing); - - var token = new JwtSecurityTokenHandler().WriteToken(securityToken); - - return (token, (int)TimeSpan.FromMinutes(Convert.ToDouble(_options.Expires)).TotalSeconds); - } - - private async Task<(string, int)> CreateRefreshTokenAsync(InsightUser user, IPAddress? ipa = null) - { - var randomNumber = new byte[32]; - - using var rng = RandomNumberGenerator.Create(); - rng.GetBytes(randomNumber); - - var refreshToken = Convert.ToBase64String(randomNumber); - - await _database.User() - .UpdateOneAsync(Builders - .Filter.Eq(p => p.UserName, user.UserName), Builders - .Update.AddToSet(p => p.RefreshTokens, new RefreshToken - { - Token = refreshToken, - Created = DateTime.Now, - Expires = DateTime.Now.AddMinutes(30), // change offset to config based - CreatedByIp = ipa?.ToString() - })); - - return (refreshToken, (int)TimeSpan.FromMinutes(30).TotalSeconds); - } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Constants/Appsettings.cs b/src/Core/Insight.Infrastructure/Constants/Appsettings.cs index df66859..d85fd32 100644 --- a/src/Core/Insight.Infrastructure/Constants/Appsettings.cs +++ b/src/Core/Insight.Infrastructure/Constants/Appsettings.cs @@ -1,58 +1,14 @@ -namespace Insight.Infrastructure; - -public static class Appsettings +namespace Insight.Infrastructure { - public static class Mongo + public class Appsettings { - public const string ConnectionString = "mongo.connection"; - } + public const string Database = "database"; + public const string JwtKey = "jwt.key"; + public const string JwtAudience = "jwt.audience"; + public const string JwtIssuer = "jwt.issuer"; + public const string JwtExp = "jwt.exp"; - public static class Influx - { - public const string Endpoint = "influx.endpoint"; - public const string Token = "influx.token"; - public const string Organization = "influx.org"; - public const string Bucket = "influx.bucket"; - public const string Service = "influx.service"; - } - - public static class Jwt - { - public const string Key = "jwt.key"; - public const string Audience = "jwt.audience"; - public const string Issuer = "jwt.issuer"; - public const string Exp = "jwt.exp"; - } - - public static class Backend - { - public const string Host = "server.host"; - public const string Port = "server.port"; - } - - public static class Agent - { - public const string Port = "agent.port"; - public const string Certificate = "agent.certificate"; - public const string CertificatePassword = "agent.certificate.password"; - } - - public static class Web - { - public const string Port = "web.port"; - public const string Certificate = "web.certificate"; - public const string CertificatePassword = "web.certificate.password"; - } - - public static class Remote - { - public const string Port = "remote.port"; - public const string Certificate = "remote.certificate"; - public const string CertificatePassword = "remote.certificate.password"; - } - - public static class Dispatch - { - public const string Webmatic = "dispatch.webmatic"; + public const string ServerHost = "server.host"; + public const string ServerPort = "server.port"; } } \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Constants/Monitoring.cs b/src/Core/Insight.Infrastructure/Constants/Monitoring.cs index f88284b..c8bcf72 100644 --- a/src/Core/Insight.Infrastructure/Constants/Monitoring.cs +++ b/src/Core/Insight.Infrastructure/Constants/Monitoring.cs @@ -1,7 +1,8 @@ -namespace Insight.Infrastructure; - -public static class Monitoring +namespace Insight.Infrastructure { - public static readonly Uri StatusUri = new("https://admin.webmatic.de/monitoring/computer/send/status"); - public static readonly Uri LogUri = new("https://admin.webmatic.de/monitoring/computer/send/log"); + public static class Monitoring + { + public static readonly Uri StatusUri = new("https://nexus.webmatic.de/rest/monitoring/send/status"); + public static readonly Uri LogUri = new("https://nexus.webmatic.de/rest/monitoring/send/log"); + } } \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Constants/Settings.cs b/src/Core/Insight.Infrastructure/Constants/Settings.cs index ec9bec6..b667086 100644 --- a/src/Core/Insight.Infrastructure/Constants/Settings.cs +++ b/src/Core/Insight.Infrastructure/Constants/Settings.cs @@ -1,6 +1,7 @@ -namespace Insight.Infrastructure; - -public class Settings +namespace Insight.Infrastructure { - public const string Database = "insight"; + public class Settings + { + public const string Database = "insight"; + } } \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Agent.cs b/src/Core/Insight.Infrastructure/Entities/Agent.cs new file mode 100644 index 0000000..d538498 --- /dev/null +++ b/src/Core/Insight.Infrastructure/Entities/Agent.cs @@ -0,0 +1,62 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; + +namespace Insight.Infrastructure.Entities +{ + [BsonIgnoreExtraElements] + public class AgentEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("serial"), Required] + public string? Serial { get; set; } + + [BsonElement("hostname")] + public string? Hostname { get; set; } + + [BsonElement("version"), BsonRepresentation(BsonType.String)] + public Version? Version { get; set; } + + [BsonElement("endpoint"), BsonRepresentation(BsonType.String)] + public string? Endpoint { get; set; } + + [BsonElement("connected")] + public DateTime? Connected { get; set; } + + [BsonElement("activity")] + public DateTime? Activity { get; set; } + + [BsonElement("bytes_sent")] + public long SentBytes { get; set; } + + [BsonElement("bytes_received")] + public long ReceivedBytes { get; set; } + + [BsonElement("packets_sent")] + public long SentPackets { get; set; } + + [BsonElement("packets_received")] + public long ReceivedPackets { get; set; } + + //[BsonElement("latency")] + //public TimeSpan? Latency { get; set; } + + [BsonIgnoreIfNull, JsonIgnore] + public List? Hosts { get; set; } + + public bool GetOnlineState() + { + if (Activity is null) return false; + return Activity.Value.ToLocalTime().Add(TimeSpan.FromSeconds(60)).Subtract(DateTime.Now).Seconds > 0; + } + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Agent/Agent.cs b/src/Core/Insight.Infrastructure/Entities/Agent/Agent.cs deleted file mode 100644 index e673e8e..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Agent/Agent.cs +++ /dev/null @@ -1,67 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.ComponentModel.DataAnnotations; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection Agent(this IMongoDatabase database) => database.GetCollection("agent"); -} - -[BsonIgnoreExtraElements] -public class AgentEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("serial"), Required] - public string? Serial { get; set; } - - [BsonElement("hostname")] - public string? Hostname { get; set; } - - [BsonElement("version"), BsonRepresentation(BsonType.String)] - public Version? Version { get; set; } - - [BsonElement("endpoint"), BsonRepresentation(BsonType.String)] - public string? Endpoint { get; set; } - - [BsonElement("connected")] - public DateTime? Connected { get; set; } - - [BsonElement("activity")] - public DateTime? Activity { get; set; } - - [BsonElement("bytes_sent")] - public long SentBytes { get; set; } - - [BsonElement("bytes_received")] - public long ReceivedBytes { get; set; } - - [BsonElement("packets_sent")] - public long SentPackets { get; set; } - - [BsonElement("packets_received")] - public long ReceivedPackets { get; set; } - - //[BsonElement("latency")] - //public TimeSpan? Latency { get; set; } - - [BsonIgnoreIfNull, JsonIgnore] - public List? Hosts { get; set; } - - public bool GetOnlineState() - { - if (Activity is null) return false; - return Activity.Value.ToLocalTime().Add(TimeSpan.FromSeconds(60)).Subtract(DateTime.Now).Seconds > 0; - } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Agent/AgentLog.cs b/src/Core/Insight.Infrastructure/Entities/Agent/AgentLog.cs deleted file mode 100644 index b8fc06e..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Agent/AgentLog.cs +++ /dev/null @@ -1,42 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection AgentLog(this IMongoDatabase database) => database.GetCollection("agent_log"); -} - -[BsonIgnoreExtraElements] -public class AgentLogEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_agent"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("agent")] - public string? Agent { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("eventid")] - public string? EventId { get; set; } - - [BsonElement("status")] - public string? Status { get; set; } - - [BsonElement("source")] - public string? Source { get; set; } - - [BsonElement("category")] - public string? Category { get; set; } - - [BsonElement("message")] - public string? Message { get; set; } - - [BsonElement("timestamp")] - public DateTime? Timestamp { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/AgentLog.cs b/src/Core/Insight.Infrastructure/Entities/AgentLog.cs new file mode 100644 index 0000000..8c32884 --- /dev/null +++ b/src/Core/Insight.Infrastructure/Entities/AgentLog.cs @@ -0,0 +1,37 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using System.Text.Json.Serialization; + +namespace Insight.Infrastructure.Entities +{ + [BsonIgnoreExtraElements] + public class AgentLogEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_agent"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("agent")] + public string? Agent { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("eventid")] + public string? EventId { get; set; } + + [BsonElement("status")] + public string? Status { get; set; } + + [BsonElement("source")] + public string? Source { get; set; } + + [BsonElement("category")] + public string? Category { get; set; } + + [BsonElement("message")] + public string? Message { get; set; } + + [BsonElement("timestamp")] + public DateTime? Timestamp { get; set; } + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Customer.cs b/src/Core/Insight.Infrastructure/Entities/Customer.cs new file mode 100644 index 0000000..983715e --- /dev/null +++ b/src/Core/Insight.Infrastructure/Entities/Customer.cs @@ -0,0 +1,29 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; + +namespace Insight.Infrastructure.Entities +{ + [BsonIgnoreExtraElements] + public class CustomerEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("name"), Required] + public string? Name { get; set; } + + [BsonElement("tag")] + public string? Tag { get; set; } + + [BsonIgnoreIfNull, JsonIgnore] + public List? Hosts { get; set; } + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Customer/Customer.cs b/src/Core/Insight.Infrastructure/Entities/Customer/Customer.cs deleted file mode 100644 index 8a1b737..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Customer/Customer.cs +++ /dev/null @@ -1,34 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.ComponentModel.DataAnnotations; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection Customer(this IMongoDatabase database) => database.GetCollection("customer"); -} - -[BsonIgnoreExtraElements] -public class CustomerEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("name"), Required] - public string? Name { get; set; } - - [BsonElement("tag")] - public string? Tag { get; set; } - - [BsonIgnoreIfNull, JsonIgnore] - public List? Hosts { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Host.cs b/src/Core/Insight.Infrastructure/Entities/Host.cs new file mode 100644 index 0000000..9297e78 --- /dev/null +++ b/src/Core/Insight.Infrastructure/Entities/Host.cs @@ -0,0 +1,38 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; + +namespace Insight.Infrastructure.Entities +{ + [BsonIgnoreExtraElements] + public class HostEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_customer"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("customer")] + public string? Customer { get; set; } + + [BsonElement("_agent"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("agent")] + public string? Agent { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("name"), Required] + public string? Name { get; set; } + + [BsonElement("description")] + public string? Description { get; set; } + + [BsonIgnoreIfNull, JsonIgnore] + public List? Customers { get; set; } + + [BsonIgnoreIfNull, JsonIgnore] + public List? Agents { get; set; } + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Host/Host.cs b/src/Core/Insight.Infrastructure/Entities/Host/Host.cs deleted file mode 100644 index 2e065c8..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Host/Host.cs +++ /dev/null @@ -1,43 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.ComponentModel.DataAnnotations; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection Host(this IMongoDatabase database) => database.GetCollection("host"); -} - -[BsonIgnoreExtraElements] -public class HostEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_customer"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("customer")] - public string? Customer { get; set; } - - [BsonElement("_agent"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("agent")] - public string? Agent { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("name"), Required] - public string? Name { get; set; } - - [BsonElement("description")] - public string? Description { get; set; } - - [BsonIgnoreIfNull, JsonIgnore] - public List? Customers { get; set; } - - [BsonIgnoreIfNull, JsonIgnore] - public List? Agents { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Host/HostApplication.cs b/src/Core/Insight.Infrastructure/Entities/Host/HostApplication.cs deleted file mode 100644 index 388b522..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Host/HostApplication.cs +++ /dev/null @@ -1,45 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection HostApplication(this IMongoDatabase database) => database.GetCollection("host_app"); -} - -[BsonIgnoreExtraElements] -public class HostApplicationEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] - public string? Batch { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("company")] - public string? Company { get; set; } - - [BsonElement("name")] - public string? Name { get; set; } - - [BsonElement("architecture")] - public string? Architecture { get; set; } - - [BsonElement("version")] - public string? Version { get; set; } - - [BsonElement("installdate")] - public DateTime? InstallDate { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Host/HostDrive.cs b/src/Core/Insight.Infrastructure/Entities/Host/HostDrive.cs deleted file mode 100644 index 72d46e7..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Host/HostDrive.cs +++ /dev/null @@ -1,57 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection HostDrive(this IMongoDatabase database) => database.GetCollection("host_drv"); -} - -[BsonIgnoreExtraElements] -public class HostDriveEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] - public string? Batch { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("index")] - public uint? Index { get; set; } - - [BsonElement("company")] - public string? Company { get; set; } - - [BsonElement("name")] - public string? Name { get; set; } - - [BsonElement("size")] - public ulong? Size { get; set; } - - [BsonElement("type")] - public string? Type { get; set; } - - [BsonElement("serial")] - public string? Serial { get; set; } - - [BsonElement("firmware")] - public string? Firmware { get; set; } - - [BsonElement("status")] - public string? Status { get; set; } - - [BsonElement("pnp")] - public string? Pnp { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Host/HostHypervisor.cs b/src/Core/Insight.Infrastructure/Entities/Host/HostHypervisor.cs deleted file mode 100644 index 0bfdcb5..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Host/HostHypervisor.cs +++ /dev/null @@ -1,194 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection HostHypervisorVirtualMaschine(this IMongoDatabase database) => database.GetCollection("host_hv_vm"); - public static IMongoCollection HostVirtualMaschineConfig(this IMongoDatabase database) => database.GetCollection("host_hv_vm_cfg"); -} - -[BsonIgnoreExtraElements] -public class HostHypervisorVirtualMaschineEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] - public string? Batch { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("uniqueid")] - public string? UniqueId { get; set; } - - [BsonElement("name")] - public string? Name { get; set; } - - [BsonElement("notes")] - public string? Notes { get; set; } - - [BsonElement("enabled")] - public string? Enabled { get; set; } - - [BsonElement("enabled_default")] - public string? EnabledDefault { get; set; } - - [BsonElement("health")] - public string? Health { get; set; } - - [BsonElement("status")] - public string? Status { get; set; } - - [BsonElement("ontime")] - public ulong? OnTime { get; set; } - - [BsonElement("replication_state")] - public string? ReplicationState { get; set; } - - [BsonElement("replication_health")] - public string? ReplicationHealth { get; set; } - - [BsonElement("version_configuration")] - public string? ConfigurationVersion { get; set; } - - [BsonElement("version_integrated_services")] - public string? IntegrationServicesVersionState { get; set; } - - [BsonElement("processid")] - public uint? ProcessId { get; set; } - - [BsonElement("processor_count")] - public uint? NumberOfProcessors { get; set; } - - [BsonElement("processor_load")] - public uint? ProcessorLoad { get; set; } - - [BsonElement("memory_available")] - public int? MemoryAvailable { get; set; } - - [BsonElement("memory_usage")] - public ulong? MemoryUsage { get; set; } - - [BsonElement("installdate")] - public DateTime? InstallDate { get; set; } - - [BsonElement("configuration_changed")] - public DateTime? TimeOfLastConfigurationChange { get; set; } - - [BsonElement("state_changed")] - public DateTime? TimeOfLastStateChange { get; set; } - - [BsonElement("replication_last")] - public DateTime? LastReplicationTime { get; set; } - - [BsonElement("guest_os")] - public string? Os { get; set; } - - [BsonIgnoreIfNull, JsonIgnore] - public List? Configs { get; set; } -} - -[BsonIgnoreExtraElements] -public class HostHypervisorVirtualMaschineConfigEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("virtualmaschine"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("virtualmaschine")] - public string? VirtualMaschine { get; set; } - - [BsonElement("batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] - public string? Batch { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("uniqueid")] - public string? UniqueId { get; set; } - - [BsonElement("parentid")] - public string? ParentId { get; set; } - - [BsonElement("type")] - public string? Type { get; set; } - - [BsonElement("name")] - public string? Name { get; set; } - - [BsonElement("notes")] - public string? Notes { get; set; } - - [BsonElement("creationtime")] - public DateTime? CreationTime { get; set; } - - [BsonElement("generation")] - public string? Generation { get; set; } - - [BsonElement("architecture")] - public string? Architecture { get; set; } - - [BsonElement("secureboot")] - public bool? SecureBootEnabled { get; set; } - - [BsonElement("automatic_snapshot")] - public bool? IsAutomaticSnapshot { get; set; } - - [BsonElement("action_start")] - public string? AutomaticStartupAction { get; set; } - - [BsonElement("action_shutdown")] - public string? AutomaticShutdownAction { get; set; } - - [BsonElement("action_recovery")] - public string? AutomaticRecoveryAction { get; set; } - - [BsonElement("auto_snapshots")] - public bool? AutomaticSnapshotsEnabled { get; set; } - - [BsonElement("serial_mainboard")] - public string? BaseBoardSerialNumber { get; set; } - - [BsonElement("serial_bios")] - public string? BIOSSerialNumber { get; set; } - - [BsonElement("bios_guid")] - public string? BIOSGUID { get; set; } - - [BsonElement("data_root")] - public string? ConfigurationDataRoot { get; set; } - - [BsonElement("file")] - public string? ConfigurationFile { get; set; } - - [BsonElement("guest_data_root")] - public string? GuestStateDataRoot { get; set; } - - [BsonElement("guest_state_file")] - public string? GuestStateFile { get; set; } - - [BsonElement("snapshot_data_root")] - public string? SnapshotDataRoot { get; set; } - - [BsonElement("suspend_data_root")] - public string? SuspendDataRoot { get; set; } - - [BsonElement("swap_data_root")] - public string? SwapFileDataRoot { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Host/HostInterface.cs b/src/Core/Insight.Infrastructure/Entities/Host/HostInterface.cs deleted file mode 100644 index 7756a47..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Host/HostInterface.cs +++ /dev/null @@ -1,227 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection HostInterface(this IMongoDatabase database) => database.GetCollection("host_if"); - public static IMongoCollection HostInterfaceAddress(this IMongoDatabase database) => database.GetCollection("host_if_addr"); - public static IMongoCollection HostInterfaceGateway(this IMongoDatabase database) => database.GetCollection("host_if_gw"); - public static IMongoCollection HostInterfaceNameserver(this IMongoDatabase database) => database.GetCollection("host_if_ns"); - public static IMongoCollection HostInterfaceRoute(this IMongoDatabase database) => database.GetCollection("host_if_rt"); -} - -[BsonIgnoreExtraElements] -public class HostInterfaceEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] - public string? Batch { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("index")] - public uint? Index { get; set; } - - [BsonElement("mac")] - public string? Mac { get; set; } - - [BsonElement("name")] - public string? Name { get; set; } - - [BsonElement("description")] - public string? Description { get; set; } - - [BsonElement("physical")] - public bool? Physical { get; set; } - - [BsonElement("status")] - public string? Status { get; set; } - - [BsonElement("suffix")] - public string? Suffix { get; set; } - - [BsonElement("speed")] - public long? Speed { get; set; } - - [BsonElement("ipv4_mtu")] - public long? Ipv4Mtu { get; set; } - - [BsonElement("ipv4_dhcp")] - public bool? Ipv4Dhcp { get; set; } - - [BsonElement("ipv4_forwarding")] - public bool? Ipv4Forwarding { get; set; } - - [BsonElement("ipv6_mtu")] - public long? Ipv6Mtu { get; set; } - - [BsonElement("sent")] - public long? Sent { get; set; } - - [BsonElement("received")] - public long? Received { get; set; } - - [BsonElement("packets_incoming_discarded")] - public long? IncomingPacketsDiscarded { get; set; } - - [BsonElement("packets_incoming_errors")] - public long? IncomingPacketsWithErrors { get; set; } - - [BsonElement("packets_incoming_unknown")] - public long? IncomingUnknownProtocolPackets { get; set; } - - [BsonElement("packets_outgoing_discarded")] - public long? OutgoingPacketsDiscarded { get; set; } - - [BsonElement("packets_outgoing_errors")] - public long? OutgoingPacketsWithErrors { get; set; } -} - -[BsonIgnoreExtraElements] -public class HostInterfaceAddressEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("_interface"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("interface")] - public string? Interface { get; set; } - - [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] - public string? Batch { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("address")] - public string? Address { get; set; } - - [BsonElement("mask")] - public string? Mask { get; set; } - - //public string? State { get; set; } - //public long? PreferredLifetime { get; set; } - //public long? ValidLifetime { get; set; } - //public long? LeaseLifetime { get; set; } - //public int? PrefixLength { get; set; } - - [BsonIgnoreIfNull, JsonIgnore] - public List? Interfaces { get; set; } -} - -[BsonIgnoreExtraElements] -public class HostInterfaceGatewayEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("_interface"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("interface")] - public string? Interface { get; set; } - - [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] - public string? Batch { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("address")] - public string? Address { get; set; } - - [BsonElement("mask")] - public string? Mask { get; set; } - - [BsonIgnoreIfNull, JsonIgnore] - public List? Interfaces { get; set; } -} - -[BsonIgnoreExtraElements] -public class HostInterfaceNameserverEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("_interface"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("interface")] - public string? Interface { get; set; } - - [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] - public string? Batch { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("address")] - public string? Address { get; set; } - - [BsonElement("mask")] - public string? Mask { get; set; } - - [BsonIgnoreIfNull, JsonIgnore] - public List? Interfaces { get; set; } -} - -[BsonIgnoreExtraElements] -public class HostInterfaceRouteEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("_interface"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("interface")] - public string? Interface { get; set; } - - [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] - public string? Batch { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("destination")] - public string? Destination { get; set; } - - [BsonElement("mask")] - public string? Mask { get; set; } - - [BsonElement("gateway")] - public string? Gateway { get; set; } - - [BsonElement("metric")] - public int? Metric { get; set; } - - [BsonIgnoreIfNull, JsonIgnore] - public List? Interfaces { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Host/HostLog.cs b/src/Core/Insight.Infrastructure/Entities/Host/HostLog.cs deleted file mode 100644 index ee34fa6..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Host/HostLog.cs +++ /dev/null @@ -1,42 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection HostLog(this IMongoDatabase database) => database.GetCollection("host_log"); -} - -[BsonIgnoreExtraElements] -public class HostLogEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("eventid")] - public string? EventId { get; set; } - - [BsonElement("status")] - public string? Status { get; set; } - - [BsonElement("source")] - public string? Source { get; set; } - - [BsonElement("category")] - public string? Category { get; set; } - - [BsonElement("message")] - public string? Message { get; set; } - - [BsonElement("timestamp")] - public DateTime? Timestamp { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Host/HostLogMonitoring.cs b/src/Core/Insight.Infrastructure/Entities/Host/HostLogMonitoring.cs deleted file mode 100644 index 6579981..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Host/HostLogMonitoring.cs +++ /dev/null @@ -1,48 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection HostLogMonitoring(this IMongoDatabase database) => database.GetCollection("host_log_mon"); -} - -[BsonIgnoreExtraElements] -public class HostLogMonitoringEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("hostname")] - public string? Hostname { get; set; } - - [BsonElement("category")] - public string? Category { get; set; } - - [BsonElement("status")] - public string? Status { get; set; } - - [BsonElement("task")] - public string? Task { get; set; } - - [BsonElement("message")] - public string? Message { get; set; } - - [BsonElement("dispatch")] - public string? Dispatch { get; set; } - - [BsonElement("timestamp")] - public DateTime? Timestamp { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Host/HostMainboard.cs b/src/Core/Insight.Infrastructure/Entities/Host/HostMainboard.cs deleted file mode 100644 index 5339e78..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Host/HostMainboard.cs +++ /dev/null @@ -1,45 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection HostMainboard(this IMongoDatabase database) => database.GetCollection("host_board"); -} - -[BsonIgnoreExtraElements] -public class HostMainboardEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("company")] - public string? Company { get; set; } - - [BsonElement("name")] - public string? Name { get; set; } - - [BsonElement("serial")] - public string? Serial { get; set; } - - [BsonElement("bios")] - public string? Bios { get; set; } - - [BsonElement("version")] - public string? Version { get; set; } - - [BsonElement("Date")] - public DateTime? Date { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Host/HostMemory.cs b/src/Core/Insight.Infrastructure/Entities/Host/HostMemory.cs deleted file mode 100644 index 0f0dc70..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Host/HostMemory.cs +++ /dev/null @@ -1,63 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection HostMemory(this IMongoDatabase database) => database.GetCollection("host_mem"); -} - -[BsonIgnoreExtraElements] -public class HostMemoryEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] - public string? Batch { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("index")] - public uint? Index { get; set; } - - [BsonElement("company")] - public string? Company { get; set; } - - [BsonElement("name")] - public string? Name { get; set; } - - [BsonElement("tag")] - public string? Tag { get; set; } - - [BsonElement("location")] - public string? Location { get; set; } - - [BsonElement("serial")] - public string? Serial { get; set; } - - [BsonElement("capacity")] - public ulong? Capacity { get; set; } - - [BsonElement("clock")] - public uint? Clock { get; set; } - - [BsonElement("clock_current")] - public uint? CurrentClock { get; set; } - - [BsonElement("voltage")] - public uint? Voltage { get; set; } - - [BsonElement("voltage_current")] - public uint? CurrentVoltage { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Host/HostOs.cs b/src/Core/Insight.Infrastructure/Entities/Host/HostOs.cs deleted file mode 100644 index 06a65df..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Host/HostOs.cs +++ /dev/null @@ -1,45 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection HostOs(this IMongoDatabase database) => database.GetCollection("host_os"); -} - -[BsonIgnoreExtraElements] -public class HostOsEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("name")] - public string? Name { get; set; } - - [BsonElement("version")] - public string? Version { get; set; } - - [BsonElement("architecture")] - public string? Architecture { get; set; } - - [BsonElement("serialnumber")] - public string? SerialNumber { get; set; } - - [BsonElement("virtual")] - public bool? Virtual { get; set; } - - [BsonElement("installed")] - public DateTime? Installed { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Host/HostPrinter.cs b/src/Core/Insight.Infrastructure/Entities/Host/HostPrinter.cs deleted file mode 100644 index afa266f..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Host/HostPrinter.cs +++ /dev/null @@ -1,45 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection HostPrinter(this IMongoDatabase database) => database.GetCollection("host_prn"); -} - -[BsonIgnoreExtraElements] -public class HostPrinterEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] - public string? Batch { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("company")] - public string? Company { get; set; } - - [BsonElement("name")] - public string? Name { get; set; } - - [BsonElement("port")] - public string? Port { get; set; } - - [BsonElement("location")] - public string? Location { get; set; } - - [BsonElement("comment")] - public string? Comment { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Host/HostProcessor.cs b/src/Core/Insight.Infrastructure/Entities/Host/HostProcessor.cs deleted file mode 100644 index a31fba5..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Host/HostProcessor.cs +++ /dev/null @@ -1,75 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection HostProcessor(this IMongoDatabase database) => database.GetCollection("host_cpu"); -} - -[BsonIgnoreExtraElements] -public class HostProcessorEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] - public string? Batch { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("index")] - public uint? Index { get; set; } - - [BsonElement("company")] - public string? Company { get; set; } - - [BsonElement("name")] - public string? Name { get; set; } - - [BsonElement("socket")] - public string? Socket { get; set; } - - [BsonElement("serial")] - public string? Serial { get; set; } - - [BsonElement("version")] - public string? Version { get; set; } - - [BsonElement("cores")] - public uint? Cores { get; set; } - - [BsonElement("logicalcores")] - public uint? LogicalCores { get; set; } - - [BsonElement("clock")] - public uint? Clock { get; set; } - - [BsonElement("clock_current")] - public uint? CurrentClock { get; set; } - - [BsonElement("l1")] - public uint? L1Size { get; set; } - - [BsonElement("l2")] - public uint? L2Size { get; set; } - - [BsonElement("l3")] - public uint? L3Size { get; set; } - - [BsonElement("virtualization")] - public bool? Virtualization { get; set; } - - [BsonElement("pnp")] - public string? PNP { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Host/HostService.cs b/src/Core/Insight.Infrastructure/Entities/Host/HostService.cs deleted file mode 100644 index c55ab70..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Host/HostService.cs +++ /dev/null @@ -1,60 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection HostService(this IMongoDatabase database) => database.GetCollection("host_svc"); -} - -[BsonIgnoreExtraElements] -public class HostServiceEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] - public string? Batch { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("company")] - public string? Company { get; set; } - - [BsonElement("name")] - public string? Name { get; set; } - - [BsonElement("displayname")] - public string? DisplayName { get; set; } - - [BsonElement("description")] - public string? Description { get; set; } - - [BsonElement("startmode")] - public string? StartMode { get; set; } - - [BsonElement("state")] - public string? State { get; set; } - - [BsonElement("processid")] - public uint? ProcessId { get; set; } - - [BsonElement("delay")] - public bool? Delay { get; set; } - - [BsonElement("path")] - public string? Path { get; set; } - - [BsonElement("account")] - public string? Account { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Host/HostSession.cs b/src/Core/Insight.Infrastructure/Entities/Host/HostSession.cs deleted file mode 100644 index f2b15d6..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Host/HostSession.cs +++ /dev/null @@ -1,45 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection HostSession(this IMongoDatabase database) => database.GetCollection("host_session"); -} - -[BsonIgnoreExtraElements] -public class HostSessionEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] - public string? Batch { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("sid")] - public string? Sid { get; set; } - - [BsonElement("user")] - public string? User { get; set; } - - [BsonElement("remote")] - public string? Remote { get; set; } - - [BsonElement("type")] - public string? Type { get; set; } - - [BsonElement("state")] - public string? State { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Host/HostStoragePool.cs b/src/Core/Insight.Infrastructure/Entities/Host/HostStoragePool.cs deleted file mode 100644 index 4d8ce19..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Host/HostStoragePool.cs +++ /dev/null @@ -1,214 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection HostStoragePool(this IMongoDatabase database) => database.GetCollection("host_sp"); - public static IMongoCollection HostStoragePoolPhysicalDisk(this IMongoDatabase database) => database.GetCollection("host_sp.pd"); - public static IMongoCollection HostStoragePoolVirtualDisk(this IMongoDatabase database) => database.GetCollection("host_sp.vd"); -} - -[BsonIgnoreExtraElements] -public class HostStoragePoolEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] - public string? Batch { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("uniqueid")] - public string? UniqueId { get; set; } - - [BsonElement("name")] - public string? Name { get; set; } - - [BsonElement("health")] - public string? Health { get; set; } - - [BsonElement("resiliency")] - public string? Resiliency { get; set; } - - [BsonElement("primordial")] - public bool? Primordial { get; set; } - - [BsonElement("readonly")] - public bool? ReadOnly { get; set; } - - [BsonElement("clustered")] - public bool? Clustered { get; set; } - - [BsonElement("size")] - public ulong? Size { get; set; } - - [BsonElement("size_allocated")] - public ulong? AllocatedSize { get; set; } - - [BsonElement("sectorsize")] - public ulong? SectorSize { get; set; } - - [BsonElement("states")] - public List? States { get; set; } - - [BsonIgnoreIfNull, JsonIgnore] - public List? PhysicalDisks { get; set; } - - [BsonIgnoreIfNull, JsonIgnore] - public List? VirtualDisks { get; set; } -} - -[BsonIgnoreExtraElements] -public class HostStoragePoolVirtualDiskEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("_storagepool"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("storagepool")] - public string? StoragePool { get; set; } - - [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] - public string? Batch { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("uniqueid")] - public string? UniqueId { get; set; } - - [BsonElement("name")] - public string? Name { get; set; } - - [BsonElement("health")] - public string? Health { get; set; } - - [BsonElement("access")] - public string? Access { get; set; } - - [BsonElement("provisioning")] - public string? Provisioning { get; set; } - - [BsonElement("redundancy")] - public uint? PhysicalRedundancy { get; set; } - - [BsonElement("resiliency")] - public string? Resiliency { get; set; } - - [BsonElement("deduplication")] - public bool? Deduplication { get; set; } - - [BsonElement("snapshot")] - public bool? Snapshot { get; set; } - - [BsonElement("size")] - public ulong? Size { get; set; } - - [BsonElement("size_allocated")] - public ulong? AllocatedSize { get; set; } - - [BsonElement("footprint")] - public ulong? Footprint { get; set; } - - [BsonElement("cache_read_size")] - public ulong? ReadCacheSize { get; set; } - - [BsonElement("cache_write_size")] - public ulong? WriteCacheSize { get; set; } - - [BsonElement("states")] - public List? States { get; set; } -} - -[BsonIgnoreExtraElements] -public class HostStoragePoolPhysicalDiskEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("_storagepool"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("storagepool")] - public string? StoragePool { get; set; } - - [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] - public string? Batch { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("uniqueid")] - public string? UniqueId { get; set; } - - [BsonElement("deviceid")] - public string? DeviceId { get; set; } - - [BsonElement("name")] - public string? Name { get; set; } - - [BsonElement("manufacturer")] - public string? Manufacturer { get; set; } - - [BsonElement("Model")] - public string? Model { get; set; } - - [BsonElement("media")] - public string? Media { get; set; } - - [BsonElement("bus")] - public string? Bus { get; set; } - - [BsonElement("health")] - public string? Health { get; set; } - - [BsonElement("usage")] - public ushort? Usage { get; set; } - - [BsonElement("location")] - public string? Location { get; set; } - - [BsonElement("serial")] - public string? Serial { get; set; } - - [BsonElement("firmware")] - public string? Firmware { get; set; } - - [BsonElement("size")] - public ulong? Size { get; set; } - - [BsonElement("size_allocated")] - public ulong? AllocatedSize { get; set; } - - [BsonElement("footprint")] - public ulong? Footprint { get; set; } - - [BsonElement("sector_size_physical")] - public ulong? PhysicalSectorSize { get; set; } - - [BsonElement("sector_size_logical")] - public ulong? LogicalSectorSize { get; set; } - - [BsonElement("states")] - public List? States { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Host/HostSysGroup.cs b/src/Core/Insight.Infrastructure/Entities/Host/HostSysGroup.cs deleted file mode 100644 index 0cfe399..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Host/HostSysGroup.cs +++ /dev/null @@ -1,45 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection HostSystemGroup(this IMongoDatabase database) => database.GetCollection("host_sysgrp"); -} - -[BsonIgnoreExtraElements] -public class HostSysGroupEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] - public string? Batch { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("sid")] - public string? Sid { get; set; } - - [BsonElement("name")] - public string? Name { get; set; } - - [BsonElement("domain")] - public string? Domain { get; set; } - - [BsonElement("description")] - public string? Description { get; set; } - - [BsonElement("localaccount")] - public bool? LocalAccount { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Host/HostSysUser.cs b/src/Core/Insight.Infrastructure/Entities/Host/HostSysUser.cs deleted file mode 100644 index 2814066..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Host/HostSysUser.cs +++ /dev/null @@ -1,66 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection HostSystemUser(this IMongoDatabase database) => database.GetCollection("host_sysusr"); -} - -[BsonIgnoreExtraElements] -public class HostSysUserEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] - public string? Batch { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("sid")] - public string? Sid { get; set; } - - [BsonElement("name")] - public string? Name { get; set; } - - [BsonElement("domain")] - public string? Domain { get; set; } - - [BsonElement("fullname")] - public string? FullName { get; set; } - - [BsonElement("description")] - public string? Description { get; set; } - - [BsonElement("status")] - public string? Status { get; set; } - - [BsonElement("localaccount")] - public bool? LocalAccount { get; set; } - - [BsonElement("disabled")] - public bool? Disabled { get; set; } - - [BsonElement("lockout")] - public bool? Lockout { get; set; } - - [BsonElement("password_changeable")] - public bool? PasswordChangeable { get; set; } - - [BsonElement("password_expires")] - public bool? PasswordExpires { get; set; } - - [BsonElement("password_required")] - public bool? PasswordRequired { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Host/HostSysUserSysGroup.cs b/src/Core/Insight.Infrastructure/Entities/Host/HostSysUserSysGroup.cs deleted file mode 100644 index b5681f5..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Host/HostSysUserSysGroup.cs +++ /dev/null @@ -1,36 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection HostSystemUserSystemGroup(this IMongoDatabase database) => database.GetCollection("host_sysusr_sysgrp"); -} - -[BsonIgnoreExtraElements] -public class HostSysUserSysGroupEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("_user"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("user")] - public string? User { get; set; } - - [BsonElement("_group"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("group")] - public string? Group { get; set; } - - [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] - public string? Batch { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Host/HostSystem.cs b/src/Core/Insight.Infrastructure/Entities/Host/HostSystem.cs deleted file mode 100644 index 610544f..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Host/HostSystem.cs +++ /dev/null @@ -1,39 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection HostSystem(this IMongoDatabase database) => database.GetCollection("host_sys"); -} - -[BsonIgnoreExtraElements] -public class HostSystemEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("localtime")] - public DateTime? LocalTime { get; set; } - - [BsonElement("bootuptime")] - public DateTime? BootUpTime { get; set; } - - [BsonElement("processes")] - public uint? Processes { get; set; } - - [BsonElement("license")] - public string? License { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Host/HostUpdate.cs b/src/Core/Insight.Infrastructure/Entities/Host/HostUpdate.cs deleted file mode 100644 index 7f497ea..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Host/HostUpdate.cs +++ /dev/null @@ -1,66 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection HostUpdate(this IMongoDatabase database) => database.GetCollection("host_upd"); -} - -[BsonIgnoreExtraElements] -public class HostUpdateEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] - public string? Batch { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("name")] - public string? Name { get; set; } - - [BsonElement("serial")] - public string? Serial { get; set; } // os update id - - [BsonElement("description")] - public string? Description { get; set; } - - [BsonElement("supporturl")] - public string? SupportUrl { get; set; } - - [BsonElement("date")] - public DateTime? Date { get; set; } - - [BsonElement("pending")] - public bool? Pending { get; set; } - - [BsonElement("result"), BsonIgnoreIfNull] // installed only - public string? Result { get; set; } - - [BsonElement("type"), BsonIgnoreIfNull] // pending only - public string? Type { get; set; } - - [BsonElement("size"), BsonIgnoreIfNull] // pending only - public decimal? Size { get; set; } - - [BsonElement("downloaded"), BsonIgnoreIfNull] // pending only - public bool? IsDownloaded { get; set; } - - [BsonElement("inputrequest"), BsonIgnoreIfNull] // pending only - public bool? CanRequestUserInput { get; set; } - - [BsonElement("reboot"), BsonIgnoreIfNull] // pending only - public string? RebootBehavior { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Host/HostVideocard.cs b/src/Core/Insight.Infrastructure/Entities/Host/HostVideocard.cs deleted file mode 100644 index 1ce11d8..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Host/HostVideocard.cs +++ /dev/null @@ -1,45 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection HostVideocard(this IMongoDatabase database) => database.GetCollection("host_gpu"); -} - -[BsonIgnoreExtraElements] -public class HostVideocardEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] - public string? Batch { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("company")] - public string? Company { get; set; } - - [BsonElement("name")] - public string? Name { get; set; } - - [BsonElement("memory")] - public ulong? Memory { get; set; } - - [BsonElement("driver")] - public string? Driver { get; set; } - - [BsonElement("date")] - public DateTime? Date { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Host/HostVolume.cs b/src/Core/Insight.Infrastructure/Entities/Host/HostVolume.cs deleted file mode 100644 index 901c644..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Host/HostVolume.cs +++ /dev/null @@ -1,81 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection HostVolume(this IMongoDatabase database) => database.GetCollection("host_vol"); -} - -[BsonIgnoreExtraElements] -public class HostVolumeEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("_drive"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("drive")] - public string? Drive { get; set; } - - [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] - public string? Batch { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("index")] - public uint? Index { get; set; } - - [BsonElement("label")] - public string? Label { get; set; } - - [BsonElement("name")] - public string? Name { get; set; } - - [BsonElement("serial")] - public string? Serial { get; set; } - - [BsonElement("size")] - public ulong? Size { get; set; } - - [BsonElement("freespace")] - public ulong? FreeSpace { get; set; } - - [BsonElement("type")] - public string? Type { get; set; } - - [BsonElement("filesystem")] - public string? FileSystem { get; set; } - - [BsonElement("compressed")] - public bool? Compressed { get; set; } - - [BsonElement("bootable")] - public bool? Bootable { get; set; } - - [BsonElement("primary")] - public bool? Primary { get; set; } - - [BsonElement("boot")] - public bool? Boot { get; set; } - - [BsonElement("blocksize")] - public ulong? BlockSize { get; set; } - - [BsonElement("blocks")] - public ulong? Blocks { get; set; } - - [BsonElement("startoffset")] - public ulong? StartingOffset { get; set; } - - [BsonElement("provider")] - public string? Provider { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/HostApplication.cs b/src/Core/Insight.Infrastructure/Entities/HostApplication.cs new file mode 100644 index 0000000..473f383 --- /dev/null +++ b/src/Core/Insight.Infrastructure/Entities/HostApplication.cs @@ -0,0 +1,40 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using System.Text.Json.Serialization; + +namespace Insight.Infrastructure.Entities +{ + [BsonIgnoreExtraElements] + public class HostApplicationEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] + public string? Batch { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("company")] + public string? Company { get; set; } + + [BsonElement("name")] + public string? Name { get; set; } + + [BsonElement("architecture")] + public string? Architecture { get; set; } + + [BsonElement("version")] + public string? Version { get; set; } + + [BsonElement("installdate")] + public DateTime? InstallDate { get; set; } + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/HostDrive.cs b/src/Core/Insight.Infrastructure/Entities/HostDrive.cs new file mode 100644 index 0000000..f8cde99 --- /dev/null +++ b/src/Core/Insight.Infrastructure/Entities/HostDrive.cs @@ -0,0 +1,52 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using System.Text.Json.Serialization; + +namespace Insight.Infrastructure.Entities +{ + [BsonIgnoreExtraElements] + public class HostDriveEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] + public string? Batch { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("index")] + public uint? Index { get; set; } + + [BsonElement("company")] + public string? Company { get; set; } + + [BsonElement("name")] + public string? Name { get; set; } + + [BsonElement("size")] + public ulong? Size { get; set; } + + [BsonElement("type")] + public string? Type { get; set; } + + [BsonElement("serial")] + public string? Serial { get; set; } + + [BsonElement("firmware")] + public string? Firmware { get; set; } + + [BsonElement("status")] + public string? Status { get; set; } + + [BsonElement("pnp")] + public string? Pnp { get; set; } + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/HostGroup/HostGroup.cs b/src/Core/Insight.Infrastructure/Entities/HostGroup/HostGroup.cs deleted file mode 100644 index 2cdaa8c..0000000 --- a/src/Core/Insight.Infrastructure/Entities/HostGroup/HostGroup.cs +++ /dev/null @@ -1,31 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.ComponentModel.DataAnnotations; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection HostGroup(this IMongoDatabase database) => database.GetCollection("hostgroup"); -} - -[BsonIgnoreExtraElements] -public class HostGroupEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("name"), Required] - public string? Name { get; set; } - - [BsonElement("description")] - public string? Description { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/HostGroup/HostGroupHost.cs b/src/Core/Insight.Infrastructure/Entities/HostGroup/HostGroupHost.cs deleted file mode 100644 index 4428915..0000000 --- a/src/Core/Insight.Infrastructure/Entities/HostGroup/HostGroupHost.cs +++ /dev/null @@ -1,30 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection HostGroupHost(this IMongoDatabase database) => database.GetCollection("hostgroup_host"); -} - -[BsonIgnoreExtraElements] -public class HostGroupHostEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_hostgroup"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("hostgroup")] - public string? HostGroup { get; set; } - - [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] - public string? Host { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/HostHypervisor.cs b/src/Core/Insight.Infrastructure/Entities/HostHypervisor.cs new file mode 100644 index 0000000..a51b202 --- /dev/null +++ b/src/Core/Insight.Infrastructure/Entities/HostHypervisor.cs @@ -0,0 +1,188 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using System.Text.Json.Serialization; + +namespace Insight.Infrastructure.Entities +{ + [BsonIgnoreExtraElements] + public class HostHypervisorVirtualMaschineEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] + public string? Batch { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("uniqueid")] + public string? UniqueId { get; set; } + + [BsonElement("name")] + public string? Name { get; set; } + + [BsonElement("notes")] + public string? Notes { get; set; } + + [BsonElement("enabled")] + public string? Enabled { get; set; } + + [BsonElement("enabled_default")] + public string? EnabledDefault { get; set; } + + [BsonElement("health")] + public string? Health { get; set; } + + [BsonElement("status")] + public string? Status { get; set; } + + [BsonElement("ontime")] + public ulong? OnTime { get; set; } + + [BsonElement("replication_state")] + public string? ReplicationState { get; set; } + + [BsonElement("replication_health")] + public string? ReplicationHealth { get; set; } + + [BsonElement("version_configuration")] + public string? ConfigurationVersion { get; set; } + + [BsonElement("version_integrated_services")] + public string? IntegrationServicesVersionState { get; set; } + + [BsonElement("processid")] + public uint? ProcessId { get; set; } + + [BsonElement("processor_count")] + public uint? NumberOfProcessors { get; set; } + + [BsonElement("processor_load")] + public uint? ProcessorLoad { get; set; } + + [BsonElement("memory_available")] + public int? MemoryAvailable { get; set; } + + [BsonElement("memory_usage")] + public ulong? MemoryUsage { get; set; } + + [BsonElement("installdate")] + public DateTime? InstallDate { get; set; } + + [BsonElement("configuration_changed")] + public DateTime? TimeOfLastConfigurationChange { get; set; } + + [BsonElement("state_changed")] + public DateTime? TimeOfLastStateChange { get; set; } + + [BsonElement("replication_last")] + public DateTime? LastReplicationTime { get; set; } + + [BsonElement("guest_os")] + public string? Os { get; set; } + + [BsonIgnoreIfNull, JsonIgnore] + public List? Configs { get; set; } + } + + [BsonIgnoreExtraElements] + public class HostHypervisorVirtualMaschineConfigEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("virtualmaschine"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("virtualmaschine")] + public string? VirtualMaschine { get; set; } + + [BsonElement("batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] + public string? Batch { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("uniqueid")] + public string? UniqueId { get; set; } + + [BsonElement("parentid")] + public string? ParentId { get; set; } + + [BsonElement("type")] + public string? Type { get; set; } + + [BsonElement("name")] + public string? Name { get; set; } + + [BsonElement("notes")] + public string? Notes { get; set; } + + [BsonElement("creationtime")] + public DateTime? CreationTime { get; set; } + + [BsonElement("generation")] + public string? Generation { get; set; } + + [BsonElement("architecture")] + public string? Architecture { get; set; } + + [BsonElement("secureboot")] + public bool? SecureBootEnabled { get; set; } + + [BsonElement("automatic_snapshot")] + public bool? IsAutomaticSnapshot { get; set; } + + [BsonElement("action_start")] + public string? AutomaticStartupAction { get; set; } + + [BsonElement("action_shutdown")] + public string? AutomaticShutdownAction { get; set; } + + [BsonElement("action_recovery")] + public string? AutomaticRecoveryAction { get; set; } + + [BsonElement("auto_snapshots")] + public bool? AutomaticSnapshotsEnabled { get; set; } + + [BsonElement("serial_mainboard")] + public string? BaseBoardSerialNumber { get; set; } + + [BsonElement("serial_bios")] + public string? BIOSSerialNumber { get; set; } + + [BsonElement("bios_guid")] + public string? BIOSGUID { get; set; } + + [BsonElement("data_root")] + public string? ConfigurationDataRoot { get; set; } + + [BsonElement("file")] + public string? ConfigurationFile { get; set; } + + [BsonElement("guest_data_root")] + public string? GuestStateDataRoot { get; set; } + + [BsonElement("guest_state_file")] + public string? GuestStateFile { get; set; } + + [BsonElement("snapshot_data_root")] + public string? SnapshotDataRoot { get; set; } + + [BsonElement("suspend_data_root")] + public string? SuspendDataRoot { get; set; } + + [BsonElement("swap_data_root")] + public string? SwapFileDataRoot { get; set; } + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/HostInterface.cs b/src/Core/Insight.Infrastructure/Entities/HostInterface.cs new file mode 100644 index 0000000..2b18c18 --- /dev/null +++ b/src/Core/Insight.Infrastructure/Entities/HostInterface.cs @@ -0,0 +1,218 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using System.Text.Json.Serialization; + +namespace Insight.Infrastructure.Entities +{ + [BsonIgnoreExtraElements] + public class HostInterfaceEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] + public string? Batch { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("index")] + public uint? Index { get; set; } + + [BsonElement("mac")] + public string? Mac { get; set; } + + [BsonElement("name")] + public string? Name { get; set; } + + [BsonElement("description")] + public string? Description { get; set; } + + [BsonElement("physical")] + public bool? Physical { get; set; } + + [BsonElement("status")] + public string? Status { get; set; } + + [BsonElement("suffix")] + public string? Suffix { get; set; } + + [BsonElement("speed")] + public long? Speed { get; set; } + + [BsonElement("ipv4_mtu")] + public long? Ipv4Mtu { get; set; } + + [BsonElement("ipv4_dhcp")] + public bool? Ipv4Dhcp { get; set; } + + [BsonElement("ipv4_forwarding")] + public bool? Ipv4Forwarding { get; set; } + + [BsonElement("ipv6_mtu")] + public long? Ipv6Mtu { get; set; } + + [BsonElement("sent")] + public long? Sent { get; set; } + + [BsonElement("received")] + public long? Received { get; set; } + + [BsonElement("packets_incoming_discarded")] + public long? IncomingPacketsDiscarded { get; set; } + + [BsonElement("packets_incoming_errors")] + public long? IncomingPacketsWithErrors { get; set; } + + [BsonElement("packets_incoming_unknown")] + public long? IncomingUnknownProtocolPackets { get; set; } + + [BsonElement("packets_outgoing_discarded")] + public long? OutgoingPacketsDiscarded { get; set; } + + [BsonElement("packets_outgoing_errors")] + public long? OutgoingPacketsWithErrors { get; set; } + } + + [BsonIgnoreExtraElements] + public class HostInterfaceAddressEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("_interface"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("interface")] + public string? Interface { get; set; } + + [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] + public string? Batch { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("address")] + public string? Address { get; set; } + + [BsonElement("mask")] + public string? Mask { get; set; } + + //public string? State { get; set; } + //public long? PreferredLifetime { get; set; } + //public long? ValidLifetime { get; set; } + //public long? LeaseLifetime { get; set; } + //public int? PrefixLength { get; set; } + + [BsonIgnoreIfNull, JsonIgnore] + public List? Interfaces { get; set; } + } + + [BsonIgnoreExtraElements] + public class HostInterfaceGatewayEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("_interface"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("interface")] + public string? Interface { get; set; } + + [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] + public string? Batch { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("address")] + public string? Address { get; set; } + + [BsonElement("mask")] + public string? Mask { get; set; } + + [BsonIgnoreIfNull, JsonIgnore] + public List? Interfaces { get; set; } + } + + [BsonIgnoreExtraElements] + public class HostInterfaceNameserverEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("_interface"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("interface")] + public string? Interface { get; set; } + + [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] + public string? Batch { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("address")] + public string? Address { get; set; } + + [BsonElement("mask")] + public string? Mask { get; set; } + + [BsonIgnoreIfNull, JsonIgnore] + public List? Interfaces { get; set; } + } + + [BsonIgnoreExtraElements] + public class HostInterfaceRouteEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("_interface"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("interface")] + public string? Interface { get; set; } + + [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] + public string? Batch { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("destination")] + public string? Destination { get; set; } + + [BsonElement("mask")] + public string? Mask { get; set; } + + [BsonElement("gateway")] + public string? Gateway { get; set; } + + [BsonElement("metric")] + public int? Metric { get; set; } + + [BsonIgnoreIfNull, JsonIgnore] + public List? Interfaces { get; set; } + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/HostLog.cs b/src/Core/Insight.Infrastructure/Entities/HostLog.cs new file mode 100644 index 0000000..c6d4ae4 --- /dev/null +++ b/src/Core/Insight.Infrastructure/Entities/HostLog.cs @@ -0,0 +1,37 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using System.Text.Json.Serialization; + +namespace Insight.Infrastructure.Entities +{ + [BsonIgnoreExtraElements] + public class HostLogEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("eventid")] + public string? EventId { get; set; } + + [BsonElement("status")] + public string? Status { get; set; } + + [BsonElement("source")] + public string? Source { get; set; } + + [BsonElement("category")] + public string? Category { get; set; } + + [BsonElement("message")] + public string? Message { get; set; } + + [BsonElement("timestamp")] + public DateTime? Timestamp { get; set; } + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/HostLogMonitoring.cs b/src/Core/Insight.Infrastructure/Entities/HostLogMonitoring.cs new file mode 100644 index 0000000..67bf429 --- /dev/null +++ b/src/Core/Insight.Infrastructure/Entities/HostLogMonitoring.cs @@ -0,0 +1,43 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using System.Text.Json.Serialization; + +namespace Insight.Infrastructure.Entities +{ + [BsonIgnoreExtraElements] + public class HostLogMonitoringEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("hostname")] + public string? Hostname { get; set; } + + [BsonElement("category")] + public string? Category { get; set; } + + [BsonElement("status")] + public string? Status { get; set; } + + [BsonElement("task")] + public string? Task { get; set; } + + [BsonElement("message")] + public string? Message { get; set; } + + [BsonElement("dispatch")] + public string? Dispatch { get; set; } + + [BsonElement("timestamp")] + public DateTime? Timestamp { get; set; } + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/HostMainboard.cs b/src/Core/Insight.Infrastructure/Entities/HostMainboard.cs new file mode 100644 index 0000000..f4fd655 --- /dev/null +++ b/src/Core/Insight.Infrastructure/Entities/HostMainboard.cs @@ -0,0 +1,40 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using System.Text.Json.Serialization; + +namespace Insight.Infrastructure.Entities +{ + [BsonIgnoreExtraElements] + public class HostMainboardEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("company")] + public string? Company { get; set; } + + [BsonElement("name")] + public string? Name { get; set; } + + [BsonElement("serial")] + public string? Serial { get; set; } + + [BsonElement("bios")] + public string? Bios { get; set; } + + [BsonElement("version")] + public string? Version { get; set; } + + [BsonElement("Date")] + public DateTime? Date { get; set; } + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/HostMemory.cs b/src/Core/Insight.Infrastructure/Entities/HostMemory.cs new file mode 100644 index 0000000..1442941 --- /dev/null +++ b/src/Core/Insight.Infrastructure/Entities/HostMemory.cs @@ -0,0 +1,58 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using System.Text.Json.Serialization; + +namespace Insight.Infrastructure.Entities +{ + [BsonIgnoreExtraElements] + public class HostMemoryEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] + public string? Batch { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("index")] + public uint? Index { get; set; } + + [BsonElement("company")] + public string? Company { get; set; } + + [BsonElement("name")] + public string? Name { get; set; } + + [BsonElement("tag")] + public string? Tag { get; set; } + + [BsonElement("location")] + public string? Location { get; set; } + + [BsonElement("serial")] + public string? Serial { get; set; } + + [BsonElement("capacity")] + public ulong? Capacity { get; set; } + + [BsonElement("clock")] + public uint? Clock { get; set; } + + [BsonElement("clock_current")] + public uint? CurrentClock { get; set; } + + [BsonElement("voltage")] + public uint? Voltage { get; set; } + + [BsonElement("voltage_current")] + public uint? CurrentVoltage { get; set; } + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/HostOs.cs b/src/Core/Insight.Infrastructure/Entities/HostOs.cs new file mode 100644 index 0000000..b0e0d8f --- /dev/null +++ b/src/Core/Insight.Infrastructure/Entities/HostOs.cs @@ -0,0 +1,40 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using System.Text.Json.Serialization; + +namespace Insight.Infrastructure.Entities +{ + [BsonIgnoreExtraElements] + public class HostOsEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("name")] + public string? Name { get; set; } + + [BsonElement("version")] + public string? Version { get; set; } + + [BsonElement("architecture")] + public string? Architecture { get; set; } + + [BsonElement("serialnumber")] + public string? SerialNumber { get; set; } + + [BsonElement("virtual")] + public bool? Virtual { get; set; } + + [BsonElement("installed")] + public DateTime? Installed { get; set; } + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/HostPrinter.cs b/src/Core/Insight.Infrastructure/Entities/HostPrinter.cs new file mode 100644 index 0000000..7131499 --- /dev/null +++ b/src/Core/Insight.Infrastructure/Entities/HostPrinter.cs @@ -0,0 +1,40 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using System.Text.Json.Serialization; + +namespace Insight.Infrastructure.Entities +{ + [BsonIgnoreExtraElements] + public class HostPrinterEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] + public string? Batch { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("company")] + public string? Company { get; set; } + + [BsonElement("name")] + public string? Name { get; set; } + + [BsonElement("port")] + public string? Port { get; set; } + + [BsonElement("location")] + public string? Location { get; set; } + + [BsonElement("comment")] + public string? Comment { get; set; } + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/HostProcessor.cs b/src/Core/Insight.Infrastructure/Entities/HostProcessor.cs new file mode 100644 index 0000000..1a81ceb --- /dev/null +++ b/src/Core/Insight.Infrastructure/Entities/HostProcessor.cs @@ -0,0 +1,70 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using System.Text.Json.Serialization; + +namespace Insight.Infrastructure.Entities +{ + [BsonIgnoreExtraElements] + public class HostProcessorEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] + public string? Batch { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("index")] + public uint? Index { get; set; } + + [BsonElement("company")] + public string? Company { get; set; } + + [BsonElement("name")] + public string? Name { get; set; } + + [BsonElement("socket")] + public string? Socket { get; set; } + + [BsonElement("serial")] + public string? Serial { get; set; } + + [BsonElement("version")] + public string? Version { get; set; } + + [BsonElement("cores")] + public uint? Cores { get; set; } + + [BsonElement("logicalcores")] + public uint? LogicalCores { get; set; } + + [BsonElement("clock")] + public uint? Clock { get; set; } + + [BsonElement("clock_current")] + public uint? CurrentClock { get; set; } + + [BsonElement("l1")] + public uint? L1Size { get; set; } + + [BsonElement("l2")] + public uint? L2Size { get; set; } + + [BsonElement("l3")] + public uint? L3Size { get; set; } + + [BsonElement("virtualization")] + public bool? Virtualization { get; set; } + + [BsonElement("pnp")] + public string? PNP { get; set; } + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/HostService.cs b/src/Core/Insight.Infrastructure/Entities/HostService.cs new file mode 100644 index 0000000..c2e71d7 --- /dev/null +++ b/src/Core/Insight.Infrastructure/Entities/HostService.cs @@ -0,0 +1,55 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using System.Text.Json.Serialization; + +namespace Insight.Infrastructure.Entities +{ + [BsonIgnoreExtraElements] + public class HostServiceEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] + public string? Batch { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("company")] + public string? Company { get; set; } + + [BsonElement("name")] + public string? Name { get; set; } + + [BsonElement("displayname")] + public string? DisplayName { get; set; } + + [BsonElement("description")] + public string? Description { get; set; } + + [BsonElement("startmode")] + public string? StartMode { get; set; } + + [BsonElement("state")] + public string? State { get; set; } + + [BsonElement("processid")] + public uint? ProcessId { get; set; } + + [BsonElement("delay")] + public bool? Delay { get; set; } + + [BsonElement("path")] + public string? Path { get; set; } + + [BsonElement("account")] + public string? Account { get; set; } + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/HostSession.cs b/src/Core/Insight.Infrastructure/Entities/HostSession.cs new file mode 100644 index 0000000..7c58585 --- /dev/null +++ b/src/Core/Insight.Infrastructure/Entities/HostSession.cs @@ -0,0 +1,40 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using System.Text.Json.Serialization; + +namespace Insight.Infrastructure.Entities +{ + [BsonIgnoreExtraElements] + public class HostSessionEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] + public string? Batch { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("sid")] + public string? Sid { get; set; } + + [BsonElement("user")] + public string? User { get; set; } + + [BsonElement("remote")] + public string? Remote { get; set; } + + [BsonElement("type")] + public string? Type { get; set; } + + [BsonElement("state")] + public string? State { get; set; } + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/HostStoragePool.cs b/src/Core/Insight.Infrastructure/Entities/HostStoragePool.cs new file mode 100644 index 0000000..67dd652 --- /dev/null +++ b/src/Core/Insight.Infrastructure/Entities/HostStoragePool.cs @@ -0,0 +1,207 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using System.Text.Json.Serialization; + +namespace Insight.Infrastructure.Entities +{ + [BsonIgnoreExtraElements] + public class HostStoragePoolEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] + public string? Batch { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("uniqueid")] + public string? UniqueId { get; set; } + + [BsonElement("name")] + public string? Name { get; set; } + + [BsonElement("health")] + public string? Health { get; set; } + + [BsonElement("resiliency")] + public string? Resiliency { get; set; } + + [BsonElement("primordial")] + public bool? Primordial { get; set; } + + [BsonElement("readonly")] + public bool? ReadOnly { get; set; } + + [BsonElement("clustered")] + public bool? Clustered { get; set; } + + [BsonElement("size")] + public ulong? Size { get; set; } + + [BsonElement("size_allocated")] + public ulong? AllocatedSize { get; set; } + + [BsonElement("sectorsize")] + public ulong? SectorSize { get; set; } + + [BsonElement("states")] + public List? States { get; set; } + + [BsonIgnoreIfNull, JsonIgnore] + public List? PhysicalDisks { get; set; } + + [BsonIgnoreIfNull, JsonIgnore] + public List? VirtualDisks { get; set; } + } + + [BsonIgnoreExtraElements] + public class HostStoragePoolVirtualDiskEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("_storagepool"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("storagepool")] + public string? StoragePool { get; set; } + + [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] + public string? Batch { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("uniqueid")] + public string? UniqueId { get; set; } + + [BsonElement("name")] + public string? Name { get; set; } + + [BsonElement("health")] + public string? Health { get; set; } + + [BsonElement("access")] + public string? Access { get; set; } + + [BsonElement("provisioning")] + public string? Provisioning { get; set; } + + [BsonElement("redundancy")] + public uint? PhysicalRedundancy { get; set; } + + [BsonElement("resiliency")] + public string? Resiliency { get; set; } + + [BsonElement("deduplication")] + public bool? Deduplication { get; set; } + + [BsonElement("snapshot")] + public bool? Snapshot { get; set; } + + [BsonElement("size")] + public ulong? Size { get; set; } + + [BsonElement("size_allocated")] + public ulong? AllocatedSize { get; set; } + + [BsonElement("footprint")] + public ulong? Footprint { get; set; } + + [BsonElement("cache_read_size")] + public ulong? ReadCacheSize { get; set; } + + [BsonElement("cache_write_size")] + public ulong? WriteCacheSize { get; set; } + + [BsonElement("states")] + public List? States { get; set; } + } + + [BsonIgnoreExtraElements] + public class HostStoragePoolPhysicalDiskEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("_storagepool"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("storagepool")] + public string? StoragePool { get; set; } + + [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] + public string? Batch { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("uniqueid")] + public string? UniqueId { get; set; } + + [BsonElement("deviceid")] + public string? DeviceId { get; set; } + + [BsonElement("name")] + public string? Name { get; set; } + + [BsonElement("manufacturer")] + public string? Manufacturer { get; set; } + + [BsonElement("Model")] + public string? Model { get; set; } + + [BsonElement("media")] + public string? Media { get; set; } + + [BsonElement("bus")] + public string? Bus { get; set; } + + [BsonElement("health")] + public string? Health { get; set; } + + [BsonElement("usage")] + public ushort? Usage { get; set; } + + [BsonElement("location")] + public string? Location { get; set; } + + [BsonElement("serial")] + public string? Serial { get; set; } + + [BsonElement("firmware")] + public string? Firmware { get; set; } + + [BsonElement("size")] + public ulong? Size { get; set; } + + [BsonElement("size_allocated")] + public ulong? AllocatedSize { get; set; } + + [BsonElement("footprint")] + public ulong? Footprint { get; set; } + + [BsonElement("sector_size_physical")] + public ulong? PhysicalSectorSize { get; set; } + + [BsonElement("sector_size_logical")] + public ulong? LogicalSectorSize { get; set; } + + [BsonElement("states")] + public List? States { get; set; } + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/HostSystem.cs b/src/Core/Insight.Infrastructure/Entities/HostSystem.cs new file mode 100644 index 0000000..7cea81e --- /dev/null +++ b/src/Core/Insight.Infrastructure/Entities/HostSystem.cs @@ -0,0 +1,34 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using System.Text.Json.Serialization; + +namespace Insight.Infrastructure.Entities +{ + [BsonIgnoreExtraElements] + public class HostSystemEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("localtime")] + public DateTime? LocalTime { get; set; } + + [BsonElement("bootuptime")] + public DateTime? BootUpTime { get; set; } + + [BsonElement("processes")] + public uint? Processes { get; set; } + + [BsonElement("license")] + public string? License { get; set; } + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/HostUpdate.cs b/src/Core/Insight.Infrastructure/Entities/HostUpdate.cs new file mode 100644 index 0000000..2e2e545 --- /dev/null +++ b/src/Core/Insight.Infrastructure/Entities/HostUpdate.cs @@ -0,0 +1,61 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using System.Text.Json.Serialization; + +namespace Insight.Infrastructure.Entities +{ + [BsonIgnoreExtraElements] + public class HostUpdateEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] + public string? Batch { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("name")] + public string? Name { get; set; } + + [BsonElement("serial")] + public string? Serial { get; set; } // os update id + + [BsonElement("description")] + public string? Description { get; set; } + + [BsonElement("supporturl")] + public string? SupportUrl { get; set; } + + [BsonElement("date")] + public DateTime? Date { get; set; } + + [BsonElement("pending")] + public bool? Pending { get; set; } + + [BsonElement("result"), BsonIgnoreIfNull] // installed only + public string? Result { get; set; } + + [BsonElement("type"), BsonIgnoreIfNull] // pending only + public string? Type { get; set; } + + [BsonElement("size"), BsonIgnoreIfNull] // pending only + public decimal? Size { get; set; } + + [BsonElement("downloaded"), BsonIgnoreIfNull] // pending only + public bool? IsDownloaded { get; set; } + + [BsonElement("inputrequest"), BsonIgnoreIfNull] // pending only + public bool? CanRequestUserInput { get; set; } + + [BsonElement("reboot"), BsonIgnoreIfNull] // pending only + public string? RebootBehavior { get; set; } + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/HostUser.cs b/src/Core/Insight.Infrastructure/Entities/HostUser.cs new file mode 100644 index 0000000..7ef4201 --- /dev/null +++ b/src/Core/Insight.Infrastructure/Entities/HostUser.cs @@ -0,0 +1,120 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using System.Text.Json.Serialization; + +namespace Insight.Infrastructure.Entities +{ + [BsonIgnoreExtraElements] + public class HostUserEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] + public string? Batch { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("sid")] + public string? Sid { get; set; } + + [BsonElement("name")] + public string? Name { get; set; } + + [BsonElement("domain")] + public string? Domain { get; set; } + + [BsonElement("fullname")] + public string? FullName { get; set; } + + [BsonElement("description")] + public string? Description { get; set; } + + [BsonElement("status")] + public string? Status { get; set; } + + [BsonElement("localaccount")] + public bool? LocalAccount { get; set; } + + [BsonElement("disabled")] + public bool? Disabled { get; set; } + + [BsonElement("lockout")] + public bool? Lockout { get; set; } + + [BsonElement("password_changeable")] + public bool? PasswordChangeable { get; set; } + + [BsonElement("password_expires")] + public bool? PasswordExpires { get; set; } + + [BsonElement("password_required")] + public bool? PasswordRequired { get; set; } + } + + [BsonIgnoreExtraElements] + public class HostGroupEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] + public string? Batch { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("sid")] + public string? Sid { get; set; } + + [BsonElement("name")] + public string? Name { get; set; } + + [BsonElement("domain")] + public string? Domain { get; set; } + + [BsonElement("description")] + public string? Description { get; set; } + + [BsonElement("localaccount")] + public bool? LocalAccount { get; set; } + } + + [BsonIgnoreExtraElements] + public class HostUserGroupEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("_user"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("user")] + public string? User { get; set; } + + [BsonElement("_group"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("group")] + public string? Group { get; set; } + + [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] + public string? Batch { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/HostVideocard.cs b/src/Core/Insight.Infrastructure/Entities/HostVideocard.cs new file mode 100644 index 0000000..a2552a9 --- /dev/null +++ b/src/Core/Insight.Infrastructure/Entities/HostVideocard.cs @@ -0,0 +1,40 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using System.Text.Json.Serialization; + +namespace Insight.Infrastructure.Entities +{ + [BsonIgnoreExtraElements] + public class HostVideocardEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] + public string? Batch { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("company")] + public string? Company { get; set; } + + [BsonElement("name")] + public string? Name { get; set; } + + [BsonElement("memory")] + public ulong? Memory { get; set; } + + [BsonElement("driver")] + public string? Driver { get; set; } + + [BsonElement("date")] + public DateTime? Date { get; set; } + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/HostVolume.cs b/src/Core/Insight.Infrastructure/Entities/HostVolume.cs new file mode 100644 index 0000000..00c19df --- /dev/null +++ b/src/Core/Insight.Infrastructure/Entities/HostVolume.cs @@ -0,0 +1,76 @@ +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using System.Text.Json.Serialization; + +namespace Insight.Infrastructure.Entities +{ + [BsonIgnoreExtraElements] + public class HostVolumeEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_host"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("host")] + public string? Host { get; set; } + + [BsonElement("_drive"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("drive")] + public string? Drive { get; set; } + + [BsonElement("_batch"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("batch")] + public string? Batch { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("index")] + public uint? Index { get; set; } + + [BsonElement("label")] + public string? Label { get; set; } + + [BsonElement("name")] + public string? Name { get; set; } + + [BsonElement("serial")] + public string? Serial { get; set; } + + [BsonElement("size")] + public ulong? Size { get; set; } + + [BsonElement("freespace")] + public ulong? FreeSpace { get; set; } + + [BsonElement("type")] + public string? Type { get; set; } + + [BsonElement("filesystem")] + public string? FileSystem { get; set; } + + [BsonElement("compressed")] + public bool? Compressed { get; set; } + + [BsonElement("bootable")] + public bool? Bootable { get; set; } + + [BsonElement("primary")] + public bool? Primary { get; set; } + + [BsonElement("boot")] + public bool? Boot { get; set; } + + [BsonElement("blocksize")] + public ulong? BlockSize { get; set; } + + [BsonElement("blocks")] + public ulong? Blocks { get; set; } + + [BsonElement("startoffset")] + public ulong? StartingOffset { get; set; } + + [BsonElement("provider")] + public string? Provider { get; set; } + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Identity.cs b/src/Core/Insight.Infrastructure/Entities/Identity.cs new file mode 100644 index 0000000..9827a9b --- /dev/null +++ b/src/Core/Insight.Infrastructure/Entities/Identity.cs @@ -0,0 +1,99 @@ +using AspNetCore.Identity.MongoDbCore.Models; +using MongoDB.Bson; +using MongoDB.Bson.Serialization.Attributes; +using MongoDbGenericRepository.Attributes; +using System.Text.Json.Serialization; + +namespace Insight.Infrastructure.Entities +{ + [CollectionName("user"), BsonIgnoreExtraElements] + public class InsightUser : MongoIdentityUser + { + public InsightUser() : base() { } + + public InsightUser(string userName, string email) : base(userName, email) { } + + [JsonPropertyName("refresh_tokens")] + public List? RefreshTokens { get; set; } + } + + [BsonIgnoreExtraElements] + public class InsightUserLogEntity + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_user"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("user")] + public string? User { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("timestamp")] + public DateTime? Timestamp { get; set; } + + [BsonElement("message")] + public string? Message { get; set; } + } + + [CollectionName("user_pref"), BsonIgnoreExtraElements] + public class InsightUserPreferences + { + [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] + public string? Id { get; set; } + + [BsonElement("_user"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("user")] + public string? User { get; set; } + + [BsonElement("insert")] + public DateTime? Insert { get; set; } + + [BsonElement("update")] + public DateTime? Update { get; set; } + + [BsonElement("darkmode")] + public bool DarkMode { get; set; } + } + + [CollectionName("role")] + public class InsightRole : MongoIdentityRole + { + public InsightRole() : base() { } + + public InsightRole(string roleName) : base(roleName) { } + } + + [BsonIgnoreExtraElements] + public class RefreshToken + { + [BsonElement("token")] + public string? Token { get; set; } + + [BsonElement("created")] + public DateTime Created { get; set; } + + [BsonElement("created_ip")] + public string? CreatedByIp { get; set; } + + [BsonElement("expires")] + public DateTime Expires { get; set; } + + [BsonElement("revoked")] + public DateTime? Revoked { get; set; } + + [BsonElement("revoked_ip")] + public string? RevokedByIp { get; set; } + + [BsonElement("revoked_reason")] + public string? ReasonRevoked { get; set; } + + [BsonIgnore, JsonIgnore] + public bool IsExpired => DateTime.Now >= Expires.ToLocalTime(); + + [BsonIgnore, JsonIgnore] + public bool IsRevoked => Revoked != null; + + [BsonIgnore, JsonIgnore] + public bool IsActive => !IsRevoked && !IsExpired; + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Identity/Identity.cs b/src/Core/Insight.Infrastructure/Entities/Identity/Identity.cs deleted file mode 100644 index 4f01e89..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Identity/Identity.cs +++ /dev/null @@ -1,104 +0,0 @@ -using AspNetCore.Identity.MongoDbCore.Models; -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using MongoDbGenericRepository.Attributes; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection User(this IMongoDatabase database) => database.GetCollection("user"); - public static IMongoCollection UserLog(this IMongoDatabase database) => database.GetCollection("user_log"); - public static IMongoCollection UserPreference(this IMongoDatabase database) => database.GetCollection("user_pref"); - public static IMongoCollection Role(this IMongoDatabase database) => database.GetCollection("role"); -} - -[CollectionName("user"), BsonIgnoreExtraElements] -public class InsightUser : MongoIdentityUser -{ - public InsightUser() : base() { } - - public InsightUser(string userName, string email) : base(userName, email) { } - - [JsonPropertyName("refresh_tokens")] - public List? RefreshTokens { get; set; } -} - -[BsonIgnoreExtraElements] -public class InsightUserLogEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_user"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("user")] - public string? User { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("timestamp")] - public DateTime? Timestamp { get; set; } - - [BsonElement("message")] - public string? Message { get; set; } -} - -[CollectionName("user_pref"), BsonIgnoreExtraElements] -public class InsightUserPreferences -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_user"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("user")] - public string? User { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - [BsonElement("darkmode")] - public bool DarkMode { get; set; } -} - -[CollectionName("role")] -public class InsightRole : MongoIdentityRole -{ - -} - -[BsonIgnoreExtraElements] -public class RefreshToken -{ - [BsonElement("token")] - public string? Token { get; set; } - - [BsonElement("created")] - public DateTime Created { get; set; } - - [BsonElement("created_ip")] - public string? CreatedByIp { get; set; } - - [BsonElement("expires")] - public DateTime Expires { get; set; } - - [BsonElement("revoked")] - public DateTime? Revoked { get; set; } - - [BsonElement("revoked_ip")] - public string? RevokedByIp { get; set; } - - [BsonElement("revoked_reason")] - public string? ReasonRevoked { get; set; } - - [BsonIgnore, JsonIgnore] - public bool IsExpired => DateTime.Now >= Expires.ToLocalTime(); - - [BsonIgnore, JsonIgnore] - public bool IsRevoked => Revoked != null; - - [BsonIgnore, JsonIgnore] - public bool IsActive => !IsRevoked && !IsExpired; -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Scheduler/Job.cs b/src/Core/Insight.Infrastructure/Entities/Scheduler/Job.cs deleted file mode 100644 index e0f0c30..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Scheduler/Job.cs +++ /dev/null @@ -1,43 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; -using Vaitr.Scheduler; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection Job(this IMongoDatabase database) => database.GetCollection("job"); -} - -[BsonIgnoreExtraElements] -public class JobEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("name")] - public string? Name { get; set; } - - [BsonElement("description")] - public string? Description { get; set; } - - [BsonElement("state"), BsonRepresentation(BsonType.String)] - public TaskState State { get; set; } - - [BsonElement("timeout")] - public TimeSpan Timeout { get; set; } - - [BsonElement("executed")] - public DateTime Executed { get; set; } - - [BsonElement("disabled")] - public bool Disabled { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Scheduler/JobLog.cs b/src/Core/Insight.Infrastructure/Entities/Scheduler/JobLog.cs deleted file mode 100644 index 5ae9db1..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Scheduler/JobLog.cs +++ /dev/null @@ -1,38 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; -using Vaitr.Scheduler; -using static Insight.Infrastructure.Entities.TriggerEntity; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection JobLog(this IMongoDatabase database) => database.GetCollection("job_log"); -} - -[BsonIgnoreExtraElements] -public class JobLogEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_job"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("job")] - public string? Job { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("timestamp")] - public DateTime? Timestamp { get; set; } - - [BsonElement("status"), BsonRepresentation(BsonType.String)] - public TaskState? Status { get; set; } - - [BsonElement("mode"), BsonRepresentation(BsonType.String)] - public ScheduleMode? Mode { get; set; } - - [BsonElement("message")] - public string? Message { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Scheduler/JobTask.cs b/src/Core/Insight.Infrastructure/Entities/Scheduler/JobTask.cs deleted file mode 100644 index a6c7fa1..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Scheduler/JobTask.cs +++ /dev/null @@ -1,30 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection JobTask(this IMongoDatabase database) => database.GetCollection("job_task"); -} - -[BsonIgnoreExtraElements] -public class JobTaskEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_job"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("job")] - public string? Job { get; set; } - - [BsonElement("_task"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("task")] - public string? Task { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Scheduler/JobTrigger.cs b/src/Core/Insight.Infrastructure/Entities/Scheduler/JobTrigger.cs deleted file mode 100644 index 6c99dc6..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Scheduler/JobTrigger.cs +++ /dev/null @@ -1,30 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection JobTrigger(this IMongoDatabase database) => database.GetCollection("job_trigger"); -} - -[BsonIgnoreExtraElements] -public class JobTriggerEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("_job"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("job")] - public string? Job { get; set; } - - [BsonElement("_trigger"), BsonRepresentation(BsonType.ObjectId), JsonPropertyName("trigger")] - public string? Trigger { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Scheduler/TaskEntity.cs b/src/Core/Insight.Infrastructure/Entities/Scheduler/TaskEntity.cs deleted file mode 100644 index 8811d08..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Scheduler/TaskEntity.cs +++ /dev/null @@ -1,33 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection Task(this IMongoDatabase database) => database.GetCollection("task"); -} - -[BsonIgnoreExtraElements] -public class TaskEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("name")] - public string? Name { get; set; } - - [BsonElement("description")] - public string? Description { get; set; } - - [BsonIgnore] - public Func? Action { get; set; } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Entities/Scheduler/TriggerEntity.cs b/src/Core/Insight.Infrastructure/Entities/Scheduler/TriggerEntity.cs deleted file mode 100644 index 95e5381..0000000 --- a/src/Core/Insight.Infrastructure/Entities/Scheduler/TriggerEntity.cs +++ /dev/null @@ -1,46 +0,0 @@ -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using MongoDB.Driver; -using System.Text.Json.Serialization; - -namespace Insight.Infrastructure.Entities; - -public static partial class MongoDatabaseExtensions -{ - public static IMongoCollection Trigger(this IMongoDatabase database) => database.GetCollection("trigger"); -} - -public class TriggerEntity -{ - [BsonId, BsonRepresentation(BsonType.ObjectId), JsonPropertyName("id")] - public string? Id { get; set; } - - [BsonElement("insert")] - public DateTime? Insert { get; set; } - - [BsonElement("update")] - public DateTime? Update { get; set; } - - [BsonElement("name")] - public string? Name { get; set; } - - [BsonElement("description")] - public string? Description { get; set; } - - [BsonElement("mode")] - public ScheduleMode Mode { get; set; } - - [BsonElement("date_start")] - public DateTime StartTime { get; set; } - - [BsonElement("date_end")] - public DateTime? EndTime { get; set; } - - [BsonElement("interval")] - public TimeSpan? Interval { get; set; } - - public enum ScheduleMode - { - Single, Loop - } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Extensions/ConfigurationExtensions.cs b/src/Core/Insight.Infrastructure/Extensions/ConfigurationExtensions.cs deleted file mode 100644 index aee6395..0000000 --- a/src/Core/Insight.Infrastructure/Extensions/ConfigurationExtensions.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Microsoft.Extensions.Configuration; - -namespace Insight.Infrastructure; - -public static class ConfigurationExtensions -{ - public static IConfigurationBuilder Defaults(this IConfigurationBuilder configuration) - { - configuration.Sources.Clear(); - configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true); - configuration.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true, reloadOnChange: true); - configuration.AddEnvironmentVariables(); - - return configuration; - } -} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Extensions/HttpRequestExtensions.cs b/src/Core/Insight.Infrastructure/Extensions/HttpRequestExtensions.cs new file mode 100644 index 0000000..27d0cb9 --- /dev/null +++ b/src/Core/Insight.Infrastructure/Extensions/HttpRequestExtensions.cs @@ -0,0 +1,47 @@ +using Insight.Infrastructure.Models; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Extensions; + +namespace Insight.Infrastructure +{ + public static class HttpRequestExtensions + { + public static void AddPagination(this HttpRequest request, PagedList pagelist) + { + var builder = new QueryBuilder(); + + foreach (var item in request.Query.Where(p => p.Key.ToLower() != "limit" || p.Key.ToLower() != "offset")) + { + builder.Add(item.Key.ToLower(), item.Value.ToString()); + } + + builder.Add("limit", pagelist.Meta.Limit.ToString()); + + if (pagelist.Meta.Offset > 0) + { + var qb = new QueryBuilder(builder); + + if (pagelist.Meta.Offset > pagelist.Meta.Limit) + { + qb.Add("offset", (pagelist.Meta.Offset - pagelist.Meta.Limit).ToString()); + } + else + { + qb.Add("offset", 0.ToString()); + } + + pagelist.Meta.Previous = $"{request.Scheme}://{request.Host}{request.PathBase}{request.Path}{qb}"; + } + + if ((pagelist.Meta.Offset + pagelist.Meta.Count) < pagelist.Meta.Total) + { + var qb = new QueryBuilder(builder) + { + { "offset", (pagelist.Meta.Offset + pagelist.Meta.Count).ToString() } + }; + + pagelist.Meta.Next = $"{request.Scheme}://{request.Host}{request.PathBase}{request.Path}{qb}"; + } + } + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Extensions/HttpResponseExtensions.cs b/src/Core/Insight.Infrastructure/Extensions/HttpResponseExtensions.cs new file mode 100644 index 0000000..6bb788d --- /dev/null +++ b/src/Core/Insight.Infrastructure/Extensions/HttpResponseExtensions.cs @@ -0,0 +1,17 @@ +using Insight.Infrastructure.Models; +using Microsoft.AspNetCore.Http; +using System.Text.Json; + +namespace Insight.Infrastructure +{ + public static class HttpResponseExtensions + { + public static void AddPagination(this HttpResponse response, PagedList pagelist) + { + response.Headers.Add("X-Pagination", JsonSerializer.Serialize(pagelist.Meta as PagedHeaderData, new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + })); + } + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Extensions/MongoCollectionExtensions.cs b/src/Core/Insight.Infrastructure/Extensions/MongoCollectionExtensions.cs index b1ee91c..bc18ab8 100644 --- a/src/Core/Insight.Infrastructure/Extensions/MongoCollectionExtensions.cs +++ b/src/Core/Insight.Infrastructure/Extensions/MongoCollectionExtensions.cs @@ -1,46 +1,83 @@ using Insight.Infrastructure.Models; +using Microsoft.AspNetCore.Http; using MongoDB.Bson; using MongoDB.Bson.Serialization; using MongoDB.Driver; -namespace Insight.Infrastructure; - -public static partial class MongoCollectionExtensions +namespace Insight.Infrastructure { - private const int _maximumLimit = 100; - - public static async Task> GetPagedAsync( - this IMongoCollection collection, - FilterDefinition? filter = null, - SortDefinition? sort = null, - int offset = 0, - int limit = 10, - CancellationToken cancellationToken = default) + public static class MongoCollectionExtensions { - if (limit > _maximumLimit) throw new InvalidOperationException("invalid limit value > 100"); + private const int _maximumLimit = 100; - var query = collection.Find(filter ?? Builders.Filter.Empty); + public static async Task> GetPagedAsync( + this IMongoCollection collection, + FilterDefinition? filter = null, + SortDefinition? sort = null, + int offset = 0, + int limit = 10, + CancellationToken cancellationToken = default) + { + if (limit > _maximumLimit) throw new InvalidOperationException("invalid limit value > 100"); - if (sort is not null) query = query.Sort(sort); + var query = collection.Find(filter ?? Builders.Filter.Empty); - var data = await query.Skip(offset).Limit(limit).ToListAsync(cancellationToken).ConfigureAwait(false); - var total = await collection.EstimatedDocumentCountAsync(null, cancellationToken).ConfigureAwait(false); + if (sort is not null) query = query.Sort(sort); - return new PagedList(data, offset, limit, total); - } + var data = await query.Skip(offset).Limit(limit).ToListAsync(cancellationToken).ConfigureAwait(false); + var total = await collection.EstimatedDocumentCountAsync(null, cancellationToken).ConfigureAwait(false); - public static async Task> GetPagedAsync( - this IMongoCollection collection, - IAggregateFluent query, - int offset = 0, - int limit = 10, - CancellationToken cancellationToken = default) - { - if (limit > _maximumLimit) throw new InvalidOperationException("invalid limit value"); + return new PagedList(data, offset, limit, total); + } - var data = await query.Skip(offset).Limit(limit).ToListAsync(cancellationToken).ConfigureAwait(false); - var total = await collection.EstimatedDocumentCountAsync(null, cancellationToken).ConfigureAwait(false); + public static async Task> GetPagedAsync( + this IMongoCollection collection, + HttpRequest request, + HttpResponse response, + FilterDefinition? filter = null, + SortDefinition? sort = null, + int offset = 0, + int limit = 10, + CancellationToken cancellationToken = default) + { + var result = await GetPagedAsync(collection, filter, sort, offset, limit, cancellationToken).ConfigureAwait(false); - return new PagedList(data.Select(x => BsonSerializer.Deserialize(x)), offset, limit, total); + request?.AddPagination(result); + response?.AddPagination(result); + + return result; + } + + public static async Task> GetPagedAsync( + this IMongoCollection collection, + IAggregateFluent query, + int offset = 0, + int limit = 10, + CancellationToken cancellationToken = default) + { + if (limit > _maximumLimit) throw new InvalidOperationException("invalid limit value"); + + var data = await query.Skip(offset).Limit(limit).ToListAsync(cancellationToken).ConfigureAwait(false); + var total = await collection.EstimatedDocumentCountAsync(null, cancellationToken).ConfigureAwait(false); + + return new PagedList(data.Select(x => BsonSerializer.Deserialize(x)), offset, limit, total); + } + + public static async Task> GetPagedAsync( + this IMongoCollection collection, + HttpRequest request, + HttpResponse response, + IAggregateFluent query, + int offset = 0, + int limit = 10, + CancellationToken cancellationToken = default) + { + var result = await GetPagedAsync(collection, query, offset, limit, cancellationToken).ConfigureAwait(false); + + request?.AddPagination(result); + response?.AddPagination(result); + + return result; + } } } \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Extensions/MongoDatabaseExtensions.cs b/src/Core/Insight.Infrastructure/Extensions/MongoDatabaseExtensions.cs new file mode 100644 index 0000000..3769e1d --- /dev/null +++ b/src/Core/Insight.Infrastructure/Extensions/MongoDatabaseExtensions.cs @@ -0,0 +1,57 @@ +using Insight.Infrastructure.Entities; +using MongoDB.Driver; + +namespace Insight.Infrastructure +{ + public static class MongoDatabaseExtensions + { + // internal users (roles), groups... + public static IMongoCollection User(this IMongoDatabase database) => database.GetCollection("user"); + public static IMongoCollection UserLog(this IMongoDatabase database) => database.GetCollection("user_log"); + public static IMongoCollection UserPreference(this IMongoDatabase database) => database.GetCollection("user_pref"); + public static IMongoCollection Role(this IMongoDatabase database) => database.GetCollection("role"); + + // customers + public static IMongoCollection Customer(this IMongoDatabase database) => database.GetCollection("customer"); + + // agents + public static IMongoCollection Agent(this IMongoDatabase database) => database.GetCollection("agent"); + public static IMongoCollection AgentLog(this IMongoDatabase database) => database.GetCollection("agent_log"); + + // host groups + public static IMongoCollection HostGroup(this IMongoDatabase database) => database.GetCollection("host"); + + // hosts + public static IMongoCollection Host(this IMongoDatabase database) => database.GetCollection("host"); + public static IMongoCollection HostLog(this IMongoDatabase database) => database.GetCollection("host_log"); + + // hosts extensions + public static IMongoCollection HostLogMonitoring(this IMongoDatabase database) => database.GetCollection("host_log_mon"); + public static IMongoCollection HostApplication(this IMongoDatabase database) => database.GetCollection("host_app"); + public static IMongoCollection HostDrive(this IMongoDatabase database) => database.GetCollection("host_drv"); + public static IMongoCollection HostVolume(this IMongoDatabase database) => database.GetCollection("host_vol"); + public static IMongoCollection HostOs(this IMongoDatabase database) => database.GetCollection("host_os"); + public static IMongoCollection HostUpdate(this IMongoDatabase database) => database.GetCollection("host_upd"); + public static IMongoCollection HostSession(this IMongoDatabase database) => database.GetCollection("host_session"); + public static IMongoCollection HostService(this IMongoDatabase database) => database.GetCollection("host_svc"); + public static IMongoCollection HostPrinter(this IMongoDatabase database) => database.GetCollection("host_prn"); + public static IMongoCollection HostMainboard(this IMongoDatabase database) => database.GetCollection("host_board"); + public static IMongoCollection HostProcessor(this IMongoDatabase database) => database.GetCollection("host_cpu"); + public static IMongoCollection HostMemory(this IMongoDatabase database) => database.GetCollection("host_mem"); + public static IMongoCollection HostVideocard(this IMongoDatabase database) => database.GetCollection("host_gpu"); + public static IMongoCollection HostSystemUser(this IMongoDatabase database) => database.GetCollection("host_sysusr"); + public static IMongoCollection HostSystemGroup(this IMongoDatabase database) => database.GetCollection("host_sysgrp"); + public static IMongoCollection HostSystemUserSystemGroup(this IMongoDatabase database) => database.GetCollection("host_sysusr_sysgrp"); + public static IMongoCollection HostSystem(this IMongoDatabase database) => database.GetCollection("host_sys"); + public static IMongoCollection HostStoragePool(this IMongoDatabase database) => database.GetCollection("host_sp"); + public static IMongoCollection HostStoragePoolPhysicalDisk(this IMongoDatabase database) => database.GetCollection("host_sp.pd"); + public static IMongoCollection HostStoragePoolVirtualDisk(this IMongoDatabase database) => database.GetCollection("host_sp.vd"); + public static IMongoCollection HostHypervisorVirtualMaschine(this IMongoDatabase database) => database.GetCollection("host_hv_vm"); + public static IMongoCollection HostVirtualMaschineConfig(this IMongoDatabase database) => database.GetCollection("host_hv_vm_cfg"); + public static IMongoCollection HostInterface(this IMongoDatabase database) => database.GetCollection("host_if"); + public static IMongoCollection HostInterfaceAddress(this IMongoDatabase database) => database.GetCollection("host_if_addr"); + public static IMongoCollection HostInterfaceGateway(this IMongoDatabase database) => database.GetCollection("host_if_gw"); + public static IMongoCollection HostInterfaceNameserver(this IMongoDatabase database) => database.GetCollection("host_if_ns"); + public static IMongoCollection HostInterfaceRoute(this IMongoDatabase database) => database.GetCollection("host_if_rt"); + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Extensions/ServiceExtensions.cs b/src/Core/Insight.Infrastructure/Extensions/ServiceExtensions.cs index ed4cab2..e8e49d6 100644 --- a/src/Core/Insight.Infrastructure/Extensions/ServiceExtensions.cs +++ b/src/Core/Insight.Infrastructure/Extensions/ServiceExtensions.cs @@ -1,36 +1,263 @@ -using Insight.Infrastructure.Services; +using AspNetCore.Identity.MongoDbCore.Extensions; +using AspNetCore.Identity.MongoDbCore.Infrastructure; +using Insight.Infrastructure.Entities; +using Insight.Infrastructure.Services; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.HttpOverrides; +using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.IdentityModel.Tokens; +using Microsoft.Net.Http.Headers; +using MongoDB.Bson; using MongoDB.Driver; using MongoDB.Driver.Core.Configuration; +using System.Text; -namespace Insight.Infrastructure; - -public static partial class ServiceExtensions +namespace Insight.Infrastructure { - public static IServiceCollection AddDatabase(this IServiceCollection services, IConfiguration configuration, ILoggerFactory? loggerFactory = null) + public static class ServiceExtensions { - var connectionString = configuration.GetValue(Appsettings.Mongo.ConnectionString) ?? throw new Exception($"{Appsettings.Mongo.ConnectionString} value not set (appsettings)"); - - var settings = MongoClientSettings.FromUrl(new MongoUrl(connectionString)); - settings.ConnectTimeout = TimeSpan.FromSeconds(3); - settings.IPv6 = false; - - if (loggerFactory is not null) + public static IServiceCollection AddDatabase(this IServiceCollection services, IConfiguration configuration, ILoggerFactory? loggerFactory = null) { - settings.LoggingSettings = new LoggingSettings(loggerFactory); + var connectionString = configuration.GetValue(Appsettings.Database) ?? throw new Exception($"{Appsettings.Database} value not set (appsettings)"); + + var settings = MongoClientSettings.FromUrl(new MongoUrl(connectionString)); + settings.ConnectTimeout = TimeSpan.FromSeconds(3); + settings.IPv6 = false; + + if (loggerFactory is not null) + { + settings.LoggingSettings = new LoggingSettings(loggerFactory); + } + + services.AddSingleton(new MongoClient(settings)); + services.AddSingleton(provider => provider.GetRequiredService()); + return services.AddSingleton(provider => provider.GetRequiredService().GetDatabase(Settings.Database)); } - services.AddSingleton(new MongoClient(settings)); - services.AddSingleton(provider => provider.GetRequiredService()); - return services.AddSingleton(provider => provider.GetRequiredService().GetDatabase(Settings.Database)); - } + public static IServiceCollection AddInfrastructureServices(this IServiceCollection services) + { + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + return services; + } - public static IServiceCollection AddIdentityServices(this IServiceCollection services) - { - services.AddTransient(); - services.AddTransient(); - return services; + public static IServiceCollection AddIdentityServices(this IServiceCollection services, IConfiguration configuration) + { + var connectionString = configuration.GetValue(Appsettings.Database) ?? throw new Exception($"{Appsettings.Database} value not set (appsettings)"); + + services.AddIdentity(options => + { + + }) + .AddMongoDbStores(connectionString, Settings.Database) + .AddDefaultTokenProviders() + .AddSignInManager(); + + return services; + } + + public static IServiceCollection AddTokenServices(this IServiceCollection services, IConfiguration configuration) + { + var options = new Models.TokenOptions( + key: configuration.GetValue(Appsettings.JwtKey) ?? throw new Exception($"{Appsettings.JwtKey} value not set (appsettings)"), + expires: configuration.GetValue(Appsettings.JwtExp) ?? throw new Exception($"{Appsettings.JwtExp} value not set (appsettings)"), + audience: configuration.GetValue(Appsettings.JwtAudience) ?? throw new Exception($"{Appsettings.JwtAudience} value not set (appsettings)"), + issuer: configuration.GetValue(Appsettings.JwtIssuer) ?? throw new Exception($"{Appsettings.JwtIssuer} value not set (appsettings)")); + + services.AddSingleton(options); + services.AddTransient(); + + return services; + } + + public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration) + { + // REWRITE TO COOKIE ONLY FOR WEB + + services.AddAuthentication(options => + { + options.DefaultScheme = "Custom"; + options.DefaultChallengeScheme = "Custom"; + }) + .AddCookie("Cookies", options => + { + //options.Cookie.Domain = "insight.webmatic.de"; + options.Cookie.Name = "insight"; + options.LoginPath = "/account/login"; + options.LogoutPath = "/account/logout"; + options.ExpireTimeSpan = TimeSpan.FromHours(1); + options.SlidingExpiration = true; + + options.Events.OnRedirectToLogin = options => + { + if (options.Request.Path.StartsWithSegments("/api") && options.Response.StatusCode == 200) + options.Response.StatusCode = 401; + else + options.Response.Redirect(options.RedirectUri); + + return Task.CompletedTask; + }; + }) + .AddJwtBearer("Bearer", options => + { + options.RequireHttpsMetadata = false; + options.SaveToken = true; + + options.TokenValidationParameters.ValidateActor = false; + + options.TokenValidationParameters.ValidAudience = configuration.GetSection("Jwt:Audience").Value; + options.TokenValidationParameters.ValidateAudience = true; + + options.TokenValidationParameters.ValidIssuer = configuration.GetSection("Jwt:Issuer").Value; + options.TokenValidationParameters.ValidateIssuer = true; + + options.TokenValidationParameters.IssuerSigningKey = new SymmetricSecurityKey( + Encoding.UTF8.GetBytes(configuration.GetSection("Jwt:Key").Value ?? throw new ArgumentNullException(nameof(TokenValidationParameters), "Jwt:Key")) + ); + + options.TokenValidationParameters.ValidateIssuerSigningKey = true; + options.TokenValidationParameters.ValidateLifetime = true; + }) + .AddPolicyScheme("Custom", "Custom", options => + { + options.ForwardDefaultSelector = context => + { + string authorization = context.Request.Headers[HeaderNames.Authorization]; + + if (!string.IsNullOrEmpty(authorization) && authorization.StartsWith("Bearer ")) return "Bearer"; + + return "Cookies"; + }; + }); + + return services; + } + + public static IServiceCollection AddBearerAuthentication(this IServiceCollection services, IConfiguration configuration) + { + services.AddAuthentication(options => + { + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultSignInScheme = JwtBearerDefaults.AuthenticationScheme; + }) + .AddJwtBearer(options => + { + options.RequireHttpsMetadata = false; + options.SaveToken = true; + + options.TokenValidationParameters.ValidateActor = false; + + options.TokenValidationParameters.ValidAudience = configuration.GetValue(Appsettings.JwtAudience) ?? throw new Exception($"{Appsettings.JwtAudience} value not set (appsettings)"); + options.TokenValidationParameters.ValidateAudience = true; + + options.TokenValidationParameters.ValidIssuer = configuration.GetValue(Appsettings.JwtIssuer) ?? throw new Exception($"{Appsettings.JwtIssuer} value not set (appsettings)"); + options.TokenValidationParameters.ValidateIssuer = true; + + options.TokenValidationParameters.IssuerSigningKey = new SymmetricSecurityKey( + Encoding.UTF8.GetBytes(configuration.GetValue(Appsettings.JwtKey) ?? throw new Exception($"{Appsettings.JwtKey} value not set (appsettings)")) + ); + + options.TokenValidationParameters.ValidateIssuerSigningKey = true; + options.TokenValidationParameters.ValidateLifetime = true; + }); + + return services; + } + + public static IServiceCollection AddProxyServices(this IServiceCollection services, IConfiguration configuration) + { + // add before routing + services.Configure(options => + { + options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; + }); + + return services; + } + + public static IServiceCollection AddRoutingServices(this IServiceCollection services, IConfiguration configuration) + { + // add after proxy + services.AddRouting(options => + { + options.LowercaseUrls = true; + }); + + return services; + } + + private static IServiceCollection AddIdentityServices2(this IServiceCollection services, IConfiguration configuration) + { + var identityOptions = new MongoDbIdentityConfiguration + { + MongoDbSettings = new MongoDbSettings + { + ConnectionString = configuration.GetSection("ConnectionStrings:Mongo").Value, + DatabaseName = "insight" + }, + IdentityOptionsAction = options => + { + options.User.RequireUniqueEmail = true; + options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@.-_"; + + options.Password.RequireDigit = false; + options.Password.RequiredLength = 8; + options.Password.RequireNonAlphanumeric = false; + options.Password.RequireUppercase = false; + options.Password.RequireLowercase = false; + + options.SignIn.RequireConfirmedAccount = false; + options.SignIn.RequireConfirmedEmail = false; + options.SignIn.RequireConfirmedPhoneNumber = false; + + options.Lockout.MaxFailedAccessAttempts = 5; + options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5); + } + }; + + services.ConfigureMongoDbIdentity(identityOptions) + .AddDefaultTokenProviders() + .AddSignInManager(); + + return services; + } + + private static IServiceCollection AddIdentityAuthentication(this IServiceCollection services, IConfiguration configuration) + { + services.AddAuthentication(options => + { + //options.DefaultAuthenticateScheme = + }); + //cookieBuilder.ApplicationCookie = builder.AddApplicationCookie(); + //cookieBuilder.ExternalCookie = builder.AddExternalCookie(); + //cookieBuilder.TwoFactorRememberMeCookie = builder.AddTwoFactorRememberMeCookie(); + //cookieBuilder.TwoFactorUserIdCookie = builder.AddTwoFactorUserIdCookie(); + //.AddCookie(options => + //{ + // options. + //}; + //.AddIdentityCookies(); + //.AddCookie(options => + //{ + // // Specify where to redirect un-authenticated users + // options.LoginPath = "/account/login"; + + // // Specify the name of the auth cookie. + // // ASP.NET picks a dumb name by default. + // options.Cookie.Name = "insight"; + //}); + + return services; + } } } \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Insight.Infrastructure.csproj b/src/Core/Insight.Infrastructure/Insight.Infrastructure.csproj index 01ab804..363fd02 100644 --- a/src/Core/Insight.Infrastructure/Insight.Infrastructure.csproj +++ b/src/Core/Insight.Infrastructure/Insight.Infrastructure.csproj @@ -1,22 +1,34 @@  - net8.0 - latest - enable - enable + net7.0 Insight.Infrastructure Insight - 2023.12.15.0 + 2025.2.24.0 + 2025.2.24.0 + true + enable none + true + + + + none + + + + none + + - - - - + + + + + diff --git a/src/Core/Insight.Infrastructure/Models/Pagination.cs b/src/Core/Insight.Infrastructure/Models/Pagination.cs index ea27d93..1ddc63a 100644 --- a/src/Core/Insight.Infrastructure/Models/Pagination.cs +++ b/src/Core/Insight.Infrastructure/Models/Pagination.cs @@ -1,48 +1,49 @@ using System.Text.Json.Serialization; -namespace Insight.Infrastructure.Models; - -public class PagedList +namespace Insight.Infrastructure.Models { - public PagedMetaData Meta { get; } = new(); - public IEnumerable Data { get; } - - public PagedList(IEnumerable data, int offset, int limit, long total) + public class PagedList { - Data = data; - Meta = new() + public PagedMetaData Meta { get; } = new(); + public IEnumerable Data { get; } + + public PagedList(IEnumerable data, int offset, int limit, long total) { - Offset = offset, - Limit = limit, - Count = data?.Count() ?? 0, - Total = total, - }; + Data = data; + Meta = new() + { + Offset = offset, + Limit = limit, + Count = data?.Count() ?? 0, + Total = total, + }; + } } -} -public class PagedDataRequest -{ - [JsonPropertyName("offset")] - public int Offset { get; set; } = 0; + public class PagedDataRequest + { + [JsonPropertyName("offset")] + public int Offset { get; set; } = 0; - [JsonPropertyName("limit")] - public int Limit { get; set; } = 10; -} + [JsonPropertyName("limit")] + public int Limit { get; set; } = 10; + } -public class PagedHeaderData : PagedDataRequest -{ - [JsonPropertyName("count")] - public int Count { get; set; } = 0; + public class PagedHeaderData : PagedDataRequest + { + [JsonPropertyName("count")] + public int Count { get; set; } = 0; - [JsonPropertyName("total")] - public long Total { get; set; } = 0; -} + [JsonPropertyName("total")] + public long Total { get; set; } = 0; + } -public class PagedMetaData : PagedHeaderData -{ - [JsonPropertyName("next")] - public string? Next { get; set; } + public class PagedMetaData : PagedHeaderData + { + [JsonPropertyName("next")] + public string? Next { get; set; } - [JsonPropertyName("previous")] - public string? Previous { get; set; } + [JsonPropertyName("previous")] + public string? Previous { get; set; } + } } \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Models/TokenOptions.cs b/src/Core/Insight.Infrastructure/Models/TokenOptions.cs new file mode 100644 index 0000000..d993465 --- /dev/null +++ b/src/Core/Insight.Infrastructure/Models/TokenOptions.cs @@ -0,0 +1,18 @@ +namespace Insight.Infrastructure.Models +{ + public class TokenOptions + { + public string Key { get; set; } + public int Expires { get; set; } + public Uri? Audience { get; set; } + public Uri? Issuer { get; set; } + + public TokenOptions(string key, int expires, Uri? audience = null, Uri? issuer = null) + { + Key = key; + Expires = expires; + Audience = audience; + Issuer = issuer; + } + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Services/AccountService.cs b/src/Core/Insight.Infrastructure/Services/AccountService.cs new file mode 100644 index 0000000..ece4505 --- /dev/null +++ b/src/Core/Insight.Infrastructure/Services/AccountService.cs @@ -0,0 +1,36 @@ +using Insight.Infrastructure.Entities; +using Insight.Infrastructure.Models; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using MongoDB.Driver; + +namespace Insight.Infrastructure.Services +{ + public class AccountService + { + private readonly IMongoDatabase _database; + private readonly ILogger _logger; + + public AccountService(IMongoDatabase database, ILogger logger) + { + _database = database; + _logger = logger; + } + + public Task> GetAsync( + FilterDefinition? filter = null, + SortDefinition? sort = null, + int offset = 0, + int limit = 10, + CancellationToken cancellationToken = default) => _database.User().GetPagedAsync(filter, sort, offset, limit, cancellationToken); + + public Task> GetAsync( + HttpRequest request, + HttpResponse response, + FilterDefinition? filter = null, + SortDefinition? sort = null, + int offset = 0, + int limit = 10, + CancellationToken cancellationToken = default) => _database.User().GetPagedAsync(request, response, filter, sort, offset, limit, cancellationToken); + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Services/AgentService.cs b/src/Core/Insight.Infrastructure/Services/AgentService.cs new file mode 100644 index 0000000..580336e --- /dev/null +++ b/src/Core/Insight.Infrastructure/Services/AgentService.cs @@ -0,0 +1,36 @@ +using Insight.Infrastructure.Entities; +using Insight.Infrastructure.Models; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using MongoDB.Driver; + +namespace Insight.Infrastructure.Services +{ + public class AgentService + { + private readonly IMongoDatabase _database; + private readonly ILogger _logger; + + public AgentService(IMongoDatabase database, ILogger logger) + { + _database = database; + _logger = logger; + } + + public Task> GetAsync( + FilterDefinition? filter = null, + SortDefinition? sort = null, + int offset = 0, + int limit = 10, + CancellationToken cancellationToken = default) => _database.Agent().GetPagedAsync(filter, sort, offset, limit, cancellationToken); + + public Task> GetAsync( + HttpRequest request, + HttpResponse response, + FilterDefinition? filter = null, + SortDefinition? sort = null, + int offset = 0, + int limit = 10, + CancellationToken cancellationToken = default) => _database.Agent().GetPagedAsync(request, response, filter, sort, offset, limit, cancellationToken); + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Services/AuthenticatorService.cs b/src/Core/Insight.Infrastructure/Services/AuthenticatorService.cs index db04a99..65f29df 100644 --- a/src/Core/Insight.Infrastructure/Services/AuthenticatorService.cs +++ b/src/Core/Insight.Infrastructure/Services/AuthenticatorService.cs @@ -1,103 +1,112 @@ using Insight.Infrastructure.Entities; using Microsoft.AspNetCore.Identity; +using MongoDB.Driver; using System.Globalization; using System.Text; using System.Text.Encodings.Web; -namespace Insight.Infrastructure.Services; - -public class AuthenticatorService(UserManager userManager) +namespace Insight.Infrastructure.Services { - private readonly UserManager _userManager = userManager; - - public async Task GetStatusAsync(InsightUser user) + public class AuthenticatorService { - return await _userManager.GetTwoFactorEnabledAsync(user).ConfigureAwait(false); - } + private readonly IMongoDatabase _database; + private readonly UserManager _userManager; - public async Task GetKeyAsync(InsightUser user) - { - return await _userManager.GetAuthenticatorKeyAsync(user).ConfigureAwait(false); - } - - public async Task ResetKeyAsync(InsightUser user) - { - var result = await _userManager.ResetAuthenticatorKeyAsync(user).ConfigureAwait(false); - return result.Succeeded; - } - - public async Task VerifyAsync(InsightUser user, string code) - { - code = code.Replace(" ", string.Empty).Replace("-", string.Empty); - return await _userManager.VerifyTwoFactorTokenAsync(user, _userManager.Options.Tokens.AuthenticatorTokenProvider, code).ConfigureAwait(false); - } - - public async Task EnableAsync(InsightUser user) - { - var result = await _userManager.SetTwoFactorEnabledAsync(user, true).ConfigureAwait(false); - return result.Succeeded; - } - - public async Task DisableAsync(InsightUser user) - { - var result = await _userManager.SetTwoFactorEnabledAsync(user, false).ConfigureAwait(false); - return result.Succeeded; - } - - public async Task DeleteAsync(InsightUser user) - { - var result = await _userManager.SetTwoFactorEnabledAsync(user, false).ConfigureAwait(false); - if (result.Succeeded is false) return false; - - result = await _userManager.RemoveAuthenticationTokenAsync(user, "[AspNetUserStore]", "AuthenticatorKey").ConfigureAwait(false); - if (result.Succeeded is false) return false; - - return true; - } - - public async Task CountRecoveryCodesAsync(InsightUser user) - { - return await _userManager.CountRecoveryCodesAsync(user).ConfigureAwait(false); - } - - public async Task UseRecoveryCodeAsync(InsightUser user, string recoveryCode) - { - var result = await _userManager.RedeemTwoFactorRecoveryCodeAsync(user, recoveryCode).ConfigureAwait(false); - return result.Succeeded; - } - - public async Task?> ResetRecoveryCodesAsync(InsightUser user, int count = 3) - { - return await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(user, count).ConfigureAwait(false); - } - - public static string GenerateQrCode(string email, string unformattedKey) - { - var encoder = UrlEncoder.Default; - - return string.Format(CultureInfo.InvariantCulture, - @"otpauth://totp/{0}:{1}?secret={2}&issuer={0}&digits=6", - encoder.Encode("Insight"), - encoder.Encode(email), - unformattedKey); - } - - public static string HumanizeKey(string unformattedKey) - { - var result = new StringBuilder(); - int currentPosition = 0; - - while (currentPosition + 4 < unformattedKey.Length) + public AuthenticatorService(IMongoDatabase database, UserManager userManager) { - result.Append(unformattedKey.AsSpan(currentPosition, 4)).Append(' '); - currentPosition += 4; + _database = database; + _userManager = userManager; } - if (currentPosition < unformattedKey.Length) + public async Task GetStatusAsync(InsightUser user) { - result.Append(unformattedKey.AsSpan(currentPosition)); + return await _userManager.GetTwoFactorEnabledAsync(user).ConfigureAwait(false); } - return result.ToString().ToLowerInvariant(); + public async Task GetKeyAsync(InsightUser user) + { + return await _userManager.GetAuthenticatorKeyAsync(user).ConfigureAwait(false); + } + + public async Task ResetKeyAsync(InsightUser user) + { + var result = await _userManager.ResetAuthenticatorKeyAsync(user).ConfigureAwait(false); + return result.Succeeded; + } + + public async Task VerifyAsync(InsightUser user, string code) + { + code = code.Replace(" ", string.Empty).Replace("-", string.Empty); + return await _userManager.VerifyTwoFactorTokenAsync(user, _userManager.Options.Tokens.AuthenticatorTokenProvider, code).ConfigureAwait(false); + } + + public async Task EnableAsync(InsightUser user) + { + var result = await _userManager.SetTwoFactorEnabledAsync(user, true).ConfigureAwait(false); + return result.Succeeded; + } + + public async Task DisableAsync(InsightUser user) + { + var result = await _userManager.SetTwoFactorEnabledAsync(user, false).ConfigureAwait(false); + return result.Succeeded; + } + + public async Task DeleteAsync(InsightUser user) + { + var result = await _userManager.SetTwoFactorEnabledAsync(user, false).ConfigureAwait(false); + if (result.Succeeded is false) return false; + + result = await _userManager.RemoveAuthenticationTokenAsync(user, "[AspNetUserStore]", "AuthenticatorKey").ConfigureAwait(false); + if (result.Succeeded is false) return false; + + return true; + } + + public async Task CountRecoveryCodesAsync(InsightUser user) + { + return await _userManager.CountRecoveryCodesAsync(user).ConfigureAwait(false); + } + + public async Task UseRecoveryCodeAsync(InsightUser user, string recoveryCode) + { + var result = await _userManager.RedeemTwoFactorRecoveryCodeAsync(user, recoveryCode).ConfigureAwait(false); + return result.Succeeded; + } + + public async Task?> ResetRecoveryCodesAsync(InsightUser user, int count = 3) + { + return await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(user, count).ConfigureAwait(false); + } + + public string GenerateQrCode(string email, string unformattedKey) + { + var encoder = UrlEncoder.Default; + + return string.Format(CultureInfo.InvariantCulture, + @"otpauth://totp/{0}:{1}?secret={2}&issuer={0}&digits=6", + encoder.Encode("Insight"), + encoder.Encode(email), + unformattedKey); + } + + public static string HumanizeKey(string unformattedKey) + { + var result = new StringBuilder(); + int currentPosition = 0; + + while (currentPosition + 4 < unformattedKey.Length) + { + result.Append(unformattedKey.AsSpan(currentPosition, 4)).Append(' '); + currentPosition += 4; + } + + if (currentPosition < unformattedKey.Length) + { + result.Append(unformattedKey.AsSpan(currentPosition)); + } + + return result.ToString().ToLowerInvariant(); + } } } \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Services/CustomerService.cs b/src/Core/Insight.Infrastructure/Services/CustomerService.cs new file mode 100644 index 0000000..c88c35b --- /dev/null +++ b/src/Core/Insight.Infrastructure/Services/CustomerService.cs @@ -0,0 +1,36 @@ +using Insight.Infrastructure.Entities; +using Insight.Infrastructure.Models; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using MongoDB.Driver; + +namespace Insight.Infrastructure.Services +{ + public class CustomerService + { + private readonly IMongoDatabase _database; + private readonly ILogger _logger; + + public CustomerService(IMongoDatabase database, ILogger logger) + { + _database = database; + _logger = logger; + } + + public Task> GetAsync( + FilterDefinition? filter = null, + SortDefinition? sort = null, + int offset = 0, + int limit = 10, + CancellationToken cancellationToken = default) => _database.Customer().GetPagedAsync(filter, sort, offset, limit, cancellationToken); + + public Task> GetAsync( + HttpRequest request, + HttpResponse response, + FilterDefinition? filter = null, + SortDefinition? sort = null, + int offset = 0, + int limit = 10, + CancellationToken cancellationToken = default) => _database.Customer().GetPagedAsync(request, response, filter, sort, offset, limit, cancellationToken); + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Services/HostService.cs b/src/Core/Insight.Infrastructure/Services/HostService.cs new file mode 100644 index 0000000..d39cfc9 --- /dev/null +++ b/src/Core/Insight.Infrastructure/Services/HostService.cs @@ -0,0 +1,36 @@ +using Insight.Infrastructure.Entities; +using Insight.Infrastructure.Models; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using MongoDB.Driver; + +namespace Insight.Infrastructure.Services +{ + public class HostService + { + private readonly IMongoDatabase _database; + private readonly ILogger _logger; + + public HostService(IMongoDatabase database, ILogger logger) + { + _database = database; + _logger = logger; + } + + public Task> GetAsync( + FilterDefinition? filter = null, + SortDefinition? sort = null, + int offset = 0, + int limit = 10, + CancellationToken cancellationToken = default) => _database.Host().GetPagedAsync(filter, sort, offset, limit, cancellationToken); + + public Task> GetAsync( + HttpRequest request, + HttpResponse response, + FilterDefinition? filter = null, + SortDefinition? sort = null, + int offset = 0, + int limit = 10, + CancellationToken cancellationToken = default) => _database.Host().GetPagedAsync(request, response, filter, sort, offset, limit, cancellationToken); + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Services/IdentityService.cs b/src/Core/Insight.Infrastructure/Services/IdentityService.cs index 80d9e98..03c7ca8 100644 --- a/src/Core/Insight.Infrastructure/Services/IdentityService.cs +++ b/src/Core/Insight.Infrastructure/Services/IdentityService.cs @@ -1,128 +1,138 @@ using Insight.Infrastructure.Entities; using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Logging; using System.Security.Claims; -namespace Insight.Infrastructure.Services; - -public class IdentityService(UserManager userManager, RoleManager roleManager) +namespace Insight.Infrastructure.Services { - private readonly UserManager _userManager = userManager; - private readonly RoleManager _roleManager = roleManager; - - public async Task SeedAsync() + public class IdentityService { - // SEED ROLES - if (await _roleManager.FindByNameAsync("system") is not InsightRole systemRole) - { - var result = await CreateRoleAsync("system"); - if (result.Succeeded is false) throw new InvalidProgramException("seeding: system role failed"); + private readonly UserManager _userManager; + private readonly RoleManager _roleManager; + private readonly ILogger _logger; - systemRole = await _roleManager.FindByNameAsync("system") ?? throw new InvalidProgramException("seeding: system role failed"); + public IdentityService(UserManager userManager, RoleManager roleManager, ILogger logger) + { + _userManager = userManager; + _roleManager = roleManager; + _logger = logger; } - if (await _roleManager.FindByNameAsync("administrator") is not InsightRole administratorRole) + public async Task SeedAsync() { - var result = await CreateRoleAsync("administrator"); - if (result.Succeeded is false) throw new InvalidProgramException("seeding: administrator role failed"); - - administratorRole = await _roleManager.FindByNameAsync("administrator") ?? throw new InvalidProgramException("seeding: administrator role failed"); - } - - if (await _roleManager.FindByNameAsync("chat") is not InsightRole chatRole) - { - var result = await CreateRoleAsync("chat"); - if (result.Succeeded is false) throw new InvalidProgramException("seeding: chat role failed"); - - chatRole = await _roleManager.FindByNameAsync("chat") ?? throw new InvalidProgramException("seeding: chat role failed"); - } - - // SEED USERS - if (await _userManager.FindByEmailAsync("system@insight.local") is not InsightUser systemUser) - { - var result = await CreateUserAsync("system@insight.local", "Replica3-Unroasted-Respect"); - if (result.Succeeded is false) throw new InvalidProgramException("seeding: system user failed"); - - systemUser = await _userManager.FindByEmailAsync("system@insight.local") ?? throw new InvalidProgramException("seeding: system user failed"); - } - - if (systemUser.Roles.Any(p => p == systemRole.Id) is false) - { - var assign = await _userManager.AddToRoleAsync(systemUser, systemRole.Name); - if (assign.Succeeded is false) throw new InvalidProgramException("seeding: system user roles failed"); - } - } - - public async Task CreateUserAsync(string email, string password) - { - var user = new InsightUser - { - UserName = email, - NormalizedUserName = email.ToUpperInvariant(), - Email = email, - NormalizedEmail = email.ToUpperInvariant(), - }; - - return await _userManager.CreateAsync(user, password); - } - - public async Task CreateRoleAsync(string name) - { - var role = new InsightRole - { - Name = name, - NormalizedName = name.ToUpperInvariant() - }; - - return await _roleManager.CreateAsync(role); - } - - public async Task LoginAsync(string email, string password, string? code = null) - { - if (await _userManager.FindByEmailAsync(email) is not InsightUser user) throw new InvalidDataException("Invalid Credentials"); - if (await _userManager.CheckPasswordAsync(user, password) is false) throw new InvalidDataException("Invalid Credentials"); - - if (await _userManager.GetTwoFactorEnabledAsync(user)) - { - if (string.IsNullOrWhiteSpace(code)) throw new InvalidOperationException("Requires 2FA Code"); - - var authCode = code.Replace(" ", string.Empty).Replace("-", string.Empty); - - if (await _userManager.VerifyTwoFactorTokenAsync(user, _userManager.Options.Tokens.AuthenticatorTokenProvider, authCode) is false) + // SEED ROLES + if (await _roleManager.FindByNameAsync("system") is not InsightRole systemRole) { - throw new InvalidDataException("Invalid 2FA Code"); + var result = await CreateRoleAsync("system"); + if (result.Succeeded is false) throw new InvalidProgramException("seeding: system role failed"); + + systemRole = await _roleManager.FindByNameAsync("system") ?? throw new InvalidProgramException("seeding: system role failed"); + } + + if (await _roleManager.FindByNameAsync("administrator") is not InsightRole administratorRole) + { + var result = await CreateRoleAsync("administrator"); + if (result.Succeeded is false) throw new InvalidProgramException("seeding: administrator role failed"); + + administratorRole = await _roleManager.FindByNameAsync("administrator") ?? throw new InvalidProgramException("seeding: administrator role failed"); + } + + if (await _roleManager.FindByNameAsync("chat") is not InsightRole chatRole) + { + var result = await CreateRoleAsync("chat"); + if (result.Succeeded is false) throw new InvalidProgramException("seeding: chat role failed"); + + chatRole = await _roleManager.FindByNameAsync("chat") ?? throw new InvalidProgramException("seeding: chat role failed"); + } + + // SEED USERS + if (await _userManager.FindByEmailAsync("system@insight.local") is not InsightUser systemUser) + { + var result = await CreateUserAsync("system@insight.local", "Replica3-Unroasted-Respect"); + if (result.Succeeded is false) throw new InvalidProgramException("seeding: system user failed"); + + systemUser = await _userManager.FindByEmailAsync("system@insight.local") ?? throw new InvalidProgramException("seeding: system user failed"); + } + + if (systemUser.Roles.Any(p => p == systemRole.Id) is false) + { + var assign = await _userManager.AddToRoleAsync(systemUser, systemRole.Name); + if (assign.Succeeded is false) throw new InvalidProgramException("seeding: system user roles failed"); } } - return user; - } - - public async Task ChangePasswordAsync(InsightUser user, string current, string @new) - { - var result = await _userManager.ChangePasswordAsync(user, current, @new).ConfigureAwait(false); - return result.Succeeded; - } - - public async Task GetByEmailAsync(string key) - { - var result = await _userManager.FindByEmailAsync(key).ConfigureAwait(false); - if (result is not null) return result; - - return null; - } - - public async Task> GetClaimsAsync(InsightUser user, bool includeRoles = true) - { - var claims = await _userManager.GetClaimsAsync(user).ConfigureAwait(false); - - if (includeRoles) + public async Task CreateUserAsync(string email, string password) { - var roles = await _userManager.GetRolesAsync(user).ConfigureAwait(false); - foreach (var role in roles) claims.Add(new Claim(ClaimTypes.Role, role)); + var user = new InsightUser + { + UserName = email, + NormalizedUserName = email.ToUpperInvariant(), + Email = email, + NormalizedEmail = email.ToUpperInvariant(), + }; + + return await _userManager.CreateAsync(user, password); } - claims.Add(new Claim(ClaimTypes.Email, user.Email)); - claims.Add(new Claim("user", user.UserName)); + public async Task CreateRoleAsync(string name) + { + var role = new InsightRole + { + Name = name, + NormalizedName = name.ToUpperInvariant() + }; - return claims; + return await _roleManager.CreateAsync(role); + } + + public async Task LoginAsync(string email, string password, string? code = null) + { + if (await _userManager.FindByEmailAsync(email) is not InsightUser user) throw new InvalidDataException("Invalid Credentials"); + if (await _userManager.CheckPasswordAsync(user, password) is false) throw new InvalidDataException("Invalid Credentials"); + + if (await _userManager.GetTwoFactorEnabledAsync(user)) + { + if (string.IsNullOrWhiteSpace(code)) throw new InvalidOperationException("Requires 2FA Code"); + + var authCode = code.Replace(" ", string.Empty).Replace("-", string.Empty); + + if (await _userManager.VerifyTwoFactorTokenAsync(user, _userManager.Options.Tokens.AuthenticatorTokenProvider, authCode) is false) + { + throw new InvalidDataException("Invalid 2FA Code"); + } + } + + return user; + } + + public async Task ChangePasswordAsync(InsightUser user, string current, string @new) + { + var result = await _userManager.ChangePasswordAsync(user, current, @new).ConfigureAwait(false); + return result.Succeeded; + } + + public async Task GetByEmailAsync(string key) + { + var result = await _userManager.FindByEmailAsync(key).ConfigureAwait(false); + if (result is not null) return result; + + return null; + } + + public async Task> GetClaimsAsync(InsightUser user, bool includeRoles = true) + { + var claims = await _userManager.GetClaimsAsync(user).ConfigureAwait(false); + + if (includeRoles) + { + var roles = await _userManager.GetRolesAsync(user).ConfigureAwait(false); + foreach (var role in roles) claims.Add(new Claim(ClaimTypes.Role, role)); + } + + claims.Add(new Claim(ClaimTypes.Email, user.Email)); + claims.Add(new Claim("user", user.UserName)); + + return claims; + } } } \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Services/InventoryService.cs b/src/Core/Insight.Infrastructure/Services/InventoryService.cs new file mode 100644 index 0000000..c5e1608 --- /dev/null +++ b/src/Core/Insight.Infrastructure/Services/InventoryService.cs @@ -0,0 +1,36 @@ +using Insight.Infrastructure.Entities; +using Insight.Infrastructure.Models; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using MongoDB.Driver; + +namespace Insight.Infrastructure.Services +{ + public class InventoryService + { + private readonly IMongoDatabase _database; + private readonly ILogger _logger; + + public InventoryService(IMongoDatabase database, ILogger logger) + { + _database = database; + _logger = logger; + } + + public Task> GetAsync( + FilterDefinition? filter = null, + SortDefinition? sort = null, + int offset = 0, + int limit = 10, + CancellationToken cancellationToken = default) => _database.HostApplication().GetPagedAsync(filter, sort, offset, limit, cancellationToken); + + public Task> GetAsync( + HttpRequest request, + HttpResponse response, + FilterDefinition? filter = null, + SortDefinition? sort = null, + int offset = 0, + int limit = 10, + CancellationToken cancellationToken = default) => _database.HostApplication().GetPagedAsync(request, response, filter, sort, offset, limit, cancellationToken); + } +} \ No newline at end of file diff --git a/src/Core/Insight.Infrastructure/Services/TokenService.cs b/src/Core/Insight.Infrastructure/Services/TokenService.cs new file mode 100644 index 0000000..11c0ff3 --- /dev/null +++ b/src/Core/Insight.Infrastructure/Services/TokenService.cs @@ -0,0 +1,149 @@ +using Insight.Domain.Models; +using Insight.Infrastructure.Entities; +using Insight.Infrastructure.Models; +using Microsoft.IdentityModel.Tokens; +using MongoDB.Driver; +using System.IdentityModel.Tokens.Jwt; +using System.Net; +using System.Security.Cryptography; +using System.Text; + +namespace Insight.Infrastructure.Services +{ + public class TokenService + { + private readonly TokenOptions _options; + private readonly IdentityService _identityService; + private readonly IMongoDatabase _database; + + public TokenService(TokenOptions options, IdentityService identityService, IMongoDatabase database) + { + _options = options; + _identityService = identityService; + _database = database; + } + + public async Task GetAsync(string email, string password, string? code = null, IPAddress? ipa = null) + { + var user = await _identityService.LoginAsync(email, password, code).ConfigureAwait(false); + + var accessToken = await CreateAccessTokenAsync(user, ipa).ConfigureAwait(false); + var refreshToken = await CreateRefreshTokenAsync(user, ipa).ConfigureAwait(false); + + return new TokenResponse + { + AccessToken = accessToken.Item1, + ExpireInSeconds = accessToken.Item2, + RefreshToken = refreshToken.Item1 + }; + } + + public async Task RefreshAsync(string refreshToken, IPAddress? ipa = null) + { + if (string.IsNullOrWhiteSpace(refreshToken)) throw new ArgumentNullException(nameof(refreshToken)); + + var user = await _database.User().Find(p => p.RefreshTokens.Any(t => t.Token == refreshToken)).FirstOrDefaultAsync(); + if (user is null || user.RefreshTokens is null) throw new InvalidDataException("Invalid Refresh Token"); + + var token = user.RefreshTokens.First(p => p.Token == refreshToken); + + if (token.IsRevoked) + { + // todo: revoke all descendant tokens in case this token has been compromised + throw new InvalidDataException("Invalid Refresh Token"); + } + + if (token.IsActive is false) + { + throw new InvalidDataException("Invalid Refresh Token"); + } + + // remove actual refresh token + user.RefreshTokens.Remove(token); + + // remove old refresh tokens from user + user.RefreshTokens.RemoveAll(p => p.IsExpired && p.IsRevoked is false); + + // update users refreshTokens + await _database.User().UpdateOneAsync(Builders + .Filter.Eq(p => p.UserName, user.UserName), Builders + .Update.Set(p => p.RefreshTokens, user.RefreshTokens)); + + // create new refresh token + var newRefreshToken = await CreateRefreshTokenAsync(user, ipa).ConfigureAwait(false); + + // create access token + var accessToken = await CreateAccessTokenAsync(user, ipa).ConfigureAwait(false); + + return new TokenResponse + { + AccessToken = accessToken.Item1, + ExpireInSeconds = accessToken.Item2, + RefreshToken = newRefreshToken.Item1, + }; + } + + public async Task RevokeAsync(string refreshToken, string reason, IPAddress? ipa = null) + { + if (string.IsNullOrWhiteSpace(refreshToken)) throw new ArgumentNullException(nameof(refreshToken)); + + var user = await _database.User().Find(p => p.RefreshTokens.Any(t => t.Token == refreshToken)).FirstOrDefaultAsync(); + if (user is null || user.RefreshTokens is null) throw new InvalidDataException("Invalid Refresh Token"); + + var token = user.RefreshTokens.First(p => p.Token == refreshToken); + + if (token.IsActive is false) + { + throw new InvalidDataException("Invalid Refresh Token"); + } + + token.Revoked = DateTime.Now; + token.RevokedByIp = ipa?.ToString(); + token.ReasonRevoked = reason; + } + + private async Task<(string, int)> CreateAccessTokenAsync(InsightUser user, IPAddress? ipa = null) + { + var claims = await _identityService.GetClaimsAsync(user).ConfigureAwait(false); + + var key = Encoding.UTF8.GetBytes(_options.Key); + var secret = new SymmetricSecurityKey(key); + var signing = new SigningCredentials(secret, SecurityAlgorithms.HmacSha256); + + var securityToken = new JwtSecurityToken( + _options.Issuer?.ToString(), + _options.Audience?.ToString(), + claims, + DateTime.Now, + DateTime.Now.AddSeconds(Convert.ToDouble(_options.Expires)), + signing); + + var token = new JwtSecurityTokenHandler().WriteToken(securityToken); + + return (token, (int)TimeSpan.FromMinutes(Convert.ToDouble(_options.Expires)).TotalSeconds); + } + + private async Task<(string, int)> CreateRefreshTokenAsync(InsightUser user, IPAddress? ipa = null) + { + var randomNumber = new byte[32]; + + using var rng = RandomNumberGenerator.Create(); + rng.GetBytes(randomNumber); + + var refreshToken = Convert.ToBase64String(randomNumber); + + await _database.User() + .UpdateOneAsync(Builders + .Filter.Eq(p => p.UserName, user.UserName), Builders + .Update.AddToSet(p => p.RefreshTokens, new RefreshToken + { + Token = refreshToken, + Created = DateTime.Now, + Expires = DateTime.Now.AddMinutes(30), // change offset to config based + CreatedByIp = ipa?.ToString() + })); + + return (refreshToken, (int)TimeSpan.FromMinutes(30).TotalSeconds); + } + } +} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/Abstractions/IAudioProvider.cs b/src/Remote/Insight.Remote.Shared/Abstractions/IAudioProvider.cs deleted file mode 100644 index 961bc17..0000000 --- a/src/Remote/Insight.Remote.Shared/Abstractions/IAudioProvider.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Insight.Remote.Shared.Abstractions; - -public interface IAudioProvider -{ - Task InitAsync(CancellationToken cancellationToken); -} diff --git a/src/Remote/Insight.Remote.Shared/Abstractions/IClipboardProvider.cs b/src/Remote/Insight.Remote.Shared/Abstractions/IClipboardProvider.cs deleted file mode 100644 index a12f525..0000000 --- a/src/Remote/Insight.Remote.Shared/Abstractions/IClipboardProvider.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Insight.Remote.Shared.Abstractions; - -public interface IClipboardProvider -{ - Task InitAsync(CancellationToken cancellationToken); - Task SetText(string clipboardText); -} diff --git a/src/Remote/Insight.Remote.Shared/Abstractions/ICursorProvider.cs b/src/Remote/Insight.Remote.Shared/Abstractions/ICursorProvider.cs deleted file mode 100644 index bcb4364..0000000 --- a/src/Remote/Insight.Remote.Shared/Abstractions/ICursorProvider.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Insight.Domain.Network.Remote.Messages; - -namespace Insight.Remote.Shared.Abstractions; - -public interface ICursorProvider -{ - Task GetAsync(CancellationToken cancellationToken); - Task SetAsync(int x, int y, CancellationToken cancellationToken); -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/Abstractions/IDesktopApp.cs b/src/Remote/Insight.Remote.Shared/Abstractions/IDesktopApp.cs deleted file mode 100644 index a7aa84a..0000000 --- a/src/Remote/Insight.Remote.Shared/Abstractions/IDesktopApp.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Insight.Domain.Enums; - -namespace Insight.Remote.Shared.Abstractions; - -public interface IDesktopApp : IDisposable -{ - Task InitAsync(RemoteControlMode mode, CancellationToken cancellationToken); -} diff --git a/src/Remote/Insight.Remote.Shared/Abstractions/IDispatcher.cs b/src/Remote/Insight.Remote.Shared/Abstractions/IDispatcher.cs deleted file mode 100644 index 897da5e..0000000 --- a/src/Remote/Insight.Remote.Shared/Abstractions/IDispatcher.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Insight.Remote.Shared.Abstractions; - -public interface IDispatcher -{ - Task RunAsync(CancellationToken cancellationToken); - Task ShutdownAsync(); - - ValueTask InvokeAsync(Action action, CancellationToken cancellationToken = default); - ValueTask InvokeAsync(Func func, CancellationToken cancellationToken = default); -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/Abstractions/IFileProvider.cs b/src/Remote/Insight.Remote.Shared/Abstractions/IFileProvider.cs deleted file mode 100644 index c238812..0000000 --- a/src/Remote/Insight.Remote.Shared/Abstractions/IFileProvider.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Insight.Remote.Shared.Services; -using Insight.Remote.Shared.ViewModels; - -namespace Insight.Remote.Shared.Abstractions; - -public interface IFileProvider -{ - string GetBaseDirectory(); - - Task ReceiveFile(byte[] buffer, string fileName, string messageId, bool endOfFile, bool startOfFile); - //void OpenFileTransferWindow(Viewer viewer); - Task UploadFile(FileUpload file, Streamer viewer, Action progressUpdateCallback, CancellationToken cancelToken); -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/Abstractions/IInputProvider.cs b/src/Remote/Insight.Remote.Shared/Abstractions/IInputProvider.cs deleted file mode 100644 index 55f4fd8..0000000 --- a/src/Remote/Insight.Remote.Shared/Abstractions/IInputProvider.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Insight.Remote.Shared.Enums; - -namespace Insight.Remote.Shared.Abstractions; - -public interface IInputProvider -{ - Task InitAsync(CancellationToken cancellationToken); - Task SendKeyDownAsync(string key, CancellationToken cancellationToken); - Task SendKeyUpAsync(string key, CancellationToken cancellationToken); - Task SendMouseMoveAsync(double percentX, double percentY, CancellationToken cancellationToken); - Task SendMouseWheelAsync(int deltaY, CancellationToken cancellationToken); - Task SendTextAsync(string transferText, CancellationToken cancellationToken); - Task ToggleBlockInputAsync(bool toggleOn, CancellationToken cancellationToken); - Task SetKeyStatesUpAsync(CancellationToken cancellationToken); - Task SendMouseButtonActionAsync(int button, ButtonAction buttonAction, double percentX, double percentY, CancellationToken cancellationToken); -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/Abstractions/IScreenProvider.cs b/src/Remote/Insight.Remote.Shared/Abstractions/IScreenProvider.cs deleted file mode 100644 index 2532b11..0000000 --- a/src/Remote/Insight.Remote.Shared/Abstractions/IScreenProvider.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Insight.Remote.Shared.Models; -using SkiaSharp; -using System.Drawing; - -namespace Insight.Remote.Shared.Abstractions; - -public interface IScreenProvider : IDisposable -{ - Rectangle CurrentScreenBounds { get; } - string SelectedScreen { get; } - - Task InitAsync(CancellationToken cancellationToken); - - IEnumerable GetDisplayNames(); - Task GetDiffAreaAsync(bool fullscreen, CancellationToken cancellationToken); - Task GetNextFrameAsync(CancellationToken cancellationToken); - - void SetSelectedScreen(string displayName); - int GetScreenCount(); - int GetSelectedScreenIndex(); - Rectangle GetVirtualScreenBounds(); -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/Enums/ButtonAction.cs b/src/Remote/Insight.Remote.Shared/Enums/ButtonAction.cs deleted file mode 100644 index 71d703d..0000000 --- a/src/Remote/Insight.Remote.Shared/Enums/ButtonAction.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Insight.Remote.Shared.Enums; - -public enum ButtonAction -{ - Down, - Up -} diff --git a/src/Remote/Insight.Remote.Shared/Extensions/ImageExtensions.cs b/src/Remote/Insight.Remote.Shared/Extensions/ImageExtensions.cs deleted file mode 100644 index 71794eb..0000000 --- a/src/Remote/Insight.Remote.Shared/Extensions/ImageExtensions.cs +++ /dev/null @@ -1,181 +0,0 @@ -using Microsoft.IO; -using RemoteControl.Shared; -using SkiaSharp; - -namespace Insight.Remote.Shared.Extensions; - -public static class ImageExtensions -{ - private static readonly RecyclableMemoryStreamManager _recycleManager = new(); - - public static Result GetImageDiff(this SKBitmap currentFrame, SKBitmap? previousFrame, bool forceFullscreen = false) - { - try - { - if (currentFrame is null) return Result.Fail("Current frame cannot be null."); - if (previousFrame is null || forceFullscreen) return Result.Ok(currentFrame.Copy()); - - if (currentFrame.Height != previousFrame.Height || - currentFrame.Width != previousFrame.Width || - currentFrame.BytesPerPixel != previousFrame.BytesPerPixel) return Result.Fail("Frames are not of equal size."); - - var width = currentFrame.Width; - var height = currentFrame.Height; - var anyChanges = false; - var diffFrame = new SKBitmap(width, height); - - var bytesPerPixel = currentFrame.BytesPerPixel; - var totalSize = currentFrame.ByteCount; - - unsafe - { - byte* scan1 = (byte*)currentFrame.GetPixels().ToPointer(); - byte* scan2 = (byte*)previousFrame.GetPixels().ToPointer(); - byte* scan3 = (byte*)diffFrame.GetPixels().ToPointer(); - - for (var row = 0; row < height; row++) - { - for (var column = 0; column < width; column++) - { - var index = row * width * bytesPerPixel + column * bytesPerPixel; - - byte* data1 = scan1 + index; - byte* data2 = scan2 + index; - byte* data3 = scan3 + index; - - if (data1[0] != data2[0] || - data1[1] != data2[1] || - data1[2] != data2[2] || - data1[3] != data2[3]) - { - anyChanges = true; - data3[0] = data2[0]; - data3[1] = data2[1]; - data3[2] = data2[2]; - data3[3] = data2[3]; - } - } - } - } - - if (anyChanges) return Result.Ok(diffFrame); - - diffFrame.Dispose(); - - return Result.Fail("No difference found."); - } - catch (Exception ex) - { - return Result.Fail(ex); - } - } - - public static SKRect GetDiffArea(this SKBitmap currentFrame, SKBitmap? previousFrame, bool forceFullscreen = false) - { - try - { - if (currentFrame is null) return SKRect.Empty; - if (previousFrame is null || forceFullscreen) return currentFrame.ToRectangle(); - - // test: fake (multiple consumers) - //return currentFrame.ToRectangle(); - - if (currentFrame.Height != previousFrame.Height || - currentFrame.Width != previousFrame.Width || - currentFrame.BytesPerPixel != previousFrame.BytesPerPixel) return SKRect.Empty; - - var width = currentFrame.Width; - var height = currentFrame.Height; - int left = int.MaxValue; - int top = int.MaxValue; - int right = int.MinValue; - int bottom = int.MinValue; - - var bytesPerPixel = currentFrame.BytesPerPixel; - var totalSize = currentFrame.ByteCount; - - unsafe - { - byte* scan1 = (byte*)currentFrame.GetPixels().ToPointer(); - byte* scan2 = (byte*)previousFrame.GetPixels().ToPointer(); - - for (var row = 0; row < height; row++) - { - for (var column = 0; column < width; column++) - { - var index = row * width * bytesPerPixel + column * bytesPerPixel; - - byte* data1 = scan1 + index; - byte* data2 = scan2 + index; - - if (data1[0] != data2[0] || - data1[1] != data2[1] || - data1[2] != data2[2]) - { - - if (row < top) - { - top = row; - } - if (row > bottom) - { - bottom = row; - } - if (column < left) - { - left = column; - } - if (column > right) - { - right = column; - } - } - - } - } - - // Check for valid bounding box. - if (left <= right && top <= bottom) - { - left = Math.Max(left - 2, 0); - top = Math.Max(top - 2, 0); - right = Math.Min(right + 2, width); - bottom = Math.Min(bottom + 2, height); - return new SKRect(left, top, right, bottom); - } - - return SKRect.Empty; - } - } - catch (Exception) - { - return SKRect.Empty; - } - } - - public static byte[] EncodeBitmap(this SKBitmap bitmap, SKEncodedImageFormat format, int quality) - { - using var ms = _recycleManager.GetStream(); - bitmap.Encode(ms, format, quality); - - return ms.ToArray(); - } - - public static SKBitmap CropBitmap(this SKBitmap bitmap, SKRect cropArea) - { - var cropped = new SKBitmap((int)cropArea.Width, (int)cropArea.Height); - - using var canvas = new SKCanvas(cropped); - canvas.DrawBitmap( - bitmap, - cropArea, - new SKRect(0, 0, cropArea.Width, cropArea.Height)); - - return cropped; - } - - public static SKRect ToRectangle(this SKBitmap bitmap) - { - return new SKRect(0, 0, bitmap.Width, bitmap.Height); - } -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/Extensions/ServiceCollectionExtensions.cs b/src/Remote/Insight.Remote.Shared/Extensions/ServiceCollectionExtensions.cs deleted file mode 100644 index 8243ea1..0000000 --- a/src/Remote/Insight.Remote.Shared/Extensions/ServiceCollectionExtensions.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Insight.Remote.Shared.Models; -using Insight.Remote.Shared.Services; -using Microsoft.Extensions.DependencyInjection; -using Vaitr.Bus; - -namespace Insight.Remote.Shared.Extensions; - -public static class ServiceCollectionExtensions -{ - public static void AddRemoteControlServices(this IServiceCollection services, Action options) - { - var appOptions = new AppOptions(); - options(appOptions); - - services.AddSingleton(appOptions); - - services.AddHostedService(); - services.AddSingleton(); - services.AddSingleton(); - } -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/Helpers/Disposer.cs b/src/Remote/Insight.Remote.Shared/Helpers/Disposer.cs deleted file mode 100644 index c77dfde..0000000 --- a/src/Remote/Insight.Remote.Shared/Helpers/Disposer.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace Insight.Remote.Shared.Helpers; - -public static class Disposer -{ - public static void TryDisposeAll(params IDisposable[] disposables) - { - if (disposables is null) - { - return; - } - - foreach (var disposable in disposables) - { - try - { - disposable?.Dispose(); - } - catch { } - } - } -} diff --git a/src/Remote/Insight.Remote.Shared/Helpers/WaitHelper.cs b/src/Remote/Insight.Remote.Shared/Helpers/WaitHelper.cs deleted file mode 100644 index e3d42e6..0000000 --- a/src/Remote/Insight.Remote.Shared/Helpers/WaitHelper.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Diagnostics; - -namespace Insight.Remote.Shared.Helpers; - -public static class WaitHelper -{ - public static async Task WaitForAsync(Func condition, TimeSpan timeout, int pollingMs = 10) - { - var sw = Stopwatch.StartNew(); - while (!condition() && sw.Elapsed < timeout) - { - await Task.Delay(pollingMs); - } - return condition(); - } -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/Insight.Remote.Shared.csproj b/src/Remote/Insight.Remote.Shared/Insight.Remote.Shared.csproj deleted file mode 100644 index 7cb0df8..0000000 --- a/src/Remote/Insight.Remote.Shared/Insight.Remote.Shared.csproj +++ /dev/null @@ -1,28 +0,0 @@ - - - - net8.0 - latest - Insight.Remote.Shared - Insight - Insight.Remote.Shared - 2023.12.15.0 - enable - enable - True - True - none - - - - - - - - - - - - - - diff --git a/src/Remote/Insight.Remote.Shared/Messages/AudioSampleReady.cs b/src/Remote/Insight.Remote.Shared/Messages/AudioSampleReady.cs deleted file mode 100644 index 4fbc2fe..0000000 --- a/src/Remote/Insight.Remote.Shared/Messages/AudioSampleReady.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace Insight.Remote.Shared.Messages; - -public record AudioSampleReady(byte[] Sample); \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/Messages/CastRequestDemand.cs b/src/Remote/Insight.Remote.Shared/Messages/CastRequestDemand.cs deleted file mode 100644 index 2f7780e..0000000 --- a/src/Remote/Insight.Remote.Shared/Messages/CastRequestDemand.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Insight.Domain.Network.Remote.Messages; - -namespace Insight.Remote.Shared.Messages; - -public record CastRequestDemand(CastRequest Request, bool Accepted); \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/Messages/ClipboardChanged.cs b/src/Remote/Insight.Remote.Shared/Messages/ClipboardChanged.cs deleted file mode 100644 index 23fde27..0000000 --- a/src/Remote/Insight.Remote.Shared/Messages/ClipboardChanged.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace Insight.Remote.Shared.Messages; - -public record ClipboardChanged(string Text); \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/Messages/ConnectionStateChanged.cs b/src/Remote/Insight.Remote.Shared/Messages/ConnectionStateChanged.cs deleted file mode 100644 index a7c0297..0000000 --- a/src/Remote/Insight.Remote.Shared/Messages/ConnectionStateChanged.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Insight.Remote.Shared.Messages; - -public record ConnectionStateChanged(ConnectionState State); - -public enum ConnectionState -{ - Unknown = 0, - Connecting = 1, - Reconnecting = 2, - Connected = 3, - Disconnected = 4, - Error = 5 -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/Messages/CursorChanged.cs b/src/Remote/Insight.Remote.Shared/Messages/CursorChanged.cs deleted file mode 100644 index d320740..0000000 --- a/src/Remote/Insight.Remote.Shared/Messages/CursorChanged.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Insight.Remote.Shared.Models; - -namespace Insight.Remote.Shared.Messages; - -public record CursorChanged(CursorInfo CursorInfo); \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/Messages/IdentityChanged.cs b/src/Remote/Insight.Remote.Shared/Messages/IdentityChanged.cs deleted file mode 100644 index 8f57218..0000000 --- a/src/Remote/Insight.Remote.Shared/Messages/IdentityChanged.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace Insight.Remote.Shared.Messages; - -public record IdentityChanged(string Id); \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/Messages/ScreenChanged.cs b/src/Remote/Insight.Remote.Shared/Messages/ScreenChanged.cs deleted file mode 100644 index 13deb12..0000000 --- a/src/Remote/Insight.Remote.Shared/Messages/ScreenChanged.cs +++ /dev/null @@ -1,5 +0,0 @@ -using System.Drawing; - -namespace Insight.Remote.Shared.Messages; - -public record ScreenChanged(Rectangle Screen); \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/Messages/WindowsSessionEnding.cs b/src/Remote/Insight.Remote.Shared/Messages/WindowsSessionEnding.cs deleted file mode 100644 index d99737d..0000000 --- a/src/Remote/Insight.Remote.Shared/Messages/WindowsSessionEnding.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Insight.Domain.Enums; - -namespace Insight.Remote.Shared.Messages; - -public record WindowsSessionEnding(SessionEndReasons Reason); \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/Messages/WindowsSessionSwitched.cs b/src/Remote/Insight.Remote.Shared/Messages/WindowsSessionSwitched.cs deleted file mode 100644 index 2f99794..0000000 --- a/src/Remote/Insight.Remote.Shared/Messages/WindowsSessionSwitched.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Insight.Domain.Enums; - -namespace Insight.Remote.Shared.Messages; - -public record WindowsSessionSwitched(SessionSwitchReason Reason, int SessionId); \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/Models/AppOptions.cs b/src/Remote/Insight.Remote.Shared/Models/AppOptions.cs deleted file mode 100644 index 7a3d6bd..0000000 --- a/src/Remote/Insight.Remote.Shared/Models/AppOptions.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Insight.Remote.Shared.Models; - -public class AppOptions -{ - public Uri? Server { get; set; } -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/Models/CursorInfo.cs b/src/Remote/Insight.Remote.Shared/Models/CursorInfo.cs deleted file mode 100644 index 4f63772..0000000 --- a/src/Remote/Insight.Remote.Shared/Models/CursorInfo.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Drawing; - -namespace Insight.Remote.Shared.Models; - -public class CursorInfo(byte[] imageBytes, Point hotspot, string cssOverride = "") -{ - public byte[] ImageBytes { get; set; } = imageBytes; - public Point HotSpot { get; set; } = hotspot; - public string CssOverride { get; set; } = cssOverride; -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/Models/FrameResult.cs b/src/Remote/Insight.Remote.Shared/Models/FrameResult.cs deleted file mode 100644 index b80c35d..0000000 --- a/src/Remote/Insight.Remote.Shared/Models/FrameResult.cs +++ /dev/null @@ -1,5 +0,0 @@ -using SkiaSharp; - -namespace Insight.Remote.Shared.Models; - -public record FrameResult(SKBitmap? Frame, bool Changed, bool Error = false); \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/Models/SentFrame.cs b/src/Remote/Insight.Remote.Shared/Models/SentFrame.cs deleted file mode 100644 index fd4c12d..0000000 --- a/src/Remote/Insight.Remote.Shared/Models/SentFrame.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Insight.Remote.Shared.Models; - -public readonly struct SentFrame(int frameSize, DateTimeOffset timestamp) -{ - public DateTimeOffset Timestamp { get; } = timestamp; - public int FrameSize { get; } = frameSize; -} diff --git a/src/Remote/Insight.Remote.Shared/Native/Linux/LibX11.cs b/src/Remote/Insight.Remote.Shared/Native/Linux/LibX11.cs deleted file mode 100644 index f7d8078..0000000 --- a/src/Remote/Insight.Remote.Shared/Native/Linux/LibX11.cs +++ /dev/null @@ -1,140 +0,0 @@ -/* - -Copyright 1985, 1986, 1987, 1991, 1998 The Open Group - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -the above copyright notice appear in all copies and that both that -copyright notice and this permission notice appear in supporting -documentation. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - -*/ - -using System.Runtime.InteropServices; - -namespace Insight.Remote.Shared.Native.Linux; - -public static unsafe class LibX11 -{ - - [DllImport("libX11")] - public static extern IntPtr XGetImage(IntPtr display, IntPtr drawable, int x, int y, int width, int height, long plane_mask, int format); - - [DllImport("libX11")] - public static extern IntPtr XDefaultVisual(IntPtr display, int screen_number); - [DllImport("libX11")] - public static extern int XScreenCount(IntPtr display); - [DllImport("libX11")] - public static extern int XDefaultScreen(IntPtr display); - [DllImport("libX11")] - public static extern IntPtr XOpenDisplay(string display_name); - [DllImport("libX11")] - public static extern void XCloseDisplay(IntPtr display); - [DllImport("libX11")] - public static extern IntPtr XRootWindow(IntPtr display, int screen_number); - - [DllImport("libX11")] - public static extern IntPtr XGetSubImage(IntPtr display, IntPtr drawable, int x, int y, uint width, uint height, ulong plane_mask, int format, IntPtr dest_image, int dest_x, int dest_y); - [DllImport("libX11")] - public static extern IntPtr XScreenOfDisplay(IntPtr display, int screen_number); - [DllImport("libX11")] - public static extern int XDisplayWidth(IntPtr display, int screen_number); - [DllImport("libX11")] - public static extern int XDisplayHeight(IntPtr display, int screen_number); - [DllImport("libX11")] - public static extern int XWidthOfScreen(IntPtr screen); - [DllImport("libX11")] - public static extern int XHeightOfScreen(IntPtr screen); - [DllImport("libX11")] - public static extern IntPtr XDefaultGC(IntPtr display, int screen_number); - [DllImport("libX11")] - public static extern IntPtr XDefaultRootWindow(IntPtr display); - [DllImport("libX11")] - public static extern void XGetInputFocus(IntPtr display, out IntPtr focus_return, out int revert_to_return); - [DllImport("libX11")] - public static extern IntPtr XStringToKeysym(string key); - [DllImport("libX11")] - public static extern uint XKeysymToKeycode(IntPtr display, IntPtr keysym); - - [DllImport("libX11")] - public static extern IntPtr XRootWindowOfScreen(IntPtr screen); - [DllImport("libX11")] - public static extern ulong XNextRequest(IntPtr display); - [DllImport("libX11")] - public static extern void XForceScreenSaver(IntPtr display, int mode); - [DllImport("libX11")] - public static extern void XSync(IntPtr display, bool discard); - [DllImport("libX11")] - public static extern void XDestroyImage(IntPtr ximage); - - [DllImport("libX11")] - public static extern void XNoOp(IntPtr display); - - [DllImport("libX11")] - public static extern void XFree(IntPtr data); - - [DllImport("libX11")] - public static extern int XGetWindowAttributes(IntPtr display, IntPtr window, out XWindowAttributes windowAttributes); - - public struct XImage - { - public int width; - public int height; /* size of image */ - public int xoffset; /* number of pixels offset in X direction */ - public int format; /* XYBitmap, XYPixmap, ZPixmap */ - //public char* data; /* pointer to image data */ - public IntPtr data; /* pointer to image data */ - public int byte_order; /* data byte order, LSBFirst, MSBFirst */ - public int bitmap_unit; /* quant. of scanline 8, 16, 32 */ - public int bitmap_bit_order; /* LSBFirst, MSBFirst */ - public int bitmap_pad; /* 8, 16, 32 either XY or ZPixmap */ - public int depth; /* depth of image */ - public int bytes_per_line; /* accelerator to next scanline */ - public int bits_per_pixel; /* bits per pixel (ZPixmap) */ - public ulong red_mask; /* bits in z arrangement */ - public ulong green_mask; - public ulong blue_mask; - public IntPtr obdata; /* hook for the object routines to hang on */ - } - - public struct XWindowAttributes - { - public int x; - public int y; - public int width; - public int height; - public int border_width; - public int depth; - public IntPtr visual; - public IntPtr root; - public int @class; - public int bit_gravity; - public int win_gravity; - public int backing_store; - public ulong backing_planes; - public ulong backing_pixel; - public bool save_under; - public IntPtr colormap; - public bool map_installed; - public int map_state; - public long all_event_masks; - public long your_event_mask; - public long do_not_propagate_mask; - public bool override_redirect; - public IntPtr screen; - } -} diff --git a/src/Remote/Insight.Remote.Shared/Native/Linux/LibXtst.cs b/src/Remote/Insight.Remote.Shared/Native/Linux/LibXtst.cs deleted file mode 100644 index 0ae3b5b..0000000 --- a/src/Remote/Insight.Remote.Shared/Native/Linux/LibXtst.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Insight.Remote.Shared.Native.Linux; - -public class LibXtst -{ - [DllImport("libXtst")] - public static extern bool XTestQueryExtension(IntPtr display, out int event_base, out int error_base, out int major_version, out int minor_version); - [DllImport("libXtst")] - public static extern void XTestFakeKeyEvent(IntPtr display, uint keycode, bool is_press, ulong delay); - [DllImport("libXtst")] - public static extern void XTestFakeButtonEvent(IntPtr display, uint button, bool is_press, ulong delay); - [DllImport("libXtst")] - public static extern void XTestFakeMotionEvent(IntPtr display, int screen_number, int x, int y, ulong delay); -} diff --git a/src/Remote/Insight.Remote.Shared/Native/Linux/Libc.cs b/src/Remote/Insight.Remote.Shared/Native/Linux/Libc.cs deleted file mode 100644 index 2abbe71..0000000 --- a/src/Remote/Insight.Remote.Shared/Native/Linux/Libc.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Insight.Remote.Shared.Native.Linux; - -public class Libc -{ - [DllImport("libc", SetLastError = true)] - public static extern uint geteuid(); -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/Native/Linux/libXrandr.cs b/src/Remote/Insight.Remote.Shared/Native/Linux/libXrandr.cs deleted file mode 100644 index 3f7d864..0000000 --- a/src/Remote/Insight.Remote.Shared/Native/Linux/libXrandr.cs +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright © 2000 Compaq Computer Corporation, Inc. - * Copyright © 2002 Hewlett-Packard Company, Inc. - * Copyright © 2006 Intel Corporation - * Copyright © 2008 Red Hat, Inc. - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. - * - * Author: Jim Gettys, HP Labs, Hewlett-Packard, Inc. - * Keith Packard, Intel Corporation - */ - - -using System.Runtime.InteropServices; - -namespace Insight.Remote.Shared.Native.Linux; - -public static class LibXrandr -{ - [StructLayout(LayoutKind.Sequential)] - public struct XRRMonitorInfo - { - // Atom - public IntPtr name; - public bool primary; - public bool automatic; - public int noutput; - public int x; - public int y; - public int width; - public int height; - public int mwidth; - public int mheight; - // RROutput* - public IntPtr outputs; - } - - [DllImport("libXrandr")] - public static extern IntPtr XRRGetMonitors(IntPtr display, IntPtr window, bool get_active, out int monitors); - - [DllImport("libXrandr")] - public static extern void XRRFreeMonitors(IntPtr monitors); - - [DllImport("libXrandr")] - public static extern IntPtr XRRAllocateMonitor(IntPtr display, int output); -} diff --git a/src/Remote/Insight.Remote.Shared/Native/Windows/ADVAPI32.cs b/src/Remote/Insight.Remote.Shared/Native/Windows/ADVAPI32.cs deleted file mode 100644 index 749ae48..0000000 --- a/src/Remote/Insight.Remote.Shared/Native/Windows/ADVAPI32.cs +++ /dev/null @@ -1,364 +0,0 @@ -using System.Runtime.InteropServices; -using System.Security; - -namespace Insight.Remote.Shared.Native.Windows; - -public static class ADVAPI32 -{ - #region Structs - public struct TOKEN_PRIVILEGES - { - public struct LUID - { - public uint LowPart; - public int HighPart; - } - [StructLayout(LayoutKind.Sequential, Pack = 4)] - public struct LUID_AND_ATTRIBUTES - { - public LUID Luid; - public uint Attributes; - } - public int PrivilegeCount; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = ANYSIZE_ARRAY)] - public LUID_AND_ATTRIBUTES[] Privileges; - } - public class USEROBJECTFLAGS - { - public int fInherit = 0; - public int fReserved = 0; - public int dwFlags = 0; - } - [StructLayout(LayoutKind.Sequential)] - public struct SECURITY_ATTRIBUTES - { - public int Length; - public IntPtr lpSecurityDescriptor; - public bool bInheritHandle; - } - [StructLayout(LayoutKind.Sequential)] - public struct PROCESS_INFORMATION - { - public IntPtr hProcess; - public IntPtr hThread; - public int dwProcessId; - public int dwThreadId; - } - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - public struct STARTUPINFO - { - public int cb; - public string lpReserved; - public string lpDesktop; - public string lpTitle; - public int dwX; - public int dwY; - public int dwXSize; - public int dwYSize; - public int dwXCountChars; - public int dwYCountChars; - public int dwFillAttribute; - public int dwFlags; - public short wShowWindow; - public short cbReserved2; - public IntPtr lpReserved2; - public IntPtr hStdInput; - public IntPtr hStdOutput; - public IntPtr hStdError; - } - #endregion - - #region Enums - public enum TOKEN_INFORMATION_CLASS - { - /// -     /// The buffer receives a TOKEN_USER structure that contains the user account of the token. -     /// - TokenUser = 1, - - /// -     /// The buffer receives a TOKEN_GROUPS structure that contains the group accounts associated with the token. -     /// - TokenGroups, - - /// -     /// The buffer receives a TOKEN_PRIVILEGES structure that contains the privileges of the token. -     /// - TokenPrivileges, - - /// -     /// The buffer receives a TOKEN_OWNER structure that contains the default owner security identifier (SID) for newly created objects. -     /// - TokenOwner, - - /// -     /// The buffer receives a TOKEN_PRIMARY_GROUP structure that contains the default primary group SID for newly created objects. -     /// - TokenPrimaryGroup, - - /// -     /// The buffer receives a TOKEN_DEFAULT_DACL structure that contains the default DACL for newly created objects. -     /// - TokenDefaultDacl, - - /// -     /// The buffer receives a TOKEN_SOURCE structure that contains the source of the token. TOKEN_QUERY_SOURCE access is needed to retrieve this information. -     /// - TokenSource, - - /// -     /// The buffer receives a TOKEN_TYPE value that indicates whether the token is a primary or impersonation token. -     /// - TokenType, - - /// -     /// The buffer receives a SECURITY_IMPERSONATION_LEVEL value that indicates the impersonation level of the token. If the access token is not an impersonation token, the function fails. -     /// - TokenImpersonationLevel, - - /// -     /// The buffer receives a TOKEN_STATISTICS structure that contains various token statistics. -     /// - TokenStatistics, - - /// -     /// The buffer receives a TOKEN_GROUPS structure that contains the list of restricting SIDs in a restricted token. -     /// - TokenRestrictedSids, - - /// -     /// The buffer receives a DWORD value that indicates the Terminal Services session identifier that is associated with the token. -     /// - TokenSessionId, - - /// -     /// The buffer receives a TOKEN_GROUPS_AND_PRIVILEGES structure that contains the user SID, the group accounts, the restricted SIDs, and the authentication ID associated with the token. -     /// - TokenGroupsAndPrivileges, - - /// -     /// Reserved. -     /// - TokenSessionReference, - - /// -     /// The buffer receives a DWORD value that is nonzero if the token includes the SANDBOX_INERT flag. -     /// - TokenSandBoxInert, - - /// -     /// Reserved. -     /// - TokenAuditPolicy, - - /// -     /// The buffer receives a TOKEN_ORIGIN value. -     /// - TokenOrigin, - - /// -     /// The buffer receives a TOKEN_ELEVATION_TYPE value that specifies the elevation level of the token. -     /// - TokenElevationType, - - /// -     /// The buffer receives a TOKEN_LINKED_TOKEN structure that contains a handle to another token that is linked to this token. -     /// - TokenLinkedToken, - - /// -     /// The buffer receives a TOKEN_ELEVATION structure that specifies whether the token is elevated. -     /// - TokenElevation, - - /// -     /// The buffer receives a DWORD value that is nonzero if the token has ever been filtered. -     /// - TokenHasRestrictions, - - /// -     /// The buffer receives a TOKEN_ACCESS_INFORMATION structure that specifies security information contained in the token. -     /// - TokenAccessInformation, - - /// -     /// The buffer receives a DWORD value that is nonzero if virtualization is allowed for the token. -     /// - TokenVirtualizationAllowed, - - /// -     /// The buffer receives a DWORD value that is nonzero if virtualization is enabled for the token. -     /// - TokenVirtualizationEnabled, - - /// -     /// The buffer receives a TOKEN_MANDATORY_LABEL structure that specifies the token's integrity level. -     /// - TokenIntegrityLevel, - - /// -     /// The buffer receives a DWORD value that is nonzero if the token has the UIAccess flag set. -     /// - TokenUIAccess, - - /// -     /// The buffer receives a TOKEN_MANDATORY_POLICY structure that specifies the token's mandatory integrity policy. -     /// - TokenMandatoryPolicy, - - /// -     /// The buffer receives the token's logon security identifier (SID). -     /// - TokenLogonSid, - - /// -     /// The maximum value for this enumeration -     /// - MaxTokenInfoClass - } - public enum LOGON_TYPE - { - LOGON32_LOGON_INTERACTIVE = 2, - LOGON32_LOGON_NETWORK, - LOGON32_LOGON_BATCH, - LOGON32_LOGON_SERVICE, - LOGON32_LOGON_UNLOCK = 7, - LOGON32_LOGON_NETWORK_CLEARTEXT, - LOGON32_LOGON_NEW_CREDENTIALS - } - public enum LOGON_PROVIDER - { - LOGON32_PROVIDER_DEFAULT, - LOGON32_PROVIDER_WINNT35, - LOGON32_PROVIDER_WINNT40, - LOGON32_PROVIDER_WINNT50 - } - [Flags] - public enum CreateProcessFlags - { - CREATE_BREAKAWAY_FROM_JOB = 0x01000000, - CREATE_DEFAULT_ERROR_MODE = 0x04000000, - CREATE_NEW_CONSOLE = 0x00000010, - CREATE_NEW_PROCESS_GROUP = 0x00000200, - CREATE_NO_WINDOW = 0x08000000, - CREATE_PROTECTED_PROCESS = 0x00040000, - CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000, - CREATE_SEPARATE_WOW_VDM = 0x00000800, - CREATE_SHARED_WOW_VDM = 0x00001000, - CREATE_SUSPENDED = 0x00000004, - CREATE_UNICODE_ENVIRONMENT = 0x00000400, - DEBUG_ONLY_THIS_PROCESS = 0x00000002, - DEBUG_PROCESS = 0x00000001, - DETACHED_PROCESS = 0x00000008, - EXTENDED_STARTUPINFO_PRESENT = 0x00080000, - INHERIT_PARENT_AFFINITY = 0x00010000 - } - public enum TOKEN_TYPE : int - { - TokenPrimary = 1, - TokenImpersonation = 2 - } - - public enum SECURITY_IMPERSONATION_LEVEL : int - { - SecurityAnonymous = 0, - SecurityIdentification = 1, - SecurityImpersonation = 2, - SecurityDelegation = 3, - } - - #endregion - - #region Constants - public const int TOKEN_DUPLICATE = 0x0002; - public const uint MAXIMUM_ALLOWED = 0x2000000; - public const int CREATE_NEW_CONSOLE = 0x00000010; - public const int CREATE_NO_WINDOW = 0x08000000; - public const int CREATE_UNICODE_ENVIRONMENT = 0x00000400; - public const int STARTF_USESHOWWINDOW = 0x00000001; - public const int DETACHED_PROCESS = 0x00000008; - public const int TOKEN_ALL_ACCESS = 0x000f01ff; - public const int PROCESS_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF; - public const int STANDARD_RIGHTS_REQUIRED = 0x000F0000; - public const int SYNCHRONIZE = 0x00100000; - - public const int IDLE_PRIORITY_CLASS = 0x40; - public const int NORMAL_PRIORITY_CLASS = 0x20; - public const int HIGH_PRIORITY_CLASS = 0x80; - public const int REALTIME_PRIORITY_CLASS = 0x100; - public const uint SE_PRIVILEGE_ENABLED_BY_DEFAULT = 0x00000001; - public const uint SE_PRIVILEGE_ENABLED = 0x00000002; - public const uint SE_PRIVILEGE_REMOVED = 0x00000004; - public const uint SE_PRIVILEGE_USED_FOR_ACCESS = 0x80000000; - public const int ANYSIZE_ARRAY = 1; - - public const int UOI_FLAGS = 1; - public const int UOI_NAME = 2; - public const int UOI_TYPE = 3; - public const int UOI_USER_SID = 4; - public const int UOI_HEAPSIZE = 5; - public const int UOI_IO = 6; - #endregion - - #region DLL Imports - [DllImport("advapi32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool AdjustTokenPrivileges(IntPtr tokenHandle, - [MarshalAs(UnmanagedType.Bool)] bool disableAllPrivileges, - ref TOKEN_PRIVILEGES newState, - uint bufferLengthInBytes, - ref TOKEN_PRIVILEGES previousState, - out uint returnLengthInBytes); - [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] - public static extern bool CreateProcessAsUser( - IntPtr hToken, - string? lpApplicationName, - string lpCommandLine, - ref SECURITY_ATTRIBUTES lpProcessAttributes, - ref SECURITY_ATTRIBUTES lpThreadAttributes, - bool bInheritHandles, - uint dwCreationFlags, - IntPtr lpEnvironment, - string? lpCurrentDirectory, - ref STARTUPINFO lpStartupInfo, - out PROCESS_INFORMATION lpProcessInformation); - - [DllImport("advapi32.dll", SetLastError = true)] - public static extern bool AllocateLocallyUniqueId(out IntPtr pLuid); - - [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = false)] - public static extern SECUR32.WinErrors LsaNtStatusToWinError(SECUR32.WinStatusCodes status); - - [DllImport("advapi32.dll", SetLastError = true)] - public static extern bool GetTokenInformation( - IntPtr TokenHandle, - SECUR32.TOKEN_INFORMATION_CLASS TokenInformationClass, - IntPtr TokenInformation, - uint TokenInformationLength, - out uint ReturnLength); - - [DllImport("advapi32.dll", SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool LogonUser( - [MarshalAs(UnmanagedType.LPStr)] string pszUserName, - [MarshalAs(UnmanagedType.LPStr)] string pszDomain, - [MarshalAs(UnmanagedType.LPStr)] string pszPassword, - int dwLogonType, - int dwLogonProvider, - out IntPtr phToken); - - [DllImport("advapi32", SetLastError = true), SuppressUnmanagedCodeSecurity] - public static extern bool OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, ref IntPtr TokenHandle); - [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] - public static extern bool DuplicateTokenEx( - IntPtr hExistingToken, - uint dwDesiredAccess, - ref SECURITY_ATTRIBUTES lpTokenAttributes, - SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, - TOKEN_TYPE TokenType, - out IntPtr phNewToken); - - [DllImport("advapi32.dll", SetLastError = false)] - public static extern uint LsaNtStatusToWinError(uint status); - #endregion -} diff --git a/src/Remote/Insight.Remote.Shared/Native/Windows/GDI32.cs b/src/Remote/Insight.Remote.Shared/Native/Windows/GDI32.cs deleted file mode 100644 index 74fb28e..0000000 --- a/src/Remote/Insight.Remote.Shared/Native/Windows/GDI32.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Insight.Remote.Shared.Native.Windows; - -public static class GDI32 -{ - #region Enums - /// - /// Specifies a raster-operation code. These codes define how the color data for the - /// source rectangle is to be combined with the color data for the destination - /// rectangle to achieve the final color. - /// - public enum TernaryRasterOperations : uint - { - /// dest = source - SRCCOPY = 0x00CC0020, - /// dest = source OR dest - SRCPAINT = 0x00EE0086, - /// dest = source AND dest - SRCAND = 0x008800C6, - /// dest = source XOR dest - SRCINVERT = 0x00660046, - /// dest = source AND (NOT dest) - SRCERASE = 0x00440328, - /// dest = (NOT source) - NOTSRCCOPY = 0x00330008, - /// dest = (NOT src) AND (NOT dest) - NOTSRCERASE = 0x001100A6, - /// dest = (source AND pattern) - MERGECOPY = 0x00C000CA, - /// dest = (NOT source) OR dest - MERGEPAINT = 0x00BB0226, - /// dest = pattern - PATCOPY = 0x00F00021, - /// dest = DPSnoo - PATPAINT = 0x00FB0A09, - /// dest = pattern XOR dest - PATINVERT = 0x005A0049, - /// dest = (NOT dest) - DSTINVERT = 0x00550009, - /// dest = BLACK - BLACKNESS = 0x00000042, - /// dest = WHITE - WHITENESS = 0x00FF0062, - /// - /// Capture window as seen on screen. This includes layered windows - /// such as WPF windows with AllowsTransparency="true" - /// - CAPTUREBLT = 0x40000000 - } - #endregion - - #region DLL Imports - - [DllImport("gdi32.dll", EntryPoint = "BitBlt", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool BitBlt([In] IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, [In] IntPtr hdcSrc, int nXSrc, int nYSrc, TernaryRasterOperations dwRop); - - [DllImport("gdi32.dll")] - public static extern IntPtr CreateDC(string lpszDriver, string lpszDevice, string lpszOutput, IntPtr lpInitData); - - [DllImport("GDI32.dll")] - public static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight); [DllImport("GDI32.dll")] - public static extern IntPtr CreateCompatibleDC(IntPtr hdc); - - [DllImport("GDI32.dll")] - public static extern bool DeleteDC(IntPtr hdc); - - [DllImport("GDI32.dll")] - public static extern bool DeleteObject(IntPtr hObject); - - [DllImport("GDI32.dll")] - public static extern IntPtr GetDeviceCaps(IntPtr hdc, int nIndex); - - [DllImport("GDI32.dll")] - public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj); - - #endregion -} diff --git a/src/Remote/Insight.Remote.Shared/Native/Windows/Kernel32.cs b/src/Remote/Insight.Remote.Shared/Native/Windows/Kernel32.cs deleted file mode 100644 index 1787667..0000000 --- a/src/Remote/Insight.Remote.Shared/Native/Windows/Kernel32.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Insight.Remote.Shared.Native.Windows; - -public static class Kernel32 -{ - [DllImport("kernel32.dll", SetLastError = true)] - public static extern bool CloseHandle(IntPtr hSnapshot); - - [DllImport("kernel32.dll", CharSet = CharSet.Auto)] - public static extern IntPtr GetCommandLine(); - - [DllImport("kernel32.dll")] - public static extern IntPtr GetConsoleWindow(); - - [return: MarshalAs(UnmanagedType.Bool)] - [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] - public static extern bool GlobalMemoryStatusEx([In, Out] MEMORYSTATUSEX lpBuffer); - - [DllImport("kernel32.dll")] - public static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId); - - [DllImport("kernel32.dll")] - public static extern bool ProcessIdToSessionId(uint dwProcessId, ref uint pSessionId); - - [DllImport("kernel32.dll")] - public static extern uint WTSGetActiveConsoleSessionId(); - - /// - /// contains information about the current state of both physical and virtual memory, including extended memory - /// - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] - public class MEMORYSTATUSEX - { - /// - /// Size of the structure, in bytes. You must set this member before calling GlobalMemoryStatusEx. - /// - public uint dwLength; - - /// - /// Number between 0 and 100 that specifies the approximate percentage of physical memory that is in use (0 indicates no memory use and 100 indicates full memory use). - /// - public uint dwMemoryLoad; - - /// - /// Total size of physical memory, in bytes. - /// - public ulong ullTotalPhys; - - /// - /// Size of physical memory available, in bytes. - /// - public ulong ullAvailPhys; - - /// - /// Size of the committed memory limit, in bytes. This is physical memory plus the size of the page file, minus a small overhead. - /// - public ulong ullTotalPageFile; - - /// - /// Size of available memory to commit, in bytes. The limit is ullTotalPageFile. - /// - public ulong ullAvailPageFile; - - /// - /// Total size of the user mode portion of the virtual address space of the calling process, in bytes. - /// - public ulong ullTotalVirtual; - - /// - /// Size of unreserved and uncommitted memory in the user mode portion of the virtual address space of the calling process, in bytes. - /// - public ulong ullAvailVirtual; - - /// - /// Size of unreserved and uncommitted memory in the extended portion of the virtual address space of the calling process, in bytes. - /// - public ulong ullAvailExtendedVirtual; - - /// - /// Initializes a new instance of the class. - /// - public MEMORYSTATUSEX() - { - dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX)); - } - } -} diff --git a/src/Remote/Insight.Remote.Shared/Native/Windows/SECUR32.cs b/src/Remote/Insight.Remote.Shared/Native/Windows/SECUR32.cs deleted file mode 100644 index aad373d..0000000 --- a/src/Remote/Insight.Remote.Shared/Native/Windows/SECUR32.cs +++ /dev/null @@ -1,376 +0,0 @@ -using Microsoft.Win32.SafeHandles; -using System.Runtime.InteropServices; -using System.Runtime.Versioning; - -namespace Insight.Remote.Shared.Native.Windows; - -public static class SECUR32 -{ - public enum WinStatusCodes : uint - { - STATUS_SUCCESS = 0 - } - - public enum WinErrors : uint - { - NO_ERROR = 0, - } - public enum WinLogonType - { - LOGON32_LOGON_INTERACTIVE = 2, - LOGON32_LOGON_NETWORK = 3, - LOGON32_LOGON_BATCH = 4, - LOGON32_LOGON_SERVICE = 5, - LOGON32_LOGON_UNLOCK = 7, - LOGON32_LOGON_NETWORK_CLEARTEXT = 8, - LOGON32_LOGON_NEW_CREDENTIALS = 9 - } - - // SECURITY_LOGON_TYPE - public enum SecurityLogonType - { - Interactive = 2, // Interactively logged on (locally or remotely) - Network, // Accessing system via network - Batch, // Started via a batch queue - Service, // Service started by service controller - Proxy, // Proxy logon - Unlock, // Unlock workstation - NetworkCleartext, // Network logon with cleartext credentials - NewCredentials, // Clone caller, new default credentials - RemoteInteractive, // Remote, yet interactive. Terminal server - CachedInteractive, // Try cached credentials without hitting the net. - CachedRemoteInteractive, // Same as RemoteInteractive, this is used internally for auditing purpose - CachedUnlock // Cached Unlock workstation - } - - [StructLayout(LayoutKind.Sequential)] - public struct LSA_UNICODE_STRING - { - public UInt16 Length; - public UInt16 MaximumLength; - public IntPtr Buffer; - } - - [StructLayout(LayoutKind.Sequential)] - public struct TOKEN_SOURCE - { - public TOKEN_SOURCE(string name) - { - SourceName = new byte[8]; - System.Text.Encoding.GetEncoding(1252).GetBytes(name, 0, name.Length, SourceName, 0); - if (!ADVAPI32.AllocateLocallyUniqueId(out SourceIdentifier)) - throw new System.ComponentModel.Win32Exception(); - } - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] SourceName; - public IntPtr SourceIdentifier; - } - [StructLayout(LayoutKind.Sequential)] - public struct KERB_INTERACTIVE_LOGON - { - public KERB_LOGON_SUBMIT_TYPE MessageType; - public string LogonDomainName; - public string UserName; - public string Password; - } - public enum KERB_LOGON_SUBMIT_TYPE - { - KerbInteractiveLogon = 2, - KerbSmartCardLogon = 6, - KerbWorkstationUnlockLogon = 7, - KerbSmartCardUnlockLogon = 8, - KerbProxyLogon = 9, - KerbTicketLogon = 10, - KerbTicketUnlockLogon = 11, - KerbS4ULogon = 12, - KerbCertificateLogon = 13, - KerbCertificateS4ULogon = 14, - KerbCertificateUnlockLogon = 15 - } - public enum TOKEN_INFORMATION_CLASS - { - /// -     /// The buffer receives a TOKEN_USER structure that contains the user account of the token. -     /// - TokenUser = 1, - - /// -     /// The buffer receives a TOKEN_GROUPS structure that contains the group accounts associated with the token. -     /// - TokenGroups, - - /// -     /// The buffer receives a TOKEN_PRIVILEGES structure that contains the privileges of the token. -     /// - TokenPrivileges, - - /// -     /// The buffer receives a TOKEN_OWNER structure that contains the default owner security identifier (SID) for newly created objects. -     /// - TokenOwner, - - /// -     /// The buffer receives a TOKEN_PRIMARY_GROUP structure that contains the default primary group SID for newly created objects. -     /// - TokenPrimaryGroup, - - /// -     /// The buffer receives a TOKEN_DEFAULT_DACL structure that contains the default DACL for newly created objects. -     /// - TokenDefaultDacl, - - /// -     /// The buffer receives a TOKEN_SOURCE structure that contains the source of the token. TOKEN_QUERY_SOURCE access is needed to retrieve this information. -     /// - TokenSource, - - /// -     /// The buffer receives a TOKEN_TYPE value that indicates whether the token is a primary or impersonation token. -     /// - TokenType, - - /// -     /// The buffer receives a SECURITY_IMPERSONATION_LEVEL value that indicates the impersonation level of the token. If the access token is not an impersonation token, the function fails. -     /// - TokenImpersonationLevel, - - /// -     /// The buffer receives a TOKEN_STATISTICS structure that contains various token statistics. -     /// - TokenStatistics, - - /// -     /// The buffer receives a TOKEN_GROUPS structure that contains the list of restricting SIDs in a restricted token. -     /// - TokenRestrictedSids, - - /// -     /// The buffer receives a DWORD value that indicates the Terminal Services session identifier that is associated with the token. -     /// - TokenSessionId, - - /// -     /// The buffer receives a TOKEN_GROUPS_AND_PRIVILEGES structure that contains the user SID, the group accounts, the restricted SIDs, and the authentication ID associated with the token. -     /// - TokenGroupsAndPrivileges, - - /// -     /// Reserved. -     /// - TokenSessionReference, - - /// -     /// The buffer receives a DWORD value that is nonzero if the token includes the SANDBOX_INERT flag. -     /// - TokenSandBoxInert, - - /// -     /// Reserved. -     /// - TokenAuditPolicy, - - /// -     /// The buffer receives a TOKEN_ORIGIN value. -     /// - TokenOrigin, - - /// -     /// The buffer receives a TOKEN_ELEVATION_TYPE value that specifies the elevation level of the token. -     /// - TokenElevationType, - - /// -     /// The buffer receives a TOKEN_LINKED_TOKEN structure that contains a handle to another token that is linked to this token. -     /// - TokenLinkedToken, - - /// -     /// The buffer receives a TOKEN_ELEVATION structure that specifies whether the token is elevated. -     /// - TokenElevation, - - /// -     /// The buffer receives a DWORD value that is nonzero if the token has ever been filtered. -     /// - TokenHasRestrictions, - - /// -     /// The buffer receives a TOKEN_ACCESS_INFORMATION structure that specifies security information contained in the token. -     /// - TokenAccessInformation, - - /// -     /// The buffer receives a DWORD value that is nonzero if virtualization is allowed for the token. -     /// - TokenVirtualizationAllowed, - - /// -     /// The buffer receives a DWORD value that is nonzero if virtualization is enabled for the token. -     /// - TokenVirtualizationEnabled, - - /// -     /// The buffer receives a TOKEN_MANDATORY_LABEL structure that specifies the token's integrity level. -     /// - TokenIntegrityLevel, - - /// -     /// The buffer receives a DWORD value that is nonzero if the token has the UIAccess flag set. -     /// - TokenUIAccess, - - /// -     /// The buffer receives a TOKEN_MANDATORY_POLICY structure that specifies the token's mandatory integrity policy. -     /// - TokenMandatoryPolicy, - - /// -     /// The buffer receives the token's logon security identifier (SID). -     /// - TokenLogonSid, - - /// -     /// The maximum value for this enumeration -     /// - MaxTokenInfoClass - } - [StructLayout(LayoutKind.Sequential)] - public readonly struct QUOTA_LIMITS - { - readonly UInt32 PagedPoolLimit; - readonly UInt32 NonPagedPoolLimit; - readonly UInt32 MinimumWorkingSetSize; - readonly UInt32 MaximumWorkingSetSize; - readonly UInt32 PagefileLimit; - readonly Int64 TimeLimit; - } - - [StructLayout(LayoutKind.Sequential)] - public struct LSA_STRING - { - public UInt16 Length; - public UInt16 MaximumLength; - public /*PCHAR*/ IntPtr Buffer; - } - - - [DllImport("secur32.dll", SetLastError = true)] - public static extern WinStatusCodes LsaLogonUser( - [In] IntPtr LsaHandle, - [In] ref LSA_STRING OriginName, - [In] SecurityLogonType LogonType, - [In] UInt32 AuthenticationPackage, - [In] IntPtr AuthenticationInformation, - [In] UInt32 AuthenticationInformationLength, - [In] /*PTOKEN_GROUPS*/ IntPtr LocalGroups, - [In] ref TOKEN_SOURCE SourceContext, - [Out] /*PVOID*/ out IntPtr ProfileBuffer, - [Out] out UInt32 ProfileBufferLength, - [Out] out Int64 LogonId, - [Out] out IntPtr Token, - [Out] out QUOTA_LIMITS Quotas, - [Out] out WinStatusCodes SubStatus - ); - - [DllImport("secur32.dll", SetLastError = true)] - public static extern WinStatusCodes LsaRegisterLogonProcess( - IntPtr LogonProcessName, - out IntPtr LsaHandle, - out ulong SecurityMode - ); - - [DllImport("secur32.dll", SetLastError = false)] - public static extern WinStatusCodes LsaLookupAuthenticationPackage([In] IntPtr LsaHandle, [In] ref LSA_STRING PackageName, [Out] out UInt32 AuthenticationPackage); - - [DllImport("secur32.dll", CharSet = CharSet.Auto, SetLastError = true)] - [ResourceExposure(ResourceScope.None)] - internal static extern int LsaConnectUntrusted( - [In, Out] ref SafeLsaLogonProcessHandle LsaHandle); - - [DllImport("secur32.dll", SetLastError = false)] - public static extern WinStatusCodes LsaConnectUntrusted([Out] out IntPtr LsaHandle); - - [System.Security.SecurityCritical] // auto-generated - internal sealed class SafeLsaLogonProcessHandle : SafeHandleZeroOrMinusOneIsInvalid - { - private SafeLsaLogonProcessHandle() : base(true) { } - - // 0 is an Invalid Handle - internal SafeLsaLogonProcessHandle(IntPtr handle) : base(true) - { - SetHandle(handle); - } - - internal static SafeLsaLogonProcessHandle InvalidHandle - { - get { return new SafeLsaLogonProcessHandle(IntPtr.Zero); } - } - - [System.Security.SecurityCritical] - protected override bool ReleaseHandle() - { - // LsaDeregisterLogonProcess returns an NTSTATUS - return LsaDeregisterLogonProcess(handle) >= 0; - } - } - - [DllImport("secur32.dll", SetLastError = true)] - [ResourceExposure(ResourceScope.None)] - internal static extern int LsaDeregisterLogonProcess(IntPtr handle); - - - public static void CreateNewSession() - { - var kli = new SECUR32.KERB_INTERACTIVE_LOGON() - { - MessageType = SECUR32.KERB_LOGON_SUBMIT_TYPE.KerbInteractiveLogon, - UserName = "", - Password = "" - }; - IntPtr kerbLogInfo; - SECUR32.LSA_STRING logonProc = new() - { - Buffer = Marshal.StringToHGlobalAuto("InstaLogon"), - Length = (ushort)Marshal.SizeOf(Marshal.StringToHGlobalAuto("InstaLogon")), - MaximumLength = (ushort)Marshal.SizeOf(Marshal.StringToHGlobalAuto("InstaLogon")) - }; - SECUR32.LSA_STRING originName = new() - { - Buffer = Marshal.StringToHGlobalAuto("InstaLogon"), - Length = (ushort)Marshal.SizeOf(Marshal.StringToHGlobalAuto("InstaLogon")), - MaximumLength = (ushort)Marshal.SizeOf(Marshal.StringToHGlobalAuto("InstaLogon")) - }; - SECUR32.LSA_STRING authPackage = new() - { - Buffer = Marshal.StringToHGlobalAuto("MICROSOFT_KERBEROS_NAME_A"), - Length = (ushort)Marshal.SizeOf(Marshal.StringToHGlobalAuto("MICROSOFT_KERBEROS_NAME_A")), - MaximumLength = (ushort)Marshal.SizeOf(Marshal.StringToHGlobalAuto("MICROSOFT_KERBEROS_NAME_A")) - }; - IntPtr hLogonProc = Marshal.AllocHGlobal(Marshal.SizeOf(logonProc)); - Marshal.StructureToPtr(logonProc, hLogonProc, false); - ADVAPI32.AllocateLocallyUniqueId(out IntPtr pluid); - LsaConnectUntrusted(out IntPtr lsaHan); - //SECUR32.LsaRegisterLogonProcess(hLogonProc, out lsaHan, out secMode); - SECUR32.LsaLookupAuthenticationPackage(lsaHan, ref authPackage, out uint authPackID); - - kerbLogInfo = Marshal.AllocHGlobal(Marshal.SizeOf(kli)); - Marshal.StructureToPtr(kli, kerbLogInfo, false); - - var ts = new SECUR32.TOKEN_SOURCE("Insta"); - SECUR32.LsaLogonUser( - lsaHan, - ref originName, - SECUR32.SecurityLogonType.Interactive, - authPackID, - kerbLogInfo, - (uint)Marshal.SizeOf(kerbLogInfo), - IntPtr.Zero, - ref ts, - out IntPtr profBuf, - out uint profBufLen, - out long logonID, - out IntPtr logonToken, - out QUOTA_LIMITS quotas, - out WinStatusCodes subStatus); - } -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/Native/Windows/Shlwapi.cs b/src/Remote/Insight.Remote.Shared/Native/Windows/Shlwapi.cs deleted file mode 100644 index c7fe64b..0000000 --- a/src/Remote/Insight.Remote.Shared/Native/Windows/Shlwapi.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Insight.Remote.Shared.Native.Windows; - -// https://docs.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-isos -public class Shlwapi -{ - [DllImport("shlwapi.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsOS(OsType osType); -} - -public enum OsType -{ - OS_WINDOWS = 0, - OS_NT = 1, - OS_WIN95ORGREATER = 2, - OS_NT4ORGREATER = 3, - OS_WIN98ORGREATER = 5, - OS_WIN98_GOLD = 6, - OS_WIN2000ORGREATER = 7, - OS_WIN2000PRO = 8, - OS_WIN2000SERVER = 9, - OS_WIN2000ADVSERVER = 10, - OS_WIN2000DATACENTER = 11, - OS_WIN2000TERMINAL = 12, - OS_EMBEDDED = 13, - OS_TERMINALCLIENT = 14, - OS_TERMINALREMOTEADMIN = 15, - OS_WIN95_GOLD = 16, - OS_MEORGREATER = 17, - OS_XPORGREATER = 18, - OS_HOME = 19, - OS_PROFESSIONAL = 20, - OS_DATACENTER = 21, - OS_ADVSERVER = 22, - OS_SERVER = 23, - OS_TERMINALSERVER = 24, - OS_PERSONALTERMINALSERVER = 25, - OS_FASTUSERSWITCHING = 26, - OS_WELCOMELOGONUI = 27, - OS_DOMAINMEMBER = 28, - OS_ANYSERVER = 29, - OS_WOW6432 = 30, - OS_WEBSERVER = 31, - OS_SMALLBUSINESSSERVER = 32, - OS_TABLETPC = 33, - OS_SERVERADMINUI = 34, - OS_MEDIACENTER = 35, - OS_APPLIANCE = 36, -} diff --git a/src/Remote/Insight.Remote.Shared/Native/Windows/User32.cs b/src/Remote/Insight.Remote.Shared/Native/Windows/User32.cs deleted file mode 100644 index 46ad8b5..0000000 --- a/src/Remote/Insight.Remote.Shared/Native/Windows/User32.cs +++ /dev/null @@ -1,1336 +0,0 @@ -using Microsoft.Win32.SafeHandles; -using System.Runtime.InteropServices; - -namespace Insight.Remote.Shared.Native.Windows; - -public static class User32 -{ - #region Constants - public const int CURSOR_SHOWING = 0x00000001; - public const uint MOUSEEVENTF_ABSOLUTE = 0x8000; - public const int MOUSEEVENTF_LEFTDOWN = 0x02; - public const int MOUSEEVENTF_LEFTUP = 0x04; - public const int MOUSEEVENTF_RIGHTDOWN = 0x08; - public const int MOUSEEVENTF_RIGHTUP = 0x10; - public const int MOUSEEVENTF_MOVE = 0x0001; - public const uint KEYEVENTF_EXTENDEDKEY = 0x0001; - public const uint KEYEVENTF_KEYUP = 0x0002; - - public const int SPIF_SENDWININICHANGE = 0x02; - public const int SPI_SETDESKWALLPAPER = 20; - public const int SPIF_UPDATEINIFILE = 1; - public const int SPIF_SENDCHANGE = 2; - - public static readonly int SPI_GETDESKWALLPAPER = 0x73; - public static readonly int MAX_PATH = 260; - #endregion - - #region Enums - [Flags] - public enum MouseEventFlags : uint - { - LEFTDOWN = 0x00000002, - LEFTUP = 0x00000004, - MIDDLEDOWN = 0x00000020, - MIDDLEUP = 0x00000040, - MOVE = 0x00000001, - ABSOLUTE = 0x00008000, - RIGHTDOWN = 0x00000008, - RIGHTUP = 0x00000010, - WHEEL = 0x00000800, - XDOWN = 0x00000080, - XUP = 0x00000100 - } - [Flags] - public enum MOUSEEVENTF : uint - { - ABSOLUTE = 0x8000, - HWHEEL = 0x01000, - MOVE = 0x0001, - MOVE_NOCOALESCE = 0x2000, - LEFTDOWN = 0x0002, - LEFTUP = 0x0004, - RIGHTDOWN = 0x0008, - RIGHTUP = 0x0010, - MIDDLEDOWN = 0x0020, - MIDDLEUP = 0x0040, - VIRTUALDESK = 0x4000, - WHEEL = 0x0800, - XDOWN = 0x0080, - XUP = 0x0100 - } - public enum MonitorState - { - MonitorStateOn = -1, - MonitorStateOff = 2, - MonitorStateStandBy = 1 - } - [Flags] - public enum KEYEVENTF : uint - { - EXTENDEDKEY = 0x0001, - KEYUP = 0x0002, - SCANCODE = 0x0008, - UNICODE = 0x0004 - } - - public enum VirtualKey : short - { - /// -         ///Left mouse button -         /// - LBUTTON = 0x01, - /// -         ///Right mouse button -         /// - RBUTTON = 0x02, - /// -         ///Control-break processing -         /// - CANCEL = 0x03, - /// -         ///Middle mouse button (three-button mouse) -         /// - MBUTTON = 0x04, - /// -         ///Windows 2000/XP: X1 mouse button -         /// - XBUTTON1 = 0x05, - /// -         ///Windows 2000/XP: X2 mouse button -         /// - XBUTTON2 = 0x06, - /// -         ///BACKSPACE key -         /// - BACK = 0x08, - /// -         ///TAB key -         /// - TAB = 0x09, - /// -         ///CLEAR key -         /// - CLEAR = 0x0C, - /// -         ///ENTER key -         /// - RETURN = 0x0D, - /// -         ///SHIFT key -         /// - SHIFT = 0x10, - /// -         ///CTRL key -         /// - CONTROL = 0x11, - /// -         ///ALT key -         /// - MENU = 0x12, - /// -         ///PAUSE key -         /// - PAUSE = 0x13, - /// -         ///CAPS LOCK key -         /// - CAPITAL = 0x14, - /// -         ///Input Method Editor (IME) Kana mode -         /// - KANA = 0x15, - /// -         ///IME Hangul mode -         /// - HANGUL = 0x15, - /// -         ///IME Junja mode -         /// - JUNJA = 0x17, - /// -         ///IME final mode -         /// - FINAL = 0x18, - /// -         ///IME Hanja mode -         /// - HANJA = 0x19, - /// -         ///IME Kanji mode -         /// - KANJI = 0x19, - /// -         ///ESC key -         /// - ESCAPE = 0x1B, - /// -         ///IME convert -         /// - CONVERT = 0x1C, - /// -         ///IME nonconvert -         /// - NONCONVERT = 0x1D, - /// -         ///IME accept -         /// - ACCEPT = 0x1E, - /// -         ///IME mode change request -         /// - MODECHANGE = 0x1F, - /// -         ///SPACEBAR -         /// - SPACE = 0x20, - /// -         ///PAGE UP key -         /// - PRIOR = 0x21, - /// -         ///PAGE DOWN key -         /// - NEXT = 0x22, - /// -         ///END key -         /// - END = 0x23, - /// -         ///HOME key -         /// - HOME = 0x24, - /// -         ///LEFT ARROW key -         /// - LEFT = 0x25, - /// -         ///UP ARROW key -         /// - UP = 0x26, - /// -         ///RIGHT ARROW key -         /// - RIGHT = 0x27, - /// -         ///DOWN ARROW key -         /// - DOWN = 0x28, - /// -         ///SELECT key -         /// - SELECT = 0x29, - /// -         ///PRINT key -         /// - PRINT = 0x2A, - /// -         ///EXECUTE key -         /// - EXECUTE = 0x2B, - /// -         ///PRINT SCREEN key -         /// - SNAPSHOT = 0x2C, - /// -         ///INS key -         /// - INSERT = 0x2D, - /// -         ///DEL key -         /// - DELETE = 0x2E, - /// -         ///HELP key -         /// - HELP = 0x2F, - /// -         ///0 key -         /// - KEY_0 = 0x30, - /// -         ///1 key -         /// - KEY_1 = 0x31, - /// -         ///2 key -         /// - KEY_2 = 0x32, - /// -         ///3 key -         /// - KEY_3 = 0x33, - /// -         ///4 key -         /// - KEY_4 = 0x34, - /// -         ///5 key -         /// - KEY_5 = 0x35, - /// -         ///6 key -         /// - KEY_6 = 0x36, - /// -         ///7 key -         /// - KEY_7 = 0x37, - /// -         ///8 key -         /// - KEY_8 = 0x38, - /// -         ///9 key -         /// - KEY_9 = 0x39, - /// -         ///A key -         /// - KEY_A = 0x41, - /// -         ///B key -         /// - KEY_B = 0x42, - /// -         ///C key -         /// - KEY_C = 0x43, - /// -         ///D key -         /// - KEY_D = 0x44, - /// -         ///E key -         /// - KEY_E = 0x45, - /// -         ///F key -         /// - KEY_F = 0x46, - /// -         ///G key -         /// - KEY_G = 0x47, - /// -         ///H key -         /// - KEY_H = 0x48, - /// -         ///I key -         /// - KEY_I = 0x49, - /// -         ///J key -         /// - KEY_J = 0x4A, - /// -         ///K key -         /// - KEY_K = 0x4B, - /// -         ///L key -         /// - KEY_L = 0x4C, - /// -         ///M key -         /// - KEY_M = 0x4D, - /// -         ///N key -         /// - KEY_N = 0x4E, - /// -         ///O key -         /// - KEY_O = 0x4F, - /// -         ///P key -         /// - KEY_P = 0x50, - /// -         ///Q key -         /// - KEY_Q = 0x51, - /// -         ///R key -         /// - KEY_R = 0x52, - /// -         ///S key -         /// - KEY_S = 0x53, - /// -         ///T key -         /// - KEY_T = 0x54, - /// -         ///U key -         /// - KEY_U = 0x55, - /// -         ///V key -         /// - KEY_V = 0x56, - /// -         ///W key -         /// - KEY_W = 0x57, - /// -         ///X key -         /// - KEY_X = 0x58, - /// -         ///Y key -         /// - KEY_Y = 0x59, - /// -         ///Z key -         /// - KEY_Z = 0x5A, - /// -         ///Left Windows key (Microsoft Natural keyboard) -         /// - LWIN = 0x5B, - /// -         ///Right Windows key (Natural keyboard) -         /// - RWIN = 0x5C, - /// -         ///Applications key (Natural keyboard) -         /// - APPS = 0x5D, - /// -         ///Computer Sleep key -         /// - SLEEP = 0x5F, - /// -         ///Numeric keypad 0 key -         /// - NUMPAD0 = 0x60, - /// -         ///Numeric keypad 1 key -         /// - NUMPAD1 = 0x61, - /// -         ///Numeric keypad 2 key -         /// - NUMPAD2 = 0x62, - /// -         ///Numeric keypad 3 key -         /// - NUMPAD3 = 0x63, - /// -         ///Numeric keypad 4 key -         /// - NUMPAD4 = 0x64, - /// -         ///Numeric keypad 5 key -         /// - NUMPAD5 = 0x65, - /// -         ///Numeric keypad 6 key -         /// - NUMPAD6 = 0x66, - /// -         ///Numeric keypad 7 key -         /// - NUMPAD7 = 0x67, - /// -         ///Numeric keypad 8 key -         /// - NUMPAD8 = 0x68, - /// -         ///Numeric keypad 9 key -         /// - NUMPAD9 = 0x69, - /// -         ///Multiply key -         /// - MULTIPLY = 0x6A, - /// -         ///Add key -         /// - ADD = 0x6B, - /// -         ///Separator key -         /// - SEPARATOR = 0x6C, - /// -         ///Subtract key -         /// - SUBTRACT = 0x6D, - /// -         ///Decimal key -         /// - DECIMAL = 0x6E, - /// -         ///Divide key -         /// - DIVIDE = 0x6F, - /// -         ///F1 key -         /// - F1 = 0x70, - /// -         ///F2 key -         /// - F2 = 0x71, - /// -         ///F3 key -         /// - F3 = 0x72, - /// -         ///F4 key -         /// - F4 = 0x73, - /// -         ///F5 key -         /// - F5 = 0x74, - /// -         ///F6 key -         /// - F6 = 0x75, - /// -         ///F7 key -         /// - F7 = 0x76, - /// -         ///F8 key -         /// - F8 = 0x77, - /// -         ///F9 key -         /// - F9 = 0x78, - /// -         ///F10 key -         /// - F10 = 0x79, - /// -         ///F11 key -         /// - F11 = 0x7A, - /// -         ///F12 key -         /// - F12 = 0x7B, - /// -         ///F13 key -         /// - F13 = 0x7C, - /// -         ///F14 key -         /// - F14 = 0x7D, - /// -         ///F15 key -         /// - F15 = 0x7E, - /// -         ///F16 key -         /// - F16 = 0x7F, - /// -         ///F17 key   -         /// - F17 = 0x80, - /// -         ///F18 key   -         /// - F18 = 0x81, - /// -         ///F19 key   -         /// - F19 = 0x82, - /// -         ///F20 key   -         /// - F20 = 0x83, - /// -         ///F21 key   -         /// - F21 = 0x84, - /// -         ///F22 key, (PPC only) Key used to lock device. -         /// - F22 = 0x85, - /// -         ///F23 key   -         /// - F23 = 0x86, - /// -         ///F24 key   -         /// - F24 = 0x87, - /// -         ///NUM LOCK key -         /// - NUMLOCK = 0x90, - /// -         ///SCROLL LOCK key -         /// - SCROLL = 0x91, - /// -         ///Left SHIFT key -         /// - LSHIFT = 0xA0, - /// -         ///Right SHIFT key -         /// - RSHIFT = 0xA1, - /// -         ///Left CONTROL key -         /// - LCONTROL = 0xA2, - /// -         ///Right CONTROL key -         /// - RCONTROL = 0xA3, - /// -         ///Left MENU key -         /// - LMENU = 0xA4, - /// -         ///Right MENU key -         /// - RMENU = 0xA5, - /// -         ///Windows 2000/XP: Browser Back key -         /// - BROWSER_BACK = 0xA6, - /// -         ///Windows 2000/XP: Browser Forward key -         /// - BROWSER_FORWARD = 0xA7, - /// -         ///Windows 2000/XP: Browser Refresh key -         /// - BROWSER_REFRESH = 0xA8, - /// -         ///Windows 2000/XP: Browser Stop key -         /// - BROWSER_STOP = 0xA9, - /// -         ///Windows 2000/XP: Browser Search key -         /// - BROWSER_SEARCH = 0xAA, - /// -         ///Windows 2000/XP: Browser Favorites key -         /// - BROWSER_FAVORITES = 0xAB, - /// -         ///Windows 2000/XP: Browser Start and Home key -         /// - BROWSER_HOME = 0xAC, - /// -         ///Windows 2000/XP: Volume Mute key -         /// - VOLUME_MUTE = 0xAD, - /// -         ///Windows 2000/XP: Volume Down key -         /// - VOLUME_DOWN = 0xAE, - /// -         ///Windows 2000/XP: Volume Up key -         /// - VOLUME_UP = 0xAF, - /// -         ///Windows 2000/XP: Next Track key -         /// - MEDIA_NEXT_TRACK = 0xB0, - /// -         ///Windows 2000/XP: Previous Track key -         /// - MEDIA_PREV_TRACK = 0xB1, - /// -         ///Windows 2000/XP: Stop Media key -         /// - MEDIA_STOP = 0xB2, - /// -         ///Windows 2000/XP: Play/Pause Media key -         /// - MEDIA_PLAY_PAUSE = 0xB3, - /// -         ///Windows 2000/XP: Start Mail key -         /// - LAUNCH_MAIL = 0xB4, - /// -         ///Windows 2000/XP: Select Media key -         /// - LAUNCH_MEDIA_SELECT = 0xB5, - /// -         ///Windows 2000/XP: Start Application 1 key -         /// - LAUNCH_APP1 = 0xB6, - /// -         ///Windows 2000/XP: Start Application 2 key -         /// - LAUNCH_APP2 = 0xB7, - /// -         ///Used for miscellaneous characters; it can vary by keyboard. -         /// - OEM_1 = 0xBA, - /// -         ///Windows 2000/XP: For any country/region, the '+' key -         /// - OEM_PLUS = 0xBB, - /// -         ///Windows 2000/XP: For any country/region, the ',' key -         /// - OEM_COMMA = 0xBC, - /// -         ///Windows 2000/XP: For any country/region, the '-' key -         /// - OEM_MINUS = 0xBD, - /// -         ///Windows 2000/XP: For any country/region, the '.' key -         /// - OEM_PERIOD = 0xBE, - /// -         ///Used for miscellaneous characters; it can vary by keyboard. -         /// - OEM_2 = 0xBF, - /// -         ///Used for miscellaneous characters; it can vary by keyboard. -         /// - OEM_3 = 0xC0, - /// -         ///Used for miscellaneous characters; it can vary by keyboard. -         /// - OEM_4 = 0xDB, - /// -         ///Used for miscellaneous characters; it can vary by keyboard. -         /// - OEM_5 = 0xDC, - /// -         ///Used for miscellaneous characters; it can vary by keyboard. -         /// - OEM_6 = 0xDD, - /// -         ///Used for miscellaneous characters; it can vary by keyboard. -         /// - OEM_7 = 0xDE, - /// -         ///Used for miscellaneous characters; it can vary by keyboard. -         /// - OEM_8 = 0xDF, - /// -         ///Windows 2000/XP: Either the angle bracket key or the backslash key on the RT 102-key keyboard -         /// - OEM_102 = 0xE2, - /// -         ///Windows 95/98/Me, Windows NT 4.0, Windows 2000/XP: IME PROCESS key -         /// - PROCESSKEY = 0xE5, - /// -         ///Windows 2000/XP: Used to pass Unicode characters as if they were keystrokes. -         ///The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, -         ///see Remark in KEYBDINPUT, SendInput, WM_KEYDOWN, and WM_KEYUP -         /// - PACKET = 0xE7, - /// -         ///Attn key -         /// - ATTN = 0xF6, - /// -         ///CrSel key -         /// - CRSEL = 0xF7, - /// -         ///ExSel key -         /// - EXSEL = 0xF8, - /// -         ///Erase EOF key -         /// - EREOF = 0xF9, - /// -         ///Play key -         /// - PLAY = 0xFA, - /// -         ///Zoom key -         /// - ZOOM = 0xFB, - /// -         ///Reserved -         /// - NONAME = 0xFC, - /// -         ///PA1 key -         /// - PA1 = 0xFD, - /// -         ///Clear key -         /// - OEM_CLEAR = 0xFE - } - public enum ScanCodeShort : short - { - LBUTTON = 0, - RBUTTON = 0, - CANCEL = 70, - MBUTTON = 0, - XBUTTON1 = 0, - XBUTTON2 = 0, - BACK = 14, - TAB = 15, - CLEAR = 76, - RETURN = 28, - SHIFT = 42, - CONTROL = 29, - MENU = 56, - PAUSE = 0, - CAPITAL = 58, - KANA = 0, - HANGUL = 0, - JUNJA = 0, - FINAL = 0, - HANJA = 0, - KANJI = 0, - ESCAPE = 1, - CONVERT = 0, - NONCONVERT = 0, - ACCEPT = 0, - MODECHANGE = 0, - SPACE = 57, - PRIOR = 73, - NEXT = 81, - END = 79, - HOME = 71, - LEFT = 75, - UP = 72, - RIGHT = 77, - DOWN = 80, - SELECT = 0, - PRINT = 0, - EXECUTE = 0, - SNAPSHOT = 84, - INSERT = 82, - DELETE = 83, - HELP = 99, - KEY_0 = 11, - KEY_1 = 2, - KEY_2 = 3, - KEY_3 = 4, - KEY_4 = 5, - KEY_5 = 6, - KEY_6 = 7, - KEY_7 = 8, - KEY_8 = 9, - KEY_9 = 10, - KEY_A = 30, - KEY_B = 48, - KEY_C = 46, - KEY_D = 32, - KEY_E = 18, - KEY_F = 33, - KEY_G = 34, - KEY_H = 35, - KEY_I = 23, - KEY_J = 36, - KEY_K = 37, - KEY_L = 38, - KEY_M = 50, - KEY_N = 49, - KEY_O = 24, - KEY_P = 25, - KEY_Q = 16, - KEY_R = 19, - KEY_S = 31, - KEY_T = 20, - KEY_U = 22, - KEY_V = 47, - KEY_W = 17, - KEY_X = 45, - KEY_Y = 21, - KEY_Z = 44, - LWIN = 91, - RWIN = 92, - APPS = 93, - SLEEP = 95, - NUMPAD0 = 82, - NUMPAD1 = 79, - NUMPAD2 = 80, - NUMPAD3 = 81, - NUMPAD4 = 75, - NUMPAD5 = 76, - NUMPAD6 = 77, - NUMPAD7 = 71, - NUMPAD8 = 72, - NUMPAD9 = 73, - MULTIPLY = 55, - ADD = 78, - SEPARATOR = 0, - SUBTRACT = 74, - DECIMAL = 83, - DIVIDE = 53, - F1 = 59, - F2 = 60, - F3 = 61, - F4 = 62, - F5 = 63, - F6 = 64, - F7 = 65, - F8 = 66, - F9 = 67, - F10 = 68, - F11 = 87, - F12 = 88, - F13 = 100, - F14 = 101, - F15 = 102, - F16 = 103, - F17 = 104, - F18 = 105, - F19 = 106, - F20 = 107, - F21 = 108, - F22 = 109, - F23 = 110, - F24 = 118, - NUMLOCK = 69, - SCROLL = 70, - LSHIFT = 42, - RSHIFT = 54, - LCONTROL = 29, - RCONTROL = 29, - LMENU = 56, - RMENU = 56, - BROWSER_BACK = 106, - BROWSER_FORWARD = 105, - BROWSER_REFRESH = 103, - BROWSER_STOP = 104, - BROWSER_SEARCH = 101, - BROWSER_FAVORITES = 102, - BROWSER_HOME = 50, - VOLUME_MUTE = 32, - VOLUME_DOWN = 46, - VOLUME_UP = 48, - MEDIA_NEXT_TRACK = 25, - MEDIA_PREV_TRACK = 16, - MEDIA_STOP = 36, - MEDIA_PLAY_PAUSE = 34, - LAUNCH_MAIL = 108, - LAUNCH_MEDIA_SELECT = 109, - LAUNCH_APP1 = 107, - LAUNCH_APP2 = 33, - OEM_1 = 39, - OEM_PLUS = 13, - OEM_COMMA = 51, - OEM_MINUS = 12, - OEM_PERIOD = 52, - OEM_2 = 53, - OEM_3 = 41, - OEM_4 = 26, - OEM_5 = 43, - OEM_6 = 27, - OEM_7 = 40, - OEM_8 = 0, - OEM_102 = 86, - PROCESSKEY = 0, - PACKET = 0, - ATTN = 0, - CRSEL = 0, - EXSEL = 0, - EREOF = 93, - PLAY = 0, - ZOOM = 98, - NONAME = 0, - PA1 = 0, - OEM_CLEAR = 0, - } - [Flags] - public enum ACCESS_MASK : uint - { - DELETE = 0x00010000, - READ_CONTROL = 0x00020000, - WRITE_DAC = 0x00040000, - WRITE_OWNER = 0x00080000, - SYNCHRONIZE = 0x00100000, - - STANDARD_RIGHTS_REQUIRED = 0x000F0000, - - STANDARD_RIGHTS_READ = 0x00020000, - STANDARD_RIGHTS_WRITE = 0x00020000, - STANDARD_RIGHTS_EXECUTE = 0x00020000, - - STANDARD_RIGHTS_ALL = 0x001F0000, - - SPECIFIC_RIGHTS_ALL = 0x0000FFFF, - - ACCESS_SYSTEM_SECURITY = 0x01000000, - - MAXIMUM_ALLOWED = 0x02000000, - - GENERIC_READ = 0x80000000, - GENERIC_WRITE = 0x40000000, - GENERIC_EXECUTE = 0x20000000, - GENERIC_ALL = 0x10000000, - - DESKTOP_READOBJECTS = 0x00000001, - DESKTOP_CREATEWINDOW = 0x00000002, - DESKTOP_CREATEMENU = 0x00000004, - DESKTOP_HOOKCONTROL = 0x00000008, - DESKTOP_JOURNALRECORD = 0x00000010, - DESKTOP_JOURNALPLAYBACK = 0x00000020, - DESKTOP_ENUMERATE = 0x00000040, - DESKTOP_WRITEOBJECTS = 0x00000080, - DESKTOP_SWITCHDESKTOP = 0x00000100, - - WINSTA_ENUMDESKTOPS = 0x00000001, - WINSTA_READATTRIBUTES = 0x00000002, - WINSTA_ACCESSCLIPBOARD = 0x00000004, - WINSTA_CREATEDESKTOP = 0x00000008, - WINSTA_WRITEATTRIBUTES = 0x00000010, - WINSTA_ACCESSGLOBALATOMS = 0x00000020, - WINSTA_EXITWINDOWS = 0x00000040, - WINSTA_ENUMERATE = 0x00000100, - WINSTA_READSCREEN = 0x00000200, - - WINSTA_ALL_ACCESS = 0x0000037F - } - public enum InputType : uint - { - MOUSE = 0, - KEYBOARD = 1, - HARDWARE = 2 - } - public enum MessageBoxType : long - { - MB_ABORTRETRYIGNORE = 0x00000002L, - MB_CANCELTRYCONTINUE = 0x00000006L, - MB_HELP = 0x00004000L, - MB_OK = 0x00000000L, - MB_OKCANCEL = 0x00000001L, - MB_RETRYCANCEL = 0x00000005L, - MB_YESNO = 0x00000004L, - MB_YESNOCANCEL = 0x00000003L, - MB_ICONEXCLAMATION = 0x00000030L, - MB_ICONWARNING = 0x00000030L, - MB_ICONINFORMATION = 0x00000040L, - MB_ICONASTERISK = 0x00000040L, - MB_ICONQUESTION = 0x00000020L, - MB_ICONSTOP = 0x00000010L, - MB_ICONERROR = 0x00000010L, - MB_ICONHAND = 0x00000010L, - MB_DEFBUTTON1 = 0x00000000L, - MB_DEFBUTTON2 = 0x00000100L, - MB_DEFBUTTON3 = 0x00000200L, - MB_DEFBUTTON4 = 0x00000300L, - MB_APPLMODAL = 0x00000000L, - MB_SYSTEMMODAL = 0x00001000L, - MB_TASKMODAL = 0x00002000L, - MB_DEFAULT_DESKTOP_ONLY = 0x00020000L, - MB_RIGHT = 0x00080000L, - MB_RTLREADING = 0x00100000L, - MB_SETFOREGROUND = 0x00010000L, - MB_TOPMOST = 0x00040000L, - MB_SERVICE_NOTIFICATION = 0x00200000L - } - - public enum MessageBoxResult : int - { - IDABORT = 3, - IDCANCEL = 2, - IDCONTINUE = 11, - IDIGNORE = 5, - IDNO = 7, - IDOK = 1, - IDRETRY = 4, - IDTRYAGAIN = 10, - IDYES = 6, - } - public enum SW - { - SW_HIDE = 0, - SW_SHOWNORMAL = 1, - SW_NORMAL = 1, - SW_SHOWMINIMIZED = 2, - SW_SHOWMAXIMIZED = 3, - SW_MAXIMIZE = 3, - SW_SHOWNOACTIVATE = 4, - SW_SHOW = 5, - SW_MINIMIZE = 6, - SW_SHOWMINNOACTIVE = 7, - SW_SHOWNA = 8, - SW_RESTORE = 9, - SW_SHOWDEFAULT = 10, - SW_MAX = 10 - } - public enum VkMapType : uint - { - MAPVK_VK_TO_VSC = 0, - MAPVK_VSC_TO_VK = 1, - MAPVK_VK_TO_CHAR = 2, - MAPVK_VSC_TO_VK_EX = 3, - MAPVK_VK_TO_VSC_EX = 4 - } - - #endregion - - #region Structs - [StructLayout(LayoutKind.Sequential)] - public struct ICONINFO - { - public bool fIcon; - public int xHotspot; - public int yHotspot; - public IntPtr hbmMask; - public IntPtr hbmColor; - } - - [StructLayout(LayoutKind.Sequential)] - public struct POINT - { - public int x; - public int y; - } - - - [StructLayout(LayoutKind.Sequential)] - public struct CursorInfo - { - public int cbSize; - public int flags; - public IntPtr hCursor; - public POINT ptScreenPos; - } - [StructLayout(LayoutKind.Sequential)] - public struct INPUT - { - public InputType type; - public InputUnion U; - public static int Size - { - get { return Marshal.SizeOf(typeof(INPUT)); } - } - } - - [StructLayout(LayoutKind.Explicit)] - public struct InputUnion - { - [FieldOffset(0)] - public MOUSEINPUT mi; - [FieldOffset(0)] - public KEYBDINPUT ki; - [FieldOffset(0)] - public HARDWAREINPUT hi; - } - [StructLayout(LayoutKind.Sequential)] - public struct MOUSEINPUT - { - public int dx; - public int dy; - public int mouseData; - public MOUSEEVENTF dwFlags; - public uint time; - public UIntPtr dwExtraInfo; - } - [StructLayout(LayoutKind.Sequential)] - public struct KEYBDINPUT - { - public VirtualKey wVk; - public ScanCodeShort wScan; - public KEYEVENTF dwFlags; - public int time; - public UIntPtr dwExtraInfo; - } - [StructLayout(LayoutKind.Sequential)] - public struct HARDWAREINPUT - { - public int uMsg; - public short wParamL; - public short wParamH; - } - #endregion - - #region DLL Imports - [DllImport("user32.dll")] - public static extern bool GetCursorInfo(out CursorInfo pci); - [DllImport("user32.dll", SetLastError = false)] - public static extern IntPtr GetDesktopWindow(); - - [DllImport("user32.dll")] - public static extern IntPtr GetCursor(); - - [DllImport("user32.dll")] - public static extern IntPtr CopyIcon(IntPtr hIcon); - - [DllImport("user32.dll")] - public static extern bool DrawIcon(IntPtr hdc, int x, int y, IntPtr hIcon); - - [DllImport("user32.dll")] - public static extern bool GetIconInfo(IntPtr hIcon, out ICONINFO piconinfo); - - [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] - public static extern void Mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, UIntPtr dwExtraInfo); - - [DllImport("user32.dll")] - public static extern void Keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo); - - [DllImport("user32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool GetCursorPos(out System.Drawing.Point lpPoint); - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool SetCursorPos(int x, int y); - - [DllImport("user32.dll")] - public static extern IntPtr SetCursor(IntPtr hcursor); - - [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] - static extern IntPtr LoadImage(IntPtr hinst, string lpszName, uint uType, - int cxDesired, int cyDesired, uint fuLoad); - - [DllImport("user32.dll")] - public static extern IntPtr CreateCursor(IntPtr hInst, int xHotSpot, int yHotSpot, - int nWidth, int nHeight, byte[] pvANDPlane, byte[] pvXORPlane); - - [DllImport("user32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool PrintWindow(IntPtr hwnd, IntPtr hDC, uint nFlags); - - [DllImport("user32.dll", SetLastError = true)] - public static extern bool SwitchDesktop(IntPtr hDesktop); - - public delegate bool EnumDesktopsDelegate(string desktop, IntPtr lParam); - - [DllImport("user32.dll")] - public static extern bool EnumDesktopsA(IntPtr hwinsta, EnumDesktopsDelegate lpEnumFunc, IntPtr lParam); - - [DllImport("user32.dll", SetLastError = true)] - public static extern IntPtr OpenInputDesktop(uint dwFlags, bool fInherit, ACCESS_MASK dwDesiredAccess); - - public delegate bool EnumWindowStationsDelegate(string windowsStation, IntPtr lParam); - - [DllImport("user32.dll")] - public static extern bool EnumWindowStations(EnumWindowStationsDelegate lpEnumFunc, IntPtr lParam); - - [DllImport("user32.dll")] - public static extern IntPtr GetShellWindow(); - - public sealed class SafeWindowStationHandle : SafeHandleZeroOrMinusOneIsInvalid - { - public SafeWindowStationHandle() - : base(true) - { - } - - protected override bool ReleaseHandle() - { - return CloseWindowStation(handle); - - } - } - - [return: MarshalAs(UnmanagedType.Bool)] - [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern bool CloseWindowStation(IntPtr hWinsta); - - [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern SafeWindowStationHandle OpenWindowStation([MarshalAs(UnmanagedType.LPTStr)] string lpszWinSta, [MarshalAs(UnmanagedType.Bool)] bool fInherit, ACCESS_MASK dwDesiredAccess); - - [DllImport("user32", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern IntPtr OpenWindowStationW([MarshalAs(UnmanagedType.LPTStr)] string lpszWinSta, [MarshalAs(UnmanagedType.Bool)] bool fInherit, ACCESS_MASK dwDesiredAccess); - - [DllImport("user32.dll", SetLastError = true)] - public static extern bool SetProcessWindowStation(IntPtr hWinSta); - - [DllImport("user32.dll")] - public static extern IntPtr GetWindowDC(IntPtr hWnd); - - public delegate bool EnumWindowsProc(IntPtr hwnd, IntPtr lParam); - - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam); - - [DllImport("User32.dll")] - public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC); - - [DllImport("User32.dll")] - public static extern IntPtr GetProcessWindowStation(); - - [DllImport("user32.dll", SetLastError = true)] - public static extern bool SetThreadDesktop(IntPtr hDesktop); - - [DllImport("user32.dll")] - public static extern IntPtr OpenDesktop(string lpszDesktop, uint dwFlags, bool fInherit, ACCESS_MASK dwDesiredAccess); - [DllImport("user32.dll", SetLastError = true)] - public static extern bool CloseDesktop(IntPtr hDesktop); - - public delegate bool EnumDesktopWindowsDelegate(IntPtr hWnd, int lParam); - - [DllImport("user32.dll")] - public static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumDesktopWindowsDelegate lpfn, IntPtr lParam); - - [DllImport("user32.dll")] - public static extern IntPtr GetDC(IntPtr hWnd); - - [DllImport("user32.dll", SetLastError = true)] - public static extern IntPtr SetActiveWindow(IntPtr hWnd); - - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool SetForegroundWindow(IntPtr hWnd); - - [DllImport("user32.dll")] - public static extern uint SendInput(uint nInputs, [MarshalAs(UnmanagedType.LPArray), In] INPUT[] pInputs, int cbSize); - [DllImport("user32.dll", SetLastError = false)] - public static extern UIntPtr GetMessageExtraInfo(); - [DllImport("sas.dll")] - public static extern void SendSAS(bool AsUser); - [DllImport("user32.dll")] - public static extern bool OpenClipboard(IntPtr hWnd); - [DllImport("user32.dll")] - public static extern bool EmptyClipboard(); - [DllImport("user32.dll")] - public static extern bool CloseClipboard(); - [DllImport("user32.dll")] - public static extern IntPtr SetClipboardData(int Format, IntPtr hMem); - - [DllImport("user32.dll", EntryPoint = "ShowWindow", SetLastError = true)] - public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); - /* -* SystemParametersInfo( -* SPI_SETDESKWALLPAPER, 0, "filename.bmp", -* SPIF_UPDATEINIFILE | SPIF_SENDCHANGE); -*/ - - [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] - public static extern int SystemParametersInfo( - int uAction, int uParam, string lpvParam, int fuWinIni); - - [DllImport("user32.dll", SetLastError = true)] - public static extern bool LockWorkStation(); - - [DllImport("user32.dll")] - public static extern short VkKeyScan(char ch); - - [DllImport("user32.dll")] - public static extern int SendMessage(int hWnd, int hMsg, int wParam, int lParam); - - [DllImport("user32.dll", EntryPoint = "BlockInput")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool BlockInput([MarshalAs(UnmanagedType.Bool)] bool fBlockIt); - - [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] - public static extern int MessageBox(IntPtr hWnd, string text, string caption, long type); - - [DllImport("USER32.dll")] - public static extern short GetKeyState(VirtualKey nVirtKey); - - [DllImport("user32.dll")] - public static extern uint MapVirtualKeyEx(uint uCode, VkMapType uMapType, IntPtr dwhkl); - - [DllImport("user32.dll")] - public static extern IntPtr GetKeyboardLayout(uint threadId = 0); - - [DllImport("user32.dll", SetLastError = true)] - public static extern bool GetUserObjectInformationW(IntPtr hObj, int nIndex, - [Out] byte[] pvInfo, uint nLength, out uint lpnLengthNeeded); - #endregion -} diff --git a/src/Remote/Insight.Remote.Shared/Native/Windows/WTSAPI32.cs b/src/Remote/Insight.Remote.Shared/Native/Windows/WTSAPI32.cs deleted file mode 100644 index 3ea95f8..0000000 --- a/src/Remote/Insight.Remote.Shared/Native/Windows/WTSAPI32.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Insight.Remote.Shared.Native.Windows; - -public static class WTSAPI32 -{ - public static IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero; - - public enum WTS_CONNECTSTATE_CLASS - { - WTSActive, - WTSConnected, - WTSConnectQuery, - WTSShadow, - WTSDisconnected, - WTSIdle, - WTSListen, - WTSReset, - WTSDown, - WTSInit - } - - public enum WTS_INFO_CLASS - { - WTSInitialProgram, - WTSApplicationName, - WTSWorkingDirectory, - WTSOEMId, - WTSSessionId, - WTSUserName, - WTSWinStationName, - WTSDomainName, - WTSConnectState, - WTSClientBuildNumber, - WTSClientName, - WTSClientDirectory, - WTSClientProductId, - WTSClientHardwareId, - WTSClientAddress, - WTSClientDisplay, - WTSClientProtocolType, - WTSIdleTime, - WTSLogonTime, - WTSIncomingBytes, - WTSOutgoingBytes, - WTSIncomingFrames, - WTSOutgoingFrames, - WTSClientInfo, - WTSSessionInfo - } - - - [DllImport("wtsapi32.dll", SetLastError = true)] - public static extern int WTSEnumerateSessions( - IntPtr hServer, - int Reserved, - int Version, - ref IntPtr ppSessionInfo, - ref int pCount); - - [DllImport("wtsapi32.dll", ExactSpelling = true, SetLastError = false)] - public static extern void WTSFreeMemory(IntPtr memory); - - [DllImport("Wtsapi32.dll")] - public static extern bool WTSQuerySessionInformation(IntPtr hServer, uint sessionId, WTS_INFO_CLASS wtsInfoClass, out IntPtr ppBuffer, out uint pBytesReturned); - - [DllImport("wtsapi32.dll", SetLastError = true)] - static extern IntPtr WTSOpenServer(string pServerName); - - [StructLayout(LayoutKind.Sequential)] - public struct WTS_SESSION_INFO - { - public uint SessionID; - [MarshalAs(UnmanagedType.LPStr)] - public string pWinStationName; - public WTS_CONNECTSTATE_CLASS State; - } -} diff --git a/src/Remote/Insight.Remote.Shared/Native/Windows/Win32Interop.cs b/src/Remote/Insight.Remote.Shared/Native/Windows/Win32Interop.cs deleted file mode 100644 index 05db7f5..0000000 --- a/src/Remote/Insight.Remote.Shared/Native/Windows/Win32Interop.cs +++ /dev/null @@ -1,285 +0,0 @@ -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Runtime.Serialization; -using System.Text; -using static Insight.Remote.Shared.Native.Windows.ADVAPI32; -using static Insight.Remote.Shared.Native.Windows.User32; - -namespace Insight.Remote.Shared.Native.Windows; - -// TODO: Use https://github.com/dotnet/pinvoke for all p/invokes. Remove signatures from this project. -public class Win32Interop -{ - private static IntPtr _lastInputDesktop; - - public static List GetActiveSessions() - { - var sessions = new List(); - var consoleSessionId = Kernel32.WTSGetActiveConsoleSessionId(); - sessions.Add(new WindowsSessionDto() - { - Id = consoleSessionId, - Type = WindowsSessionType.Console, - Name = "Console", - Username = GetUsernameFromSessionId(consoleSessionId) - }); - - IntPtr ppSessionInfo = IntPtr.Zero; - var count = 0; - var enumSessionResult = WTSAPI32.WTSEnumerateSessions(WTSAPI32.WTS_CURRENT_SERVER_HANDLE, 0, 1, ref ppSessionInfo, ref count); - var dataSize = Marshal.SizeOf(typeof(WTSAPI32.WTS_SESSION_INFO)); - var current = ppSessionInfo; - - if (enumSessionResult != 0) - { - for (int i = 0; i < count; i++) - { - var wtsInfo = Marshal.PtrToStructure(current, typeof(WTSAPI32.WTS_SESSION_INFO)); - if (wtsInfo is null) - { - continue; - } - var sessionInfo = (WTSAPI32.WTS_SESSION_INFO)wtsInfo; - current += dataSize; - if (sessionInfo.State == WTSAPI32.WTS_CONNECTSTATE_CLASS.WTSActive && sessionInfo.SessionID != consoleSessionId) - { - - sessions.Add(new WindowsSessionDto() - { - Id = sessionInfo.SessionID, - Name = sessionInfo.pWinStationName, - Type = WindowsSessionType.RDP, - Username = GetUsernameFromSessionId(sessionInfo.SessionID) - }); - } - } - } - - return sessions; - } - - public static string GetCommandLine() - { - var commandLinePtr = Kernel32.GetCommandLine(); - return Marshal.PtrToStringAuto(commandLinePtr) ?? string.Empty; - } - - public static bool GetCurrentDesktop(out string desktopName) - { - var inputDesktop = OpenInputDesktop(); - try - { - byte[] deskBytes = new byte[256]; - if (!GetUserObjectInformationW(inputDesktop, UOI_NAME, deskBytes, 256, out uint lenNeeded)) - { - desktopName = string.Empty; - return false; - } - - desktopName = Encoding.Unicode.GetString(deskBytes.Take((int)lenNeeded).ToArray()).Replace("\0", ""); - return true; - } - finally - { - CloseDesktop(inputDesktop); - } - } - - public static string GetUsernameFromSessionId(uint sessionId) - { - var username = string.Empty; - - if (WTSAPI32.WTSQuerySessionInformation(IntPtr.Zero, sessionId, WTSAPI32.WTS_INFO_CLASS.WTSUserName, out var buffer, out var strLen) && strLen > 1) - { - username = Marshal.PtrToStringAnsi(buffer); - WTSAPI32.WTSFreeMemory(buffer); - } - - return username ?? string.Empty; - } - - public static IntPtr OpenInputDesktop() - { - return User32.OpenInputDesktop(0, true, ACCESS_MASK.GENERIC_ALL); - } - - public static bool CreateInteractiveSystemProcess( - string commandLine, - int targetSessionId, - bool forceConsoleSession, - string desktopName, - bool hiddenWindow, - out PROCESS_INFORMATION procInfo) - { - uint winlogonPid = 0; - var hUserTokenDup = IntPtr.Zero; - var hPToken = IntPtr.Zero; - var hProcess = IntPtr.Zero; - - procInfo = new PROCESS_INFORMATION(); - - // If not force console, find target session. If not present, - // use last active session. - var dwSessionId = Kernel32.WTSGetActiveConsoleSessionId(); - if (!forceConsoleSession) - { - var activeSessions = GetActiveSessions(); - if (activeSessions.Any(x => x.Id == targetSessionId)) - { - dwSessionId = (uint)targetSessionId; - } - else - { - dwSessionId = activeSessions.Last().Id; - } - } - - // Obtain the process ID of the winlogon process that is running within the currently active session. - var processes = Process.GetProcessesByName("winlogon"); - foreach (Process p in processes) - { - if ((uint)p.SessionId == dwSessionId) - { - winlogonPid = (uint)p.Id; - } - } - - // Obtain a handle to the winlogon process. - hProcess = Kernel32.OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid); - - // Obtain a handle to the access token of the winlogon process. - if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE, ref hPToken)) - { - Kernel32.CloseHandle(hProcess); - return false; - } - - // Security attibute structure used in DuplicateTokenEx and CreateProcessAsUser. - var sa = new SECURITY_ATTRIBUTES(); - sa.Length = Marshal.SizeOf(sa); - - // Copy the access token of the winlogon process; the newly created token will be a primary token. - if (!DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa, SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, TOKEN_TYPE.TokenPrimary, out hUserTokenDup)) - { - Kernel32.CloseHandle(hProcess); - Kernel32.CloseHandle(hPToken); - return false; - } - - // By default, CreateProcessAsUser creates a process on a non-interactive window station, meaning - // the window station has a desktop that is invisible and the process is incapable of receiving - // user input. To remedy this we set the lpDesktop parameter to indicate we want to enable user - // interaction with the new process. - var si = new STARTUPINFO(); - si.cb = Marshal.SizeOf(si); - si.lpDesktop = @"winsta0\" + desktopName; - - // Flags that specify the priority and creation method of the process. - uint dwCreationFlags; - if (hiddenWindow) - { - dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT | CREATE_NO_WINDOW; - si.dwFlags = STARTF_USESHOWWINDOW; - si.wShowWindow = 0; - } - else - { - dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE; - } - - // Create a new process in the current user's logon session. - var result = CreateProcessAsUser( - hUserTokenDup, - null, - commandLine, - ref sa, - ref sa, - false, - dwCreationFlags, - IntPtr.Zero, - null, - ref si, - out procInfo); - - // Invalidate the handles. - Kernel32.CloseHandle(hProcess); - Kernel32.CloseHandle(hPToken); - Kernel32.CloseHandle(hUserTokenDup); - - return result; - } - - public static void SetMonitorState(MonitorState state) - { - SendMessage(0xFFFF, 0x112, 0xF170, (int)state); - } - - public static MessageBoxResult ShowMessageBox(IntPtr owner, - string message, - string caption, - MessageBoxType messageBoxType) - { - return (MessageBoxResult)MessageBox(owner, message, caption, (long)messageBoxType); - } - - public static bool SwitchToInputDesktop() - { - try - { - CloseDesktop(_lastInputDesktop); - var inputDesktop = OpenInputDesktop(); - - if (inputDesktop == IntPtr.Zero) - { - return false; - } - - var result = SetThreadDesktop(inputDesktop) && SwitchDesktop(inputDesktop); - _lastInputDesktop = inputDesktop; - return result; - } - catch - { - return false; - } - } - - public static void SetConsoleWindowVisibility(bool isVisible) - { - var handle = Kernel32.GetConsoleWindow(); - - if (isVisible) - { - ShowWindow(handle, (int)SW.SW_SHOW); - } - else - { - ShowWindow(handle, (int)SW.SW_HIDE); - } - - Kernel32.CloseHandle(handle); - } - - [DataContract] - public class WindowsSessionDto - { - [DataMember(Name = "ID")] - public uint Id { get; set; } - - [DataMember(Name = "Name")] - public string Name { get; set; } = string.Empty; - - [DataMember(Name = "Type")] - public WindowsSessionType Type { get; set; } - - [DataMember(Name = "Username")] - public string Username { get; set; } = string.Empty; - } - - [DataContract] - public enum WindowsSessionType - { - Console = 1, - RDP = 2 - } -} diff --git a/src/Remote/Insight.Remote.Shared/Network/Handlers/RemoteHandler.cs b/src/Remote/Insight.Remote.Shared/Network/Handlers/RemoteHandler.cs deleted file mode 100644 index 1b078d7..0000000 --- a/src/Remote/Insight.Remote.Shared/Network/Handlers/RemoteHandler.cs +++ /dev/null @@ -1,149 +0,0 @@ -using Insight.Domain.Enums; -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Remote.Messages; -using Insight.Remote.Shared.Messages; -using Insight.Remote.Shared.Services; -using Microsoft.Extensions.Logging; -using Vaitr.Bus; - -namespace Insight.Remote.Shared.Network.Handlers; - -public class RemoteHandler(Bus bus, Streamer streamer, ILogger logger) : IMessageHandler -{ - private readonly Bus _bus = bus; - private readonly Streamer _streamer = streamer; - private readonly ILogger _logger = logger; - - public async ValueTask HandleAsync(RemoteSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage - { - if (message is RemoteSessionResponse sessionResponse) - { - await OnSessionResponse(sender, sessionResponse, cancellationToken); - } - else if (message is CastRequest castRequest) - { - await OnCastRequest(sender, castRequest, cancellationToken); - } - else if (message is CastAbort castAbort) - { - await OnCastAbort(sender, castAbort, cancellationToken); - } - else if (message is CastScreenReceived screenDataReceived) - { - await OnScreenDataReceived(sender, screenDataReceived, cancellationToken); - } - else if (message is CastCursorReceived cursorCallbackData) - { - await OnCursorDataReceived(sender, cursorCallbackData, cancellationToken); - } - } - - private async Task OnSessionResponse(RemoteSession session, RemoteSessionResponse sessionResponse, CancellationToken cancellationToken) - { - if (session.Id is not string sessionId) return; - - _logger.LogInformation("Remote {session} => SessionResponse", sessionId); - - session.Id = sessionResponse.SessionId; - - await _bus.PublishAsync(new IdentityChanged(sessionId), cancellationToken); - } - - private async Task OnCastRequest(RemoteSession session, CastRequest castRequest, CancellationToken cancellationToken) - { - _logger.LogInformation("Remote {session.Id} => CastRequest", session.Id); - - //if (request.RequesterName is null || request.ConnectionId is null) return; - - var permitCast = false; - - switch (castRequest.Mode) - { - case RemoteControlMode.Unattended: - { - if (session.AccessKey == castRequest.AccessKey) permitCast = true; - break; - } - case RemoteControlMode.Attended: - { - // timeout source - var waiter = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - - // subscribe token for demand response - using var response = _bus.Subscribe((message) => - { - if (message.Accepted is false) return; - - permitCast = true; - waiter.Cancel(); - }, null); - - // send internal demand request - await _bus.PublishAsync(castRequest, cancellationToken); - - // wait for timeout async - try { await Task.Delay(TimeSpan.FromSeconds(5), waiter.Token); } - catch (TaskCanceledException) { } - break; - } - } - - try - { - var response = new CastRequestResponse(castRequest) - { - Accepted = permitCast - }; - - await session.SendAsync(response, cancellationToken); - } - catch (Exception ex) - { - _logger.LogError("{exception}", ex.Message); - } - - //DesktopStream? viewer = _viewerPool.Values.FirstOrDefault(p => p.ConnectionId == request.ConnectionId); - - //if (viewer is null) - //{ - // viewer = _viewerFactory.Create(); - // _viewerPool.AddOrUpdate(viewer.Uid, viewer, (uid, v) => viewer); - //} - - _ = InitViewerSession(castRequest, cancellationToken); - } - - private async Task OnCastAbort(RemoteSession session, CastAbort castAbort, CancellationToken cancellationToken) - { - _logger.LogInformation("Remote {session} => CastAbort", session.Id); - - await _streamer.CancelAsync(castAbort, cancellationToken); - } - - private async Task OnScreenDataReceived(RemoteSession session, CastScreenReceived screenDataReceived, CancellationToken cancellationToken) - { - //_logger.LogInformation($"Remote {session.Id} => ScreenDataReceived"); - - await _streamer.FrameReceivedAsync(screenDataReceived, cancellationToken); - } - - private async Task OnCursorDataReceived(RemoteSession session, CastCursorReceived cursorCallbackData, CancellationToken cancellationToken) - { - //_logger.LogInformation($"Remote {session.Id} => ScreenDataReceived"); - - await _streamer.CursorReceivedAsync(cursorCallbackData, cancellationToken); - } - - private async Task InitViewerSession(CastRequest castRequest, CancellationToken cancellationToken) - { - try - { - await _streamer.InitAsync(castRequest, cancellationToken); - } - catch (Exception ex) - { - _logger.LogError("{exception}", ex.ToString()); - } - } -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/Network/RemoteSession.cs b/src/Remote/Insight.Remote.Shared/Network/RemoteSession.cs deleted file mode 100644 index 024369d..0000000 --- a/src/Remote/Insight.Remote.Shared/Network/RemoteSession.cs +++ /dev/null @@ -1,104 +0,0 @@ -using Insight.Domain.Enums; -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Remote.Messages; -using Insight.Remote.Shared.Messages; -using Microsoft.Extensions.Logging; -using Vaitr.Bus; -using Vaitr.Network; - -namespace Insight.Remote.Shared.Network; - -public class RemoteSession( - Bus bus, - IEnumerable> handlers, - ISerializer serializer, - ILogger logger) : TcpSession(serializer, logger) -{ - public string? Id { get; set; } - public string? AccessKey { get; set; } - public RemoteControlMode Mode { get; } = RunningAsService() ? RemoteControlMode.Unattended : RemoteControlMode.Attended; - - private readonly Bus _bus = bus; - private readonly IEnumerable> _handlers = handlers; - - protected override async ValueTask OnConnectedAsync(CancellationToken cancellationToken) - { - _logger.LogInformation("Remote ({ep?}) connected", RemoteEndPoint); - - await _bus.PublishAsync(new ConnectionStateChanged(ConnectionState.Connected), cancellationToken); - - await SendAsync(new RemoteSessionRequest - { - Hostname = "Debug Host", - Mode = RemoteControlMode.Attended - }, cancellationToken); - } - - protected override async ValueTask OnDisconnectedAsync(CancellationToken cancellationToken) - { - _logger.LogInformation("Remote ({ep?}) disconnected", RemoteEndPoint); - - await _bus.PublishAsync(new ConnectionStateChanged(ConnectionState.Disconnected)); - } - - protected override ValueTask OnSentAsync(IPacketContext context, CancellationToken cancellationToken) - { - //await base.OnSentAsync(context, cancellationToken); - return default; - } - - protected override async ValueTask OnReceivedAsync(IPacketContext context, CancellationToken cancellationToken) - { - //await base.OnReceivedAsync(context, cancellationToken); - - foreach (var handler in _handlers) - { - try - { - await handler.HandleAsync(this, context.Packet, cancellationToken); - } - catch (Exception ex) - { - _logger.LogWarning("Remote ({ep?}) {ex}", RemoteEndPoint, ex.ToString()); - } - } - } - - protected override ValueTask OnHeartbeatAsync(CancellationToken cancellationToken) - { - _logger.LogInformation("Remote ({ep?}) Heartbeat", RemoteEndPoint); - - return default; - } - - private ValueTask OnWindowsSessionSwitchedAsync(WindowsSessionSwitched message, CancellationToken cancellationToken) - { - try - { - //await SendAsync(new NotifySessionChanged(message.SessionId, message.Reason), cancellationToken); - } - catch (Exception ex) - { - _logger.LogError("{exception}", ex.Message); - } - - return default; - } - - private static ValueTask OnWindowsSessionEndingAsync(WindowsSessionEnding message, CancellationToken cancellationToken) - { - //await DisconnectViewersAsync(); - return default; - } - - private static bool RunningAsService() - { - //if (OperatingSystem.IsWindows()) - //{ - // return ServiceController.GetServices().Any(serviceController => serviceController.ServiceName.Equals("remotecontrol")); - //} - - return false; - } -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/Reactive/AsyncRelayCommand.cs b/src/Remote/Insight.Remote.Shared/Reactive/AsyncRelayCommand.cs deleted file mode 100644 index d6be6c0..0000000 --- a/src/Remote/Insight.Remote.Shared/Reactive/AsyncRelayCommand.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System.Windows.Input; - -namespace Insight.Remote.Shared.Reactive; - -public class AsyncRelayCommand : ICommand -{ - private readonly Func _canExecute; - private readonly Func _execute; - public AsyncRelayCommand(Func execute) - { - _execute = execute; - _canExecute = () => true; - } - - public AsyncRelayCommand(Func execute, Func canExecute) - { - _execute = execute; - _canExecute = canExecute; - } - - public event EventHandler? CanExecuteChanged; - public bool CanExecute(object? parameter) - { - return _canExecute.Invoke(); - } - - public void Execute(object? parameter) - { - _execute.Invoke(); - } - - public void NotifyCanExecuteChanged() - { - CanExecuteChanged?.Invoke(this, EventArgs.Empty); - } -} - -public class AsyncRelayCommand : ICommand -{ - private readonly Func _canExecute; - private readonly Func _execute; - - public AsyncRelayCommand(Func execute) - { - _execute = execute; - _canExecute = (parameter) => true; - } - - public AsyncRelayCommand(Func execute, Func canExecute) - { - _execute = execute; - _canExecute = canExecute; - } - - public event EventHandler? CanExecuteChanged; - - public bool CanExecute(object? parameter) - { - if (parameter is null) - { - return _canExecute.Invoke(default); - } - - if (parameter is not T typedParam) - { - throw new InvalidOperationException("Paramter is not of the correct type."); - } - - return _canExecute.Invoke(typedParam); - } - - // Async void is una*void*able here (heh, heh) due to ICommand's interface. - // Though we shouldn't need to in modern .NET, we're handling UnobservedTaskException - // in IServiceProviderExtensions.UseRemoteControl. In older versions of .NET, this - // would have been required to prevent the app from terminating. - public async void Execute(object? parameter) - { - if (parameter is null) - { - await _execute.Invoke(default); - return; - } - - if (parameter is not T typedParam) - { - throw new InvalidOperationException("Paramter is not of the correct type."); - } - - await _execute.Invoke(typedParam); - } - - public void NotifyCanExecuteChanged() - { - CanExecuteChanged?.Invoke(this, EventArgs.Empty); - } -} diff --git a/src/Remote/Insight.Remote.Shared/Reactive/ObservableObject.cs b/src/Remote/Insight.Remote.Shared/Reactive/ObservableObject.cs deleted file mode 100644 index db2edd8..0000000 --- a/src/Remote/Insight.Remote.Shared/Reactive/ObservableObject.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System.Collections.Concurrent; -using System.ComponentModel; -using System.Runtime.CompilerServices; - -namespace Insight.Remote.Shared.Reactive; - -public class ObservableObject : INotifyPropertyChanged -{ - private readonly ConcurrentDictionary _backingFields = new(); - - public event PropertyChangedEventHandler? PropertyChanged; - - public void NotifyPropertyChanged([CallerMemberName] string propertyName = "") - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - - protected T? Get([CallerMemberName] string propertyName = "") - { - if (_backingFields.TryGetValue(propertyName, out var value) && - value is T typedValue) - { - return typedValue; - } - - return default; - } - - protected T Get(T defaultValue, [CallerMemberName] string propertyName = "") - { - if (_backingFields.TryGetValue(propertyName, out var value) && - value is T typedValue) - { - return typedValue; - } - - return defaultValue; - } - - protected void Set(T newValue, [CallerMemberName] string propertyName = "") - { - _backingFields.AddOrUpdate(propertyName, newValue, (k, v) => newValue); - NotifyPropertyChanged(propertyName); - } -} diff --git a/src/Remote/Insight.Remote.Shared/Reactive/RelayCommand.cs b/src/Remote/Insight.Remote.Shared/Reactive/RelayCommand.cs deleted file mode 100644 index dcd449e..0000000 --- a/src/Remote/Insight.Remote.Shared/Reactive/RelayCommand.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System.Windows.Input; - -namespace Insight.Remote.Shared.Reactive; - -public class RelayCommand : ICommand -{ - private readonly Func _canExecute; - private readonly Action _execute; - public RelayCommand(Action execute) - { - _execute = execute; - _canExecute = () => true; - } - - public RelayCommand(Action execute, Func canExecute) - { - _execute = execute; - _canExecute = canExecute; - } - - public event EventHandler? CanExecuteChanged; - public bool CanExecute(object? parameter) - { - return _canExecute.Invoke(); - } - - public void Execute(object? parameter) - { - _execute.Invoke(); - } -} - -public class RelayCommand : ICommand -{ - private readonly Func _canExecute; - private readonly Action _execute; - - public RelayCommand(Action execute) - { - _execute = execute; - _canExecute = (parameter) => true; - } - - public RelayCommand(Action execute, Func canExecute) - { - _execute = execute; - _canExecute = canExecute; - } - - public event EventHandler? CanExecuteChanged; - - public bool CanExecute(object? parameter) - { - if (parameter is null) - { - return _canExecute.Invoke(default); - } - - if (parameter is not T typedParam) - { - throw new InvalidOperationException("Paramter is not of the correct type."); - } - - return _canExecute.Invoke(typedParam); - } - - public void Execute(object? parameter) - { - if (parameter is null) - { - _execute.Invoke(default); - return; - } - - if (parameter is not T typedParam) - { - throw new InvalidOperationException("Paramter is not of the correct type."); - } - - _execute.Invoke(typedParam); - } - - public void NotifyCanExecuteChanged() - { - CanExecuteChanged?.Invoke(this, EventArgs.Empty); - } -} diff --git a/src/Remote/Insight.Remote.Shared/Services/Runtime.cs b/src/Remote/Insight.Remote.Shared/Services/Runtime.cs deleted file mode 100644 index 2022385..0000000 --- a/src/Remote/Insight.Remote.Shared/Services/Runtime.cs +++ /dev/null @@ -1,69 +0,0 @@ -using Insight.Domain.Enums; -using Insight.Remote.Shared.Abstractions; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; - -namespace Insight.Remote.Shared.Services; - -public class Runtime : IHostedService -{ - private readonly CancellationTokenSource _cts = new(); - - private Task? _desktopTask; - private readonly Thread? _uiThread; - - private readonly IDesktopApp _desktopApp; - private readonly IDispatcher _dispatcher; - private readonly IHostApplicationLifetime _lifetime; - private readonly ILogger _logger; - - public Runtime( - IDesktopApp desktopApp, - IDispatcher dispatcher, - IHostApplicationLifetime lifetime, - ILogger logger) - { - _desktopApp = desktopApp; - _dispatcher = dispatcher; - _lifetime = lifetime; - _logger = logger; - - _lifetime.ApplicationStopping.Register(_cts.Cancel); - } - - public Task StartAsync(CancellationToken cancellationToken) - { - // init app (os specific providers) - _desktopTask = _desktopApp.InitAsync(RemoteControlMode.Attended, _cts.Token); - - // init ui dispatcher / if mode is attended (interactive) - //if (true) - //{ - // _uiThread = await _dispatcher.RunAsync(_cts.Token); - //} - - // todo - // report unattended accesskey to api ($"https://localhost:7024?mode=Unattended&sessionId={appState.SessionId}&accessKey={appState.AccessKey}") - - return Task.CompletedTask; - } - - public async Task StopAsync(CancellationToken cancellationToken) - { - _cts.Cancel(); - - if (_desktopTask is not null) await _desktopTask; - - if (_uiThread is not null) - { - await _dispatcher.ShutdownAsync(); - - using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(3)); - - while (_uiThread.ThreadState == ThreadState.Running) - { - await Task.Delay(100, timeout.Token); - } - } - } -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/Services/Streamer.cs b/src/Remote/Insight.Remote.Shared/Services/Streamer.cs deleted file mode 100644 index 1c8821f..0000000 --- a/src/Remote/Insight.Remote.Shared/Services/Streamer.cs +++ /dev/null @@ -1,354 +0,0 @@ -using Insight.Domain.Network; -using Insight.Domain.Network.Remote.Messages; -using Insight.Remote.Shared.Abstractions; -using Insight.Remote.Shared.Extensions; -using Insight.Remote.Shared.Models; -using Insight.Remote.Shared.Network; -using Microsoft.Extensions.Logging; -using Microsoft.IO; -using SkiaSharp; -using System.Collections.Concurrent; -using System.Diagnostics; -using Vaitr.Bus; -using Vaitr.Network; - -namespace Insight.Remote.Shared.Services; - -public class Streamer( - Bus bus, - ISessionPool remotePool, - IFileProvider fileProvider, - IClipboardProvider clipboardProvider, - IAudioProvider audioProvider, - IInputProvider inputProvider, - ICursorProvider cursorProvider, - IScreenProvider screenProvider, - ILogger logger) : IDisposable -{ - public int ImageQuality { get; set; } = 50; - public bool HasControl { get; set; } = true; - public bool HasAudio { get; set; } = false; - public bool IsResponsive { get; private set; } = true; - public double CurrentFps { get; private set; } - public double CurrentMbps { get; private set; } - public TimeSpan? RoundTripLatency { get; private set; } - - private CancellationTokenSource? _cts; - private volatile int _framesSentSinceLastReceipt; - private DateTimeOffset _lastFrameReceived = DateTimeOffset.Now; - private DateTimeOffset _lastFrameSent = DateTimeOffset.Now; - private uint _pingFailures = 0; - - private readonly RecyclableMemoryStreamManager _recycleStreams = new(); - private readonly ConcurrentQueue _fpsQueue = new(); - private readonly ConcurrentQueue _sentFrames = new(); - - private readonly Bus _bus = bus; - private readonly ISessionPool _remotePool = remotePool; - private readonly IFileProvider _fileProvider = fileProvider; - private readonly IClipboardProvider _clipboardProvider = clipboardProvider; - private readonly IAudioProvider _audioProvider = audioProvider; - private readonly IInputProvider _inputProvider = inputProvider; - private readonly ICursorProvider _cursorProvider = cursorProvider; - private readonly IScreenProvider _screenProvider = screenProvider; - private readonly ILogger _logger = logger; - - public async Task InitAsync(CastRequest request, CancellationToken cancellationToken) - { - _cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - - if (_remotePool.FirstOrDefault().Value is not RemoteSession remoteSession) return; - - //using var audioToken = _bus.SubscribeAsync(async (message, token) => await OnAudioSampleReadyAsync(remoteSession, message, stop.Token), null); - //using var clipboardToken = _bus.SubscribeAsync(async (message, token) => await OnClipboardChangedAsync(remoteSession, message, stop.Token), null); - - //using var sessionSwitchToken = _bus.Subscribe((x) => stop?.Cancel(), null); - //using var sessionEndingToken = _bus.Subscribe((x) => stop?.Cancel(), null); - - try - { - // send initial display informations - var screenBounds = _screenProvider.CurrentScreenBounds; - - await remoteSession.SendAsync(new CastDisplay - { - Id = remoteSession.Id, - DisplayNames = _screenProvider.GetDisplayNames(), - SelectedDisplay = _screenProvider.SelectedScreen, - ScreenWidth = screenBounds.Width, - ScreenHeight = screenBounds.Height, - MachineName = Environment.MachineName - }, cancellationToken); - - //if (OperatingSystem.IsWindows()) - //{ - // await SendChunkedAsync(new WindowsSessionsDto(Win32Interop.GetActiveSessions()), DtoType.WindowsSessions, stop.Token); - //} - - // start => wait for async stream tasks - await Task.WhenAll( - StreamMetricAsync(remoteSession, _cts.Token), - StreamScreenAsync(remoteSession, _cts.Token), - StreamCursorAsync(remoteSession, _cts.Token) - ); - } - catch (OperationCanceledException) { } - catch (Exception ex) - { - _logger.LogError("{exception}", ex.Message); - } - finally - { - _logger.LogInformation("Viewer Disconnected ({responsive})", IsResponsive); - _cts?.Cancel(); - - IsResponsive = true; - } - } - - private async Task StreamMetricAsync(RemoteSession remoteSession, CancellationToken cancellationToken) - { - using var timer = new PeriodicTimer(TimeSpan.FromMilliseconds(1000)); - - while (await timer.WaitForNextTickAsync(cancellationToken) && IsResponsive) - { - // calculate mbps - if (_sentFrames.IsEmpty) CurrentMbps = 0; - else if (_sentFrames.Count == 1) CurrentMbps = _sentFrames.First().FrameSize / 1024 / 1024 * 8; - else if (_sentFrames.Count > 1) CurrentMbps = (double)_sentFrames.Sum(x => x.FrameSize) / 1024 / 1024 * 8 / (_sentFrames.Last().Timestamp - _sentFrames.First().Timestamp).TotalSeconds; - - _sentFrames.Clear(); - - // calculate fps - if (_fpsQueue.IsEmpty) CurrentFps = 0; - else CurrentFps = _fpsQueue.Count / (_fpsQueue.Last() - _fpsQueue.First()).TotalSeconds; - - _fpsQueue.Clear(); - - // calculate latency - try - { - var tick = Stopwatch.GetTimestamp(); - - // new one - //var result = await _client.Connection.InvokeAsync(nameof(PingViewer), new PingViewer(ConnectionId), cancellationToken); - - RoundTripLatency = Stopwatch.GetElapsedTime(tick); - IsResponsive = true; - _pingFailures = 0; - } - catch (Exception) - { - RoundTripLatency = null; - IsResponsive = _pingFailures > 3; - _pingFailures++; - } - - await remoteSession.SendAsync(new CastMetric - { - Id = remoteSession.Id, - Timestamp = DateTimeOffset.Now, - Mbps = CurrentMbps, - Fps = CurrentFps, - RTT = RoundTripLatency.HasValue ? RoundTripLatency.Value.TotalMilliseconds : 0, - }, cancellationToken); - } - } - - private async Task StreamScreenAsync(RemoteSession remoteSession, CancellationToken cancellationToken) - { - var init = true; - var errors = 0; - - while (cancellationToken.IsCancellationRequested is false && IsResponsive) - { - if (errors >= 3) - { - IsResponsive = false; - break; - } - - // Prevent publisher from overwhelming consumer bewteen receipts. - var synced = await WaitForAsync(() => _framesSentSinceLastReceipt < 10, TimeSpan.FromSeconds(3), 10, cancellationToken); - - // Prevent viewer from getting too far behind. - synced &= await WaitForAsync(() => _lastFrameSent - _lastFrameReceived < TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(3), 10, cancellationToken); - - if (synced is false) - { - _logger.LogWarning("Viewer is behind on frames and did not catch up in time."); - - errors++; - continue; - } - - var frameResult = await _screenProvider.GetNextFrameAsync(cancellationToken); - if (frameResult.Frame is null || frameResult.Error) - { - // consider message viewer to reconnect or doing screenProvider rewrite to dispatch on seperate thread - await Task.Delay(1000, cancellationToken); - continue; - } - else if (frameResult.Changed is false) - { - await Task.Delay(20, cancellationToken); - continue; - } - - var diffArea = await _screenProvider.GetDiffAreaAsync(init, cancellationToken); - if (diffArea.IsEmpty) - { - await Task.Delay(20, cancellationToken); - continue; - } - - using var croppedFrame = frameResult.Frame.CropBitmap(diffArea); - - var encodedImageBytes = croppedFrame.EncodeBitmap(SKEncodedImageFormat.Jpeg, ImageQuality); - if (encodedImageBytes.Length == 0) - { - await Task.Delay(20, cancellationToken); - continue; - } - - Interlocked.Increment(ref _framesSentSinceLastReceipt); - - var frame = new SentFrame(encodedImageBytes.Length, DateTimeOffset.Now); - _lastFrameSent = frame.Timestamp; - _sentFrames.Enqueue(frame); - _fpsQueue.Enqueue(DateTimeOffset.Now); - - init = false; - - var screenBounds = _screenProvider.CurrentScreenBounds; - - await remoteSession.SendAsync(new CastScreen - { - Id = remoteSession.Id, - Timestamp = _lastFrameSent, - ViewWidth = screenBounds.Width, - ViewHeight = screenBounds.Height, - Left = diffArea.Left, - Top = diffArea.Top, - Width = diffArea.Width, - Height = diffArea.Height, - Image = encodedImageBytes, - }, cancellationToken); - } - } - - private async Task StreamCursorAsync(RemoteSession remoteSession, CancellationToken cancellationToken) - { - CastCursor? cacheCursor = null; - - while (cancellationToken.IsCancellationRequested is false && IsResponsive) - { - try - { - var cursor = await _cursorProvider.GetAsync(cancellationToken); - if (cursor is null || cursor == cacheCursor) continue; - - cursor.Id = remoteSession.Id; - - await remoteSession.SendAsync(cursor, cancellationToken); - cacheCursor = cursor; - } - catch (Exception ex) - { - _logger.LogError("{exception}", ex.Message); - } - finally - { - await Task.Delay(20, cancellationToken); - } - } - } - - //public async Task SendFileAsync(FileUpload fileUpload, Action progressUpdateCallback, CancellationToken cancellationToken) - //{ - // try - // { - // var messageId = Guid.NewGuid().ToString(); - // var fileDto = new FileDto() - // { - // EndOfFile = false, - // FileName = fileUpload.DisplayName, - // MessageId = messageId, - // StartOfFile = true - // }; - - // await SendChunkedAsync(fileDto, DtoType.File, cancellationToken); - - // using var fs = File.OpenRead(fileUpload.FilePath); - // using var br = new BinaryReader(fs); - // while (fs.Position < fs.Length) - // { - // if (cancellationToken.IsCancellationRequested) - // { - // return; - // } - - // fileDto = new FileDto() - // { - // Buffer = br.ReadBytes(40_000), - // FileName = fileUpload.DisplayName, - // MessageId = messageId - // }; - - // await SendChunkedAsync(fileDto, DtoType.File, cancellationToken); - - // progressUpdateCallback((double)fs.Position / fs.Length); - // } - - // fileDto = new FileDto() - // { - // EndOfFile = true, - // FileName = fileUpload.DisplayName, - // MessageId = messageId, - // StartOfFile = false - // }; - - // await SendChunkedAsync(fileDto, DtoType.File, cancellationToken); - - // progressUpdateCallback(1); - // } - // catch (Exception ex) - // { - // _logger.LogError(ex, "Error while sending file."); - // } - //} - - public Task CancelAsync(CastAbort castAbort, CancellationToken cancellationToken) - { - _cts?.Cancel(); - return Task.CompletedTask; - } - - public Task FrameReceivedAsync(CastScreenReceived screenDataReceived, CancellationToken cancellationToken) - { - if (screenDataReceived.Timestamp is null) return Task.CompletedTask; - - _lastFrameReceived = screenDataReceived.Timestamp.Value.ToLocalTime(); - _framesSentSinceLastReceipt = 0; - - return Task.CompletedTask; - } - - public async Task CursorReceivedAsync(CastCursorReceived cursorCallbackData, CancellationToken cancellationToken) - { - await _cursorProvider.SetAsync(cursorCallbackData.X, cursorCallbackData.Y, cancellationToken); - } - - private static async Task WaitForAsync(Func condition, TimeSpan timeout, int pollingMs = 10, CancellationToken cancellationToken = default) - { - var ts = Stopwatch.GetTimestamp(); - - while (!condition() && Stopwatch.GetElapsedTime(ts) < timeout) await Task.Delay(pollingMs, cancellationToken); - return condition(); - } - - public void Dispose() - { - GC.SuppressFinalize(this); - } -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Shared/ViewModels/FileUpload.cs b/src/Remote/Insight.Remote.Shared/ViewModels/FileUpload.cs deleted file mode 100644 index a5c756b..0000000 --- a/src/Remote/Insight.Remote.Shared/ViewModels/FileUpload.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Insight.Remote.Shared.Reactive; - -namespace Insight.Remote.Shared.ViewModels; - -public partial class FileUpload : ObservableObject -{ - public string FilePath - { - get => Get(defaultValue: string.Empty); - set => Set(value); - } - - - public double PercentProgress - { - get => Get(); - set => Set(value); - } - - public CancellationTokenSource CancellationTokenSource { get; } = new CancellationTokenSource(); - - public string DisplayName => Path.GetFileName(FilePath); -} diff --git a/src/Remote/Insight.Remote.Windows/Insight.Remote.Windows.csproj b/src/Remote/Insight.Remote.Windows/Insight.Remote.Windows.csproj deleted file mode 100644 index 27c43b2..0000000 --- a/src/Remote/Insight.Remote.Windows/Insight.Remote.Windows.csproj +++ /dev/null @@ -1,40 +0,0 @@ - - - - Exe - net8.0-windows - latest - true - true - Remote Control - remote - 2023.12.14.0 - Insight.Remote.Windows - enable - enable - True - none - true - - - - - - - - - - - - - - - - $(DefaultXamlRuntime) - - - $(DefaultXamlRuntime) - - - - diff --git a/src/Remote/Insight.Remote.Windows/Models/DirectXOutput.cs b/src/Remote/Insight.Remote.Windows/Models/DirectXOutput.cs deleted file mode 100644 index d38ac8a..0000000 --- a/src/Remote/Insight.Remote.Windows/Models/DirectXOutput.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Insight.Remote.Shared.Helpers; -using SharpDX.Direct3D11; -using SharpDX.DXGI; - -namespace Insight.Remote.Windows.Models; - -public class DirectXOutput(Adapter1 adapter, - SharpDX.Direct3D11.Device device, - OutputDuplication outputDuplication, - Texture2D texture2D, - DisplayModeRotation rotation) : IDisposable -{ - public Adapter1 Adapter { get; } = adapter; - public Rectangle Bounds { get; set; } = new Rectangle(0, 0, texture2D.Description.Width, texture2D.Description.Height); - public SharpDX.Direct3D11.Device Device { get; } = device; - public OutputDuplication OutputDuplication { get; } = outputDuplication; - public DisplayModeRotation Rotation { get; } = rotation; - public Texture2D Texture2D { get; } = texture2D; - - public void Dispose() - { - OutputDuplication.ReleaseFrame(); - Disposer.TryDisposeAll(OutputDuplication, Texture2D, Adapter, Device); - GC.SuppressFinalize(this); - } -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Windows/Program.cs b/src/Remote/Insight.Remote.Windows/Program.cs deleted file mode 100644 index 7b15e5a..0000000 --- a/src/Remote/Insight.Remote.Windows/Program.cs +++ /dev/null @@ -1,77 +0,0 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Remote.Shared.Abstractions; -using Insight.Remote.Shared.Extensions; -using Insight.Remote.Shared.Network; -using Insight.Remote.Shared.Network.Handlers; -using Insight.Remote.Windows.Services; -using Insight.Remote.Windows.ViewModels; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Vaitr.Network; -using Vaitr.Network.Hosting; - -namespace Insight.Remote.Windows; - -internal class Program -{ - public static async Task Main(string[] args) - { - var builder = Host.CreateDefaultBuilder(args); - builder.UseWindowsService(); - - builder.ConfigureLogging(logger => - { - logger.ClearProviders(); - logger.SetMinimumLevel(LogLevel.Trace); - logger.AddSimpleConsole(options => - { - options.IncludeScopes = false; - options.SingleLine = true; - options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff "; - }); - - logger.AddFilter("Microsoft", LogLevel.None); - }); - - builder.ConfigureServices(services => - { - // CORE - services.AddRemoteControlServices(options => - { - options.Server = new Uri("https://localhost:7024"); - }); - - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - - // NETWORKING - services.UseHostedClient(options => - { - options.Host = "127.0.0.1"; - options.Port = 3003; - options.Keepalive = 10000; - options.Timeout = 30000; - options.Encryption = Encryption.Tls12; - options.Compression = true; - - options.UseSerializer>(); - }); - - services.AddSingleton(); - services.AddSingleton, RemoteHandler>(); - }); - - var host = builder.Build(); - await host.RunAsync(); - } -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Windows/Properties/launchSettings.json b/src/Remote/Insight.Remote.Windows/Properties/launchSettings.json deleted file mode 100644 index 1f711eb..0000000 --- a/src/Remote/Insight.Remote.Windows/Properties/launchSettings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "profiles": { - "Attended": { - "commandName": "Project", - "commandLineArgs": "" - }, - "Unattended": { - "commandName": "Project", - "commandLineArgs": "-m Unattended -s deb9a957-9c88-4705-b58e-b9f20b1e64f0 -a vERyLonGAndCOMpleXKeY -o Immense -r Han" - } - } -} diff --git a/src/Remote/Insight.Remote.Windows/Resources/Styles.xaml b/src/Remote/Insight.Remote.Windows/Resources/Styles.xaml deleted file mode 100644 index f0d8157..0000000 --- a/src/Remote/Insight.Remote.Windows/Resources/Styles.xaml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Windows/Services/WinApp.cs b/src/Remote/Insight.Remote.Windows/Services/WinApp.cs deleted file mode 100644 index ff592c9..0000000 --- a/src/Remote/Insight.Remote.Windows/Services/WinApp.cs +++ /dev/null @@ -1,184 +0,0 @@ -using Insight.Domain.Enums; -using Insight.Domain.Network.Remote.Messages; -using Insight.Remote.Shared.Abstractions; -using Insight.Remote.Shared.Messages; -using Insight.Remote.Shared.Native.Windows; -using Insight.Remote.Windows.ViewModels; -using Insight.Remote.Windows.Views; -using Microsoft.Extensions.Logging; -using Microsoft.Win32; -using System.Collections.Concurrent; -using System.Diagnostics; -using System.Runtime.Versioning; -using Vaitr.Bus; - -namespace Insight.Remote.Windows.Services; - -[SupportedOSPlatform("windows")] -internal class WinApp( - IInputProvider inputProvider, - ICursorProvider cursorProvider, - IAudioProvider audioProvider, - IClipboardProvider clipboardProvider, - IDispatcher dispatcher, - MainViewModel mainViewModel, - Bus bus, - ILogger logger) : IDesktopApp -{ - private MainWindow? _mainWindow; - private bool _disposed; - - private readonly IInputProvider _inputProvider = inputProvider; - private readonly ICursorProvider _cursorProvider = cursorProvider; - private readonly IAudioProvider _audioProvider = audioProvider; - private readonly IClipboardProvider _clipboardProvider = clipboardProvider; - private readonly IDispatcher _dispatcher = dispatcher; - private readonly MainViewModel _maiViewModel = mainViewModel; - private readonly Bus _bus = bus; - private readonly ILogger _logger = logger; - - public async Task InitAsync(RemoteControlMode mode, CancellationToken cancellationToken) - { - // subscriptions - using var requestToken = _bus.SubscribeAsync(OnCastRequestAsync, null); - - // maintain list of background tasks - var tasks = new List - { - InvokeEventsAsync(cancellationToken), - - _inputProvider.InitAsync(cancellationToken), - _audioProvider.InitAsync(cancellationToken), - _clipboardProvider.InitAsync(cancellationToken) - }; - - // switch user modes - if (mode == RemoteControlMode.Attended) - { - // generate and show main window - await _dispatcher.InvokeAsync(() => - { - _mainWindow = new MainWindow(_maiViewModel); - _mainWindow.Show(); - }, cancellationToken); - } - else - { - if (Win32Interop.GetCurrentDesktop(out var currentDesktopName) is false) - { - _logger.LogWarning("Failed to get initial desktop name."); - } - else - { - _logger.LogInformation("Setting initial desktop to {currentDesktopName}.", currentDesktopName); - } - - if (Win32Interop.SwitchToInputDesktop() is false) - { - _logger.LogWarning("Failed to set initial desktop."); - } - } - - // await tasks => rewrite thread of clipboard - foreach (var task in tasks) - { - try - { - await task; - } - catch (TaskCanceledException) { } - catch (Exception ex) - { - _logger.LogError("{exception}", ex.Message); - } - } - } - - private async Task InvokeEventsAsync(CancellationToken cancellationToken) - { - SystemEvents.SessionSwitch += OnSessionSwitch; - SystemEvents.SessionEnding += OnSessionEnding; - - var queue = new ConcurrentQueue(); - - using var switchToken = _bus.Subscribe(queue.Enqueue, null); - using var endingToken = _bus.Subscribe(queue.Enqueue, null); - - while (cancellationToken.IsCancellationRequested is false) - { - try - { - if (queue.TryDequeue(out var result) is false) - { - await Task.Delay(1000, cancellationToken); - continue; - } - - if (result is SessionSwitchEventArgs switchArgs) - { - _logger.LogInformation("Session changing. Reason: {reason}", switchArgs.Reason); - - var reason = (Domain.Enums.SessionSwitchReason)(int)switchArgs.Reason; - await _bus.PublishAsync(new WindowsSessionSwitched(reason, Process.GetCurrentProcess().SessionId), cancellationToken); - } - else if (result is SessionEndedEventArgs endingArgs) - { - _logger.LogInformation("Session ending. Reason: {reason}", endingArgs.Reason); - - var reason = (Domain.Enums.SessionEndReasons)endingArgs.Reason; - await _bus.PublishAsync(new WindowsSessionEnding(reason), cancellationToken); - } - } - catch (TaskCanceledException) { } - catch (Exception ex) - { - _logger.LogError("{exception}", ex.Message); - } - } - - SystemEvents.SessionSwitch -= OnSessionSwitch; - SystemEvents.SessionEnding -= OnSessionEnding; - } - - private async ValueTask OnCastRequestAsync(CastRequest request, CancellationToken cancellationToken) - { - // test (bypass) - //if (request.Mode != RemoteControlMode.Unattended) - //{ - // var result = await _dispatcher.InvokeAsync(() => - // { - // return System.Windows.MessageBox.Show($"Accept connection request from {request.RequesterName}?", "Connection Request", - // MessageBoxButton.YesNo, - // MessageBoxImage.Question); - // }, cancellationToken); - - // switch (result) - // { - // case MessageBoxResult.No: await _bus.PublishAsync(new CastRequestDemand(request, false), cancellationToken); return; - // } - //} - - await _bus.PublishAsync(new CastRequestDemand(request, true), cancellationToken); - } - - private void OnSessionSwitch(object sender, SessionSwitchEventArgs e) => _bus.Publish(e); - private void OnSessionEnding(object sender, SessionEndingEventArgs e) => _bus.Publish(e); - - public void Dispose() - { - Dispose(disposing: true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (_disposed) return; - - if (disposing) - { - - } - - _disposed = true; - } -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Windows/Services/WinAudioProvider.cs b/src/Remote/Insight.Remote.Windows/Services/WinAudioProvider.cs deleted file mode 100644 index 3b3f13e..0000000 --- a/src/Remote/Insight.Remote.Windows/Services/WinAudioProvider.cs +++ /dev/null @@ -1,76 +0,0 @@ -using Insight.Domain.Network.Remote.Messages; -using Insight.Remote.Shared.Abstractions; -using Microsoft.Extensions.Logging; -using NAudio.Wave; -using System.IO; -using Vaitr.Bus; - -namespace Insight.Remote.Windows.Services; - -internal class WinAudioProvider(Bus bus, ILogger logger) : IAudioProvider -{ - private WasapiLoopbackCapture? _capturer; - private WaveFormat? _targetFormat; - - private readonly Bus _bus = bus; - private readonly ILogger _logger = logger; - - public async Task InitAsync(CancellationToken cancellationToken) - { - _capturer = new WasapiLoopbackCapture(); - - try - { - _targetFormat ??= new WaveFormat(16000, 8, 1); - - _capturer.DataAvailable += OnDataAvailable; - _capturer.StartRecording(); - - while (cancellationToken.IsCancellationRequested is false) - { - await Task.Delay(500, cancellationToken); - } - } - catch (TaskCanceledException) { } - catch (Exception ex) - { - _logger.LogError(ex, "Error while creating audio capturer. Make sure a sound device is installed and working."); - } - finally - { - _capturer.DataAvailable -= OnDataAvailable; - _capturer.StopRecording(); - _capturer.Dispose(); - } - } - - private async void OnDataAvailable(object? sender, WaveInEventArgs args) - { - if (_capturer is null || args.Buffer.All(x => x == 0) || args.BytesRecorded <= 0) return; - - // gets auto-disposed after writer - using var inputStream = new MemoryStream(); - - // writer needs to be disposed here - using (var writer = new WaveFileWriter(inputStream, _capturer.WaveFormat)) - writer.Write(args.Buffer); - - // gets auto-disposed after reader - using var workStream = new MemoryStream(inputStream.ToArray()); - using var reader = new WaveFileReader(workStream); - - using var outputStream = new MemoryStream(); - - // resample to 16-bit - using (var resampler = new MediaFoundationResampler(reader, _targetFormat)) - { - WaveFileWriter.WriteWavFileToStream(outputStream, resampler); - } - - // invoke event - await _bus.PublishAsync(new CastAudio - { - Buffer = outputStream.ToArray() - }, cancellationToken: default); - } -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Windows/Services/WinClipboardProvider.cs b/src/Remote/Insight.Remote.Windows/Services/WinClipboardProvider.cs deleted file mode 100644 index 58991cc..0000000 --- a/src/Remote/Insight.Remote.Windows/Services/WinClipboardProvider.cs +++ /dev/null @@ -1,86 +0,0 @@ -using Insight.Remote.Shared.Abstractions; -using Insight.Remote.Shared.Messages; -using Insight.Remote.Shared.Native.Windows; -using Microsoft.Extensions.Logging; -using System.Collections.Concurrent; -using Vaitr.Bus; -using Clipboard = System.Windows.Clipboard; - -namespace Insight.Remote.Windows.Services; - -internal class WinClipboardProvider(Bus bus, ILogger logger) : IClipboardProvider -{ - private readonly ConcurrentQueue _setQueue = new(); - - private readonly Bus _bus = bus; - private readonly ILogger _logger = logger; - - public async Task InitAsync(CancellationToken cancellationToken) - { - var thread = new Thread(async () => - { - string? lastClipboardValue = null; - - while (cancellationToken.IsCancellationRequested is false) - { - try - { - if (_setQueue.TryDequeue(out var item)) - { - //_logger.LogCritical("set clipboard"); - - if (string.IsNullOrWhiteSpace(item)) Clipboard.Clear(); - else Clipboard.SetText(item); - } - else - { - // _logger.LogCritical("get clipboard"); - - Win32Interop.SwitchToInputDesktop(); - - if (Clipboard.ContainsText() && Clipboard.GetText() != lastClipboardValue) - { - lastClipboardValue = Clipboard.GetText(); - - await _bus.PublishAsync(new ClipboardChanged(lastClipboardValue), cancellationToken); - } - } - } - catch (Exception ex) - { - _logger.LogError(ex, "Error while setting clipboard text."); - } - finally - { - Thread.Sleep(1000); - } - } - }); - - thread.SetApartmentState(ApartmentState.STA); - thread.IsBackground = true; - thread.Start(); - - while (cancellationToken.IsCancellationRequested is false) - { - try - { - if (thread.IsAlive) - { - await Task.Delay(1000, cancellationToken); - } - } - catch (TaskCanceledException) { } - catch (Exception ex) - { - _logger.LogError("{exception}", ex.Message); - } - } - } - - public Task SetText(string clipboardText) - { - _setQueue.Enqueue(clipboardText); - return Task.CompletedTask; - } -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Windows/Services/WinCursorProvider.cs b/src/Remote/Insight.Remote.Windows/Services/WinCursorProvider.cs deleted file mode 100644 index 57ac63a..0000000 --- a/src/Remote/Insight.Remote.Windows/Services/WinCursorProvider.cs +++ /dev/null @@ -1,107 +0,0 @@ -using Insight.Domain.Network.Remote.Messages; -using Insight.Remote.Shared.Abstractions; -using Insight.Remote.Shared.Native.Windows; -using Microsoft.Extensions.Logging; -using System.Drawing.Imaging; -using System.IO; -using System.Runtime.InteropServices; - -namespace Insight.Remote.Windows.Services; - -internal class WinCursorProvider(ILogger logger) : ICursorProvider -{ - private readonly SemaphoreSlim _semaphore = new(1, 1); - private readonly ILogger _logger = logger; - - private User32.CursorInfo _cursor = new(); - private CastCursor _lastCursor = new(); - private nint _lastHandle = 0; - private byte[] _lastIconBytes = []; - - public async Task GetAsync(CancellationToken cancellationToken) - { - try - { - await _semaphore.WaitAsync(cancellationToken); - - _cursor.cbSize = Marshal.SizeOf(_cursor); - - if (User32.GetCursorInfo(out _cursor) is false) return null; - - if (_cursor.flags != User32.CURSOR_SHOWING) - { - _lastCursor = EmptyCursor; - return _lastCursor; - } - - if (_cursor.ptScreenPos.x == _lastCursor.X && - _cursor.ptScreenPos.y == _lastCursor.Y && - _cursor.hCursor == _lastHandle) return _lastCursor; - - var iconBytes = Array.Empty(); - - if (_cursor.hCursor == _lastHandle) iconBytes = _lastIconBytes; - else - { - using var ms = new MemoryStream(); - using var icon = Icon.FromHandle(_cursor.hCursor); - icon.ToBitmap().Save(ms, ImageFormat.Png); - - iconBytes = ms.ToArray(); - _lastIconBytes = iconBytes; - } - - _lastHandle = _cursor.hCursor; - - _lastCursor = new CastCursor - { - X = _cursor.ptScreenPos.x, - Y = _cursor.ptScreenPos.y, - Icon = iconBytes - }; - - return _lastCursor; - } - catch (TaskCanceledException) - { - return null; - } - catch (Exception ex) - { - _logger.LogError("{exception}", ex.Message); - return null; - } - finally - { - _semaphore.Release(); - } - } - - public async Task SetAsync(int x, int y, CancellationToken cancellationToken) - { - if (_semaphore.CurrentCount == 0) return; - - try - { - await _semaphore.WaitAsync(cancellationToken); - - User32.SetCursorPos(x, y); - } - catch (OperationCanceledException) { } - catch (Exception ex) - { - _logger.LogError("{exception}", ex.Message); - } - finally - { - _semaphore.Release(); - } - } - - private static CastCursor EmptyCursor => new() - { - X = 0, - Y = 0, - Icon = [] - }; -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Windows/Services/WinDispatcher.cs b/src/Remote/Insight.Remote.Windows/Services/WinDispatcher.cs deleted file mode 100644 index cf37691..0000000 --- a/src/Remote/Insight.Remote.Windows/Services/WinDispatcher.cs +++ /dev/null @@ -1,72 +0,0 @@ -using Insight.Remote.Shared.Abstractions; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using System.Windows.Threading; -using Application = System.Windows.Application; - -namespace Insight.Remote.Windows.Services; - -internal class WinDispatcher(IHostApplicationLifetime lifetime, ILogger logger) : IDispatcher -{ - private Application? _app; - - private readonly ManualResetEvent _appSignal = new(false); - - private readonly IHostApplicationLifetime _lifetime = lifetime; - private readonly ILogger _logger = logger; - - public async Task RunAsync(CancellationToken cancellationToken) - { - var startSignal = new SemaphoreSlim(0, 1); - - var thread = new Thread(() => - { - _app = new Application(); - _app.Startup += (s, e) => startSignal.Release(); - _app.Run(); - }); - - thread.SetApartmentState(ApartmentState.STA); - thread.Start(); - - await startSignal.WaitAsync(cancellationToken).ConfigureAwait(false); - _appSignal.Set(); - - return thread; - } - - public async Task ShutdownAsync() - { - _lifetime.StopApplication(); - - if (_app is null) return; - - try - { - _logger.LogInformation("Shutting down WPF thread."); - - await InvokeAsync(_app.Shutdown); - } - catch (TaskCanceledException) { } - catch (Exception ex) - { - _logger.LogError("{exception}", ex.Message); - } - } - - public async ValueTask InvokeAsync(Action action, CancellationToken cancellationToken = default) - { - if (_app is null) return; - if (_appSignal.WaitOne(5000) is false) return; - - await _app.Dispatcher.InvokeAsync(action, DispatcherPriority.Normal, cancellationToken); - } - - public async ValueTask InvokeAsync(Func func, CancellationToken cancellationToken = default) - { - if (_app is null) return default; - if (_appSignal.WaitOne(5000) is false) return default; - - return await _app.Dispatcher.InvokeAsync(func, DispatcherPriority.Normal, cancellationToken); - } -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Windows/Services/WinFileProvider.cs b/src/Remote/Insight.Remote.Windows/Services/WinFileProvider.cs deleted file mode 100644 index a5bf732..0000000 --- a/src/Remote/Insight.Remote.Windows/Services/WinFileProvider.cs +++ /dev/null @@ -1,171 +0,0 @@ -using Insight.Remote.Shared.Abstractions; -using Insight.Remote.Shared.Services; -using Insight.Remote.Shared.ViewModels; -using Microsoft.Extensions.Logging; -using System.Collections.Concurrent; -using System.Diagnostics; -using System.IO; -using System.Runtime.Versioning; -using System.Security.AccessControl; -using System.Security.Principal; -using System.Windows; -using MessageBoxOptions = System.Windows.MessageBoxOptions; - -namespace Insight.Remote.Windows.Services; - -[SupportedOSPlatform("windows")] -internal class WinFileProvider(ILogger logger) : IFileProvider -{ - private static MessageBoxResult? _result; - private static readonly ConcurrentDictionary _partialTransfers = new(); - private static readonly SemaphoreSlim _writeLock = new(1, 1); - private readonly ILogger _logger = logger; - - public string GetBaseDirectory() - { - var programDataPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData); - return Directory.CreateDirectory(Path.Combine(programDataPath, "RemoteControl", "Shared")).FullName; - } - - public async Task ReceiveFile(byte[] buffer, string fileName, string messageId, bool endOfFile, bool startOfFile) - { - try - { - await _writeLock.WaitAsync(); - - var baseDir = GetBaseDirectory(); - - SetFileOrFolderPermissions(baseDir); - - if (startOfFile) - { - var filePath = Path.Combine(baseDir, fileName); - - if (File.Exists(filePath)) - { - var count = 0; - var ext = Path.GetExtension(fileName); - var fileWithoutExt = Path.GetFileNameWithoutExtension(fileName); - while (File.Exists(filePath)) - { - filePath = Path.Combine(baseDir, $"{fileWithoutExt}-{count}{ext}"); - count++; - } - } - - File.Create(filePath).Close(); - SetFileOrFolderPermissions(filePath); - var fs = new FileStream(filePath, FileMode.OpenOrCreate); - _partialTransfers.AddOrUpdate(messageId, fs, (k, v) => fs); - } - - var fileStream = _partialTransfers[messageId]; - - if (buffer?.Length > 0) - { - await fileStream.WriteAsync(buffer); - } - - if (endOfFile) - { - fileStream.Close(); - _partialTransfers.Remove(messageId, out _); - } - } - catch (Exception ex) - { - _logger.LogError(ex, "Error while receiving file."); - } - finally - { - _writeLock.Release(); - if (endOfFile) - { - await Task.Run(ShowTransferComplete); - } - } - } - - public Task UploadFile(FileUpload fileUpload, Streamer viewer, Action progressUpdateCallback, CancellationToken cancelToken) - { - try - { - //await viewer.SendFileAsync(fileUpload, progressUpdateCallback, cancelToken); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error while uploading file."); - } - - return Task.CompletedTask; - } - - private static void SetFileOrFolderPermissions(string path) - { - FileSystemSecurity ds; - - var aclSections = AccessControlSections.Access | AccessControlSections.Group | AccessControlSections.Owner; - if (File.Exists(path)) - { - ds = new FileSecurity(path, aclSections); - } - else if (Directory.Exists(path)) - { - ds = new DirectorySecurity(path, aclSections); - } - else - { - return; - } - - var sid = new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null); - var account = (NTAccount)sid.Translate(typeof(NTAccount)); - - var accessAlreadySet = false; - - foreach (FileSystemAccessRule rule in ds.GetAccessRules(true, true, typeof(NTAccount))) - { - if (rule.IdentityReference == account && - rule.FileSystemRights.HasFlag(FileSystemRights.Modify) && - rule.AccessControlType == AccessControlType.Allow) - { - accessAlreadySet = true; - break; - } - } - - if (!accessAlreadySet) - { - ds.AddAccessRule(new FileSystemAccessRule(account, FileSystemRights.Modify, AccessControlType.Allow)); - if (File.Exists(path)) - { - new FileInfo(path).SetAccessControl((FileSecurity)ds); - } - else if (Directory.Exists(path)) - { - new DirectoryInfo(path).SetAccessControl((DirectorySecurity)ds); - } - } - } - - private void ShowTransferComplete() - { - // Prevent multiple dialogs from popping up. - if (_result is null) - { - _result = System.Windows.MessageBox.Show("File transfer complete. Show folder?", - "Transfer Complete", - MessageBoxButton.YesNo, - MessageBoxImage.Question, - MessageBoxResult.Yes, - MessageBoxOptions.ServiceNotification); - - if (_result == MessageBoxResult.Yes) - { - Process.Start("explorer.exe", GetBaseDirectory()); - } - - _result = null; - } - } -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Windows/Services/WinInputProvider.cs b/src/Remote/Insight.Remote.Windows/Services/WinInputProvider.cs deleted file mode 100644 index 69dedd4..0000000 --- a/src/Remote/Insight.Remote.Windows/Services/WinInputProvider.cs +++ /dev/null @@ -1,400 +0,0 @@ -using Insight.Remote.Shared.Abstractions; -using Insight.Remote.Shared.Enums; -using Insight.Remote.Shared.Native.Windows; -using Microsoft.Extensions.Logging; -using System.Threading.Channels; - -namespace Insight.Remote.Windows.Services; - -internal class WinInputProvider(IScreenProvider screenProvider, ILogger logger) : IInputProvider -{ - private volatile bool _inputBlocked; - - private readonly Channel _inputs = Channel.CreateUnbounded(new UnboundedChannelOptions { AllowSynchronousContinuations = false }); - - private readonly IScreenProvider _screenProvider = screenProvider; - private readonly ILogger _logger = logger; - - public async Task InitAsync(CancellationToken cancellationToken) - { - try - { - while (cancellationToken.IsCancellationRequested is false) - { - await ThreadedInputProcessing(cancellationToken); - await Task.Delay(1000, cancellationToken); - } - } - catch (OperationCanceledException) { } - catch (Exception ex) - { - _logger.LogError("{exception}", ex.ToString()); - } - } - - private async Task ThreadedInputProcessing(CancellationToken cancellationToken) - { - var semaphore = new SemaphoreSlim(0, 1); - - var thread = new Thread(async () => - { - //_logger.LogInformation("New input processing thread started on thread {threadId}", Thread.CurrentThread.ManagedThreadId); - - while (cancellationToken.IsCancellationRequested is false) - { - try - { - if (await _inputs.Reader.WaitToReadAsync(cancellationToken) is false) return; - - // Thread likely has hooks in current desktop. SendKeys will create one with no way to unhook it - // Start a new thread for processing input => break - if (Win32Interop.SwitchToInputDesktop() is false) - { - _logger.LogWarning("Desktop switch failed during input processing."); - break; - } - - var input = await _inputs.Reader.ReadAsync(cancellationToken); - if (_inputBlocked) continue; - - input(); - } - catch (OperationCanceledException) { } - catch (Exception ex) - { - _logger.LogError("{exception}", ex.Message); - } - } - - //_logger.LogInformation("Stopping input processing on thread {threadId}", Environment.CurrentManagedThreadId); - semaphore.Release(); - }); - - thread.SetApartmentState(ApartmentState.STA); - thread.Start(); - - try - { - await semaphore.WaitAsync(cancellationToken); - } - catch (OperationCanceledException) { } - catch (Exception ex) - { - _logger.LogError("{exception}", ex.ToString()); - } - } - - public async Task SendKeyDownAsync(string key, CancellationToken cancellationToken) - { - if (ConvertJavaScriptKeyToVirtualKey(key, out var keyCode) is false || keyCode is null) return; - - try - { - await _inputs.Writer.WriteAsync(() => - { - var union = new User32.InputUnion() - { - ki = new User32.KEYBDINPUT() - { - wVk = keyCode.Value, - wScan = (User32.ScanCodeShort)User32.MapVirtualKeyEx((uint)keyCode.Value, User32.VkMapType.MAPVK_VK_TO_VSC, User32.GetKeyboardLayout()), - time = 0, - dwExtraInfo = User32.GetMessageExtraInfo() - } - }; - - var input = new User32.INPUT() { type = User32.InputType.KEYBOARD, U = union }; - _ = User32.SendInput(1, [input], User32.INPUT.Size); - }, cancellationToken); - } - catch (OperationCanceledException) { } - catch (Exception ex) - { - _logger.LogError("{exception}", ex.ToString()); - } - } - - public async Task SendKeyUpAsync(string key, CancellationToken cancellationToken) - { - if (ConvertJavaScriptKeyToVirtualKey(key, out var keyCode) is false || keyCode is null) return; - - try - { - await _inputs.Writer.WriteAsync(() => - { - var union = new User32.InputUnion() - { - ki = new User32.KEYBDINPUT() - { - wVk = keyCode.Value, - wScan = (User32.ScanCodeShort)User32.MapVirtualKeyEx((uint)keyCode.Value, User32.VkMapType.MAPVK_VK_TO_VSC, User32.GetKeyboardLayout()), - time = 0, - dwFlags = User32.KEYEVENTF.KEYUP, - dwExtraInfo = User32.GetMessageExtraInfo() - } - }; - var input = new User32.INPUT() { type = User32.InputType.KEYBOARD, U = union }; - _ = User32.SendInput(1, [input], User32.INPUT.Size); - }, cancellationToken); - } - catch (OperationCanceledException) { } - catch (Exception ex) - { - _logger.LogError("{exception}", ex.ToString()); - } - } - - public async Task SendMouseButtonActionAsync(int button, ButtonAction buttonAction, double percentX, double percentY, CancellationToken cancellationToken) - { - try - { - await _inputs.Writer.WriteAsync(() => - { - User32.MOUSEEVENTF mouseEvent; - switch (button) - { - case 0: - switch (buttonAction) - { - case ButtonAction.Down: - mouseEvent = User32.MOUSEEVENTF.LEFTDOWN; - break; - case ButtonAction.Up: - mouseEvent = User32.MOUSEEVENTF.LEFTUP; - break; - default: - return; - } - break; - case 1: - switch (buttonAction) - { - case ButtonAction.Down: - mouseEvent = User32.MOUSEEVENTF.MIDDLEDOWN; - break; - case ButtonAction.Up: - mouseEvent = User32.MOUSEEVENTF.MIDDLEUP; - break; - default: - return; - } - break; - case 2: - switch (buttonAction) - { - case ButtonAction.Down: - mouseEvent = User32.MOUSEEVENTF.RIGHTDOWN; - break; - case ButtonAction.Up: - mouseEvent = User32.MOUSEEVENTF.RIGHTUP; - break; - default: - return; - } - break; - default: - return; - } - - var xyPercent = GetAbsolutePercentFromRelativePercent(percentX, percentY, _screenProvider); - - // Coordinates must be normalized. The bottom-right coordinate is mapped to 65535. - var normalizedX = xyPercent.Item1 * 65535D; - var normalizedY = xyPercent.Item2 * 65535D; - var union = new User32.InputUnion() { mi = new User32.MOUSEINPUT() { dwFlags = User32.MOUSEEVENTF.ABSOLUTE | mouseEvent | User32.MOUSEEVENTF.VIRTUALDESK, dx = (int)normalizedX, dy = (int)normalizedY, time = 0, mouseData = 0, dwExtraInfo = User32.GetMessageExtraInfo() } }; - var input = new User32.INPUT() { type = User32.InputType.MOUSE, U = union }; - _ = User32.SendInput(1, [input], User32.INPUT.Size); - }, cancellationToken); - } - catch (OperationCanceledException) { } - catch (Exception ex) - { - _logger.LogError("{exception}", ex.ToString()); - } - } - - public async Task SendMouseMoveAsync(double percentX, double percentY, CancellationToken cancellationToken) - { - try - { - await _inputs.Writer.WriteAsync(() => - { - var xyPercent = GetAbsolutePercentFromRelativePercent(percentX, percentY, _screenProvider); - // Coordinates must be normalized. The bottom-right coordinate is mapped to 65535. - var normalizedX = xyPercent.Item1 * 65535D; - var normalizedY = xyPercent.Item2 * 65535D; - var union = new User32.InputUnion() { mi = new User32.MOUSEINPUT() { dwFlags = User32.MOUSEEVENTF.ABSOLUTE | User32.MOUSEEVENTF.MOVE | User32.MOUSEEVENTF.VIRTUALDESK, dx = (int)normalizedX, dy = (int)normalizedY, time = 0, mouseData = 0, dwExtraInfo = User32.GetMessageExtraInfo() } }; - var input = new User32.INPUT() { type = User32.InputType.MOUSE, U = union }; - _ = User32.SendInput(1, [input], User32.INPUT.Size); - }, cancellationToken); - } - catch (OperationCanceledException) { } - catch (Exception ex) - { - _logger.LogError("{exception}", ex.ToString()); - } - } - - public async Task SendMouseWheelAsync(int deltaY, CancellationToken cancellationToken) - { - try - { - await _inputs.Writer.WriteAsync(() => - { - if (deltaY < 0) - { - deltaY = -120; - } - else if (deltaY > 0) - { - deltaY = 120; - } - var union = new User32.InputUnion() { mi = new User32.MOUSEINPUT() { dwFlags = User32.MOUSEEVENTF.WHEEL, dx = 0, dy = 0, time = 0, mouseData = deltaY, dwExtraInfo = User32.GetMessageExtraInfo() } }; - var input = new User32.INPUT() { type = User32.InputType.MOUSE, U = union }; - _ = User32.SendInput(1, [input], User32.INPUT.Size); - }, cancellationToken); - } - catch (OperationCanceledException) { } - catch (Exception ex) - { - _logger.LogError("{exception}", ex.ToString()); - } - } - - public async Task SendTextAsync(string transferText, CancellationToken cancellationToken) - { - try - { - await _inputs.Writer.WriteAsync(() => - { - SendKeys.SendWait(transferText); - }, cancellationToken); - } - catch (OperationCanceledException) { } - catch (Exception ex) - { - _logger.LogError("{exception}", ex.ToString()); - } - } - - public async Task SetKeyStatesUpAsync(CancellationToken cancellationToken) - { - try - { - await _inputs.Writer.WriteAsync(() => - { - foreach (User32.VirtualKey key in Enum.GetValues(typeof(User32.VirtualKey))) - { - try - { - var state = User32.GetKeyState(key); - if (state == -127) - { - var union = new User32.InputUnion() - { - ki = new User32.KEYBDINPUT() - { - wVk = key, - wScan = 0, - time = 0, - dwFlags = User32.KEYEVENTF.KEYUP, - dwExtraInfo = User32.GetMessageExtraInfo() - } - }; - var input = new User32.INPUT() { type = User32.InputType.KEYBOARD, U = union }; - _ = User32.SendInput(1, [input], User32.INPUT.Size); - } - } - catch { } - } - }, cancellationToken); - } - catch (TaskCanceledException) { } - catch (Exception ex) - { - _logger.LogError("{exception}", ex.ToString()); - } - } - - public async Task ToggleBlockInputAsync(bool toggleOn, CancellationToken cancellationToken) - { - try - { - await _inputs.Writer.WriteAsync(() => - { - _inputBlocked = toggleOn; - var result = User32.BlockInput(toggleOn); - - _logger.LogInformation("Result of ToggleBlockInput set to {toggleOn}: {result}", toggleOn, result); - }, cancellationToken); - } - catch (TaskCanceledException) { } - catch (Exception ex) - { - _logger.LogError("{exception}", ex.ToString()); - } - } - - private bool ConvertJavaScriptKeyToVirtualKey(string key, out User32.VirtualKey? result) - { - result = key switch - { - "Down" or "ArrowDown" => User32.VirtualKey.DOWN, - "Up" or "ArrowUp" => User32.VirtualKey.UP, - "Left" or "ArrowLeft" => User32.VirtualKey.LEFT, - "Right" or "ArrowRight" => User32.VirtualKey.RIGHT, - "Enter" => User32.VirtualKey.RETURN, - "Esc" or "Escape" => User32.VirtualKey.ESCAPE, - "Alt" => User32.VirtualKey.MENU, - "Control" => User32.VirtualKey.CONTROL, - "Shift" => User32.VirtualKey.SHIFT, - "PAUSE" => User32.VirtualKey.PAUSE, - "BREAK" => User32.VirtualKey.PAUSE, - "Backspace" => User32.VirtualKey.BACK, - "Tab" => User32.VirtualKey.TAB, - "CapsLock" => User32.VirtualKey.CAPITAL, - "Delete" => User32.VirtualKey.DELETE, - "Home" => User32.VirtualKey.HOME, - "End" => User32.VirtualKey.END, - "PageUp" => User32.VirtualKey.PRIOR, - "PageDown" => User32.VirtualKey.NEXT, - "NumLock" => User32.VirtualKey.NUMLOCK, - "Insert" => User32.VirtualKey.INSERT, - "ScrollLock" => User32.VirtualKey.SCROLL, - "F1" => User32.VirtualKey.F1, - "F2" => User32.VirtualKey.F2, - "F3" => User32.VirtualKey.F3, - "F4" => User32.VirtualKey.F4, - "F5" => User32.VirtualKey.F5, - "F6" => User32.VirtualKey.F6, - "F7" => User32.VirtualKey.F7, - "F8" => User32.VirtualKey.F8, - "F9" => User32.VirtualKey.F9, - "F10" => User32.VirtualKey.F10, - "F11" => User32.VirtualKey.F11, - "F12" => User32.VirtualKey.F12, - "Meta" => User32.VirtualKey.LWIN, - "ContextMenu" => User32.VirtualKey.MENU, - _ => key.Length == 1 ? (User32.VirtualKey)User32.VkKeyScan(Convert.ToChar(key)) : null - }; - - if (result is not null) return true; - - _logger.LogWarning("Unable to parse key input: {key}.", key); - return false; - } - - private static Tuple GetAbsolutePercentFromRelativePercent(double percentX, double percentY, IScreenProvider capturer) - { - var absoluteX = capturer.CurrentScreenBounds.Width * percentX + capturer.CurrentScreenBounds.Left - capturer.GetVirtualScreenBounds().Left; - var absoluteY = capturer.CurrentScreenBounds.Height * percentY + capturer.CurrentScreenBounds.Top - capturer.GetVirtualScreenBounds().Top; - return new Tuple(absoluteX / capturer.GetVirtualScreenBounds().Width, absoluteY / capturer.GetVirtualScreenBounds().Height); - } - - private static Tuple GetAbsolutePointFromRelativePercent(double percentX, double percentY, IScreenProvider capturer) - { - var absoluteX = capturer.CurrentScreenBounds.Width * percentX + capturer.CurrentScreenBounds.Left; - var absoluteY = capturer.CurrentScreenBounds.Height * percentY + capturer.CurrentScreenBounds.Top; - return new Tuple(absoluteX, absoluteY); - } -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Windows/Services/WinScreenCapturer.cs b/src/Remote/Insight.Remote.Windows/Services/WinScreenCapturer.cs deleted file mode 100644 index 1d5ee21..0000000 --- a/src/Remote/Insight.Remote.Windows/Services/WinScreenCapturer.cs +++ /dev/null @@ -1,524 +0,0 @@ -// The DirectX capture code is based off examples from the -// SharpDX Samples at https://github.com/sharpdx/SharpDX. - -// Copyright (c) 2010-2013 SharpDX - Alexandre Mutel -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -using Insight.Remote.Shared.Abstractions; -using Insight.Remote.Shared.Extensions; -using Insight.Remote.Shared.Models; -using Insight.Remote.Shared.Native.Windows; -using Insight.Remote.Windows.Models; -using Microsoft.Extensions.Logging; -using Microsoft.Win32; -using RemoteControl.Shared; -using SharpDX; -using SharpDX.Direct3D11; -using SharpDX.DXGI; -using SkiaSharp; -using SkiaSharp.Views.Desktop; -using System.Diagnostics.CodeAnalysis; -using System.Drawing.Imaging; -using System.Runtime.InteropServices; -using System.Runtime.Versioning; -using Vaitr.Bus; -using Result = RemoteControl.Shared.Result; - -namespace Insight.Remote.Windows.Services; - -[SupportedOSPlatform("windows")] -internal class WinScreenCapturer : IScreenProvider -{ - public event EventHandler? ScreenChanged; - public Rectangle GetVirtualScreenBounds() => SystemInformation.VirtualScreen; - - private SKBitmap? CurrentFrame - { - get => _currentFrame; - set - { - if (_currentFrame != null) - { - _previousFrame?.Dispose(); - _previousFrame = _currentFrame; - } - _currentFrame = value; - } - } - - public int GetScreenCount() => Screen.AllScreens.Length; - public IEnumerable GetDisplayNames() => Screen.AllScreens.Select(x => x.DeviceName); - public Rectangle CurrentScreenBounds { get; private set; } = Screen.PrimaryScreen?.Bounds ?? Rectangle.Empty; - public string SelectedScreen { get; private set; } = Screen.PrimaryScreen?.DeviceName ?? string.Empty; - - private readonly object _screenBoundsLock = new(); - private SKBitmap? _currentFrame; - private SKBitmap? _previousFrame; - private bool _initialized; - - private readonly SemaphoreSlim _semaphore = new(1, 1); - private readonly Dictionary _bitBltScreens = []; - private readonly Dictionary _directxScreens = []; - - private readonly Bus _bus; - private readonly ILogger _logger; - - public WinScreenCapturer(Bus bus, ILogger logger) - { - _bus = bus; - _logger = logger; - - SystemEvents.DisplaySettingsChanged += SystemEvents_DisplaySettingsChanged; - } - - public Task InitAsync(CancellationToken cancellationToken) - { - Win32Interop.SwitchToInputDesktop(); - - InitBitBlt(); - InitDirectX(); - - _initialized = true; - - return Task.CompletedTask; - } - - public void SetSelectedScreen(string displayName) - { - lock (_screenBoundsLock) - { - if (displayName == SelectedScreen) return; - - if (_bitBltScreens.ContainsKey(displayName)) SelectedScreen = displayName; - else SelectedScreen = _bitBltScreens.Keys.First(); - - RefreshCurrentScreenBounds(); - } - } - - public async Task GetNextFrameAsync(CancellationToken cancellationToken) - { - try - { - await _semaphore.WaitAsync(cancellationToken); - - if (Win32Interop.SwitchToInputDesktop() is false) - { - // Something will occasionally prevent this from succeeding after active - // desktop has changed to/from WinLogon (err code 170). I'm guessing a hook - // is getting put in the desktop, which causes SetThreadDesktop to fail. - // The caller can start a new thread, which seems to resolve it. - var errCode = Marshal.GetLastWin32Error(); - - _logger.LogError("Failed to switch to input desktop. Last Win32 error code: {errCode}", errCode); - - return new FrameResult(null, false, true); - } - - if (_initialized is false) - { - _logger.LogWarning("Init needed in GetNextFrame."); - await InitAsync(cancellationToken); - } - - var frame = GetDirectXFrame(); - if (frame is null || frame.IsSuccess is false) - { - var bitBltResult = GetBitBltFrame(); - if (bitBltResult.IsSuccess is false) - { - var ex = bitBltResult.Exception ?? new("Unknown error."); - _logger.LogError(ex, "Error while getting next frame."); - return new FrameResult(null, false, true); - } - - CurrentFrame = bitBltResult.Value; - } - else if (frame.IsSuccess && frame.Bitmap is not null && IsEmpty(frame.Bitmap) is false) - { - CurrentFrame = frame.Bitmap; - } - - return new FrameResult(CurrentFrame, frame is not null && frame.HadChanges, false); - } - catch (TaskCanceledException) - { - return new FrameResult(null, false, true); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error while getting next frame."); - _initialized = false; - - return new FrameResult(null, false, true); - } - finally - { - _semaphore.Release(); - } - } - - public SKRect GetFrameDiffArea(bool fullscreen) - { - if (CurrentFrame is null) return SKRect.Empty; - return CurrentFrame.GetDiffArea(_previousFrame, fullscreen); - } - - public async Task GetDiffAreaAsync(bool fullscreen, CancellationToken cancellationToken) - { - if (CurrentFrame is null) return SKRect.Empty; - - try - { - await _semaphore.WaitAsync(cancellationToken); - - return CurrentFrame.GetDiffArea(_previousFrame, fullscreen); - } - finally - { - _semaphore.Release(); - } - } - - public int GetSelectedScreenIndex() - { - if (_bitBltScreens.TryGetValue(SelectedScreen, out var index)) return index; - return 0; - } - - private Result GetBitBltFrame() - { - try - { - using var bitmap = new Bitmap(CurrentScreenBounds.Width, CurrentScreenBounds.Height, PixelFormat.Format32bppArgb); - using (var graphic = Graphics.FromImage(bitmap)) - { - graphic.CopyFromScreen(CurrentScreenBounds.Left, CurrentScreenBounds.Top, 0, 0, new Size(CurrentScreenBounds.Width, CurrentScreenBounds.Height)); - } - return Result.Ok(bitmap.ToSKBitmap()); - } - catch (Exception ex) - { - _logger.LogError(ex, "Capturer error in BitBltCapture."); - _initialized = false; - return Result.Fail("Error while capturing BitBlt frame."); - } - } - - private DxCaptureResult GetDirectXFrame() - { - if (_directxScreens.TryGetValue(SelectedScreen, out var dxOutput) is false) - { - return DxCaptureResult.Fail("DirectX output not found."); - } - - try - { - var outputDuplication = dxOutput.OutputDuplication; - var device = dxOutput.Device; - var texture2D = dxOutput.Texture2D; - var bounds = dxOutput.Bounds; - - var result = outputDuplication.TryAcquireNextFrame(timeoutInMilliseconds: 25, out var duplicateFrameInfo, out var screenResource); - - if (!result.Success) - { - return DxCaptureResult.TryAcquireFailed(result); - } - - if (duplicateFrameInfo.AccumulatedFrames == 0) - { - try - { - outputDuplication.ReleaseFrame(); - } - catch { } - return DxCaptureResult.NoAccumulatedFrames(result); - } - - using Texture2D screenTexture2D = screenResource.QueryInterface(); - device.ImmediateContext.CopyResource(screenTexture2D, texture2D); - var dataBox = device.ImmediateContext.MapSubresource(texture2D, 0, MapMode.Read, SharpDX.Direct3D11.MapFlags.None); - using var bitmap = new Bitmap(bounds.Width, bounds.Height, PixelFormat.Format32bppArgb); - var bitmapData = bitmap.LockBits(bounds, ImageLockMode.WriteOnly, bitmap.PixelFormat); - var dataBoxPointer = dataBox.DataPointer; - var bitmapDataPointer = bitmapData.Scan0; - for (var y = 0; y < bounds.Height; y++) - { - Utilities.CopyMemory(bitmapDataPointer, dataBoxPointer, bounds.Width * 4); - dataBoxPointer = IntPtr.Add(dataBoxPointer, dataBox.RowPitch); - bitmapDataPointer = IntPtr.Add(bitmapDataPointer, bitmapData.Stride); - } - bitmap.UnlockBits(bitmapData); - device.ImmediateContext.UnmapSubresource(texture2D, 0); - screenResource?.Dispose(); - - switch (dxOutput.Rotation) - { - case DisplayModeRotation.Unspecified: - case DisplayModeRotation.Identity: - break; - case DisplayModeRotation.Rotate90: - bitmap.RotateFlip(RotateFlipType.Rotate270FlipNone); - break; - case DisplayModeRotation.Rotate180: - bitmap.RotateFlip(RotateFlipType.Rotate180FlipNone); - break; - case DisplayModeRotation.Rotate270: - bitmap.RotateFlip(RotateFlipType.Rotate90FlipNone); - break; - default: - break; - } - - return DxCaptureResult.Ok(bitmap.ToSKBitmap(), result); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error while getting DirectX frame."); - } - finally - { - try - { - dxOutput.OutputDuplication.ReleaseFrame(); - } - catch { } - } - - return DxCaptureResult.Fail("Failed to get DirectX frame."); - } - - private void ClearDirectXOutputs() - { - foreach (var screen in _directxScreens.Values) - { - try - { - screen.Dispose(); - } - catch { } - } - - _directxScreens.Clear(); - } - - private void InitBitBlt() - { - _bitBltScreens.Clear(); - - for (var i = 0; i < Screen.AllScreens.Length; i++) - { - _bitBltScreens.Add(Screen.AllScreens[i].DeviceName, i); - } - } - - private void InitDirectX() - { - try - { - ClearDirectXOutputs(); - - using var factory = new Factory1(); - foreach (var adapter in factory.Adapters1.Where(x => (x.Outputs?.Length ?? 0) > 0)) - { - foreach (var output in adapter.Outputs) - { - //_logger.LogWarning(output.Description.DeviceName); - - try - { - var device = new SharpDX.Direct3D11.Device(adapter); - var output1 = output.QueryInterface(); - - var bounds = output1.Description.DesktopBounds; - var width = bounds.Right - bounds.Left; - var height = bounds.Bottom - bounds.Top; - - // Create Staging texture CPU-accessible - var textureDesc = new Texture2DDescription - { - CpuAccessFlags = CpuAccessFlags.Read, - BindFlags = BindFlags.None, - Format = Format.B8G8R8A8_UNorm, - Width = width, - Height = height, - OptionFlags = ResourceOptionFlags.None, - MipLevels = 1, - ArraySize = 1, - SampleDescription = { Count = 1, Quality = 0 }, - Usage = ResourceUsage.Staging - }; - - var texture2D = new Texture2D(device, textureDesc); - - _directxScreens.Add( - output1.Description.DeviceName, - new DirectXOutput(adapter, - device, - output1.DuplicateOutput(device), - texture2D, - output1.Description.Rotation)); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error while initializing DirectX."); - } - } - } - } - catch (Exception ex) - { - _logger.LogError(ex, "Error while initializing DirectX."); - } - } - - private bool IsEmpty(SKBitmap bitmap) - { - if (bitmap is null) return true; - - var height = bitmap.Height; - var width = bitmap.Width; - var bytesPerPixel = bitmap.BytesPerPixel; - - try - { - unsafe - { - byte* scan = (byte*)bitmap.GetPixels(); - - for (var row = 0; row < height; row++) - { - for (var column = 0; column < width; column++) - { - var index = row * width * bytesPerPixel + column * bytesPerPixel; - - byte* data = scan + index; - - for (var i = 0; i < bytesPerPixel; i++) - { - if (data[i] != 0) - { - return false; - } - } - } - } - - return true; - } - } - catch - { - return true; - } - } - - private void RefreshCurrentScreenBounds() - { - CurrentScreenBounds = Screen.AllScreens[_bitBltScreens[SelectedScreen]].Bounds; - - _initialized = false; - } - - private void SystemEvents_DisplaySettingsChanged(object? sender, EventArgs e) - { - RefreshCurrentScreenBounds(); - } - - public void Dispose() - { - try - { - SystemEvents.DisplaySettingsChanged -= SystemEvents_DisplaySettingsChanged; - ClearDirectXOutputs(); - GC.SuppressFinalize(this); - } - catch { } - } - - private class DxCaptureResult - { - public SKBitmap? Bitmap { get; init; } - public SharpDX.Result? DxResult { get; init; } - public string FailureReason { get; init; } = string.Empty; - - [MemberNotNull(nameof(Bitmap))] - public bool HadChanges { get; init; } - - public bool IsSuccess { get; init; } - - internal static DxCaptureResult Fail(string failureReason) - { - return new DxCaptureResult() - { - FailureReason = failureReason - }; - } - - internal static DxCaptureResult Fail(string failureReason, SharpDX.Result dxResult) - { - return new DxCaptureResult() - { - FailureReason = failureReason, - DxResult = dxResult - }; - } - - internal static DxCaptureResult NoAccumulatedFrames(SharpDX.Result dxResult) - { - return new DxCaptureResult() - { - FailureReason = "No frames were accumulated.", - DxResult = dxResult, - IsSuccess = true - }; - } - - internal static DxCaptureResult Ok(SKBitmap sKBitmap, SharpDX.Result result) - { - return new DxCaptureResult() - { - Bitmap = sKBitmap, - DxResult = result, - HadChanges = true, - IsSuccess = true, - }; - } - - internal static DxCaptureResult TryAcquireFailed(SharpDX.Result dxResult) - { - if (dxResult.Code == SharpDX.DXGI.ResultCode.WaitTimeout.Code) - { - return new DxCaptureResult() - { - FailureReason = "Timed out while waiting for the next frame.", - DxResult = dxResult, - IsSuccess = true - }; - } - return new DxCaptureResult() - { - FailureReason = "TryAcquireFrame returned failure.", - DxResult = dxResult - }; - } - } -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Windows/ViewModels/MainViewModel.cs b/src/Remote/Insight.Remote.Windows/ViewModels/MainViewModel.cs deleted file mode 100644 index 8f9c07d..0000000 --- a/src/Remote/Insight.Remote.Windows/ViewModels/MainViewModel.cs +++ /dev/null @@ -1,155 +0,0 @@ -using Insight.Remote.Shared.Abstractions; -using Insight.Remote.Shared.Messages; -using Insight.Remote.Shared.Native.Windows; -using Insight.Remote.Shared.Reactive; -using Microsoft.Extensions.Logging; -using System.Diagnostics; -using System.Security.Principal; -using Vaitr.Bus; - -namespace Insight.Remote.Windows.ViewModels; - -public class MainViewModel : ViewModelBase -{ - public string StatusMessage - { - get => Get() ?? string.Empty; - set => Set(value); - } - - public bool IsAdministrator { get; } = new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator); - public bool CanElevateToAdmin => !IsAdministrator; - public bool CanElevateToService => IsAdministrator && !WindowsIdentity.GetCurrent().IsSystem; - - public RelayCommand ElevateToAdminCommand { get; } - public RelayCommand ElevateToServiceCommand { get; } - - private string? _lastId; - - private readonly List _subscriptions = []; - - private readonly Bus _bus; - private readonly IDispatcher _dispatcher; - private readonly ILogger _logger; - - public MainViewModel(Bus bus, IDispatcher dispatcher, ILogger logger) - { - _bus = bus; - _dispatcher = dispatcher; - _logger = logger; - - ElevateToAdminCommand = new RelayCommand(ElevateToAdmin, () => CanElevateToAdmin); - ElevateToServiceCommand = new RelayCommand(ElevateToService, () => CanElevateToService); - - _subscriptions.Add(_bus.SubscribeAsync(OnConnectionStateChangedAsync, null)); - _subscriptions.Add(_bus.SubscribeAsync(OnIdentityChangedAsync, null)); - } - - private async ValueTask OnConnectionStateChangedAsync(ConnectionStateChanged message, CancellationToken cancellationToken) - { - switch (message.State) - { - case ConnectionState.Connecting: - { - await _dispatcher.InvokeAsync(() => StatusMessage = "Connecting...", cancellationToken); - break; - } - case ConnectionState.Reconnecting: - { - await _dispatcher.InvokeAsync(() => StatusMessage = "Reconnecting...", cancellationToken); - break; - } - case ConnectionState.Connected: - { - await _dispatcher.InvokeAsync(() => StatusMessage = "Connected", cancellationToken); - break; - } - case ConnectionState.Disconnected: - { - await _dispatcher.InvokeAsync(() => StatusMessage = "Disconnected", cancellationToken); - break; - } - case ConnectionState.Error: - { - await _dispatcher.InvokeAsync(() => StatusMessage = "Error", cancellationToken); - break; - } - } - } - - private async ValueTask OnIdentityChangedAsync(IdentityChanged message, CancellationToken cancellationToken) - { - var format = ""; - for (var i = 0; i < message.Id.Length; i += 3) format += $"{message.Id.Substring(i, 3)} "; - - _lastId = format.Trim(); - - if (_lastId is not null) await _dispatcher.InvokeAsync(() => StatusMessage = _lastId, cancellationToken); - } - - public void Shutdown() - { - _dispatcher.ShutdownAsync(); - } - - private void ElevateToAdmin() - { - try - { - var commandLine = Win32Interop.GetCommandLine().Replace(" --elevate", ""); - var sections = commandLine.Split('"', StringSplitOptions.RemoveEmptyEntries); - var filePath = sections.First(); - var arguments = string.Join('"', sections.Skip(1)); - var psi = new ProcessStartInfo(filePath, arguments) - { - Verb = "RunAs", - UseShellExecute = true, - WindowStyle = ProcessWindowStyle.Hidden - }; - Process.Start(psi); - Environment.Exit(0); - } - // Exception can be thrown if UAC is dialog is cancelled. - catch { } - } - - private void ElevateToService() - { - try - { - var psi = new ProcessStartInfo("cmd.exe") - { - WindowStyle = ProcessWindowStyle.Hidden, - CreateNoWindow = true - }; - - var commandLine = Win32Interop.GetCommandLine().Replace(" --elevate", ""); - var sections = commandLine.Split('"', StringSplitOptions.RemoveEmptyEntries); - var filePath = sections.First(); - var arguments = string.Join('"', sections.Skip(1)); - - _logger.LogInformation("Creating temporary service with file path {filePath} and arguments {arguments}.", - filePath, - arguments); - - psi.Arguments = $"/c sc create RemoteControl_Temp binPath=\"{filePath} {arguments} --elevate\""; - Process.Start(psi)?.WaitForExit(); - psi.Arguments = "/c sc start RemoteControl_Temp"; - Process.Start(psi)?.WaitForExit(); - psi.Arguments = "/c sc delete RemoteControl_Temp"; - Process.Start(psi)?.WaitForExit(); - - _dispatcher.ShutdownAsync(); - } - catch { } - } -} - -public class FakeMainViewModel : ViewModelBase -{ - public RelayCommand ElevateToAdminCommand { get; } = new(() => { }); - public RelayCommand ElevateToServiceCommand { get; } = new(() => { }); - - public static bool IsAdministrator => false; - public string StatusMessage { get; set; } = "test"; -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Windows/ViewModels/ViewModelBase.cs b/src/Remote/Insight.Remote.Windows/ViewModels/ViewModelBase.cs deleted file mode 100644 index b1cccf8..0000000 --- a/src/Remote/Insight.Remote.Windows/ViewModels/ViewModelBase.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Insight.Remote.Shared.Reactive; - -namespace Insight.Remote.Windows.ViewModels; - -public interface IViewModelBase -{ - string? ProductName { get; } -} - -public abstract class ViewModelBase : ObservableObject, IViewModelBase -{ - public string? ProductName { get; } = "Remote Control"; -} \ No newline at end of file diff --git a/src/Remote/Insight.Remote.Windows/Views/MainWindow.xaml b/src/Remote/Insight.Remote.Windows/Views/MainWindow.xaml deleted file mode 100644 index 01dc5c2..0000000 --- a/src/Remote/Insight.Remote.Windows/Views/MainWindow.xaml +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Remote/Insight.Remote.Windows/Views/MainWindow.xaml.cs b/src/Remote/Insight.Remote.Windows/Views/MainWindow.xaml.cs deleted file mode 100644 index 838b819..0000000 --- a/src/Remote/Insight.Remote.Windows/Views/MainWindow.xaml.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Insight.Remote.Windows.ViewModels; -using System.ComponentModel; -using System.Windows; -using System.Windows.Input; -using Button = System.Windows.Controls.Button; -using MessageBox = System.Windows.MessageBox; - -namespace Insight.Remote.Windows.Views; - -public partial class MainWindow : Window -{ - public MainViewModel? ViewModel => DataContext as MainViewModel; - - public MainWindow() - { - InitializeComponent(); - } - - public MainWindow(MainViewModel viewModel) - { - DataContext = viewModel; - InitializeComponent(); - } - - private void Window_Loaded(object sender, RoutedEventArgs e) - { - if (DesignerProperties.GetIsInDesignMode(this)) return; - if (DataContext is not MainViewModel) return; - } - - private void Window_Closing(object sender, CancelEventArgs e) - { - if (DataContext is not MainViewModel vm) return; - vm.Shutdown(); - } - - private void OptionsButton_Click(object sender, RoutedEventArgs e) - { - if (sender is not Button button) return; - button.ContextMenu.IsOpen = true; - } - - private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) - { - DragMove(); - } - - private void ElevateToAdminMenuItem_Click(object sender, RoutedEventArgs e) - { - if (DataContext is not MainViewModel vm) return; - - if (vm.ElevateToAdminCommand.CanExecute(null)) vm.ElevateToAdminCommand.Execute(null); - else MessageBox.Show("Unable to execute in current state.", "Unable to Execute", MessageBoxButton.OK, MessageBoxImage.Warning); - } - - private void ElevateToServiceMenuItem_Click(object sender, RoutedEventArgs e) - { - if (DataContext is not MainViewModel vm) return; - - if (vm.ElevateToServiceCommand.CanExecute(null)) vm.ElevateToServiceCommand.Execute(null); - else MessageBox.Show("Unable to execute in current state.", "Unable to Execute", MessageBoxButton.OK, MessageBoxImage.Warning); - } -} \ No newline at end of file diff --git a/src/Server/Insight.Server/Constants/Appsettings.cs b/src/Server/Insight.Server/Constants/Appsettings.cs new file mode 100644 index 0000000..29f0dd7 --- /dev/null +++ b/src/Server/Insight.Server/Constants/Appsettings.cs @@ -0,0 +1,14 @@ +namespace Insight.Server +{ + internal static class Appsettings + { + internal const string AgentServerPort = "agent.server.port"; + internal const string AgentServerCertificate = "agent.server.certificate"; + internal const string AgentServerCertificatePassword = "agent.server.certificate.password"; + internal const string DispatchWebmatic = "dispatch.webmatic"; + + internal const string WebServerPort = "web.server.port"; + internal const string WebServerCertificate = "web.server.certificate"; + internal const string WebServerCertificatePassword = "web.server.certificate.password"; + } +} \ No newline at end of file diff --git a/src/Server/Insight.Server/Controllers/BlankController.cs b/src/Server/Insight.Server/Controllers/BlankController.cs deleted file mode 100644 index e58d21a..0000000 --- a/src/Server/Insight.Server/Controllers/BlankController.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Microsoft.AspNetCore.Mvc; - -namespace Insight.Server.Controllers -{ - [ApiController] - [Route("[controller]")] - public class BlankController(ILogger logger) : ControllerBase - { - private readonly ILogger _logger = logger; - - [HttpGet(Name = "Test")] - public async Task Get() - { - return Ok(); - } - } -} diff --git a/src/Server/Insight.Server/Extensions/Async.cs b/src/Server/Insight.Server/Extensions/Async.cs new file mode 100644 index 0000000..2b41b74 --- /dev/null +++ b/src/Server/Insight.Server/Extensions/Async.cs @@ -0,0 +1,53 @@ +using System.Threading.Tasks.Dataflow; + +namespace Insight.Server.Extensions +{ + public static class Async + { + public static async Task ParallelForEach( + this IAsyncEnumerable source, + Func body, + int maxDegreeOfParallelism = DataflowBlockOptions.Unbounded, + TaskScheduler scheduler = null) + { + var options = new ExecutionDataflowBlockOptions + { + MaxDegreeOfParallelism = maxDegreeOfParallelism + }; + + if (scheduler != null) + options.TaskScheduler = scheduler; + + var block = new ActionBlock(body, options); + + await foreach (var item in source) + block.Post(item); + + block.Complete(); + await block.Completion; + } + + public static async Task ParallelForEach( + this IEnumerable source, + Func body, + int maxDegreeOfParallelism = DataflowBlockOptions.Unbounded, + TaskScheduler scheduler = null) + { + var options = new ExecutionDataflowBlockOptions + { + MaxDegreeOfParallelism = maxDegreeOfParallelism + }; + + if (scheduler != null) + options.TaskScheduler = scheduler; + + var block = new ActionBlock(body, options); + + foreach (var item in source) + block.Post(item); + + block.Complete(); + await block.Completion; + } + } +} diff --git a/src/Server/Insight.Server/Extensions/ConfigurationExtensions.cs b/src/Server/Insight.Server/Extensions/ConfigurationExtensions.cs new file mode 100644 index 0000000..6f0abe0 --- /dev/null +++ b/src/Server/Insight.Server/Extensions/ConfigurationExtensions.cs @@ -0,0 +1,14 @@ +using Microsoft.Extensions.Configuration; + +namespace Insight.Server.Extensions +{ + public static class ConfigurationExtensions + { + public static IConfigurationBuilder Defaults(this IConfigurationBuilder configuration) + { + configuration.Sources.Clear(); + configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true); + return configuration.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true, reloadOnChange: true); + } + } +} \ No newline at end of file diff --git a/src/Server/Insight.Server/Extensions/ServiceExtensions.cs b/src/Server/Insight.Server/Extensions/ServiceExtensions.cs deleted file mode 100644 index 3632a6f..0000000 --- a/src/Server/Insight.Server/Extensions/ServiceExtensions.cs +++ /dev/null @@ -1,150 +0,0 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Infrastructure; -using Insight.Server.Network.Agent; -using Insight.Server.Network.Agent.Handlers; -using Insight.Server.Network.Globals; -using Insight.Server.Network.Web; -using Microsoft.OpenApi.Models; -using OpenTelemetry.Metrics; -using OpenTelemetry.Resources; -using System.Net; -using Vaitr.Network; -using Vaitr.Network.Hosting; - -namespace Insight.Server.Extensions; - -internal static class ServiceExtensions -{ - internal static WebApplicationBuilder AddMetrics(this WebApplicationBuilder builder) - { - builder.Services.AddOpenTelemetry() - .WithMetrics(provider => - { - provider.ConfigureResource(configure => - { - configure.Clear(); - configure.AddService(builder.Configuration.GetValue(Appsettings.Influx.Service) ?? throw new Exception($"{Appsettings.Influx.Service} value not set (appsettings)")); - }) - .AddRuntimeInstrumentation() - .AddProcessInstrumentation() - .AddAspNetCoreInstrumentation() - .AddHttpClientInstrumentation() - //.AddMeter("test") - .AddInfluxDBMetricsExporter(configure => - { - configure.Endpoint = builder.Configuration.GetValue(Appsettings.Influx.Endpoint) ?? throw new Exception($"{Appsettings.Influx.Endpoint} value not set (appsettings)"); - configure.Token = builder.Configuration.GetValue(Appsettings.Influx.Token) ?? throw new Exception($"{Appsettings.Influx.Token} value not set (appsettings)"); - configure.Org = builder.Configuration.GetValue(Appsettings.Influx.Organization) ?? throw new Exception($"{Appsettings.Influx.Organization} value not set (appsettings)"); - configure.Bucket = builder.Configuration.GetValue(Appsettings.Influx.Bucket) ?? throw new Exception($"{Appsettings.Influx.Bucket} value not set (appsettings)"); - - configure.MetricExportIntervalMilliseconds = 1000; - }); - } - ); - - //builder.Services.AddSingleton(); - - return builder; - } - - internal static WebApplicationBuilder AddSwagger(this WebApplicationBuilder builder) - { - builder.Services.AddSwaggerGen(options => - { - options.SwaggerDoc("v1", new OpenApiInfo - { - Title = "Insight Server", - Version = "v1" - }); - }); - - return builder; - } - - internal static WebApplicationBuilder AddAgentBackend(this WebApplicationBuilder builder) - { - // SERVER - builder.Services.UseHostedServer(options => - { - options.Address = IPAddress.Any; - options.Port = builder.Configuration.GetValue(Appsettings.Agent.Port) ?? throw new Exception($"{Appsettings.Agent.Port} value not set (appsettings)"); - options.Keepalive = 10000; - options.Timeout = 30000; - options.Backlog = 128; - - options.Compression = true; - options.Encryption = Encryption.Tls12; - options.Certificate = builder.Configuration.GetValue(Appsettings.Agent.Certificate) ?? throw new Exception($"{Appsettings.Agent.Certificate} value not set (appsettings)"); - options.CertificatePassword = builder.Configuration.GetValue(Appsettings.Agent.CertificatePassword) ?? throw new Exception($"{Appsettings.Agent.CertificatePassword} value not set (appsettings)"); - - options.UseSerializer>(); - }); - - // HANDLER - builder.Services.AddSingleton, CustomHandler>(); - builder.Services.AddSingleton, ProxyHandler>(); - builder.Services.AddSingleton, DriveHandler>(); - builder.Services.AddSingleton, Network.Agent.Handlers.EventHandler>(); - builder.Services.AddSingleton, InterfaceHandler>(); - builder.Services.AddSingleton, MainboardHandler>(); - builder.Services.AddSingleton, MemoryHandler>(); - builder.Services.AddSingleton, OperationSystemHandler>(); - builder.Services.AddSingleton, PrinterHandler>(); - builder.Services.AddSingleton, ProcessorHandler>(); - builder.Services.AddSingleton, ServiceHandler>(); - builder.Services.AddSingleton, SessionHandler>(); - builder.Services.AddSingleton, SoftwareHandler>(); - builder.Services.AddSingleton, StoragePoolHandler>(); - builder.Services.AddSingleton, SystemInfoHandler>(); - builder.Services.AddSingleton, TrapHandler>(); - builder.Services.AddSingleton, UpdateHandler>(); - builder.Services.AddSingleton, UserHandler>(); - builder.Services.AddSingleton, VideocardHandler>(); - builder.Services.AddSingleton, VirtualMaschineHandler>(); - - return builder; - } - - internal static WebApplicationBuilder AddWebBackend(this WebApplicationBuilder builder) - { - // SERVER - builder.Services.UseHostedServer(options => - { - options.Address = IPAddress.Any; - options.Port = builder.Configuration.GetValue(Appsettings.Web.Port) ?? throw new Exception($"{Appsettings.Web.Port} value not set (appsettings)"); - options.Keepalive = 10000; - options.Timeout = 30000; - options.Backlog = 128; - options.Encryption = Encryption.Tls12; - options.Compression = true; - - options.Certificate = builder.Configuration.GetValue(Appsettings.Web.Certificate) ?? throw new Exception($"{Appsettings.Web.Certificate} value not set (appsettings)"); - options.CertificatePassword = builder.Configuration.GetValue(Appsettings.Web.CertificatePassword) ?? throw new Exception($"{Appsettings.Web.CertificatePassword} value not set (appsettings)"); - - options.UseSerializer>(); - }); - - // HANDLER - builder.Services.AddSingleton, ProxyHandler>(); - - return builder; - } - - internal static WebApplication ConfigureSwagger(this WebApplication app) - { - app.UseSwagger(options => - { - options.RouteTemplate = "api/swagger/{documentName}/swagger.json"; - }); - - app.UseSwaggerUI(options => - { - options.DefaultModelsExpandDepth(-1); - options.SwaggerEndpoint("/api/swagger/v1/swagger.json", "v1"); - options.RoutePrefix = "api/swagger"; - }); - - return app; - } -} \ No newline at end of file diff --git a/src/Server/Insight.Server/Insight.Server.csproj b/src/Server/Insight.Server/Insight.Server.csproj index 41d6fbe..8c489df 100644 --- a/src/Server/Insight.Server/Insight.Server.csproj +++ b/src/Server/Insight.Server/Insight.Server.csproj @@ -1,43 +1,75 @@ - + - Exe - net8.0 - latest - Insight - server - 2024.1.10.0 - Insight.Server - enable - enable - none - true + Exe + net7.0 + latest + Insight + server + 2025.2.24.0 + 2025.2.24.0 + Insight.Server + enable + enable + none + true + + none + + + + none + + - - - - - - - - - - - + + - - + + Always + true + PreserveNewest + + + Always + true + PreserveNewest + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + true + Never + diff --git a/src/Server/Insight.Server/Insight.Server.http b/src/Server/Insight.Server/Insight.Server.http deleted file mode 100644 index 4d3b8e8..0000000 --- a/src/Server/Insight.Server/Insight.Server.http +++ /dev/null @@ -1,6 +0,0 @@ -@Insight.Server2_HostAddress = http://localhost:5197 - -GET {{Insight.Server2_HostAddress}}/weatherforecast/ -Accept: application/json - -### diff --git a/src/Server/Insight.Server/Models/MonitorMessage.cs b/src/Server/Insight.Server/Models/MonitorMessage.cs index 3886d21..e3eef9a 100644 --- a/src/Server/Insight.Server/Models/MonitorMessage.cs +++ b/src/Server/Insight.Server/Models/MonitorMessage.cs @@ -1,26 +1,27 @@ -using Insight.Domain.Enums; +using Insight.Agent.Enums; -namespace Insight.Server.Models; - -internal class MonitorMessage +namespace Insight.Server.Models { - public DateTime? Timestamp { get; set; } - public string? Community { get; set; } - public ApplicationEnum? Application { get; set; } - public CategoryEnum? Category { get; set; } - public StatusEnum? Status { get; set; } - public string? Endpoint { get; set; } - public string? Hostname { get; set; } - public string? Subject { get; set; } - public string? Message { get; set; } - - public enum ApplicationEnum + internal class MonitorMessage { - Unknown = 0, - Insight = 1, - Acronis = 2, - Veeam = 3, - QNAP = 4, - FreeNas = 5 + public DateTime? Timestamp { get; set; } + public string? Community { get; set; } + public ApplicationEnum? Application { get; set; } + public CategoryEnum? Category { get; set; } + public StatusEnum? Status { get; set; } + public string? Endpoint { get; set; } + public string? Hostname { get; set; } + public string? Subject { get; set; } + public string? Message { get; set; } + + public enum ApplicationEnum + { + Unknown = 0, + Insight = 1, + Acronis = 2, + Veeam = 3, + QNAP = 4, + FreeNas = 5 + } } } diff --git a/src/Server/Insight.Server/Network/Agent/AgentSession.cs b/src/Server/Insight.Server/Network/Agent/AgentSession.cs deleted file mode 100644 index 363853e..0000000 --- a/src/Server/Insight.Server/Network/Agent/AgentSession.cs +++ /dev/null @@ -1,203 +0,0 @@ -using Insight.Domain.Enums; -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; -using Insight.Infrastructure.Entities; -using MongoDB.Driver; -using Vaitr.Network; - -namespace Insight.Server.Network.Agent; - -public class AgentSession( - IMongoDatabase database, - IEnumerable> handlers, - ISerializer serializer, - ILogger logger) : TcpSession(serializer, logger) -{ - public string? Id { get; set; } - - private readonly IMongoDatabase _database = database; - private readonly IEnumerable> _handlers = handlers; - - protected override async ValueTask OnConnectedAsync(CancellationToken cancellationToken) - { - _logger.LogInformation("Agent ({ep?}) connected", RemoteEndPoint); - - // auth request - await SendAsync(new AuthenticationRequest(), cancellationToken); - - // wait for ack - for (int i = 0; i < 200; i++) - { - if (Id is not null) - break; - - await Task.Delay(50, cancellationToken).ConfigureAwait(false); - } - - // if ack not received - if (Id is null) - { - _logger.LogError("Agent ({ep?}) authentication timeout", RemoteEndPoint); - Disconnect(); - return; - } - - _logger.LogInformation("Agent ({ep?} / {id}) authenticated", RemoteEndPoint, Id); - - // insert log - await WriteLogAsync(CategoryEnum.Network, StatusEnum.Information, $"Connected ({RemoteEndPoint})", default); - - // update entity - await UpdateAsync(default); - - // init inventory task - _ = InitInventoryAsync(cancellationToken); - } - - protected override async ValueTask OnDisconnectedAsync(CancellationToken cancellationToken) - { - _logger.LogInformation("Agent ({ep?}) disconnected", RemoteEndPoint); - - // insert log - await WriteLogAsync(CategoryEnum.Network, StatusEnum.Information, $"Disconnected ({RemoteEndPoint})", default); - - // update entity - await UpdateAsync(default); - } - - protected override async ValueTask OnSentAsync(IPacketContext context, CancellationToken cancellationToken) - { - await base.OnSentAsync(context, cancellationToken); - - // update entity - await UpdateAsync(cancellationToken); - } - - protected override async ValueTask OnReceivedAsync(IPacketContext context, CancellationToken cancellationToken) - { - await base.OnReceivedAsync(context, cancellationToken); - - // only accept auth response if not authenticated - if (Id is null) - { - if (context.Packet is not AuthenticationResponse authentication) return; - await OnAuthenticationAsync(authentication, cancellationToken); - } - - // update entity - await UpdateAsync(cancellationToken); - - // pass message to handlers - foreach (var handler in _handlers) - { - try - { - await handler.HandleAsync(this, context.Packet, cancellationToken); - } - catch (Exception ex) - { - _logger.LogWarning("Agent ({ep?}) {ex}", RemoteEndPoint, ex.ToString()); - } - } - } - - protected override async ValueTask OnHeartbeatAsync(CancellationToken cancellationToken) - { - _logger.LogInformation("Agent ({ep?}) Heartbeat", RemoteEndPoint); - - // update entity - await UpdateAsync(cancellationToken); - } - - private async ValueTask OnAuthenticationAsync(AuthenticationResponse authentication, CancellationToken cancellationToken) - { - // check serial - if (authentication.Serial == default) - throw new InvalidDataException($"authentication failed ({nameof(authentication.Serial)})"); - - // check version - //if (authentication.Version == default || authentication.Version < Domain.Constants.Configuration.Version) - // throw new InvalidDataException($"authentication failed ({nameof(authentication.Version)})"); - - // upsert agent - await _database.Agent() - .UpdateOneAsync(Builders - .Filter - .Eq(p => p.Serial, authentication.Serial.ToString()), Builders.Update - .SetOnInsert(p => p.Insert, DateTime.Now) - .SetOnInsert(p => p.Serial, authentication.Serial.ToString()) - .Set(p => p.Update, DateTime.Now) - .Set(p => p.Connected, DateTime.Now) - .Set(p => p.Version, authentication.Version) - .Set(p => p.Endpoint, RemoteEndPoint?.ToString()) - .Set(p => p.Hostname, authentication.Hostname), new UpdateOptions - { - IsUpsert = true - }, cancellationToken) - .ConfigureAwait(false); - - // get agent - var agentEntity = await _database.Agent() - .Find(Builders - .Filter - .Eq(p => p.Serial, authentication.Serial.ToString())) - .FirstOrDefaultAsync(cancellationToken) - .ConfigureAwait(false); - - // set session id - Id = agentEntity.Id; - } - - private async ValueTask WriteLogAsync(CategoryEnum category, StatusEnum status, string message, CancellationToken cancellationToken) - { - await _database.AgentLog() - .InsertOneAsync(new AgentLogEntity - { - Insert = DateTime.Now, - Agent = Id, - Category = category.ToString(), - Status = status.ToString(), - Message = message, - Timestamp = DateTime.Now - }, cancellationToken: cancellationToken) - .ConfigureAwait(false); - } - - private async ValueTask UpdateAsync(CancellationToken cancellationToken) - { - await _database.Agent().UpdateOneAsync(Builders - .Filter - .Eq(p => p.Id, Id), Builders - .Update - .Set(p => p.Update, DateTime.Now) - .Set(p => p.Activity, Activity) - .Set(p => p.SentBytes, SentBytes) - .Set(p => p.SentPackets, SentPackets) - .Set(p => p.ReceivedBytes, ReceivedBytes) - .Set(p => p.ReceivedPackets, ReceivedPackets), null, cancellationToken) - .ConfigureAwait(false); - } - - private async Task InitInventoryAsync(CancellationToken cancellationToken) - { - while (cancellationToken.IsCancellationRequested is false) - { - // find assigned host - var hostCount = await _database.Host() - .CountDocumentsAsync(Builders.Filter.Eq(p => p.Agent, Id), cancellationToken: cancellationToken) - .ConfigureAwait(false); - - // if not assigned => short delay - if (hostCount == 0) - { - await Task.Delay(TimeSpan.FromMinutes(1), cancellationToken); - continue; - } - - // send request - await SendAsync(new InventoryRequest(), cancellationToken); - await Task.Delay(TimeSpan.FromHours(1), cancellationToken); - } - } -} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Agent/Handlers/CustomHandler.cs b/src/Server/Insight.Server/Network/Agent/Handlers/CustomHandler.cs deleted file mode 100644 index 14e1e87..0000000 --- a/src/Server/Insight.Server/Network/Agent/Handlers/CustomHandler.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; -using Microsoft.Extensions.Logging; - -namespace Insight.Server.Network.Agent.Handlers; - -public class CustomHandler(ILogger logger) : IMessageHandler -{ - private readonly ILogger _logger = logger; - - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage - { - switch (message) - { - case Response response: - await OnResponseAsync(sender, response, cancellationToken); - break; - } - } - - private ValueTask OnResponseAsync(AgentSession sender, Response response, CancellationToken cancellationToken) - { - _logger.LogWarning("Response: {response}", response.ResponseData); - return default; - } -} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Agent/Handlers/DriveHandler.cs b/src/Server/Insight.Server/Network/Agent/Handlers/DriveHandler.cs deleted file mode 100644 index 2fe86a6..0000000 --- a/src/Server/Insight.Server/Network/Agent/Handlers/DriveHandler.cs +++ /dev/null @@ -1,141 +0,0 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; -using Insight.Infrastructure.Entities; -using MongoDB.Bson; -using MongoDB.Driver; - -namespace Insight.Server.Network.Agent.Handlers; - -public class DriveHandler(IMongoDatabase database) : IMessageHandler -{ - private readonly IMongoDatabase _database = database; - - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage - { - switch (message) - { - case Collection drives: - await OnDrivesAsync(sender, drives, cancellationToken); - break; - } - } - - private async ValueTask OnDrivesAsync(AgentSession session, List drives, CancellationToken cancellationToken) - { - var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); - if (agentEntity is null) return; - - var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); - if (hostEntity is null) return; - - var batch = ObjectId.GenerateNewId().ToString(); - var date = DateTime.Now; - - var driveBulk = new List>(); - - if (drives is not null && drives.Count != 0) - { - foreach (var drive in drives) - { - var driveFilter = Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Eq(x => x.Index, drive.Index) - }); - - var driveUpdate = Builders.Update - .SetOnInsert(p => p.Insert, date) - .SetOnInsert(p => p.Host, hostEntity.Id) - .SetOnInsert(p => p.Index, drive.Index) - .Set(p => p.Update, date) - .Set(p => p.Batch, batch) - .Set(p => p.Company, drive.Manufacturer) - .Set(p => p.Name, drive.Name) - .Set(p => p.Size, drive.Size) - .Set(p => p.Type, drive.InterfaceType) - .Set(p => p.Serial, drive.SerialNumber) - .Set(p => p.Firmware, drive.FirmwareRevision) - .Set(p => p.Status, drive.Status) - .Set(p => p.Pnp, drive.PNPDeviceID); - - driveBulk.Add(new UpdateOneModel(driveFilter, driveUpdate) - { - IsUpsert = true - }); - } - } - - driveBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Ne(x => x.Batch, batch) - }))); - - var driveResult = await _database.HostDrive().BulkWriteAsync(driveBulk, cancellationToken: cancellationToken); - - // volumes - - var volumeBulk = new List>(); - - if (drives is not null && drives.Count != 0) - { - foreach (var drive in drives) - { - var driveId = await _database.HostDrive() - .Find(p => p.Host == hostEntity.Id && p.Index == drive.Index) - .Project(p => p.Id) - .FirstOrDefaultAsync(cancellationToken: default); - - if (drive.Volumes is not null && drive.Volumes.Count != 0) - { - foreach (var volume in drive.Volumes) - { - var volumeFilter = Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Eq(x => x.Drive, driveId), - Builders.Filter.Eq(x => x.Index, volume.Index) - }); - - var volumeUpdate = Builders.Update - .SetOnInsert(p => p.Insert, date) - .SetOnInsert(p => p.Host, hostEntity.Id) - .SetOnInsert(p => p.Drive, driveId) - .SetOnInsert(p => p.Index, volume.Index) - .Set(p => p.Update, date) - .Set(p => p.Batch, batch) - .Set(p => p.Name, volume.Name) - .Set(p => p.Label, volume.Id) - .Set(p => p.Serial, volume.SerialNumber) - .Set(p => p.Size, volume.Size) - .Set(p => p.FreeSpace, volume.FreeSpace) - .Set(p => p.Type, volume.Type) - .Set(p => p.FileSystem, volume.FileSystem) - .Set(p => p.Compressed, volume.Compressed) - .Set(p => p.Bootable, volume.Bootable) - .Set(p => p.Primary, volume.PrimaryPartition) - .Set(p => p.Boot, volume.Bootable) - .Set(p => p.BlockSize, volume.BlockSize) - .Set(p => p.Blocks, volume.NumberOfBlocks) - .Set(p => p.StartingOffset, volume.StartingOffset) - .Set(p => p.Provider, volume.ProviderName); - - volumeBulk.Add(new UpdateOneModel(volumeFilter, volumeUpdate) - { - IsUpsert = true - }); - } - } - } - } - - volumeBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Ne(x => x.Batch, batch) - }))); - - var volumeResult = await _database.HostVolume().BulkWriteAsync(volumeBulk, cancellationToken: cancellationToken); - } -} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Agent/Handlers/EventHandler.cs b/src/Server/Insight.Server/Network/Agent/Handlers/EventHandler.cs deleted file mode 100644 index ee6080c..0000000 --- a/src/Server/Insight.Server/Network/Agent/Handlers/EventHandler.cs +++ /dev/null @@ -1,261 +0,0 @@ -using Insight.Domain.Enums; -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; -using Insight.Infrastructure.Entities; -using MongoDB.Driver; -using static Insight.Domain.Network.Agent.Messages.Event; - -namespace Insight.Server.Network.Agent.Handlers; - -public class EventHandler(IMongoDatabase database) : IMessageHandler -{ - private readonly IMongoDatabase _database = database; - - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage - { - switch (message) - { - case Event @event: - await OnEventAsync(sender, @event, cancellationToken); - break; - } - } - - private async ValueTask OnEventAsync(AgentSession session, Event @event, CancellationToken cancellationToken) - { - var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); - if (agentEntity is null) return; - - var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); - if (hostEntity is null) return; - - if (FilterEventId(@event)) return; - - var hostLog = await InsertHostLogAsync(hostEntity, @event, cancellationToken); - - if (hostLog is null || FilterMonitoringHostLog(hostLog)) return; - - await _database.HostLogMonitoring() - .InsertOneAsync(new HostLogMonitoringEntity - { - Host = hostEntity.Id, - Insert = hostLog.Insert, - Timestamp = hostLog.Timestamp, - Category = hostLog.Category, - Status = hostLog.Status, - Message = hostLog.Message, - Dispatch = DispatchEnum.Pending.ToString() - }, cancellationToken: cancellationToken); - } - - private async ValueTask InsertAgentLogAsync(AgentSession session, Event @event, CancellationToken cancellationToken) - { - var agentEntity = await _database.Agent() - .Aggregate() - .Match(Builders.Filter.Eq(p => p.Id, session.Id)) - .Lookup(_database.Host(), p => p.Serial, p => p.Agent, p => p.Hosts) - .FirstOrDefaultAsync(cancellationToken); - - if (agentEntity is null) return null; - - StatusEnum? status = @event.Status switch - { - StatusType.Information => StatusEnum.Information, - StatusType.Warning => StatusEnum.Warning, - StatusType.Error => StatusEnum.Error, - _ => null - }; - - CategoryEnum? category = @event.Category?.ToLower() switch - { - "network" => CategoryEnum.Network, - "application" => CategoryEnum.Application, - "security" => CategoryEnum.Security, - "system" => CategoryEnum.System, - _ => CategoryEnum.None - }; - - var date = DateTime.Now; - - var log = new AgentLogEntity - { - Insert = date, - Agent = agentEntity.Id, - Timestamp = @event.Timestamp, - EventId = @event.EventId.ToString(), - Source = @event.Source, - Status = status.ToString(), - Category = category.ToString(), - Message = @event.Message - }; - - await _database.AgentLog().InsertOneAsync(log, cancellationToken: cancellationToken); - return log; - } - - private async ValueTask InsertHostLogAsync(HostEntity hostEntity, Event @event, CancellationToken cancellationToken) - { - StatusEnum? status = @event.Status switch - { - StatusType.Information => StatusEnum.Information, - StatusType.Warning => StatusEnum.Warning, - StatusType.Error => StatusEnum.Error, - StatusType.Critical => StatusEnum.Error, - StatusType.Unknown => null, - _ => null - }; - - var category = CategoryEnum.None; - - if (@event.Category is not null) - { - switch (@event.Category) - { - case var _ when @event.Category.Contains("network", StringComparison.InvariantCultureIgnoreCase): - category = CategoryEnum.Network; - break; - - case var _ when @event.Category.Contains("application", StringComparison.InvariantCultureIgnoreCase): - category = CategoryEnum.Application; - break; - - case var _ when @event.Category.Contains("security", StringComparison.InvariantCultureIgnoreCase): - category = CategoryEnum.Security; - break; - - case var _ when @event.Category.Contains("system", StringComparison.InvariantCultureIgnoreCase): - category = CategoryEnum.System; - break; - - case var _ when @event.Category.Contains("printservice", StringComparison.InvariantCultureIgnoreCase): - category = CategoryEnum.Printer; - break; - - case var _ when @event.Category.Contains("taskscheduler", StringComparison.InvariantCultureIgnoreCase): - category = CategoryEnum.Task; - break; - - case var _ when @event.Category.Contains("terminalservices", StringComparison.InvariantCultureIgnoreCase): - category = CategoryEnum.RDP; - break; - - case var _ when @event.Category.Contains("smbclient", StringComparison.InvariantCultureIgnoreCase): - category = CategoryEnum.Network; - break; - - case var _ when @event.Category.Contains("smbserver", StringComparison.InvariantCultureIgnoreCase): - category = CategoryEnum.Network; - break; - - case var _ when @event.Category.Contains("storagespaces", StringComparison.InvariantCultureIgnoreCase): - category = CategoryEnum.System; - break; - - case var _ when @event.Category.Contains("diagnostics", StringComparison.InvariantCultureIgnoreCase): - category = CategoryEnum.System; - break; - - default: - break; - } - } - - var date = DateTime.Now; - - var log = new HostLogEntity - { - Insert = date, - Host = hostEntity.Id, - Timestamp = @event.Timestamp, - EventId = @event.EventId.ToString(), - Status = status.ToString(), - Source = @event.Source, - Category = category.ToString(), - Message = @event.Message - }; - - await _database.HostLog().InsertOneAsync(log, cancellationToken: cancellationToken); - return log; - } - - private static bool FilterEventId(Event @event) - { - var filter = new List - { - 0, - 3, - 4, - 16, - 37, - 900, - 902, - 903, - 1001, - 1003, - 1008, - 1023, - 1066, - 4624, - 4625, - 4634, - 4648, - 4672, - 4776, - 4798, - 4799, - 5058, - 5059, - 5061, - 5379, - 5612, - 5781, - //7036, - 8014, - 8016, - 8019, - 8194, - 8224, - 9009, - 9027, - 10001, - 10016, - 16384, - 16394, - 36874, - 36888, - }; - - if (filter.Any(p => p == @event.EventId)) return true; - return false; - } - - private static bool FilterMonitoringHostLog(HostLogEntity hostLog) - { - if (Enum.TryParse(hostLog.Status, out StatusType status) is false) return true; - - if (hostLog.Category == CategoryEnum.System.ToString()) - { - if (hostLog.Source == "Service Control Manager" && status < StatusType.Warning) return true; - } - - if (hostLog.Category == CategoryEnum.Task.ToString()) - { - if (status < StatusType.Error) return true; - } - - // skip rdp infos - if (hostLog.Category == CategoryEnum.RDP.ToString()) - { - if (hostLog.EventId == "261") return true; - } - - // skip smbclient (veeam errors) - if (hostLog.Category == CategoryEnum.Security.ToString()) - { - if (hostLog.Source == "Microsoft-Windows-SMBClient") return true; - } - - return false; - } -} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Agent/Handlers/InterfaceHandler.cs b/src/Server/Insight.Server/Network/Agent/Handlers/InterfaceHandler.cs deleted file mode 100644 index c986aad..0000000 --- a/src/Server/Insight.Server/Network/Agent/Handlers/InterfaceHandler.cs +++ /dev/null @@ -1,295 +0,0 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; -using Insight.Infrastructure.Entities; -using MongoDB.Bson; -using MongoDB.Driver; - -namespace Insight.Server.Network.Agent.Handlers; - -public class InterfaceHandler(IMongoDatabase database) : IMessageHandler -{ - private readonly IMongoDatabase _database = database; - - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage - { - switch (message) - { - case Collection interfaces: - await OnInterfacesAsync(sender, interfaces, cancellationToken); - break; - } - } - - private async ValueTask OnInterfacesAsync(AgentSession session, List interfaces, CancellationToken cancellationToken) - { - var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); - if (agentEntity is null) return; - - var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); - if (hostEntity is null) return; - - var batch = ObjectId.GenerateNewId().ToString(); - var date = DateTime.Now; - - // interfaces - - if (interfaces is not null && interfaces.Count != 0) - { - var interfaceBulk = new List>(); - - foreach (var @interface in interfaces) - { - var interfaceFilter = Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Eq(x => x.Index, @interface.Index) - }); - - var interfaceUpdate = Builders.Update - .SetOnInsert(p => p.Insert, date) - .SetOnInsert(p => p.Host, hostEntity.Id) - .SetOnInsert(p => p.Index, @interface.Index) - .Set(p => p.Update, date) - .Set(p => p.Batch, batch) - - .Set(p => p.Mac, @interface?.Mac) - .Set(p => p.Name, @interface?.Name) - .Set(p => p.Description, @interface?.Description) - .Set(p => p.Physical, @interface?.Physical) - .Set(p => p.Status, @interface?.Status?.ToString()) - .Set(p => p.Suffix, @interface?.Suffix) - .Set(p => p.Speed, @interface?.Speed) - .Set(p => p.Ipv4Mtu, @interface?.Ipv4Mtu) - .Set(p => p.Ipv4Dhcp, @interface?.Ipv4Dhcp) - - .Set(p => p.Ipv4Forwarding, @interface?.Ipv4Forwarding) - .Set(p => p.Ipv6Mtu, @interface?.Ipv6Mtu) - .Set(p => p.Sent, @interface?.Sent) - .Set(p => p.Received, @interface?.Received) - .Set(p => p.IncomingPacketsDiscarded, @interface?.IncomingPacketsDiscarded) - .Set(p => p.IncomingPacketsWithErrors, @interface?.IncomingPacketsWithErrors) - .Set(p => p.IncomingUnknownProtocolPackets, @interface?.IncomingUnknownProtocolPackets) - .Set(p => p.OutgoingPacketsDiscarded, @interface?.OutgoingPacketsDiscarded) - .Set(p => p.OutgoingPacketsWithErrors, @interface?.OutgoingPacketsWithErrors); - - interfaceBulk.Add(new UpdateOneModel(interfaceFilter, interfaceUpdate) - { - IsUpsert = true - }); - } - - interfaceBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Ne(x => x.Batch, batch) - }))); - - var interfaceResult = await _database.HostInterface().BulkWriteAsync(interfaceBulk, cancellationToken: cancellationToken); - } - - // addresses - - if (interfaces is not null && interfaces.Count != 0) - { - var addressBulk = new List>(); - - foreach (var @interface in interfaces) - { - var interfaceId = await _database.HostInterface() - .Find(p => p.Host == hostEntity.Id && p.Index == @interface.Index) - .Project(p => p.Id) - .FirstOrDefaultAsync(cancellationToken: default); - - if (@interface.Addresses is not null && @interface.Addresses.Count != 0) - { - foreach (var address in @interface.Addresses) - { - var addressFilter = Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Eq(x => x.Interface, interfaceId), - Builders.Filter.Eq(x => x.Address, address?.IpAddress?.Address), - Builders.Filter.Eq(x => x.Mask, address?.Ipv4Mask?.Address) - }); - - var addressUpdate = Builders.Update - .SetOnInsert(p => p.Insert, date) - .SetOnInsert(p => p.Host, hostEntity.Id) - .SetOnInsert(p => p.Interface, interfaceId) - .SetOnInsert(p => p.Address, address?.IpAddress?.Address) - .SetOnInsert(p => p.Mask, address?.Ipv4Mask?.Address) - .Set(p => p.Update, date) - .Set(p => p.Batch, batch); - - addressBulk.Add(new UpdateOneModel(addressFilter, addressUpdate) - { - IsUpsert = true - }); - } - } - } - - addressBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Ne(x => x.Batch, batch) - }))); - - var addressResult = await _database.HostInterfaceAddress().BulkWriteAsync(addressBulk, cancellationToken: cancellationToken); - } - - // gateways - - if (interfaces is not null && interfaces.Count != 0) - { - var gatewayBulk = new List>(); - - foreach (var @interface in interfaces) - { - var interfaceId = await _database.HostInterface() - .Find(p => p.Host == hostEntity.Id && p.Index == @interface.Index) - .Project(p => p.Id) - .FirstOrDefaultAsync(cancellationToken: default); - - if (@interface.Gateways is not null && @interface.Gateways.Count != 0) - { - foreach (var gateway in @interface.Gateways) - { - var gatewayFilter = Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Eq(x => x.Interface, interfaceId), - Builders.Filter.Eq(x => x.Address, gateway?.Address) - }); - - var gatewayUpdate = Builders.Update - .SetOnInsert(p => p.Insert, date) - .SetOnInsert(p => p.Host, hostEntity.Id) - .SetOnInsert(p => p.Interface, interfaceId) - .SetOnInsert(p => p.Address, gateway?.Address) - .Set(p => p.Update, date) - .Set(p => p.Batch, batch); - - gatewayBulk.Add(new UpdateOneModel(gatewayFilter, gatewayUpdate) - { - IsUpsert = true - }); - } - } - } - - gatewayBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Ne(x => x.Batch, batch) - }))); - - var gatewayResult = await _database.HostInterfaceGateway().BulkWriteAsync(gatewayBulk, cancellationToken: cancellationToken); - } - - // nameservers - - if (interfaces is not null && interfaces.Count != 0) - { - var nameserverBulk = new List>(); - - foreach (var @interface in interfaces) - { - var interfaceId = await _database.HostInterface() - .Find(p => p.Host == hostEntity.Id && p.Index == @interface.Index) - .Project(p => p.Id) - .FirstOrDefaultAsync(cancellationToken: default); - - if (@interface.Dns is not null && @interface.Dns.Count != 0) - { - foreach (var nameserver in @interface.Dns) - { - var nameserverFilter = Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Eq(x => x.Interface, interfaceId), - Builders.Filter.Eq(x => x.Address, nameserver?.Address) - }); - - var nameserverUpdate = Builders.Update - .SetOnInsert(p => p.Insert, date) - .SetOnInsert(p => p.Host, hostEntity.Id) - .SetOnInsert(p => p.Interface, interfaceId) - .SetOnInsert(p => p.Address, nameserver?.Address) - .Set(p => p.Update, date) - .Set(p => p.Batch, batch); - - nameserverBulk.Add(new UpdateOneModel(nameserverFilter, nameserverUpdate) - { - IsUpsert = true - }); - } - } - } - - nameserverBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Ne(x => x.Batch, batch) - }))); - - var nameserverResult = await _database.HostInterfaceNameserver().BulkWriteAsync(nameserverBulk, cancellationToken: cancellationToken); - } - - // routes - - if (interfaces is not null && interfaces.Count != 0) - { - var routeBulk = new List>(); - - foreach (var @interface in interfaces) - { - var interfaceId = await _database.HostInterface() - .Find(p => p.Host == hostEntity.Id && p.Index == @interface.Index) - .Project(p => p.Id) - .FirstOrDefaultAsync(cancellationToken: default); - - if (@interface.Routes is not null && @interface.Routes.Count != 0) - { - foreach (var route in @interface.Routes) - { - var routeFilter = Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Eq(x => x.Interface, interfaceId), - Builders.Filter.Eq(x => x.Destination, route?.Destination?.Address), - Builders.Filter.Eq(x => x.Gateway, route?.Gateway?.Address), - Builders.Filter.Eq(x => x.Mask, route?.Mask), - }); - - var routeUpdate = Builders.Update - .SetOnInsert(p => p.Insert, date) - .SetOnInsert(p => p.Host, hostEntity.Id) - .SetOnInsert(p => p.Interface, interfaceId) - .SetOnInsert(p => p.Destination, route?.Destination?.Address) - .SetOnInsert(p => p.Gateway, route?.Gateway?.Address) - .SetOnInsert(p => p.Mask, route?.Mask) - .Set(p => p.Update, date) - .Set(p => p.Batch, batch) - - .Set(p => p.Metric, route?.Metric); - - routeBulk.Add(new UpdateOneModel(routeFilter, routeUpdate) - { - IsUpsert = true - }); - } - } - } - - routeBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Ne(x => x.Batch, batch) - }))); - - var routeResult = await _database.HostInterfaceRoute().BulkWriteAsync(routeBulk, cancellationToken: cancellationToken); - } - } -} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Agent/Handlers/MemoryHandler.cs b/src/Server/Insight.Server/Network/Agent/Handlers/MemoryHandler.cs deleted file mode 100644 index 97e1ae5..0000000 --- a/src/Server/Insight.Server/Network/Agent/Handlers/MemoryHandler.cs +++ /dev/null @@ -1,79 +0,0 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; -using Insight.Infrastructure.Entities; -using MongoDB.Bson; -using MongoDB.Driver; - -namespace Insight.Server.Network.Agent.Handlers; - -public class MemoryHandler(IMongoDatabase database) : IMessageHandler -{ - private readonly IMongoDatabase _database = database; - - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage - { - switch (message) - { - case Collection memory: - await OnMemoryAsync(sender, memory, cancellationToken); - break; - } - } - - private async ValueTask OnMemoryAsync(AgentSession session, List memory, CancellationToken cancellationToken) - { - var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); - if (agentEntity is null) return; - - var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); - if (hostEntity is null) return; - - var batch = ObjectId.GenerateNewId().ToString(); - var date = DateTime.Now; - - var bulk = new List>(); - - if (memory is not null && memory.Count != 0) - { - foreach (var mem in memory) - { - var filterDefinition = Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Eq(x => x.Index, mem.Index) - }); - - var updateDefinition = Builders.Update - .SetOnInsert(p => p.Insert, date) - .SetOnInsert(p => p.Host, hostEntity.Id) - .SetOnInsert(p => p.Index, mem.Index) - .Set(p => p.Update, date) - .Set(p => p.Batch, batch) - .Set(p => p.Company, mem.Manufacturer) - .Set(p => p.Name, mem.Model) - .Set(p => p.Tag, mem.Tag) - .Set(p => p.Location, mem.Location) - .Set(p => p.Serial, mem.Serial) - .Set(p => p.Capacity, mem.Capacity) - .Set(p => p.Clock, mem.Speed) - .Set(p => p.CurrentClock, mem.ConfiguredSpeed) - .Set(p => p.Voltage, mem.Voltage) - .Set(p => p.CurrentVoltage, mem.ConfiguredVoltage); - - bulk.Add(new UpdateOneModel(filterDefinition, updateDefinition) - { - IsUpsert = true - }); - } - } - - bulk.Add(new DeleteManyModel(Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Ne(x => x.Batch, batch) - }))); - - var result = await _database.HostMemory().BulkWriteAsync(bulk, cancellationToken: cancellationToken); - } -} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Agent/Handlers/OperationSystemHandler.cs b/src/Server/Insight.Server/Network/Agent/Handlers/OperationSystemHandler.cs deleted file mode 100644 index 3fb0d47..0000000 --- a/src/Server/Insight.Server/Network/Agent/Handlers/OperationSystemHandler.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; -using Insight.Infrastructure.Entities; -using MongoDB.Driver; - -namespace Insight.Server.Network.Agent.Handlers; - -public class OperationSystemHandler(IMongoDatabase database) : IMessageHandler -{ - private readonly IMongoDatabase _database = database; - - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage - { - switch (message) - { - case OperationSystem os: - await OnOperationSystemAsync(sender, os, cancellationToken); - break; - } - } - - private async ValueTask OnOperationSystemAsync(AgentSession session, OperationSystem operatingSystem, CancellationToken cancellationToken) - { - var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); - if (agentEntity is null) return; - - var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); - if (hostEntity is null) return; - - var date = DateTime.Now; - - await _database.HostOs().UpdateOneAsync(p => p.Host == hostEntity.Id, Builders.Update - .SetOnInsert(p => p.Insert, date) - .SetOnInsert(p => p.Host, hostEntity.Id) - .Set(p => p.Update, date) - .Set(p => p.Name, operatingSystem.Name) - .Set(p => p.Version, operatingSystem.Version) - .Set(p => p.Architecture, operatingSystem.Architecture.ToString()) - .Set(p => p.SerialNumber, operatingSystem.SerialNumber) - .Set(p => p.Virtual, operatingSystem.Virtual) - .Set(p => p.Installed, operatingSystem.InstallDate), new UpdateOptions - { - IsUpsert = true - }, cancellationToken); - } -} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Agent/Handlers/PrinterHandler.cs b/src/Server/Insight.Server/Network/Agent/Handlers/PrinterHandler.cs deleted file mode 100644 index e57f0c0..0000000 --- a/src/Server/Insight.Server/Network/Agent/Handlers/PrinterHandler.cs +++ /dev/null @@ -1,72 +0,0 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; -using Insight.Infrastructure.Entities; -using MongoDB.Bson; -using MongoDB.Driver; - -namespace Insight.Server.Network.Agent.Handlers; - -public class PrinterHandler(IMongoDatabase database) : IMessageHandler -{ - private readonly IMongoDatabase _database = database; - - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage - { - switch (message) - { - case Collection printers: - await OnPrintersAsync(sender, printers, cancellationToken); - break; - } - } - - private async ValueTask OnPrintersAsync(AgentSession session, List printers, CancellationToken cancellationToken) - { - var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); - if (agentEntity is null) return; - - var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); - if (hostEntity is null) return; - - var batch = ObjectId.GenerateNewId().ToString(); - var date = DateTime.Now; - - var bulk = new List>(); - - if (printers is not null && printers.Count != 0) - { - foreach (var printer in printers) - { - var filterDefinition = Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Eq(x => x.Name, printer.Name) - }); - - var updateDefinition = Builders.Update - .SetOnInsert(p => p.Insert, date) - .SetOnInsert(p => p.Host, hostEntity.Id) - .SetOnInsert(p => p.Name, printer.Name) - .Set(p => p.Update, date) - .Set(p => p.Batch, batch) - .Set(p => p.Port, printer.Port) - .Set(p => p.Location, printer.Location) - .Set(p => p.Comment, printer.Comment); - - bulk.Add(new UpdateOneModel(filterDefinition, updateDefinition) - { - IsUpsert = true - }); - } - } - - bulk.Add(new DeleteManyModel(Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Ne(x => x.Batch, batch) - }))); - - var result = await _database.HostPrinter().BulkWriteAsync(bulk, cancellationToken: cancellationToken); - } -} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Agent/Handlers/ProcessorHandler.cs b/src/Server/Insight.Server/Network/Agent/Handlers/ProcessorHandler.cs deleted file mode 100644 index d11ed9c..0000000 --- a/src/Server/Insight.Server/Network/Agent/Handlers/ProcessorHandler.cs +++ /dev/null @@ -1,83 +0,0 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; -using Insight.Infrastructure.Entities; -using MongoDB.Bson; -using MongoDB.Driver; - -namespace Insight.Server.Network.Agent.Handlers; - -public class ProcessorHandler(IMongoDatabase database) : IMessageHandler -{ - private readonly IMongoDatabase _database = database; - - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage - { - switch (message) - { - case Collection processors: - await OnProcessorsAsync(sender, processors, cancellationToken); - break; - } - } - - private async ValueTask OnProcessorsAsync(AgentSession session, List processors, CancellationToken cancellationToken) - { - var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); - if (agentEntity is null) return; - - var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); - if (hostEntity is null) return; - - var batch = ObjectId.GenerateNewId().ToString(); - var date = DateTime.Now; - - var bulk = new List>(); - - if (processors is not null && processors.Count != 0) - { - foreach (var processor in processors) - { - var filterDefinition = Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Eq(x => x.Index, processor.Index) - }); - - var updateDefinition = Builders.Update - .SetOnInsert(p => p.Insert, date) - .SetOnInsert(p => p.Host, hostEntity.Id) - .SetOnInsert(p => p.Index, processor.Index) - .Set(p => p.Update, date) - .Set(p => p.Batch, batch) - .Set(p => p.Company, processor.Manufacturer) - .Set(p => p.Name, processor.Name) - .Set(p => p.Socket, processor.Socket) - .Set(p => p.Serial, processor.SerialNumber) - .Set(p => p.Version, processor.Version) - .Set(p => p.Cores, processor.Cores) - .Set(p => p.LogicalCores, processor.LogicalCores) - .Set(p => p.Clock, processor.MaxSpeed) - .Set(p => p.CurrentClock, processor.CurrentSpeed) - .Set(p => p.L1Size, processor.L1Size) - .Set(p => p.L2Size, processor.L2Size) - .Set(p => p.L3Size, processor.L3Size) - .Set(p => p.Virtualization, processor.Virtualization) - .Set(p => p.PNP, processor.DeviceId); - - bulk.Add(new UpdateOneModel(filterDefinition, updateDefinition) - { - IsUpsert = true - }); - } - } - - bulk.Add(new DeleteManyModel(Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Ne(x => x.Batch, batch) - }))); - - var result = await _database.HostProcessor().BulkWriteAsync(bulk, cancellationToken: cancellationToken); - } -} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Agent/Handlers/ServiceHandler.cs b/src/Server/Insight.Server/Network/Agent/Handlers/ServiceHandler.cs deleted file mode 100644 index be6d45a..0000000 --- a/src/Server/Insight.Server/Network/Agent/Handlers/ServiceHandler.cs +++ /dev/null @@ -1,77 +0,0 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; -using Insight.Infrastructure.Entities; -using MongoDB.Bson; -using MongoDB.Driver; - -namespace Insight.Server.Network.Agent.Handlers; - -public class ServiceHandler(IMongoDatabase database) : IMessageHandler -{ - private readonly IMongoDatabase _database = database; - - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage - { - switch (message) - { - case Collection services: - await OnServicesAsync(sender, services, cancellationToken); - break; - } - } - - private async ValueTask OnServicesAsync(AgentSession session, List services, CancellationToken cancellationToken) - { - var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); - if (agentEntity is null) return; - - var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); - if (hostEntity is null) return; - - var batch = ObjectId.GenerateNewId().ToString(); - var date = DateTime.Now; - - var bulk = new List>(); - - if (services is not null && services.Count != 0) - { - foreach (var service in services) - { - var filterDefinition = Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Eq(x => x.Name, service.Name) - }); - - var updateDefinition = Builders.Update - .SetOnInsert(p => p.Insert, date) - .SetOnInsert(p => p.Host, hostEntity.Id) - .SetOnInsert(p => p.Name, service.Name) - .Set(p => p.Update, date) - .Set(p => p.Batch, batch) - .Set(p => p.DisplayName, service.Display) - .Set(p => p.Description, service.Description) - .Set(p => p.StartMode, service.StartMode.ToString()) - .Set(p => p.State, service.Status.ToString()) - .Set(p => p.ProcessId, service.ProcessId) - .Set(p => p.Delay, service.Delay) - .Set(p => p.Path, service.PathName) - .Set(p => p.Account, service.Account); - - bulk.Add(new UpdateOneModel(filterDefinition, updateDefinition) - { - IsUpsert = true - }); - } - } - - bulk.Add(new DeleteManyModel(Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Ne(x => x.Batch, batch) - }))); - - var result = await _database.HostService().BulkWriteAsync(bulk, cancellationToken: cancellationToken); - } -} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Agent/Handlers/SessionHandler.cs b/src/Server/Insight.Server/Network/Agent/Handlers/SessionHandler.cs deleted file mode 100644 index b1ecdc6..0000000 --- a/src/Server/Insight.Server/Network/Agent/Handlers/SessionHandler.cs +++ /dev/null @@ -1,73 +0,0 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; -using Insight.Infrastructure.Entities; -using MongoDB.Bson; -using MongoDB.Driver; - -namespace Insight.Server.Network.Agent.Handlers; - -public class SessionHandler(IMongoDatabase database) : IMessageHandler -{ - private readonly IMongoDatabase _database = database; - - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage - { - switch (message) - { - case Collection sessions: - await OnSessionsAsync(sender, sessions, cancellationToken); - break; - } - } - - private async ValueTask OnSessionsAsync(AgentSession session, List sessions, CancellationToken cancellationToken) - { - var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); - if (agentEntity is null) return; - - var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); - if (hostEntity is null) return; - - var batch = ObjectId.GenerateNewId().ToString(); - var date = DateTime.Now; - - var bulk = new List>(); - - if (sessions is not null && sessions.Count != 0) - { - foreach (var sess in sessions) - { - var filterDefinition = Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Eq(x => x.Sid, sess.Sid) - }); - - var updateDefinition = Builders.Update - .SetOnInsert(p => p.Insert, date) - .SetOnInsert(p => p.Host, hostEntity.Id) - .SetOnInsert(p => p.Sid, sess.Sid) - .Set(p => p.Update, date) - .Set(p => p.Batch, batch) - .Set(p => p.User, sess.User) - .Set(p => p.Remote, sess.Remote) - .Set(p => p.Type, sess.Type) - .Set(p => p.State, sess.Status); - - bulk.Add(new UpdateOneModel(filterDefinition, updateDefinition) - { - IsUpsert = true - }); - } - } - - bulk.Add(new DeleteManyModel(Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Ne(x => x.Batch, batch) - }))); - - var result = await _database.HostSession().BulkWriteAsync(bulk, cancellationToken: cancellationToken); - } -} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Agent/Handlers/SoftwareHandler.cs b/src/Server/Insight.Server/Network/Agent/Handlers/SoftwareHandler.cs deleted file mode 100644 index acb7d0e..0000000 --- a/src/Server/Insight.Server/Network/Agent/Handlers/SoftwareHandler.cs +++ /dev/null @@ -1,74 +0,0 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; -using Insight.Infrastructure.Entities; -using MongoDB.Bson; -using MongoDB.Driver; - -namespace Insight.Server.Network.Agent.Handlers; - -public class SoftwareHandler(IMongoDatabase database) : IMessageHandler -{ - private readonly IMongoDatabase _database = database; - - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage - { - switch (message) - { - case Collection applications: - await OnApplicationsAsync(sender, applications, cancellationToken); - break; - } - } - - private async ValueTask OnApplicationsAsync(AgentSession session, List applications, CancellationToken cancellationToken) - { - var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); - if (agentEntity is null) return; - - var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); - if (hostEntity is null) return; - - var batch = ObjectId.GenerateNewId().ToString(); - var date = DateTime.Now; - - var bulk = new List>(); - - if (applications is not null && applications.Count != 0) - { - foreach (var app in applications) - { - var filterDefinition = Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Eq(x => x.Name, app.Name), - Builders.Filter.Eq(x => x.Architecture, app.Architecture?.ToString()) - }); - - var updateDefinition = Builders.Update - .SetOnInsert(p => p.Insert, date) - .SetOnInsert(p => p.Host, hostEntity.Id) - .SetOnInsert(p => p.Name, app.Name) - .SetOnInsert(p => p.Architecture, app.Architecture?.ToString()) - .Set(p => p.Update, date) - .Set(p => p.Batch, batch) - .Set(p => p.Company, app.Publisher) - .Set(p => p.Version, app.Version) - .Set(p => p.InstallDate, app.InstallDate); - - bulk.Add(new UpdateOneModel(filterDefinition, updateDefinition) - { - IsUpsert = true - }); - } - } - - bulk.Add(new DeleteManyModel(Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Ne(x => x.Batch, batch) - }))); - - var result = await _database.HostApplication().BulkWriteAsync(bulk, cancellationToken: cancellationToken); - } -} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Agent/Handlers/StoragePoolHandler.cs b/src/Server/Insight.Server/Network/Agent/Handlers/StoragePoolHandler.cs deleted file mode 100644 index c443248..0000000 --- a/src/Server/Insight.Server/Network/Agent/Handlers/StoragePoolHandler.cs +++ /dev/null @@ -1,243 +0,0 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; -using Insight.Infrastructure.Entities; -using MongoDB.Bson; -using MongoDB.Driver; - -namespace Insight.Server.Network.Agent.Handlers; - -public class StoragePoolHandler(IMongoDatabase database) : IMessageHandler -{ - private readonly IMongoDatabase _database = database; - - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage - { - switch (message) - { - case Collection storagePools: - await OnStoragePoolsAsync(sender, storagePools, cancellationToken); - break; - } - } - - private async ValueTask OnStoragePoolsAsync(AgentSession session, List? storagePools, CancellationToken cancellationToken) - { - var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); - if (agentEntity is null) return; - - var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); - if (hostEntity is null) return; - - var batch = ObjectId.GenerateNewId().ToString(); - var date = DateTime.Now; - - // storagepools - - if (storagePools is not null && storagePools.Count != 0) - { - var storagepoolBulk = new List>(); - - foreach (var storagePool in storagePools) - { - var storagePoolFilter = Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Eq(x => x.UniqueId, storagePool.UniqueId) - }); - - List? states = null; - - if (storagePool.States is not null) - { - states = []; - - foreach (var state in storagePool.States) - states.Add(state.ToString()); - } - - var storagePoolUpdate = Builders.Update - .SetOnInsert(p => p.Insert, date) - .SetOnInsert(p => p.Host, hostEntity.Id) - .SetOnInsert(p => p.UniqueId, storagePool.UniqueId) - .Set(p => p.Update, date) - .Set(p => p.Batch, batch) - - .Set(p => p.Name, storagePool.FriendlyName) - .Set(p => p.Health, storagePool.Health?.ToString()) - .Set(p => p.Resiliency, storagePool.Resiliency) - .Set(p => p.Primordial, storagePool.IsPrimordial) - .Set(p => p.ReadOnly, storagePool.IsReadOnly) - .Set(p => p.Clustered, storagePool.IsClustered) - .Set(p => p.Size, storagePool.Size) - .Set(p => p.AllocatedSize, storagePool.AllocatedSize) - .Set(p => p.SectorSize, storagePool.SectorSize) - .Set(p => p.States, states); - - storagepoolBulk.Add(new UpdateOneModel(storagePoolFilter, storagePoolUpdate) - { - IsUpsert = true - }); - } - - storagepoolBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Ne(x => x.Batch, batch) - }))); - - var storagePoolResult = await _database.HostStoragePool().BulkWriteAsync(storagepoolBulk, cancellationToken: cancellationToken); - } - - // physicaldisks - - if (storagePools is not null && storagePools.Count != 0) - { - var physicalDiskBulk = new List>(); - - foreach (var storagePool in storagePools) - { - var storagePoolId = await _database.HostStoragePool() - .Find(p => p.Host == hostEntity.Id && p.UniqueId == storagePool.UniqueId) - .Project(p => p.Id) - .FirstOrDefaultAsync(cancellationToken: default); - - if (storagePool.PhysicalDisks is not null && storagePool.PhysicalDisks.Count != 0) - { - foreach (var physicalDisk in storagePool.PhysicalDisks) - { - var physicalDiskFilter = Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Eq(x => x.StoragePool, storagePoolId), - Builders.Filter.Eq(x => x.UniqueId, physicalDisk.UniqueId) - }); - - List? states = null; - - if (physicalDisk.States is not null) - { - states = []; - - foreach (var state in physicalDisk.States) - states.Add(state.ToString()); - } - - var physicalDiskUpdate = Builders.Update - .SetOnInsert(p => p.Insert, date) - .SetOnInsert(p => p.Host, hostEntity.Id) - .SetOnInsert(p => p.StoragePool, storagePoolId) - .SetOnInsert(p => p.UniqueId, physicalDisk.UniqueId) - .Set(p => p.Update, date) - .Set(p => p.Batch, batch) - - .Set(p => p.DeviceId, physicalDisk.DeviceId) - .Set(p => p.Name, physicalDisk.FriendlyName) - .Set(p => p.Manufacturer, physicalDisk.Manufacturer) - .Set(p => p.Model, physicalDisk.Model) - .Set(p => p.Media, physicalDisk.MediaType.ToString()) - .Set(p => p.Bus, physicalDisk.BusType.ToString()) - .Set(p => p.Health, physicalDisk.Health.ToString()) - .Set(p => p.Usage, physicalDisk.Usage) - .Set(p => p.Location, physicalDisk.PhysicalLocation) - .Set(p => p.Serial, physicalDisk.SerialNumber) - .Set(p => p.Firmware, physicalDisk.FirmwareVersion) - .Set(p => p.Size, physicalDisk.Size) - .Set(p => p.AllocatedSize, physicalDisk.AllocatedSize) - .Set(p => p.Footprint, physicalDisk.VirtualDiskFootprint) - .Set(p => p.LogicalSectorSize, physicalDisk.LogicalSectorSize) - .Set(p => p.PhysicalSectorSize, physicalDisk.PhysicalSectorSize) - .Set(p => p.States, states); - - physicalDiskBulk.Add(new UpdateOneModel(physicalDiskFilter, physicalDiskUpdate) - { - IsUpsert = true - }); - } - } - } - - physicalDiskBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Ne(x => x.Batch, batch) - }))); - - var physicalDiskResult = await _database.HostStoragePoolPhysicalDisk().BulkWriteAsync(physicalDiskBulk, cancellationToken: cancellationToken); - } - - // virtual disks - - if (storagePools is not null && storagePools.Count != 0) - { - var virtualDiskBulk = new List>(); - - foreach (var storagePool in storagePools) - { - if (storagePool.VirtualDisks is not null && storagePool.VirtualDisks.Count != 0) - { - foreach (var virtualDisk in storagePool.VirtualDisks) - { - var storagePoolId = await _database.HostStoragePool() - .Find(p => p.Host == hostEntity.Id && p.UniqueId == storagePool.UniqueId) - .Project(p => p.Id) - .FirstOrDefaultAsync(cancellationToken: default); - - var virtualDiskFilter = Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Eq(x => x.StoragePool, storagePoolId), - Builders.Filter.Eq(x => x.UniqueId, virtualDisk.UniqueId) - }); - - List? states = null; - - if (virtualDisk.States is not null) - { - states = []; - - foreach (var state in virtualDisk.States) - states.Add(state.ToString()); - } - - var virtualDiskUpdate = Builders.Update - .SetOnInsert(p => p.Insert, date) - .SetOnInsert(p => p.Host, hostEntity.Id) - .SetOnInsert(p => p.StoragePool, storagePoolId) - .SetOnInsert(p => p.UniqueId, virtualDisk.UniqueId) - .Set(p => p.Update, date) - .Set(p => p.Batch, batch) - - .Set(p => p.Name, virtualDisk.FriendlyName) - .Set(p => p.Health, virtualDisk.Health.ToString()) - .Set(p => p.Access, virtualDisk.AccessType.ToString()) - .Set(p => p.Provisioning, virtualDisk.ProvisioningType.ToString()) - .Set(p => p.PhysicalRedundancy, virtualDisk.PhysicalDiskRedundancy) - .Set(p => p.Resiliency, virtualDisk.ResiliencySettingName) - .Set(p => p.Deduplication, virtualDisk.Deduplication) - .Set(p => p.Snapshot, virtualDisk.IsSnapshot) - .Set(p => p.Size, virtualDisk.Size) - .Set(p => p.AllocatedSize, virtualDisk.AllocatedSize) - .Set(p => p.Footprint, virtualDisk.FootprintOnPool) - .Set(p => p.ReadCacheSize, virtualDisk.ReadCacheSize) - .Set(p => p.WriteCacheSize, virtualDisk.WriteCacheSize) - .Set(p => p.States, states); - - virtualDiskBulk.Add(new UpdateOneModel(virtualDiskFilter, virtualDiskUpdate) - { - IsUpsert = true - }); - } - } - } - - virtualDiskBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Ne(x => x.Batch, batch) - }))); - - var virtualDiskResult = await _database.HostStoragePoolVirtualDisk().BulkWriteAsync(virtualDiskBulk, cancellationToken: cancellationToken); - } - } -} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Agent/Handlers/SystemInfoHandler.cs b/src/Server/Insight.Server/Network/Agent/Handlers/SystemInfoHandler.cs deleted file mode 100644 index 58a2e09..0000000 --- a/src/Server/Insight.Server/Network/Agent/Handlers/SystemInfoHandler.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; -using Insight.Infrastructure.Entities; -using MongoDB.Driver; - -namespace Insight.Server.Network.Agent.Handlers; - -public class SystemInfoHandler(IMongoDatabase database) : IMessageHandler -{ - private readonly IMongoDatabase _database = database; - - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage - { - switch (message) - { - case SystemInfo systemInfo: - await OnSystemInfoAsync(sender, systemInfo, cancellationToken); - break; - } - } - - private async ValueTask OnSystemInfoAsync(AgentSession session, SystemInfo? system, CancellationToken cancellationToken) - { - var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session?.Id)).FirstOrDefaultAsync(cancellationToken); - if (agentEntity is null) return; - - var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity?.Id)).FirstOrDefaultAsync(cancellationToken); - if (hostEntity is null) return; - - var date = DateTime.Now; - - if (hostEntity.Id is null) return; - - await _database.HostSystem().UpdateOneAsync(p => p.Host == hostEntity.Id, Builders.Update - .SetOnInsert(p => p.Insert, date) - .SetOnInsert(p => p.Host, hostEntity.Id) - .Set(p => p.Update, date) - .Set(p => p.BootUpTime, system?.LastBootUpTime) - .Set(p => p.LocalTime, system?.LocalDateTime) - .Set(p => p.Processes, system?.Processes) - .Set(p => p.License, system?.License), new UpdateOptions - { - IsUpsert = true - }, cancellationToken); - } -} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Agent/Handlers/TrapHandler.cs b/src/Server/Insight.Server/Network/Agent/Handlers/TrapHandler.cs deleted file mode 100644 index 0ef5449..0000000 --- a/src/Server/Insight.Server/Network/Agent/Handlers/TrapHandler.cs +++ /dev/null @@ -1,264 +0,0 @@ -using Insight.Domain.Enums; -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; -using Insight.Infrastructure.Entities; -using Insight.Server.Models; -using MongoDB.Driver; -using System.Text; -using System.Text.RegularExpressions; -using static Insight.Server.Models.MonitorMessage; - -namespace Insight.Server.Network.Agent.Handlers; - -public partial class TrapHandler(IMongoDatabase database) : IMessageHandler -{ - private readonly IMongoDatabase _database = database; - - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage - { - switch (message) - { - case Trap trap: - await OnTrapAsync(sender, trap, cancellationToken); - break; - } - } - - private async ValueTask OnTrapAsync(AgentSession session, Trap? trap, CancellationToken cancellationToken) - { - if (trap is null) return; - - var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); - if (agentEntity is null) return; - - var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); - if (hostEntity is null) return; - - if (TryParse(trap, out var monitoring) is false) - { - //_logger.LogWarning($"Failed to parse"); - } - - // insert monitoring log - var monitoringLog = new HostLogMonitoringEntity - { - Host = hostEntity.Id, - Insert = DateTime.Now, - Timestamp = monitoring?.Timestamp, - Category = monitoring?.Category?.ToString(), - Status = monitoring?.Status?.ToString(), - Hostname = monitoring?.Hostname, - Task = monitoring?.Subject, - Message = monitoring?.Message, - Dispatch = DispatchEnum.Pending.ToString() - }; - - await _database.HostLogMonitoring() - .InsertOneAsync(monitoringLog, cancellationToken: cancellationToken); - - // insert host log - var log = new HostLogEntity - { - Insert = monitoringLog.Insert, - Host = monitoringLog.Host, - Category = monitoringLog.Category, - Status = monitoringLog.Status, - Source = "Trap", - Message = monitoringLog?.Task, - Timestamp = monitoringLog?.Insert - }; - - if (monitoringLog?.Message is not null) log.Message += $"\n{monitoringLog.Message}"; - - await _database.HostLog() - .InsertOneAsync(log, cancellationToken: cancellationToken) - .ConfigureAwait(false); - } - - private static bool TryParse(Trap packet, out MonitorMessage? monitoring) - { - monitoring = null; - - if (packet is null || packet.Data is null || packet.Data.Count == 0) - return false; - - monitoring = new MonitorMessage - { - Community = packet.Community, - Category = CategoryEnum.Monitoring, - Endpoint = packet.Endpoint, - Timestamp = packet.Timestamp - }; - - if (Enum.TryParse(packet.Community, true, out var application)) - monitoring.Application = application; - - StatusEnum? status; - string? task; - string? message; - - switch (application) - { - case ApplicationEnum.Acronis: - monitoring.Application = ApplicationEnum.Acronis; - if (ParseAcronis(packet.Data, out status, out task, out message) is false) return false; - break; - case ApplicationEnum.Veeam: - monitoring.Application = ApplicationEnum.Veeam; - if (ParseVeeam(packet.Data, out status, out task, out message) is false) return false; - break; - case ApplicationEnum.QNAP: - monitoring.Application = ApplicationEnum.QNAP; - monitoring.Category = CategoryEnum.System; - monitoring.Hostname = packet.Hostname; - if (ParseQnap(packet.Data, out status, out task, out message) is false) return false; - break; - default: - return false; - } - - monitoring.Status = status; - monitoring.Subject = task; - monitoring.Message = message; - - return true; - } - - [GeneratedRegex(@"\s+")] - private static partial Regex AcronisRegex(); - - private static bool ParseAcronis(List> data, out StatusEnum? status, out string? task, out string? message) - { - status = data[0].Value?.ToLower() switch - { - "erfolgreich" => StatusEnum.Information, - "success" => StatusEnum.Information, - "information" => StatusEnum.Information, - "warnung" => StatusEnum.Warning, - "warning" => StatusEnum.Warning, - "fehler" => StatusEnum.Error, - "failed" => StatusEnum.Error, - "error" => StatusEnum.Error, - _ => null, - }; - - task = null; - message = null; - - var trim = data[1].Value?.Split(':', StringSplitOptions.None); - if (trim is null || trim.Length == 0) return false; - - task = trim[1].Split("'", StringSplitOptions.None)[1].Split("'")[0].Trim(); - message = trim[1].Split("' ", StringSplitOptions.None)[1].Trim(); - if (message is not null) return true; - - if (data[1].Value is not string val) return false; - - var content = AcronisRegex().Replace(val, ""); - var bytes = Enumerable.Range(0, content.Length) - .Where(x => x % 2 == 0) - .Select(x => Convert.ToByte(content.Substring(x, 2), 16)) - .ToArray(); - - content = Encoding.UTF8.GetString(bytes); - - trim = content.Split(':', StringSplitOptions.None); - if (trim is null || trim.Length == 0) return false; - - task = trim[1].Split("'", StringSplitOptions.None)[1].Split("'")[0].Trim(); - message = trim[1].Split("' ", StringSplitOptions.None)[1].Trim(); - return message is not null; - } - - private static bool ParseVeeam(List> data, out StatusEnum? status, out string? task, out string? message) - { - status = null; - task = null; - message = null; - - var parsed = false; - - try - { - var summary = false; - - if (Guid.TryParse(data[0].Value, out _)) - summary = true; - - if (data[1].Value?.ToLower() == "backup configuration job") - return false; - - status = (summary ? data[2].Value?.ToLower() : data[3].Value?.ToLower()) switch - { - "success" => StatusEnum.Information, - "warning" => StatusEnum.Warning, - "failed" => StatusEnum.Error, - "error" => StatusEnum.Error, - _ => null, - }; - - task = data[1].Value; - parsed = true; - } - catch (Exception) - { - - } - - if (parsed) return true; - return false; - } - - private static bool ParseQnap(List> data, out StatusEnum? status, out string? task, out string? message) - { - status = StatusEnum.Information; - task = null; - message = string.Empty; - - var parsed = false; - - try - { - var keywords = new Dictionary - { - { "power", StatusEnum.Information }, - { "rights", StatusEnum.Information }, - { "added", StatusEnum.Information }, - { "changed", StatusEnum.Information }, - { "password", StatusEnum.Information }, - { "firmware", StatusEnum.Information }, - { "restarting", StatusEnum.Information }, - { "detected", StatusEnum.Warning }, - { "external", StatusEnum.Warning }, - { "threshold", StatusEnum.Warning }, - { "file system", StatusEnum.Warning }, - { "raid", StatusEnum.Warning }, - { "full", StatusEnum.Error }, - { "failure", StatusEnum.Error }, - { "failed", StatusEnum.Error }, - { "resyncing", StatusEnum.Error }, - { "degraded", StatusEnum.Error }, - { "error", StatusEnum.Error }, - { "without error", StatusEnum.Information }, - { "ncsi", StatusEnum.Information } - }; - - foreach (var key in keywords) - if (Regex.IsMatch(string.Concat(data).ToLowerInvariant(), $@"\b{key.Key}\b")) - status = key.Value; - - foreach (var kv in data) - message += kv.Value; - - parsed = true; - } - catch (Exception) - { - //_logger.LogError("{ex}", ex); - } - - if (parsed) return true; - return false; - } -} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Agent/Handlers/UpdateHandler.cs b/src/Server/Insight.Server/Network/Agent/Handlers/UpdateHandler.cs deleted file mode 100644 index 9185b26..0000000 --- a/src/Server/Insight.Server/Network/Agent/Handlers/UpdateHandler.cs +++ /dev/null @@ -1,117 +0,0 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; -using Insight.Infrastructure.Entities; -using MongoDB.Bson; -using MongoDB.Driver; - -namespace Insight.Server.Network.Agent.Handlers; - -public class UpdateHandler(IMongoDatabase database) : IMessageHandler -{ - private readonly IMongoDatabase _database = database; - - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage - { - switch (message) - { - case UpdateCollection updates: - await OnUpdatesAsync(sender, updates, cancellationToken); - break; - } - } - - private async ValueTask OnUpdatesAsync(AgentSession session, UpdateCollection updates, CancellationToken cancellationToken) - { - var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); - if (agentEntity is null) return; - - var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); - if (hostEntity is null) return; - - var batch = ObjectId.GenerateNewId().ToString(); - var date = DateTime.Now; - - var bulk = new List>(); - - if (updates is not null) - { - if (updates.Installed is not null && updates.Installed.Count != 0) - { - foreach (var update in updates.Installed) - { - var filterDefinition = Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Eq(x => x.Serial, update.Id) - }); - - var updateDefinition = Builders.Update - .SetOnInsert(p => p.Insert, date) - .SetOnInsert(p => p.Host, hostEntity.Id) - .SetOnInsert(p => p.Serial, update.Id) - .Set(p => p.Update, date) - .Set(p => p.Batch, batch) - - .Set(p => p.Pending, false) - .Set(p => p.Name, update.Name) - .Set(p => p.Description, update.Description) - .Set(p => p.SupportUrl, update.SupportUrl) - .Set(p => p.Result, update.Result.ToString()) - .Set(p => p.Date, update.Date); - - bulk.Add(new UpdateOneModel(filterDefinition, updateDefinition) - { - IsUpsert = true - }); - } - } - - if (updates.Pending is not null && updates.Pending.Count != 0) - { - foreach (var update in updates.Pending) - { - var filterDefinition = Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Eq(x => x.Serial, update.Id) - }); - - var updateDefinition = Builders.Update - .SetOnInsert(p => p.Insert, date) - .SetOnInsert(p => p.Host, hostEntity.Id) - .SetOnInsert(p => p.Serial, update.Id) - .Set(p => p.Update, date) - .Set(p => p.Batch, batch) - - .Set(p => p.Pending, true) - .Set(p => p.Name, update.Name) - .Set(p => p.Description, update.Description) - .Set(p => p.SupportUrl, update.SupportUrl) - .Set(p => p.Result, update.Result?.ToString()) - - .Set(p => p.Type, update.Type.ToString()) - .Set(p => p.Size, update.Size) - .Set(p => p.IsDownloaded, update.IsDownloaded) - .Set(p => p.CanRequestUserInput, update.CanRequestUserInput) - .Set(p => p.RebootBehavior, update.RebootBehavior?.ToString()) - - .Set(p => p.Date, update.Date); - - bulk.Add(new UpdateOneModel(filterDefinition, updateDefinition) - { - IsUpsert = true - }); - } - } - } - - bulk.Add(new DeleteManyModel(Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Ne(x => x.Batch, batch) - }))); - - var result = await _database.HostUpdate().BulkWriteAsync(bulk, cancellationToken: cancellationToken); - } -} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Agent/Handlers/UserHandler.cs b/src/Server/Insight.Server/Network/Agent/Handlers/UserHandler.cs deleted file mode 100644 index 5051971..0000000 --- a/src/Server/Insight.Server/Network/Agent/Handlers/UserHandler.cs +++ /dev/null @@ -1,183 +0,0 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; -using Insight.Infrastructure.Entities; -using MongoDB.Bson; -using MongoDB.Driver; - -namespace Insight.Server.Network.Agent.Handlers; - -public class UserHandler(IMongoDatabase database) : IMessageHandler -{ - private readonly IMongoDatabase _database = database; - - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage - { - switch (message) - { - case Collection users: - await OnUsersAsync(sender, users, cancellationToken); - break; - } - } - - private async ValueTask OnUsersAsync(AgentSession session, List? users, CancellationToken cancellationToken) - { - var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); - if (agentEntity is null) return; - - var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); - if (hostEntity is null) return; - - var batch = ObjectId.GenerateNewId().ToString(); - var date = DateTime.Now; - - // users - - if (users is not null && users.Count != 0) - { - var userBulk = new List>(); - - foreach (var user in users) - { - var userFilter = Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Eq(x => x.Domain, user?.Domain), - Builders.Filter.Eq(x => x.Name, user?.Name) - }); - - var userUpdate = Builders.Update - .SetOnInsert(p => p.Insert, date) - .SetOnInsert(p => p.Host, hostEntity.Id) - .SetOnInsert(p => p.Domain, user?.Domain) - .SetOnInsert(p => p.Name, user?.Name) - .Set(p => p.Update, date) - .Set(p => p.Batch, batch) - - .Set(p => p.Sid, user?.Sid) - .Set(p => p.FullName, user?.FullName) - .Set(p => p.Description, user?.Description) - .Set(p => p.Status, user?.Status) - .Set(p => p.LocalAccount, user?.LocalAccount) - .Set(p => p.Disabled, user?.Disabled) - .Set(p => p.Lockout, user?.Lockout) - .Set(p => p.PasswordChangeable, user?.PasswordChangeable) - .Set(p => p.PasswordExpires, user?.PasswordExpires) - .Set(p => p.PasswordRequired, user?.PasswordRequired); - - userBulk.Add(new UpdateOneModel(userFilter, userUpdate) - { - IsUpsert = true - }); - } - - userBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Ne(x => x.Batch, batch) - }))); - - var userResult = await _database.HostSystemUser().BulkWriteAsync(userBulk, cancellationToken: cancellationToken); - } - - // groups - - if (users is not null && users.Count != 0) - { - var groupBulk = new List>(); - - var distinctGroups = users.SelectMany(p => p.Groups ?? []) - .GroupBy(p => new { p?.Domain, p?.Name }) - .Select(p => p.First()); - - foreach (var group in distinctGroups) - { - var groupFilter = Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Eq(x => x.Domain, group?.Domain), - Builders.Filter.Eq(x => x.Name, group?.Name) - }); - - var groupUpdate = Builders.Update - .SetOnInsert(p => p.Insert, date) - .SetOnInsert(p => p.Host, hostEntity.Id) - .SetOnInsert(p => p.Domain, group?.Domain) - .SetOnInsert(p => p.Name, group?.Name) - .Set(p => p.Update, date) - .Set(p => p.Batch, batch) - - .Set(p => p.Sid, group?.Sid) - .Set(p => p.Description, group?.Description) - .Set(p => p.LocalAccount, group?.LocalAccount); - - groupBulk.Add(new UpdateOneModel(groupFilter, groupUpdate) - { - IsUpsert = true - }); - } - - groupBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Ne(x => x.Batch, batch) - }))); - - var groupResult = await _database.HostSystemGroup().BulkWriteAsync(groupBulk, cancellationToken: cancellationToken); - } - - // relations - if (users is not null && users.Count != 0) - { - var relationBulk = new List>(); - - foreach (var user in users) - { - var userId = await _database.HostSystemUser() - .Find(p => p.Host == hostEntity.Id && p.Domain == user.Domain && p.Name == user.Name) - .Project(p => p.Id) - .FirstOrDefaultAsync(cancellationToken: default); - - if (user.Groups is not null && user.Groups.Count != 0) - { - foreach (var group in user.Groups) - { - var groupId = await _database.HostSystemGroup() - .Find(p => p.Host == hostEntity.Id && p.Domain == group.Domain && p.Name == group.Name) - .Project(p => p.Id) - .FirstOrDefaultAsync(cancellationToken: default); - - var relationFilter = Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Eq(x => x.User, userId), - Builders.Filter.Eq(x => x.Group, groupId) - }); - - var relationUpdate = Builders.Update - .SetOnInsert(p => p.Insert, date) - .SetOnInsert(p => p.Host, hostEntity.Id) - .SetOnInsert(p => p.User, userId) - .SetOnInsert(p => p.Group, groupId) - .Set(p => p.Update, date) - .Set(p => p.Batch, batch); - - relationBulk.Add(new UpdateOneModel(relationFilter, relationUpdate) - { - IsUpsert = true - }); - } - } - } - - relationBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Ne(x => x.Batch, batch) - }))); - - var relationResult = await _database.HostSystemUserSystemGroup().BulkWriteAsync(relationBulk, cancellationToken: cancellationToken); - } - } -} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Agent/Handlers/VideocardHandler.cs b/src/Server/Insight.Server/Network/Agent/Handlers/VideocardHandler.cs deleted file mode 100644 index b8316b5..0000000 --- a/src/Server/Insight.Server/Network/Agent/Handlers/VideocardHandler.cs +++ /dev/null @@ -1,73 +0,0 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; -using Insight.Infrastructure.Entities; -using MongoDB.Bson; -using MongoDB.Driver; - -namespace Insight.Server.Network.Agent.Handlers; - -public class VideocardHandler(IMongoDatabase database) : IMessageHandler -{ - private readonly IMongoDatabase _database = database; - - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage - { - switch (message) - { - case Collection videocards: - await OnVideocardsAsync(sender, videocards, cancellationToken); - break; - } - } - - private async ValueTask OnVideocardsAsync(AgentSession session, List? videocards, CancellationToken cancellationToken) - { - var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); - if (agentEntity is null) return; - - var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); - if (hostEntity is null) return; - - var batch = ObjectId.GenerateNewId().ToString(); - var date = DateTime.Now; - - var bulk = new List>(); - - if (videocards is not null && videocards.Count != 0) - { - foreach (var videocard in videocards) - { - var filterDefinition = Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Eq(x => x.Name, videocard.Model) - }); - - var updateDefinition = Builders.Update - .SetOnInsert(p => p.Insert, date) - .SetOnInsert(p => p.Host, hostEntity.Id) - .SetOnInsert(p => p.Name, videocard.Model) - .Set(p => p.Update, date) - .Set(p => p.Batch, batch) - .Set(p => p.Company, null) - .Set(p => p.Memory, videocard.Memory) - .Set(p => p.Driver, videocard.DriverVersion) - .Set(p => p.Date, videocard.DriverDate); - - bulk.Add(new UpdateOneModel(filterDefinition, updateDefinition) - { - IsUpsert = true - }); - } - - bulk.Add(new DeleteManyModel(Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Ne(x => x.Batch, batch) - }))); - - var result = await _database.HostVideocard().BulkWriteAsync(bulk, cancellationToken: cancellationToken); - } - } -} diff --git a/src/Server/Insight.Server/Network/Agent/Handlers/VirtualMaschineHandler.cs b/src/Server/Insight.Server/Network/Agent/Handlers/VirtualMaschineHandler.cs deleted file mode 100644 index c70dd02..0000000 --- a/src/Server/Insight.Server/Network/Agent/Handlers/VirtualMaschineHandler.cs +++ /dev/null @@ -1,173 +0,0 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; -using Insight.Infrastructure.Entities; -using MongoDB.Bson; -using MongoDB.Driver; - -namespace Insight.Server.Network.Agent.Handlers; - -public class VirtualMaschineHandler(IMongoDatabase database) : IMessageHandler -{ - private readonly IMongoDatabase _database = database; - - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage - { - switch (message) - { - case Collection virtualMaschines: - await OnVirtualMaschinesAsync(sender, virtualMaschines, cancellationToken); - break; - } - } - - private async ValueTask OnVirtualMaschinesAsync(AgentSession session, List? virtualMaschines, CancellationToken cancellationToken) - { - var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); - if (agentEntity is null) return; - - var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); - if (hostEntity is null) return; - - var batch = ObjectId.GenerateNewId().ToString(); - var date = DateTime.Now; - - // virtual maschines - if (virtualMaschines is not null && virtualMaschines.Count != 0) - { - var virtualMaschineBulk = new List>(); - - foreach (var virtualMaschine in virtualMaschines) - { - var virtualMaschineFilter = Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Eq(x => x.UniqueId, virtualMaschine.Id.ToString()) - }); - - var virtualMaschineUpdate = Builders.Update - .SetOnInsert(p => p.Insert, date) - .SetOnInsert(p => p.Host, hostEntity.Id) - .SetOnInsert(p => p.UniqueId, virtualMaschine.Id.ToString()) - .Set(p => p.Update, date) - .Set(p => p.Batch, batch) - - .Set(p => p.Name, virtualMaschine?.Name) - .Set(p => p.Notes, virtualMaschine?.Notes) - .Set(p => p.Enabled, virtualMaschine?.Enabled?.ToString()) - .Set(p => p.EnabledDefault, virtualMaschine?.EnabledDefault?.ToString()) - .Set(p => p.Health, virtualMaschine?.HealthState?.ToString()) - .Set(p => p.Status, virtualMaschine?.Status) - .Set(p => p.OnTime, virtualMaschine?.OnTime) - .Set(p => p.ReplicationState, virtualMaschine?.ReplicationState?.ToString()) - .Set(p => p.ReplicationHealth, virtualMaschine?.ReplicationHealth?.ToString()) - .Set(p => p.ConfigurationVersion, virtualMaschine?.ConfigurationVersion) - .Set(p => p.IntegrationServicesVersionState, virtualMaschine?.IntegrationServicesVersionState?.ToString()) - .Set(p => p.ProcessId, virtualMaschine?.ProcessId) - .Set(p => p.NumberOfProcessors, virtualMaschine?.NumberOfProcessors) - .Set(p => p.ProcessorLoad, virtualMaschine?.ProcessorLoad) - .Set(p => p.MemoryAvailable, virtualMaschine?.MemoryAvailable) - .Set(p => p.MemoryUsage, virtualMaschine?.MemoryUsage) - .Set(p => p.InstallDate, virtualMaschine?.InstallDate) - .Set(p => p.ConfigurationVersion, virtualMaschine?.ConfigurationVersion) - .Set(p => p.TimeOfLastStateChange, virtualMaschine?.TimeOfLastStateChange) - .Set(p => p.LastReplicationTime, virtualMaschine?.LastReplicationTime) - .Set(p => p.Os, virtualMaschine?.GuestOperatingSystem); - - virtualMaschineBulk.Add(new UpdateOneModel(virtualMaschineFilter, virtualMaschineUpdate) - { - IsUpsert = true - }); - } - - virtualMaschineBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Ne(x => x.Batch, batch) - }))); - - var virtualMaschineResult = await _database.HostHypervisorVirtualMaschine().BulkWriteAsync(virtualMaschineBulk, cancellationToken: cancellationToken); - } - - // virtual maschine configurations - - if (virtualMaschines is not null && virtualMaschines.Count != 0) - { - var configurationBulk = new List>(); - - foreach (var virtualmaschine in virtualMaschines) - { - var virtualMaschineId = await _database.HostHypervisorVirtualMaschine() - .Find(p => p.Host == hostEntity.Id && p.UniqueId == virtualmaschine.Id.ToString()) - .Project(p => p.Id) - .FirstOrDefaultAsync(cancellationToken: default); - - if (virtualmaschine.Configurations is not null && virtualmaschine.Configurations.Count != 0) - { - foreach (var config in virtualmaschine.Configurations) - { - var configFilter = Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Eq(x => x.VirtualMaschine, virtualMaschineId), - Builders.Filter.Eq(x => x.UniqueId, config.Id) - }); - - // custom "notes" concat - string notes = string.Empty; - - if (config?.Notes is not null) - foreach (var n in config.Notes) notes += n; - - if (config?.Id is null) continue; - - var configUpdate = Builders.Update - .SetOnInsert(p => p.Insert, date) - .SetOnInsert(p => p.Host, hostEntity.Id) - .SetOnInsert(p => p.VirtualMaschine, virtualMaschineId) - .SetOnInsert(p => p.UniqueId, config.Id) - .Set(p => p.Update, date) - .Set(p => p.Batch, batch) - - .Set(p => p.ParentId, config.ParentId) - .Set(p => p.Type, config.Type) - .Set(p => p.Name, config.Name) - .Set(p => p.Notes, notes) - .Set(p => p.CreationTime, config.CreationTime) - .Set(p => p.Generation, config.Generation) - .Set(p => p.Architecture, config.Architecture) - .Set(p => p.SecureBootEnabled, config.SecureBootEnabled) - .Set(p => p.IsAutomaticSnapshot, config.IsAutomaticSnapshot) - .Set(p => p.AutomaticStartupAction, config.AutomaticStartupAction?.ToString()) - .Set(p => p.AutomaticShutdownAction, config.AutomaticShutdownAction?.ToString()) - .Set(p => p.AutomaticRecoveryAction, config.AutomaticRecoveryAction?.ToString()) - .Set(p => p.AutomaticSnapshotsEnabled, config.AutomaticSnapshotsEnabled) - .Set(p => p.BaseBoardSerialNumber, config.BaseBoardSerialNumber) - .Set(p => p.BIOSSerialNumber, config.BIOSSerialNumber) - .Set(p => p.BIOSGUID, config.BIOSGUID) - .Set(p => p.ConfigurationDataRoot, config.ConfigurationDataRoot) - .Set(p => p.ConfigurationFile, config.ConfigurationFile) - .Set(p => p.GuestStateDataRoot, config.GuestStateDataRoot) - .Set(p => p.GuestStateFile, config.GuestStateFile) - .Set(p => p.SnapshotDataRoot, config.SnapshotDataRoot) - .Set(p => p.SuspendDataRoot, config.SuspendDataRoot) - .Set(p => p.SwapFileDataRoot, config.SwapFileDataRoot); - - configurationBulk.Add(new UpdateOneModel(configFilter, configUpdate) - { - IsUpsert = true - }); - } - } - } - - configurationBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> - { - Builders.Filter.Eq(x => x.Host, hostEntity.Id), - Builders.Filter.Ne(x => x.Batch, batch) - }))); - - var configurationResult = await _database.HostVirtualMaschineConfig().BulkWriteAsync(configurationBulk, cancellationToken: cancellationToken); - } - } -} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/AgentSession.cs b/src/Server/Insight.Server/Network/AgentSession.cs new file mode 100644 index 0000000..31871b6 --- /dev/null +++ b/src/Server/Insight.Server/Network/AgentSession.cs @@ -0,0 +1,80 @@ +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; +using Insight.Server.Network.Handlers.Agent; +using Microsoft.Extensions.Logging; +using System.Net.Sockets; +using Vaitr.Network; + +namespace Insight.Server.Network; + +public class AgentSession(AgentHandler agentHandler, IEnumerable> handlers, Socket socket, Stream stream, TcpConnectionOptions options, MemPackSerializer serializer, ILogger logger) + : TcpSession(socket, stream, options, serializer, logger) +{ + public string? Id { get; set; } + + private readonly AgentHandler _agentHandler = agentHandler; + private readonly IEnumerable> _handlers = handlers; + + protected override async ValueTask OnConnectedAsync(CancellationToken cancellationToken) + { + _logger.LogInformation("Agent ({ep?}) connected", RemoteEndPoint); + + var request = new AuthenticationRequest(); + + foreach (var handler in _handlers) + { + await handler.HandleAsync(this, request, cancellationToken); + } + + await _agentHandler.ConnectedAsync(this, default); + await _agentHandler.StatisticUpdateAsync(this, default); + + _logger.LogInformation("Agent ({ep?}) ID: {id}", RemoteEndPoint, Id); + } + + protected override async ValueTask OnDisconnectedAsync(CancellationToken cancellationToken) + { + _logger.LogInformation("Agent ({ep?}) disconnected", RemoteEndPoint); + + await _agentHandler.StatisticUpdateAsync(this, default); + await _agentHandler.DisconnectedAsync(this, default); + } + + protected override async ValueTask OnSentAsync(PacketContext context, CancellationToken cancellationToken) + { + await _agentHandler.StatisticUpdateAsync(this, cancellationToken); + } + + protected override async ValueTask OnReceivedAsync(PacketContext context, CancellationToken cancellationToken) + { + if (Id is null && context.Data is not Authentication) return; + + await _agentHandler.StatisticUpdateAsync(this, cancellationToken); + + foreach (var handler in _handlers) + { + try + { + await handler.HandleAsync(this, context.Data, cancellationToken); + } + catch (Exception ex) + { + _logger.LogWarning("Agent ({ep?}) {ex}", RemoteEndPoint, ex.ToString()); + + //await _mediator.Send(new AgentLog(new AgentLogEntity + //{ + // Category = CategoryEnum.Network.ToString(), + // Status = StatusEnum.Error.ToString(), + // Message = e.StackTrace + //}, this), cancellationToken).ConfigureAwait(false); + } + } + } + + protected override async ValueTask OnKeepAliveAsync(CancellationToken cancellationToken) + { + _logger.LogInformation("Agent ({ep?}) Heartbeat", RemoteEndPoint); + + await _agentHandler.StatisticUpdateAsync(this, cancellationToken); + } +} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Handlers/Agent/AgentHandler.cs b/src/Server/Insight.Server/Network/Handlers/Agent/AgentHandler.cs new file mode 100644 index 0000000..d3f08be --- /dev/null +++ b/src/Server/Insight.Server/Network/Handlers/Agent/AgentHandler.cs @@ -0,0 +1,162 @@ +using Insight.Agent.Enums; +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; +using Insight.Infrastructure; +using Insight.Infrastructure.Entities; +using Microsoft.Extensions.Logging; +using MongoDB.Driver; + +namespace Insight.Server.Network.Handlers.Agent +{ + public class AgentHandler : IAgentMessageHandler + { + private readonly IMongoDatabase _database; + private readonly ILogger _logger; + + public AgentHandler(IMongoDatabase database, ILogger logger) + { + _database = database; + _logger = logger; + } + + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage + { + if (message is AuthenticationRequest authenticationRequest) + { + await AuthenticationRequestAsync(sender, authenticationRequest, cancellationToken); + } + + if (message is Authentication authentication) + { + await AuthenticationAsync(sender, authentication, cancellationToken); + } + } + + private async ValueTask AuthenticationRequestAsync(AgentSession session, AuthenticationRequest message, CancellationToken cancellationToken) + { + await session.SendAsync(message, cancellationToken); + + for (int i = 0; i < 200; i++) + { + if (session.Id is not null) + { + _logger.LogInformation("Agent ({ep?}) authenticated", session.RemoteEndPoint); + return; + } + + await Task.Delay(50, cancellationToken).ConfigureAwait(false); + } + + _logger.LogError("Authentication Timeout ({ep?})", session.RemoteEndPoint); + session.Disconnect(); + } + + private async ValueTask AuthenticationAsync(AgentSession session, Authentication authentication, CancellationToken cancellationToken) + { + if (authentication is null) + { + throw new NullReferenceException($"authentication failed (empty response)"); + } + + if (authentication.Serial == default) + { + throw new InvalidDataException($"authentication failed ({nameof(authentication.Serial)})"); + } + + //if (authentication.Version == default || authentication.Version < Domain.Constants.Configuration.Version) + //{ + // throw new InvalidDataException($"authentication failed ({nameof(authentication.Version)})"); + //} + + // upsert agent + await _database.Agent().UpdateOneAsync(Builders + .Filter + .Eq(p => p.Serial, authentication.Serial.ToString()), Builders.Update + .SetOnInsert(p => p.Insert, DateTime.Now) + .SetOnInsert(p => p.Serial, authentication.Serial.ToString()) + .Set(p => p.Update, DateTime.Now) + .Set(p => p.Connected, DateTime.Now) + .Set(p => p.Version, authentication.Version) + .Set(p => p.Endpoint, session.RemoteEndPoint?.ToString()) + .Set(p => p.Hostname, authentication.Hostname), new UpdateOptions + { + IsUpsert = true + }, cancellationToken) + .ConfigureAwait(false); + + // get agent + var agentEntity = await _database.Agent() + .Find(Builders + .Filter + .Eq(p => p.Serial, authentication.Serial.ToString())) + .FirstOrDefaultAsync(cancellationToken) + .ConfigureAwait(false); + + // set session id + session.Id = agentEntity.Id; + } + + public async ValueTask ConnectedAsync(AgentSession session, CancellationToken cancellationToken) + { + if (session.Id is null) return; + + // insert connect log + await _database.AgentLog() + .InsertOneAsync(new AgentLogEntity + { + Insert = DateTime.Now, + Agent = session.Id, + Category = CategoryEnum.Network.ToString(), + Status = StatusEnum.Information.ToString(), + Message = $"Connected ({session.RemoteEndPoint})", + Timestamp = DateTime.Now + }, cancellationToken: cancellationToken) + .ConfigureAwait(false); + } + + public async ValueTask DisconnectedAsync(AgentSession session, CancellationToken cancellationToken) + { + if (session.Id is null) return; + + // insert disconnect log + await _database.AgentLog() + .InsertOneAsync(new AgentLogEntity + { + Insert = DateTime.Now, + Agent = session.Id, + Category = CategoryEnum.Network.ToString(), + Status = StatusEnum.Information.ToString(), + Message = $"Disconnected ({session.RemoteEndPoint})", + Timestamp = DateTime.Now + }, cancellationToken: cancellationToken) + .ConfigureAwait(false); + } + + public async ValueTask StatisticUpdateAsync(AgentSession session, CancellationToken cancellationToken) + { + if (session.Id is null) return; + + // update agents stats + await _database.Agent().UpdateOneAsync(Builders + .Filter + .Eq(p => p.Id, session.Id), Builders + .Update + .Set(p => p.Update, DateTime.Now) + .Set(p => p.Activity, session.Activity) + .Set(p => p.SentBytes, session.TotalOutputBytes) + .Set(p => p.ReceivedBytes, session.TotalInputBytes) + .Set(p => p.SentPackets, session.TotalOutputPackets) + .Set(p => p.ReceivedPackets, session.TotalInputPackets), null, cancellationToken) + .ConfigureAwait(false); + } + + public async ValueTask LogAsync(AgentSession session, AgentLogEntity log, CancellationToken cancellationToken) + { + if (session.Id is null) return; + + await _database.AgentLog() + .InsertOneAsync(log, cancellationToken: cancellationToken) + .ConfigureAwait(false); + } + } +} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Handlers/Agent/ConsoleHandler.cs b/src/Server/Insight.Server/Network/Handlers/Agent/ConsoleHandler.cs new file mode 100644 index 0000000..2d9946e --- /dev/null +++ b/src/Server/Insight.Server/Network/Handlers/Agent/ConsoleHandler.cs @@ -0,0 +1,50 @@ +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; +using Insight.Web.Messages; +using Microsoft.Extensions.Logging; +using MongoDB.Driver; +using Vaitr.Network; + +namespace Insight.Server.Network.Handlers.Agent +{ + public class ConsoleHandler : IAgentMessageHandler + { + private readonly TcpSessionPool _webPool; + private readonly IMongoDatabase _database; + private readonly ILogger _logger; + + public ConsoleHandler( + TcpSessionPool webPool, + IMongoDatabase database, + ILogger logger) + { + _webPool = webPool; + _database = database; + _logger = logger; + } + + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage + { + if (message is ConsoleQuery consoleQuery) + { + await OnConsoleQueryAsync(sender, consoleQuery, cancellationToken); + } + } + + private async ValueTask OnConsoleQueryAsync(AgentSession session, ConsoleQuery query, CancellationToken cancellationToken) + { + // check if web online + if (_webPool.FirstOrDefault().Value is not WebSession web) return; + + await web.SendAsync(new ConsoleQueryProxy + { + Id = query.Id, + HostId = query.HostId, + Query = query.Query, + Data = query.Data, + Errors = query.Errors, + HadErrors = query.HadErrors + }, cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Handlers/Agent/DriveHandler.cs b/src/Server/Insight.Server/Network/Handlers/Agent/DriveHandler.cs new file mode 100644 index 0000000..ec5652c --- /dev/null +++ b/src/Server/Insight.Server/Network/Handlers/Agent/DriveHandler.cs @@ -0,0 +1,145 @@ +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; +using Insight.Infrastructure; +using Insight.Infrastructure.Entities; +using MongoDB.Bson; +using MongoDB.Driver; + +namespace Insight.Server.Network.Handlers.Agent +{ + public class DriveHandler : IAgentMessageHandler + { + private readonly IMongoDatabase _database; + + public DriveHandler(IMongoDatabase database) + { + _database = database; + } + + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage + { + if (message is DriveList drives) + { + await OnDrivesAsync(sender, drives, cancellationToken); + } + } + + private async ValueTask OnDrivesAsync(AgentSession session, List drives, CancellationToken cancellationToken) + { + var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); + if (agentEntity is null) return; + + var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); + if (hostEntity is null) return; + + var batch = ObjectId.GenerateNewId().ToString(); + var date = DateTime.Now; + + var driveBulk = new List>(); + + if (drives is not null && drives.Any()) + { + foreach (var drive in drives) + { + var driveFilter = Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Eq(x => x.Index, drive.Index) + }); + + var driveUpdate = Builders.Update + .SetOnInsert(p => p.Insert, date) + .SetOnInsert(p => p.Host, hostEntity.Id) + .SetOnInsert(p => p.Index, drive.Index) + .Set(p => p.Update, date) + .Set(p => p.Batch, batch) + .Set(p => p.Company, drive.Manufacturer) + .Set(p => p.Name, drive.Name) + .Set(p => p.Size, drive.Size) + .Set(p => p.Type, drive.InterfaceType) + .Set(p => p.Serial, drive.SerialNumber) + .Set(p => p.Firmware, drive.FirmwareRevision) + .Set(p => p.Status, drive.Status) + .Set(p => p.Pnp, drive.PNPDeviceID); + + driveBulk.Add(new UpdateOneModel(driveFilter, driveUpdate) + { + IsUpsert = true + }); + } + } + + driveBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Ne(x => x.Batch, batch) + }))); + + var driveResult = await _database.HostDrive().BulkWriteAsync(driveBulk, cancellationToken: cancellationToken); + + // volumes + + var volumeBulk = new List>(); + + if (drives is not null && drives.Any()) + { + foreach (var drive in drives) + { + var driveId = await _database.HostDrive() + .Find(p => p.Host == hostEntity.Id && p.Index == drive.Index) + .Project(p => p.Id) + .FirstOrDefaultAsync(); + + if (drive.Volumes is not null && drive.Volumes.Any()) + { + foreach (var volume in drive.Volumes) + { + var volumeFilter = Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Eq(x => x.Drive, driveId), + Builders.Filter.Eq(x => x.Index, volume.Index) + }); + + var volumeUpdate = Builders.Update + .SetOnInsert(p => p.Insert, date) + .SetOnInsert(p => p.Host, hostEntity.Id) + .SetOnInsert(p => p.Drive, driveId) + .SetOnInsert(p => p.Index, volume.Index) + .Set(p => p.Update, date) + .Set(p => p.Batch, batch) + .Set(p => p.Name, volume.Name) + .Set(p => p.Label, volume.Id) + .Set(p => p.Serial, volume.SerialNumber) + .Set(p => p.Size, volume.Size) + .Set(p => p.FreeSpace, volume.FreeSpace) + .Set(p => p.Type, volume.Type) + .Set(p => p.FileSystem, volume.FileSystem) + .Set(p => p.Compressed, volume.Compressed) + .Set(p => p.Bootable, volume.Bootable) + .Set(p => p.Primary, volume.PrimaryPartition) + .Set(p => p.Boot, volume.Bootable) + .Set(p => p.BlockSize, volume.BlockSize) + .Set(p => p.Blocks, volume.NumberOfBlocks) + .Set(p => p.StartingOffset, volume.StartingOffset) + .Set(p => p.Provider, volume.ProviderName); + + volumeBulk.Add(new UpdateOneModel(volumeFilter, volumeUpdate) + { + IsUpsert = true + }); + } + } + } + } + + volumeBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Ne(x => x.Batch, batch) + }))); + + var volumeResult = await _database.HostVolume().BulkWriteAsync(volumeBulk, cancellationToken: cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Handlers/Agent/EventHandler.cs b/src/Server/Insight.Server/Network/Handlers/Agent/EventHandler.cs new file mode 100644 index 0000000..1bd5c22 --- /dev/null +++ b/src/Server/Insight.Server/Network/Handlers/Agent/EventHandler.cs @@ -0,0 +1,266 @@ +using Insight.Agent.Enums; +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; +using Insight.Infrastructure; +using Insight.Infrastructure.Entities; +using Microsoft.Extensions.Logging; +using MongoDB.Driver; +using static Insight.Agent.Messages.Event; + +namespace Insight.Server.Network.Handlers.Agent +{ + public class EventHandler : IAgentMessageHandler + { + private readonly IMongoDatabase _database; + private readonly ILogger _logger; + + public EventHandler(IMongoDatabase database, ILogger logger) + { + _database = database; + _logger = logger; + } + + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage + { + if (message is Event @event) + { + await OnEventAsync(sender, @event, cancellationToken); + } + } + + private async ValueTask OnEventAsync(AgentSession session, Event @event, CancellationToken cancellationToken) + { + var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); + if (agentEntity is null) return; + + var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); + if (hostEntity is null) return; + + if (FilterEventId(@event)) return; + + var hostLog = await InsertHostLogAsync(hostEntity, @event, cancellationToken); + + if (hostLog is null || FilterMonitoringHostLog(hostLog)) return; + + await _database.HostLogMonitoring() + .InsertOneAsync(new HostLogMonitoringEntity + { + Host = hostEntity.Id, + Insert = hostLog.Insert, + Timestamp = hostLog.Timestamp, + Category = hostLog.Category, + Status = hostLog.Status, + Message = hostLog.Message, + Dispatch = DispatchEnum.Pending.ToString() + }, cancellationToken: cancellationToken); + } + + private async ValueTask InsertAgentLogAsync(AgentSession session, Event @event, CancellationToken cancellationToken) + { + var agentEntity = await _database.Agent() + .Aggregate() + .Match(Builders.Filter.Eq(p => p.Id, session.Id)) + .Lookup(_database.Host(), p => p.Serial, p => p.Agent, p => p.Hosts) + .FirstOrDefaultAsync(cancellationToken); + + if (agentEntity is null) return null; + + StatusEnum? status = @event.Status switch + { + StatusType.Information => StatusEnum.Information, + StatusType.Warning => StatusEnum.Warning, + StatusType.Error => StatusEnum.Error, + _ => null + }; + + CategoryEnum? category = @event.Category.ToLower() switch + { + "network" => CategoryEnum.Network, + "application" => CategoryEnum.Application, + "security" => CategoryEnum.Security, + "system" => CategoryEnum.System, + _ => null + }; + + var date = DateTime.Now; + + var log = new AgentLogEntity + { + Insert = date, + Agent = agentEntity.Id, + Timestamp = @event.Timestamp, + EventId = @event.EventId.ToString(), + Source = @event.Source, + Status = status.ToString(), + Category = category.ToString(), + Message = @event.Message + }; + + await _database.AgentLog().InsertOneAsync(log, cancellationToken: cancellationToken); + return log; + } + + private async ValueTask InsertHostLogAsync(HostEntity hostEntity, Event @event, CancellationToken cancellationToken) + { + StatusEnum? status = @event.Status switch + { + StatusType.Information => StatusEnum.Information, + StatusType.Warning => StatusEnum.Warning, + StatusType.Error => StatusEnum.Error, + StatusType.Critical => StatusEnum.Error, + StatusType.Unknown => null, + _ => null + }; + + CategoryEnum? category = null; + switch (@event.Category) + { + case var _ when @event.Category.Contains("network", StringComparison.InvariantCultureIgnoreCase): + category = CategoryEnum.Network; + break; + + case var _ when @event.Category.Contains("application", StringComparison.InvariantCultureIgnoreCase): + category = CategoryEnum.Application; + break; + + case var _ when @event.Category.Contains("security", StringComparison.InvariantCultureIgnoreCase): + category = CategoryEnum.Security; + break; + + case var _ when @event.Category.Contains("system", StringComparison.InvariantCultureIgnoreCase): + category = CategoryEnum.System; + break; + + case var _ when @event.Category.Contains("printservice", StringComparison.InvariantCultureIgnoreCase): + category = CategoryEnum.Printer; + break; + + case var _ when @event.Category.Contains("taskscheduler", StringComparison.InvariantCultureIgnoreCase): + category = CategoryEnum.Task; + break; + + case var _ when @event.Category.Contains("terminalservices", StringComparison.InvariantCultureIgnoreCase): + category = CategoryEnum.RDP; + break; + + case var _ when @event.Category.Contains("smbclient", StringComparison.InvariantCultureIgnoreCase): + category = CategoryEnum.Network; + break; + + case var _ when @event.Category.Contains("smbserver", StringComparison.InvariantCultureIgnoreCase): + category = CategoryEnum.Network; + break; + + case var _ when @event.Category.Contains("storagespaces", StringComparison.InvariantCultureIgnoreCase): + category = CategoryEnum.System; + break; + + case var _ when @event.Category.Contains("diagnostics", StringComparison.InvariantCultureIgnoreCase): + category = CategoryEnum.System; + break; + + default: + break; + } + + var date = DateTime.Now; + + var log = new HostLogEntity + { + Insert = date, + Host = hostEntity.Id, + Timestamp = @event.Timestamp, + EventId = @event.EventId.ToString(), + Status = status.ToString(), + Source = @event.Source, + Category = category?.ToString(), + Message = @event.Message + }; + + await _database.HostLog().InsertOneAsync(log, cancellationToken: cancellationToken); + return log; + } + + private bool FilterEventId(Event @event) + { + var filter = new List + { + 0, + 3, + 4, + 16, + 37, + 900, + 902, + 903, + 1001, + 1003, + 1008, + 1023, + 1066, + 4624, + 4625, + 4634, + 4648, + 4672, + 4776, + 4798, + 4799, + 5058, + 5059, + 5061, + 5379, + 5612, + 5781, + //7036, + 8014, + 8016, + 8019, + 8194, + 8224, + 9009, + 9027, + 10001, + 10016, + 16384, + 16394, + 36874, + 36888, + }; + + if (filter.Any(p => p == @event.EventId)) return true; + return false; + } + + private bool FilterMonitoringHostLog(HostLogEntity hostLog) + { + //_logger.LogDebug($"try filter event: {hostLog.Category}.{hostLog.Source}.{hostLog.Status}"); + + if (Enum.TryParse(hostLog.Status, out StatusType status) is false) return true; + + if (hostLog.Category == CategoryEnum.System.ToString()) + { + if (hostLog.Source == "Service Control Manager" && status < StatusType.Warning) return true; + } + + if (hostLog.Category == CategoryEnum.Task.ToString()) + { + if (status < StatusType.Error) return true; + } + + // skip rdp infos + if (hostLog.Category == CategoryEnum.RDP.ToString()) + { + if (hostLog.EventId == "261") return true; + } + + // skip smbclient (veeam errors) + if (hostLog.Category == CategoryEnum.Security.ToString()) + { + if (hostLog.Source == "Microsoft-Windows-SMBClient") return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Handlers/Agent/InterfaceHandler.cs b/src/Server/Insight.Server/Network/Handlers/Agent/InterfaceHandler.cs new file mode 100644 index 0000000..7cfc212 --- /dev/null +++ b/src/Server/Insight.Server/Network/Handlers/Agent/InterfaceHandler.cs @@ -0,0 +1,299 @@ +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; +using Insight.Infrastructure; +using Insight.Infrastructure.Entities; +using MongoDB.Bson; +using MongoDB.Driver; + +namespace Insight.Server.Network.Handlers.Agent +{ + public class InterfaceHandler : IAgentMessageHandler + { + private readonly IMongoDatabase _database; + + public InterfaceHandler(IMongoDatabase database) + { + _database = database; + } + + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage + { + if (message is InterfaceList interfaces) + { + await OnInterfacesAsync(sender, interfaces, cancellationToken); + } + } + + private async ValueTask OnInterfacesAsync(AgentSession session, List interfaces, CancellationToken cancellationToken) + { + var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); + if (agentEntity is null) return; + + var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); + if (hostEntity is null) return; + + var batch = ObjectId.GenerateNewId().ToString(); + var date = DateTime.Now; + + // interfaces + + if (interfaces is not null && interfaces.Any()) + { + var interfaceBulk = new List>(); + + foreach (var @interface in interfaces) + { + var interfaceFilter = Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Eq(x => x.Index, @interface.Index) + }); + + var interfaceUpdate = Builders.Update + .SetOnInsert(p => p.Insert, date) + .SetOnInsert(p => p.Host, hostEntity.Id) + .SetOnInsert(p => p.Index, @interface.Index) + .Set(p => p.Update, date) + .Set(p => p.Batch, batch) + + .Set(p => p.Mac, @interface?.Mac) + .Set(p => p.Name, @interface?.Name) + .Set(p => p.Description, @interface?.Description) + .Set(p => p.Physical, @interface?.Physical) + .Set(p => p.Status, @interface?.Status?.ToString()) + .Set(p => p.Suffix, @interface?.Suffix) + .Set(p => p.Speed, @interface?.Speed) + .Set(p => p.Ipv4Mtu, @interface?.Ipv4Mtu) + .Set(p => p.Ipv4Dhcp, @interface?.Ipv4Dhcp) + + .Set(p => p.Ipv4Forwarding, @interface?.Ipv4Forwarding) + .Set(p => p.Ipv6Mtu, @interface?.Ipv6Mtu) + .Set(p => p.Sent, @interface?.Sent) + .Set(p => p.Received, @interface?.Received) + .Set(p => p.IncomingPacketsDiscarded, @interface?.IncomingPacketsDiscarded) + .Set(p => p.IncomingPacketsWithErrors, @interface?.IncomingPacketsWithErrors) + .Set(p => p.IncomingUnknownProtocolPackets, @interface?.IncomingUnknownProtocolPackets) + .Set(p => p.OutgoingPacketsDiscarded, @interface?.OutgoingPacketsDiscarded) + .Set(p => p.OutgoingPacketsWithErrors, @interface?.OutgoingPacketsWithErrors); + + interfaceBulk.Add(new UpdateOneModel(interfaceFilter, interfaceUpdate) + { + IsUpsert = true + }); + } + + interfaceBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Ne(x => x.Batch, batch) + }))); + + var interfaceResult = await _database.HostInterface().BulkWriteAsync(interfaceBulk, cancellationToken: cancellationToken); + } + + // addresses + + if (interfaces is not null && interfaces.Any()) + { + var addressBulk = new List>(); + + foreach (var @interface in interfaces) + { + var interfaceId = await _database.HostInterface() + .Find(p => p.Host == hostEntity.Id && p.Index == @interface.Index) + .Project(p => p.Id) + .FirstOrDefaultAsync(); + + if (@interface.Addresses is not null && @interface.Addresses.Any()) + { + foreach (var address in @interface.Addresses) + { + var addressFilter = Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Eq(x => x.Interface, interfaceId), + Builders.Filter.Eq(x => x.Address, address?.IpAddress?.Address), + Builders.Filter.Eq(x => x.Mask, address?.Ipv4Mask?.Address) + }); + + var addressUpdate = Builders.Update + .SetOnInsert(p => p.Insert, date) + .SetOnInsert(p => p.Host, hostEntity.Id) + .SetOnInsert(p => p.Interface, interfaceId) + .SetOnInsert(p => p.Address, address?.IpAddress?.Address) + .SetOnInsert(p => p.Mask, address?.Ipv4Mask?.Address) + .Set(p => p.Update, date) + .Set(p => p.Batch, batch); + + addressBulk.Add(new UpdateOneModel(addressFilter, addressUpdate) + { + IsUpsert = true + }); + } + } + } + + addressBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Ne(x => x.Batch, batch) + }))); + + var addressResult = await _database.HostInterfaceAddress().BulkWriteAsync(addressBulk, cancellationToken: cancellationToken); + } + + // gateways + + if (interfaces is not null && interfaces.Any()) + { + var gatewayBulk = new List>(); + + foreach (var @interface in interfaces) + { + var interfaceId = await _database.HostInterface() + .Find(p => p.Host == hostEntity.Id && p.Index == @interface.Index) + .Project(p => p.Id) + .FirstOrDefaultAsync(); + + if (@interface.Gateways is not null && @interface.Gateways.Any()) + { + foreach (var gateway in @interface.Gateways) + { + var gatewayFilter = Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Eq(x => x.Interface, interfaceId), + Builders.Filter.Eq(x => x.Address, gateway?.Address) + }); + + var gatewayUpdate = Builders.Update + .SetOnInsert(p => p.Insert, date) + .SetOnInsert(p => p.Host, hostEntity.Id) + .SetOnInsert(p => p.Interface, interfaceId) + .SetOnInsert(p => p.Address, gateway?.Address) + .Set(p => p.Update, date) + .Set(p => p.Batch, batch); + + gatewayBulk.Add(new UpdateOneModel(gatewayFilter, gatewayUpdate) + { + IsUpsert = true + }); + } + } + } + + gatewayBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Ne(x => x.Batch, batch) + }))); + + var gatewayResult = await _database.HostInterfaceGateway().BulkWriteAsync(gatewayBulk, cancellationToken: cancellationToken); + } + + // nameservers + + if (interfaces is not null && interfaces.Any()) + { + var nameserverBulk = new List>(); + + foreach (var @interface in interfaces) + { + var interfaceId = await _database.HostInterface() + .Find(p => p.Host == hostEntity.Id && p.Index == @interface.Index) + .Project(p => p.Id) + .FirstOrDefaultAsync(); + + if (@interface.Dns is not null && @interface.Dns.Any()) + { + foreach (var nameserver in @interface.Dns) + { + var nameserverFilter = Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Eq(x => x.Interface, interfaceId), + Builders.Filter.Eq(x => x.Address, nameserver?.Address) + }); + + var nameserverUpdate = Builders.Update + .SetOnInsert(p => p.Insert, date) + .SetOnInsert(p => p.Host, hostEntity.Id) + .SetOnInsert(p => p.Interface, interfaceId) + .SetOnInsert(p => p.Address, nameserver?.Address) + .Set(p => p.Update, date) + .Set(p => p.Batch, batch); + + nameserverBulk.Add(new UpdateOneModel(nameserverFilter, nameserverUpdate) + { + IsUpsert = true + }); + } + } + } + + nameserverBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Ne(x => x.Batch, batch) + }))); + + var nameserverResult = await _database.HostInterfaceNameserver().BulkWriteAsync(nameserverBulk, cancellationToken: cancellationToken); + } + + // routes + + if (interfaces is not null && interfaces.Any()) + { + var routeBulk = new List>(); + + foreach (var @interface in interfaces) + { + var interfaceId = await _database.HostInterface() + .Find(p => p.Host == hostEntity.Id && p.Index == @interface.Index) + .Project(p => p.Id) + .FirstOrDefaultAsync(); + + if (@interface.Routes is not null && @interface.Routes.Any()) + { + foreach (var route in @interface.Routes) + { + var routeFilter = Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Eq(x => x.Interface, interfaceId), + Builders.Filter.Eq(x => x.Destination, route?.Destination?.Address), + Builders.Filter.Eq(x => x.Gateway, route?.Gateway?.Address), + Builders.Filter.Eq(x => x.Mask, route?.Mask), + }); + + var routeUpdate = Builders.Update + .SetOnInsert(p => p.Insert, date) + .SetOnInsert(p => p.Host, hostEntity.Id) + .SetOnInsert(p => p.Interface, interfaceId) + .SetOnInsert(p => p.Destination, route?.Destination?.Address) + .SetOnInsert(p => p.Gateway, route?.Gateway?.Address) + .SetOnInsert(p => p.Mask, route?.Mask) + .Set(p => p.Update, date) + .Set(p => p.Batch, batch) + + .Set(p => p.Metric, route?.Metric); + + routeBulk.Add(new UpdateOneModel(routeFilter, routeUpdate) + { + IsUpsert = true + }); + } + } + } + + routeBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Ne(x => x.Batch, batch) + }))); + + var routeResult = await _database.HostInterfaceRoute().BulkWriteAsync(routeBulk, cancellationToken: cancellationToken); + } + } + } +} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Agent/Handlers/MainboardHandler.cs b/src/Server/Insight.Server/Network/Handlers/Agent/MainboardHandler.cs similarity index 74% rename from src/Server/Insight.Server/Network/Agent/Handlers/MainboardHandler.cs rename to src/Server/Insight.Server/Network/Handlers/Agent/MainboardHandler.cs index 95811a8..10e6121 100644 --- a/src/Server/Insight.Server/Network/Agent/Handlers/MainboardHandler.cs +++ b/src/Server/Insight.Server/Network/Handlers/Agent/MainboardHandler.cs @@ -1,22 +1,25 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; +using Insight.Infrastructure; using Insight.Infrastructure.Entities; using MongoDB.Driver; -namespace Insight.Server.Network.Agent.Handlers +namespace Insight.Server.Network.Handlers.Agent { - public class MainboardHandler(IMongoDatabase database) : IMessageHandler + public class MainboardHandler : IAgentMessageHandler { - private readonly IMongoDatabase _database = database; + private readonly IMongoDatabase _database; - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage + public MainboardHandler(IMongoDatabase database) { - switch (message) + _database = database; + } + + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage + { + if (message is Mainboard mainboard) { - case Mainboard mainboard: - await OnMainboardAsync(sender, mainboard, cancellationToken); - break; + await OnMainboardAsync(sender, mainboard, cancellationToken); } } diff --git a/src/Server/Insight.Server/Network/Handlers/Agent/MemoryHandler.cs b/src/Server/Insight.Server/Network/Handlers/Agent/MemoryHandler.cs new file mode 100644 index 0000000..99d78cd --- /dev/null +++ b/src/Server/Insight.Server/Network/Handlers/Agent/MemoryHandler.cs @@ -0,0 +1,83 @@ +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; +using Insight.Infrastructure; +using Insight.Infrastructure.Entities; +using MongoDB.Bson; +using MongoDB.Driver; + +namespace Insight.Server.Network.Handlers.Agent +{ + public class MemoryHandler : IAgentMessageHandler + { + private readonly IMongoDatabase _database; + + public MemoryHandler(IMongoDatabase database) + { + _database = database; + } + + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage + { + if (message is MemoryList memory) + { + await OnMemoryAsync(sender, memory, cancellationToken); + } + } + + private async ValueTask OnMemoryAsync(AgentSession session, List memory, CancellationToken cancellationToken) + { + var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); + if (agentEntity is null) return; + + var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); + if (hostEntity is null) return; + + var batch = ObjectId.GenerateNewId().ToString(); + var date = DateTime.Now; + + var bulk = new List>(); + + if (memory is not null && memory.Any()) + { + foreach (var mem in memory) + { + var filterDefinition = Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Eq(x => x.Index, mem.Index) + }); + + var updateDefinition = Builders.Update + .SetOnInsert(p => p.Insert, date) + .SetOnInsert(p => p.Host, hostEntity.Id) + .SetOnInsert(p => p.Index, mem.Index) + .Set(p => p.Update, date) + .Set(p => p.Batch, batch) + .Set(p => p.Company, mem.Manufacturer) + .Set(p => p.Name, mem.Model) + .Set(p => p.Tag, mem.Tag) + .Set(p => p.Location, mem.Location) + .Set(p => p.Serial, mem.Serial) + .Set(p => p.Capacity, mem.Capacity) + .Set(p => p.Clock, mem.Speed) + .Set(p => p.CurrentClock, mem.ConfiguredSpeed) + .Set(p => p.Voltage, mem.Voltage) + .Set(p => p.CurrentVoltage, mem.ConfiguredVoltage); + + bulk.Add(new UpdateOneModel(filterDefinition, updateDefinition) + { + IsUpsert = true + }); + } + } + + bulk.Add(new DeleteManyModel(Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Ne(x => x.Batch, batch) + }))); + + var result = await _database.HostMemory().BulkWriteAsync(bulk, cancellationToken: cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Handlers/Agent/OperationSystemHandler.cs b/src/Server/Insight.Server/Network/Handlers/Agent/OperationSystemHandler.cs new file mode 100644 index 0000000..ca8743e --- /dev/null +++ b/src/Server/Insight.Server/Network/Handlers/Agent/OperationSystemHandler.cs @@ -0,0 +1,51 @@ +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; +using Insight.Infrastructure; +using Insight.Infrastructure.Entities; +using MongoDB.Driver; + +namespace Insight.Server.Network.Handlers.Agent +{ + public class OperationSystemHandler : IAgentMessageHandler + { + private readonly IMongoDatabase _database; + + public OperationSystemHandler(IMongoDatabase database) + { + _database = database; + } + + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage + { + if (message is OperationSystem os) + { + await OnOperationSystemAsync(sender, os, cancellationToken); + } + } + + private async ValueTask OnOperationSystemAsync(AgentSession session, OperationSystem operatingSystem, CancellationToken cancellationToken) + { + var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); + if (agentEntity is null) return; + + var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); + if (hostEntity is null) return; + + var date = DateTime.Now; + + await _database.HostOs().UpdateOneAsync(p => p.Host == hostEntity.Id, Builders.Update + .SetOnInsert(p => p.Insert, date) + .SetOnInsert(p => p.Host, hostEntity.Id) + .Set(p => p.Update, date) + .Set(p => p.Name, operatingSystem.Name) + .Set(p => p.Version, operatingSystem.Version) + .Set(p => p.Architecture, operatingSystem.Architecture.ToString()) + .Set(p => p.SerialNumber, operatingSystem.SerialNumber) + .Set(p => p.Virtual, operatingSystem.Virtual) + .Set(p => p.Installed, operatingSystem.InstallDate), new UpdateOptions + { + IsUpsert = true + }, cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Handlers/Agent/PrinterHandler.cs b/src/Server/Insight.Server/Network/Handlers/Agent/PrinterHandler.cs new file mode 100644 index 0000000..eed8b2c --- /dev/null +++ b/src/Server/Insight.Server/Network/Handlers/Agent/PrinterHandler.cs @@ -0,0 +1,76 @@ +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; +using Insight.Infrastructure; +using Insight.Infrastructure.Entities; +using MongoDB.Bson; +using MongoDB.Driver; + +namespace Insight.Server.Network.Handlers.Agent +{ + public class PrinterHandler : IAgentMessageHandler + { + private readonly IMongoDatabase _database; + + public PrinterHandler(IMongoDatabase database) + { + _database = database; + } + + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage + { + if (message is PrinterList printers) + { + await OnPrintersAsync(sender, printers, cancellationToken); + } + } + + private async ValueTask OnPrintersAsync(AgentSession session, List printers, CancellationToken cancellationToken) + { + var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); + if (agentEntity is null) return; + + var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); + if (hostEntity is null) return; + + var batch = ObjectId.GenerateNewId().ToString(); + var date = DateTime.Now; + + var bulk = new List>(); + + if (printers is not null && printers.Any()) + { + foreach (var printer in printers) + { + var filterDefinition = Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Eq(x => x.Name, printer.Name) + }); + + var updateDefinition = Builders.Update + .SetOnInsert(p => p.Insert, date) + .SetOnInsert(p => p.Host, hostEntity.Id) + .SetOnInsert(p => p.Name, printer.Name) + .Set(p => p.Update, date) + .Set(p => p.Batch, batch) + .Set(p => p.Port, printer.Port) + .Set(p => p.Location, printer.Location) + .Set(p => p.Comment, printer.Comment); + + bulk.Add(new UpdateOneModel(filterDefinition, updateDefinition) + { + IsUpsert = true + }); + } + } + + bulk.Add(new DeleteManyModel(Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Ne(x => x.Batch, batch) + }))); + + var result = await _database.HostPrinter().BulkWriteAsync(bulk, cancellationToken: cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Handlers/Agent/ProcessorHandler.cs b/src/Server/Insight.Server/Network/Handlers/Agent/ProcessorHandler.cs new file mode 100644 index 0000000..a4f9c5d --- /dev/null +++ b/src/Server/Insight.Server/Network/Handlers/Agent/ProcessorHandler.cs @@ -0,0 +1,87 @@ +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; +using Insight.Infrastructure; +using Insight.Infrastructure.Entities; +using MongoDB.Bson; +using MongoDB.Driver; + +namespace Insight.Server.Network.Handlers.Agent +{ + public class ProcessorHandler : IAgentMessageHandler + { + private readonly IMongoDatabase _database; + + public ProcessorHandler(IMongoDatabase database) + { + _database = database; + } + + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage + { + if (message is ProcessorList processors) + { + await OnProcessorsAsync(sender, processors, cancellationToken); + } + } + + private async ValueTask OnProcessorsAsync(AgentSession session, List processors, CancellationToken cancellationToken) + { + var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); + if (agentEntity is null) return; + + var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); + if (hostEntity is null) return; + + var batch = ObjectId.GenerateNewId().ToString(); + var date = DateTime.Now; + + var bulk = new List>(); + + if (processors is not null && processors.Any()) + { + foreach (var processor in processors) + { + var filterDefinition = Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Eq(x => x.Index, processor.Index) + }); + + var updateDefinition = Builders.Update + .SetOnInsert(p => p.Insert, date) + .SetOnInsert(p => p.Host, hostEntity.Id) + .SetOnInsert(p => p.Index, processor.Index) + .Set(p => p.Update, date) + .Set(p => p.Batch, batch) + .Set(p => p.Company, processor.Manufacturer) + .Set(p => p.Name, processor.Name) + .Set(p => p.Socket, processor.Socket) + .Set(p => p.Serial, processor.SerialNumber) + .Set(p => p.Version, processor.Version) + .Set(p => p.Cores, processor.Cores) + .Set(p => p.LogicalCores, processor.LogicalCores) + .Set(p => p.Clock, processor.MaxSpeed) + .Set(p => p.CurrentClock, processor.CurrentSpeed) + .Set(p => p.L1Size, processor.L1Size) + .Set(p => p.L2Size, processor.L2Size) + .Set(p => p.L3Size, processor.L3Size) + .Set(p => p.Virtualization, processor.Virtualization) + .Set(p => p.PNP, processor.DeviceId); + + bulk.Add(new UpdateOneModel(filterDefinition, updateDefinition) + { + IsUpsert = true + }); + } + } + + bulk.Add(new DeleteManyModel(Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Ne(x => x.Batch, batch) + }))); + + var result = await _database.HostProcessor().BulkWriteAsync(bulk, cancellationToken: cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Handlers/Agent/ServiceHandler.cs b/src/Server/Insight.Server/Network/Handlers/Agent/ServiceHandler.cs new file mode 100644 index 0000000..1108236 --- /dev/null +++ b/src/Server/Insight.Server/Network/Handlers/Agent/ServiceHandler.cs @@ -0,0 +1,81 @@ +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; +using Insight.Infrastructure; +using Insight.Infrastructure.Entities; +using MongoDB.Bson; +using MongoDB.Driver; + +namespace Insight.Server.Network.Handlers.Agent +{ + public class ServiceHandler : IAgentMessageHandler + { + private readonly IMongoDatabase _database; + + public ServiceHandler(IMongoDatabase database) + { + _database = database; + } + + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage + { + if (message is ServiceList services) + { + await OnServicesAsync(sender, services, cancellationToken); + } + } + + private async ValueTask OnServicesAsync(AgentSession session, List services, CancellationToken cancellationToken) + { + var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); + if (agentEntity is null) return; + + var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); + if (hostEntity is null) return; + + var batch = ObjectId.GenerateNewId().ToString(); + var date = DateTime.Now; + + var bulk = new List>(); + + if (services is not null && services.Any()) + { + foreach (var service in services) + { + var filterDefinition = Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Eq(x => x.Name, service.Name) + }); + + var updateDefinition = Builders.Update + .SetOnInsert(p => p.Insert, date) + .SetOnInsert(p => p.Host, hostEntity.Id) + .SetOnInsert(p => p.Name, service.Name) + .Set(p => p.Update, date) + .Set(p => p.Batch, batch) + .Set(p => p.DisplayName, service.Display) + .Set(p => p.Description, service.Description) + .Set(p => p.StartMode, service.StartMode.ToString()) + .Set(p => p.State, service.Status.ToString()) + .Set(p => p.ProcessId, service.ProcessId) + .Set(p => p.Delay, service.Delay) + .Set(p => p.Path, service.PathName) + .Set(p => p.Account, service.Account); + + bulk.Add(new UpdateOneModel(filterDefinition, updateDefinition) + { + IsUpsert = true + }); + } + } + + bulk.Add(new DeleteManyModel(Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Ne(x => x.Batch, batch) + }))); + + var result = await _database.HostService().BulkWriteAsync(bulk, cancellationToken: cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Handlers/Agent/SessionHandler.cs b/src/Server/Insight.Server/Network/Handlers/Agent/SessionHandler.cs new file mode 100644 index 0000000..ffad33d --- /dev/null +++ b/src/Server/Insight.Server/Network/Handlers/Agent/SessionHandler.cs @@ -0,0 +1,77 @@ +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; +using Insight.Infrastructure; +using Insight.Infrastructure.Entities; +using MongoDB.Bson; +using MongoDB.Driver; + +namespace Insight.Server.Network.Handlers.Agent +{ + public class SessionHandler : IAgentMessageHandler + { + private readonly IMongoDatabase _database; + + public SessionHandler(IMongoDatabase database) + { + _database = database; + } + + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage + { + if (message is SessionList sessions) + { + await OnSessionsAsync(sender, sessions, cancellationToken); + } + } + + private async ValueTask OnSessionsAsync(AgentSession session, List sessions, CancellationToken cancellationToken) + { + var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); + if (agentEntity is null) return; + + var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); + if (hostEntity is null) return; + + var batch = ObjectId.GenerateNewId().ToString(); + var date = DateTime.Now; + + var bulk = new List>(); + + if (sessions is not null && sessions.Any()) + { + foreach (var sess in sessions) + { + var filterDefinition = Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Eq(x => x.Sid, sess.Sid) + }); + + var updateDefinition = Builders.Update + .SetOnInsert(p => p.Insert, date) + .SetOnInsert(p => p.Host, hostEntity.Id) + .SetOnInsert(p => p.Sid, sess.Sid) + .Set(p => p.Update, date) + .Set(p => p.Batch, batch) + .Set(p => p.User, sess.User) + .Set(p => p.Remote, sess.Remote) + .Set(p => p.Type, sess.Type) + .Set(p => p.State, sess.Status); + + bulk.Add(new UpdateOneModel(filterDefinition, updateDefinition) + { + IsUpsert = true + }); + } + } + + bulk.Add(new DeleteManyModel(Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Ne(x => x.Batch, batch) + }))); + + var result = await _database.HostSession().BulkWriteAsync(bulk, cancellationToken: cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Handlers/Agent/SoftwareHandler.cs b/src/Server/Insight.Server/Network/Handlers/Agent/SoftwareHandler.cs new file mode 100644 index 0000000..1e986fa --- /dev/null +++ b/src/Server/Insight.Server/Network/Handlers/Agent/SoftwareHandler.cs @@ -0,0 +1,78 @@ +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; +using Insight.Infrastructure; +using Insight.Infrastructure.Entities; +using MongoDB.Bson; +using MongoDB.Driver; + +namespace Insight.Server.Network.Handlers.Agent +{ + public class SoftwareHandler : IAgentMessageHandler + { + private readonly IMongoDatabase _database; + + public SoftwareHandler(IMongoDatabase database) + { + _database = database; + } + + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage + { + if (message is ApplicationList applications) + { + await OnApplicationsAsync(sender, applications, cancellationToken); + } + } + + private async ValueTask OnApplicationsAsync(AgentSession session, List applications, CancellationToken cancellationToken) + { + var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); + if (agentEntity is null) return; + + var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); + if (hostEntity is null) return; + + var batch = ObjectId.GenerateNewId().ToString(); + var date = DateTime.Now; + + var bulk = new List>(); + + if (applications is not null && applications.Any()) + { + foreach (var app in applications) + { + var filterDefinition = Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Eq(x => x.Name, app.Name), + Builders.Filter.Eq(x => x.Architecture, app.Architecture?.ToString()) + }); + + var updateDefinition = Builders.Update + .SetOnInsert(p => p.Insert, date) + .SetOnInsert(p => p.Host, hostEntity.Id) + .SetOnInsert(p => p.Name, app.Name) + .SetOnInsert(p => p.Architecture, app.Architecture?.ToString()) + .Set(p => p.Update, date) + .Set(p => p.Batch, batch) + .Set(p => p.Company, app.Publisher) + .Set(p => p.Version, app.Version) + .Set(p => p.InstallDate, app.InstallDate); + + bulk.Add(new UpdateOneModel(filterDefinition, updateDefinition) + { + IsUpsert = true + }); + } + } + + bulk.Add(new DeleteManyModel(Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Ne(x => x.Batch, batch) + }))); + + var result = await _database.HostApplication().BulkWriteAsync(bulk, cancellationToken: cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Handlers/Agent/StoragePoolHandler.cs b/src/Server/Insight.Server/Network/Handlers/Agent/StoragePoolHandler.cs new file mode 100644 index 0000000..7b00c9c --- /dev/null +++ b/src/Server/Insight.Server/Network/Handlers/Agent/StoragePoolHandler.cs @@ -0,0 +1,253 @@ +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; +using Insight.Infrastructure; +using Insight.Infrastructure.Entities; +using MongoDB.Bson; +using MongoDB.Driver; + +namespace Insight.Server.Network.Handlers.Agent +{ + public class StoragePoolHandler : IAgentMessageHandler + { + private readonly IMongoDatabase _database; + + public StoragePoolHandler(IMongoDatabase database) + { + _database = database; + } + + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage + { + if (message is StoragePoolList storagePools) + { + await OnStoragePoolsAsync(sender, storagePools, cancellationToken); + } + } + + private async ValueTask OnStoragePoolsAsync(AgentSession session, List? storagePools, CancellationToken cancellationToken) + { + var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); + if (agentEntity is null) return; + + var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); + if (hostEntity is null) return; + + var batch = ObjectId.GenerateNewId().ToString(); + var date = DateTime.Now; + + // storagepools + + if (storagePools is not null && storagePools.Any()) + { + var storagepoolBulk = new List>(); + + foreach (var storagePool in storagePools) + { + var storagePoolFilter = Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Eq(x => x.UniqueId, storagePool.UniqueId) + }); + + List? states = null; + + if (storagePool.States is not null) + { + states = new List(); + + foreach (var state in storagePool.States) + { + states.Add(state.ToString()); + } + } + + var storagePoolUpdate = Builders.Update + .SetOnInsert(p => p.Insert, date) + .SetOnInsert(p => p.Host, hostEntity.Id) + .SetOnInsert(p => p.UniqueId, storagePool.UniqueId) + .Set(p => p.Update, date) + .Set(p => p.Batch, batch) + + .Set(p => p.Name, storagePool.FriendlyName) + .Set(p => p.Health, storagePool.Health?.ToString()) + .Set(p => p.Resiliency, storagePool.Resiliency) + .Set(p => p.Primordial, storagePool.IsPrimordial) + .Set(p => p.ReadOnly, storagePool.IsReadOnly) + .Set(p => p.Clustered, storagePool.IsClustered) + .Set(p => p.Size, storagePool.Size) + .Set(p => p.AllocatedSize, storagePool.AllocatedSize) + .Set(p => p.SectorSize, storagePool.SectorSize) + .Set(p => p.States, states); + + storagepoolBulk.Add(new UpdateOneModel(storagePoolFilter, storagePoolUpdate) + { + IsUpsert = true + }); + } + + storagepoolBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Ne(x => x.Batch, batch) + }))); + + var storagePoolResult = await _database.HostStoragePool().BulkWriteAsync(storagepoolBulk, cancellationToken: cancellationToken); + } + + // physicaldisks + + if (storagePools is not null && storagePools.Any()) + { + var physicalDiskBulk = new List>(); + + foreach (var storagePool in storagePools) + { + var storagePoolId = await _database.HostStoragePool() + .Find(p => p.Host == hostEntity.Id && p.UniqueId == storagePool.UniqueId) + .Project(p => p.Id) + .FirstOrDefaultAsync(); + + if (storagePool.PhysicalDisks is not null && storagePool.PhysicalDisks.Any()) + { + foreach (var physicalDisk in storagePool.PhysicalDisks) + { + var physicalDiskFilter = Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Eq(x => x.StoragePool, storagePoolId), + Builders.Filter.Eq(x => x.UniqueId, physicalDisk.UniqueId) + }); + + List? states = null; + + if (physicalDisk.States is not null) + { + states = new List(); + + foreach (var state in physicalDisk.States) + { + states.Add(state.ToString()); + } + } + + var physicalDiskUpdate = Builders.Update + .SetOnInsert(p => p.Insert, date) + .SetOnInsert(p => p.Host, hostEntity.Id) + .SetOnInsert(p => p.StoragePool, storagePoolId) + .SetOnInsert(p => p.UniqueId, physicalDisk.UniqueId) + .Set(p => p.Update, date) + .Set(p => p.Batch, batch) + + .Set(p => p.DeviceId, physicalDisk.DeviceId) + .Set(p => p.Name, physicalDisk.FriendlyName) + .Set(p => p.Manufacturer, physicalDisk.Manufacturer) + .Set(p => p.Model, physicalDisk.Model) + .Set(p => p.Media, physicalDisk.MediaType.ToString()) + .Set(p => p.Bus, physicalDisk.BusType.ToString()) + .Set(p => p.Health, physicalDisk.Health.ToString()) + .Set(p => p.Usage, physicalDisk.Usage) + .Set(p => p.Location, physicalDisk.PhysicalLocation) + .Set(p => p.Serial, physicalDisk.SerialNumber) + .Set(p => p.Firmware, physicalDisk.FirmwareVersion) + .Set(p => p.Size, physicalDisk.Size) + .Set(p => p.AllocatedSize, physicalDisk.AllocatedSize) + .Set(p => p.Footprint, physicalDisk.VirtualDiskFootprint) + .Set(p => p.LogicalSectorSize, physicalDisk.LogicalSectorSize) + .Set(p => p.PhysicalSectorSize, physicalDisk.PhysicalSectorSize) + .Set(p => p.States, states); + + physicalDiskBulk.Add(new UpdateOneModel(physicalDiskFilter, physicalDiskUpdate) + { + IsUpsert = true + }); + } + } + } + + physicalDiskBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Ne(x => x.Batch, batch) + }))); + + var physicalDiskResult = await _database.HostStoragePoolPhysicalDisk().BulkWriteAsync(physicalDiskBulk, cancellationToken: cancellationToken); + } + + // virtual disks + + if (storagePools is not null && storagePools.Any()) + { + var virtualDiskBulk = new List>(); + + foreach (var storagePool in storagePools) + { + if (storagePool.VirtualDisks is not null && storagePool.VirtualDisks.Any()) + { + foreach (var virtualDisk in storagePool.VirtualDisks) + { + var storagePoolId = await _database.HostStoragePool() + .Find(p => p.Host == hostEntity.Id && p.UniqueId == storagePool.UniqueId) + .Project(p => p.Id) + .FirstOrDefaultAsync(); + + var virtualDiskFilter = Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Eq(x => x.StoragePool, storagePoolId), + Builders.Filter.Eq(x => x.UniqueId, virtualDisk.UniqueId) + }); + + List? states = null; + + if (virtualDisk.States is not null) + { + states = new List(); + + foreach (var state in virtualDisk.States) + { + states.Add(state.ToString()); + } + } + + var virtualDiskUpdate = Builders.Update + .SetOnInsert(p => p.Insert, date) + .SetOnInsert(p => p.Host, hostEntity.Id) + .SetOnInsert(p => p.StoragePool, storagePoolId) + .SetOnInsert(p => p.UniqueId, virtualDisk.UniqueId) + .Set(p => p.Update, date) + .Set(p => p.Batch, batch) + + .Set(p => p.Name, virtualDisk.FriendlyName) + .Set(p => p.Health, virtualDisk.Health.ToString()) + .Set(p => p.Access, virtualDisk.AccessType.ToString()) + .Set(p => p.Provisioning, virtualDisk.ProvisioningType.ToString()) + .Set(p => p.PhysicalRedundancy, virtualDisk.PhysicalDiskRedundancy) + .Set(p => p.Resiliency, virtualDisk.ResiliencySettingName) + .Set(p => p.Deduplication, virtualDisk.Deduplication) + .Set(p => p.Snapshot, virtualDisk.IsSnapshot) + .Set(p => p.Size, virtualDisk.Size) + .Set(p => p.AllocatedSize, virtualDisk.AllocatedSize) + .Set(p => p.Footprint, virtualDisk.FootprintOnPool) + .Set(p => p.ReadCacheSize, virtualDisk.ReadCacheSize) + .Set(p => p.WriteCacheSize, virtualDisk.WriteCacheSize) + .Set(p => p.States, states); + + virtualDiskBulk.Add(new UpdateOneModel(virtualDiskFilter, virtualDiskUpdate) + { + IsUpsert = true + }); + } + } + } + + virtualDiskBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Ne(x => x.Batch, batch) + }))); + + var virtualDiskResult = await _database.HostStoragePoolVirtualDisk().BulkWriteAsync(virtualDiskBulk, cancellationToken: cancellationToken); + } + } + } +} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Handlers/Agent/SystemInfoHandler.cs b/src/Server/Insight.Server/Network/Handlers/Agent/SystemInfoHandler.cs new file mode 100644 index 0000000..7abab05 --- /dev/null +++ b/src/Server/Insight.Server/Network/Handlers/Agent/SystemInfoHandler.cs @@ -0,0 +1,49 @@ +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; +using Insight.Infrastructure; +using Insight.Infrastructure.Entities; +using MongoDB.Driver; + +namespace Insight.Server.Network.Handlers.Agent +{ + public class SystemInfoHandler : IAgentMessageHandler + { + private readonly IMongoDatabase _database; + + public SystemInfoHandler(IMongoDatabase database) + { + _database = database; + } + + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage + { + if (message is SystemInfo systemInfo) + { + await OnSystemInfoAsync(sender, systemInfo, cancellationToken); + } + } + + private async ValueTask OnSystemInfoAsync(AgentSession session, SystemInfo? system, CancellationToken cancellationToken) + { + var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); + if (agentEntity is null) return; + + var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); + if (hostEntity is null) return; + + var date = DateTime.Now; + + await _database.HostSystem().UpdateOneAsync(p => p.Host == hostEntity.Id, Builders.Update + .SetOnInsert(p => p.Insert, date) + .SetOnInsert(p => p.Host, hostEntity.Id) + .Set(p => p.Update, date) + .Set(p => p.BootUpTime, system.LastBootUpTime) + .Set(p => p.LocalTime, system.LocalDateTime) + .Set(p => p.Processes, system.Processes) + .Set(p => p.License, system.License), new UpdateOptions + { + IsUpsert = true + }, cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Handlers/Agent/TrapHandler.cs b/src/Server/Insight.Server/Network/Handlers/Agent/TrapHandler.cs new file mode 100644 index 0000000..9d8b817 --- /dev/null +++ b/src/Server/Insight.Server/Network/Handlers/Agent/TrapHandler.cs @@ -0,0 +1,289 @@ +using Insight.Agent.Enums; +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; +using Insight.Infrastructure; +using Insight.Infrastructure.Entities; +using Insight.Server.Models; +using MongoDB.Driver; +using System.Text; +using System.Text.RegularExpressions; +using static Insight.Server.Models.MonitorMessage; + +namespace Insight.Server.Network.Handlers.Agent +{ + public class TrapHandler : IAgentMessageHandler + { + private readonly IMongoDatabase _database; + + public TrapHandler(IMongoDatabase database) + { + _database = database; + } + + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage + { + if (message is Trap trap) + { + await OnTrapAsync(sender, trap, cancellationToken); + } + } + + private async ValueTask OnTrapAsync(AgentSession session, Trap? trap, CancellationToken cancellationToken) + { + if (trap is null) return; + + var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); + if (agentEntity is null) return; + + var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); + if (hostEntity is null) return; + + if (TryParse(trap, out var monitoring) is false) + { + //_logger.LogWarning($"Failed to parse"); + } + + // insert monitoring log + var monitoringLog = new HostLogMonitoringEntity + { + Host = hostEntity.Id, + Insert = DateTime.Now, + Timestamp = monitoring?.Timestamp, + Category = monitoring?.Category?.ToString(), + Status = monitoring?.Status?.ToString(), + Hostname = monitoring?.Hostname, + Task = monitoring?.Subject, + Message = monitoring?.Message, + Dispatch = DispatchEnum.Pending.ToString() + }; + + await _database.HostLogMonitoring() + .InsertOneAsync(monitoringLog, cancellationToken: cancellationToken); + + // insert host log + var log = new HostLogEntity + { + Insert = monitoringLog.Insert, + Host = monitoringLog.Host, + Category = monitoringLog.Category, + Status = monitoringLog.Status, + Source = "Trap", + Message = monitoringLog?.Task, + Timestamp = monitoringLog?.Insert + }; + + if (monitoringLog?.Message is not null) log.Message += $"\n{monitoringLog.Message}"; + + await _database.HostLog() + .InsertOneAsync(log, cancellationToken: cancellationToken) + .ConfigureAwait(false); + } + + private static bool TryParse(Trap packet, out MonitorMessage? monitoring) + { + monitoring = null; + + if (packet is null || packet.Data is null || packet.Data.Any() is false) return false; + + monitoring = new MonitorMessage + { + Community = packet.Community, + Category = CategoryEnum.Monitoring, + Endpoint = packet.Endpoint, + Timestamp = packet.Timestamp + }; + + if (Enum.TryParse(packet.Community, true, out var application)) + { + monitoring.Application = application; + } + + StatusEnum? status; + string? task; + string? message; + + switch (application) + { + case ApplicationEnum.Acronis: + monitoring.Application = ApplicationEnum.Acronis; + if (ParseAcronis(packet.Data, out status, out task, out message) is false) return false; + break; + case ApplicationEnum.Veeam: + monitoring.Application = ApplicationEnum.Veeam; + if (ParseVeeam(packet.Data, out status, out task, out message) is false) return false; + break; + case ApplicationEnum.QNAP: + monitoring.Application = ApplicationEnum.QNAP; + monitoring.Category = CategoryEnum.System; + monitoring.Hostname = packet.Hostname; + if (ParseQnap(packet.Data, out status, out task, out message) is false) return false; + break; + default: + return false; + } + + monitoring.Status = status; + monitoring.Subject = task; + monitoring.Message = message; + + return true; + } + + private static bool ParseAcronis(List> data, out StatusEnum? status, out string? task, out string? message) + { + status = data[0].Value.ToLower() switch + { + "erfolgreich" => StatusEnum.Information, + "success" => StatusEnum.Information, + "information" => StatusEnum.Information, + "warnung" => StatusEnum.Warning, + "warning" => StatusEnum.Warning, + "fehler" => StatusEnum.Error, + "failed" => StatusEnum.Error, + "error" => StatusEnum.Error, + _ => null, + }; + + task = null; + message = null; + + var parsed = false; + + try + { + var trim = data[1].Value.Split(new string[] { ":" }, StringSplitOptions.None); + task = trim[1].Split(new string[] { "'" }, StringSplitOptions.None)[1].Split("'")[0].Trim(); + message = trim[1].Split(new string[] { "' " }, StringSplitOptions.None)[1].Trim(); + + parsed = true; + } + catch (Exception) + { + // skipped for base64 parse + } + + if (parsed) return true; + + try + { + var content = Regex.Replace(data[1].Value, @"\s+", ""); + var bytes = Enumerable.Range(0, content.Length) + .Where(x => x % 2 == 0) + .Select(x => Convert.ToByte(content.Substring(x, 2), 16)) + .ToArray(); + + content = Encoding.UTF8.GetString(bytes); + + var trim = content.Split(new string[] { ":" }, StringSplitOptions.None); + task = trim[1].Split(new string[] { "'" }, StringSplitOptions.None)[1].Split("'")[0].Trim(); + message = trim[1].Split(new string[] { "' " }, StringSplitOptions.None)[1].Trim(); + + parsed = true; + } + catch (Exception ex) + { + //_logger.LogError("{ex}", ex); + } + + if (parsed) return true; + return false; + } + + private static bool ParseVeeam(List> data, out StatusEnum? status, out string? task, out string? message) + { + status = null; + task = null; + message = null; + + var parsed = false; + + try + { + var summary = false; + + if (Guid.TryParse(data[0].Value, out _)) + summary = true; + + if (data[1].Value.ToLower() == "backup configuration job") + return false; + + status = (summary ? data[2].Value.ToLower() : data[3].Value.ToLower()) switch + { + "success" => StatusEnum.Information, + "warning" => StatusEnum.Warning, + "failed" => StatusEnum.Error, + "error" => StatusEnum.Error, + _ => null, + }; + + task = data[1].Value; + parsed = true; + } + catch (Exception) + { + + } + + if (parsed) return true; + return false; + } + + private static bool ParseQnap(List> data, out StatusEnum? status, out string? task, out string? message) + { + status = StatusEnum.Information; + task = null; + message = string.Empty; + + var parsed = false; + + try + { + var keywords = new Dictionary + { + { "power", StatusEnum.Information }, + { "rights", StatusEnum.Information }, + { "added", StatusEnum.Information }, + { "changed", StatusEnum.Information }, + { "password", StatusEnum.Information }, + { "firmware", StatusEnum.Information }, + { "restarting", StatusEnum.Information }, + { "detected", StatusEnum.Warning }, + { "external", StatusEnum.Warning }, + { "threshold", StatusEnum.Warning }, + { "file system", StatusEnum.Warning }, + { "raid", StatusEnum.Warning }, + { "full", StatusEnum.Error }, + { "failure", StatusEnum.Error }, + { "failed", StatusEnum.Error }, + { "resyncing", StatusEnum.Error }, + { "degraded", StatusEnum.Error }, + { "error", StatusEnum.Error }, + { "without error", StatusEnum.Information }, + { "ncsi", StatusEnum.Information } + }; + + foreach (var key in keywords) + { + if (Regex.IsMatch(string.Concat(data).ToLowerInvariant(), $@"\b{key.Key}\b")) + { + status = key.Value; + } + } + + foreach (var kv in data) + { + message += kv.Value; + } + + parsed = true; + } + catch (Exception ex) + { + //_logger.LogError("{ex}", ex); + } + + if (parsed) return true; + return false; + } + } +} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Handlers/Agent/UpdateHandler.cs b/src/Server/Insight.Server/Network/Handlers/Agent/UpdateHandler.cs new file mode 100644 index 0000000..f1fe72d --- /dev/null +++ b/src/Server/Insight.Server/Network/Handlers/Agent/UpdateHandler.cs @@ -0,0 +1,121 @@ +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; +using Insight.Infrastructure; +using Insight.Infrastructure.Entities; +using MongoDB.Bson; +using MongoDB.Driver; + +namespace Insight.Server.Network.Handlers.Agent +{ + public class UpdateHandler : IAgentMessageHandler + { + private readonly IMongoDatabase _database; + + public UpdateHandler(IMongoDatabase database) + { + _database = database; + } + + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage + { + if (message is UpdateList updates) + { + await OnUpdatesAsync(sender, updates, cancellationToken); + } + } + + private async ValueTask OnUpdatesAsync(AgentSession session, UpdateList updates, CancellationToken cancellationToken) + { + var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); + if (agentEntity is null) return; + + var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); + if (hostEntity is null) return; + + var batch = ObjectId.GenerateNewId().ToString(); + var date = DateTime.Now; + + var bulk = new List>(); + + if (updates is not null) + { + if (updates.Installed is not null && updates.Installed.Any()) + { + foreach (var update in updates.Installed) + { + var filterDefinition = Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Eq(x => x.Serial, update.Id) + }); + + var updateDefinition = Builders.Update + .SetOnInsert(p => p.Insert, date) + .SetOnInsert(p => p.Host, hostEntity.Id) + .SetOnInsert(p => p.Serial, update.Id) + .Set(p => p.Update, date) + .Set(p => p.Batch, batch) + + .Set(p => p.Pending, false) + .Set(p => p.Name, update.Name) + .Set(p => p.Description, update.Description) + .Set(p => p.SupportUrl, update.SupportUrl) + .Set(p => p.Result, update.Result.ToString()) + .Set(p => p.Date, update.Date); + + bulk.Add(new UpdateOneModel(filterDefinition, updateDefinition) + { + IsUpsert = true + }); + } + } + + if (updates.Pending is not null && updates.Pending.Any()) + { + foreach (var update in updates.Pending) + { + var filterDefinition = Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Eq(x => x.Serial, update.Id) + }); + + var updateDefinition = Builders.Update + .SetOnInsert(p => p.Insert, date) + .SetOnInsert(p => p.Host, hostEntity.Id) + .SetOnInsert(p => p.Serial, update.Id) + .Set(p => p.Update, date) + .Set(p => p.Batch, batch) + + .Set(p => p.Pending, true) + .Set(p => p.Name, update.Name) + .Set(p => p.Description, update.Description) + .Set(p => p.SupportUrl, update.SupportUrl) + .Set(p => p.Result, update.Result?.ToString()) + + .Set(p => p.Type, update.Type.ToString()) + .Set(p => p.Size, update.Size) + .Set(p => p.IsDownloaded, update.IsDownloaded) + .Set(p => p.CanRequestUserInput, update.CanRequestUserInput) + .Set(p => p.RebootBehavior, update.RebootBehavior?.ToString()) + + .Set(p => p.Date, update.Date); + + bulk.Add(new UpdateOneModel(filterDefinition, updateDefinition) + { + IsUpsert = true + }); + } + } + } + + bulk.Add(new DeleteManyModel(Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Ne(x => x.Batch, batch) + }))); + + var result = await _database.HostUpdate().BulkWriteAsync(bulk, cancellationToken: cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Handlers/Agent/UserHandler.cs b/src/Server/Insight.Server/Network/Handlers/Agent/UserHandler.cs new file mode 100644 index 0000000..5e09d66 --- /dev/null +++ b/src/Server/Insight.Server/Network/Handlers/Agent/UserHandler.cs @@ -0,0 +1,188 @@ +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; +using Insight.Infrastructure; +using Insight.Infrastructure.Entities; +using MongoDB.Bson; +using MongoDB.Driver; + +namespace Insight.Server.Network.Handlers.Agent +{ + public class UserHandler : IAgentMessageHandler + { + private readonly IMongoDatabase _database; + + public UserHandler(IMongoDatabase database) + { + _database = database; + } + + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage + { + if (message is UserList users) + { + await OnUsersAsync(sender, users, cancellationToken); + } + } + + private async ValueTask OnUsersAsync(AgentSession session, List? users, CancellationToken cancellationToken) + { + var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); + if (agentEntity is null) return; + + var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); + if (hostEntity is null) return; + + var batch = ObjectId.GenerateNewId().ToString(); + var date = DateTime.Now; + + // users + + if (users is not null && users.Any()) + { + var userBulk = new List>(); + + foreach (var user in users) + { + var userFilter = Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Eq(x => x.Domain, user?.Domain), + Builders.Filter.Eq(x => x.Name, user?.Name) + }); + + var userUpdate = Builders.Update + .SetOnInsert(p => p.Insert, date) + .SetOnInsert(p => p.Host, hostEntity.Id) + .SetOnInsert(p => p.Domain, user?.Domain) + .SetOnInsert(p => p.Name, user?.Name) + .Set(p => p.Update, date) + .Set(p => p.Batch, batch) + + .Set(p => p.Sid, user?.Sid) + .Set(p => p.FullName, user?.FullName) + .Set(p => p.Description, user?.Description) + .Set(p => p.Status, user?.Status) + .Set(p => p.LocalAccount, user?.LocalAccount) + .Set(p => p.Disabled, user?.Disabled) + .Set(p => p.Lockout, user?.Lockout) + .Set(p => p.PasswordChangeable, user?.PasswordChangeable) + .Set(p => p.PasswordExpires, user?.PasswordExpires) + .Set(p => p.PasswordRequired, user?.PasswordRequired); + + userBulk.Add(new UpdateOneModel(userFilter, userUpdate) + { + IsUpsert = true + }); + } + + userBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Ne(x => x.Batch, batch) + }))); + + var userResult = await _database.HostSystemUser().BulkWriteAsync(userBulk, cancellationToken: cancellationToken); + } + + // groups + + if (users is not null && users.Any()) + { + var groupBulk = new List>(); + + var distinctGroups = users.SelectMany(p => p.Groups) + .GroupBy(p => new { p?.Domain, p?.Name }) + .Select(p => p.First()); + + foreach (var group in distinctGroups) + { + var groupFilter = Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Eq(x => x.Domain, group?.Domain), + Builders.Filter.Eq(x => x.Name, group?.Name) + }); + + var groupUpdate = Builders.Update + .SetOnInsert(p => p.Insert, date) + .SetOnInsert(p => p.Host, hostEntity.Id) + .SetOnInsert(p => p.Domain, group?.Domain) + .SetOnInsert(p => p.Name, group?.Name) + .Set(p => p.Update, date) + .Set(p => p.Batch, batch) + + .Set(p => p.Sid, group?.Sid) + .Set(p => p.Description, group?.Description) + .Set(p => p.LocalAccount, group?.LocalAccount); + + groupBulk.Add(new UpdateOneModel(groupFilter, groupUpdate) + { + IsUpsert = true + }); + } + + groupBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Ne(x => x.Batch, batch) + }))); + + var groupResult = await _database.HostSystemGroup().BulkWriteAsync(groupBulk, cancellationToken: cancellationToken); + } + + // relations + + if (users is not null && users.Any()) + { + var relationBulk = new List>(); + + foreach (var user in users) + { + var userId = await _database.HostSystemUser() + .Find(p => p.Host == hostEntity.Id && p.Domain == user.Domain && p.Name == user.Name) + .Project(p => p.Id) + .FirstOrDefaultAsync(); + + if (user.Groups is not null && user.Groups.Any()) + { + foreach (var group in user.Groups) + { + var groupId = await _database.HostSystemGroup() + .Find(p => p.Host == hostEntity.Id && p.Domain == group.Domain && p.Name == group.Name) + .Project(p => p.Id) + .FirstOrDefaultAsync(); + + var relationFilter = Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Eq(x => x.User, userId), + Builders.Filter.Eq(x => x.Group, groupId) + }); + + var relationUpdate = Builders.Update + .SetOnInsert(p => p.Insert, date) + .SetOnInsert(p => p.Host, hostEntity.Id) + .SetOnInsert(p => p.User, userId) + .SetOnInsert(p => p.Group, groupId) + .Set(p => p.Update, date) + .Set(p => p.Batch, batch); + + relationBulk.Add(new UpdateOneModel(relationFilter, relationUpdate) + { + IsUpsert = true + }); + } + } + } + + relationBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Ne(x => x.Batch, batch) + }))); + + var relationResult = await _database.HostSystemUserSystemGroup().BulkWriteAsync(relationBulk, cancellationToken: cancellationToken); + } + } + } +} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Handlers/Agent/VideocardHandler.cs b/src/Server/Insight.Server/Network/Handlers/Agent/VideocardHandler.cs new file mode 100644 index 0000000..bf8e648 --- /dev/null +++ b/src/Server/Insight.Server/Network/Handlers/Agent/VideocardHandler.cs @@ -0,0 +1,77 @@ +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; +using Insight.Infrastructure; +using Insight.Infrastructure.Entities; +using MongoDB.Bson; +using MongoDB.Driver; + +namespace Insight.Server.Network.Handlers.Agent +{ + public class VideocardHandler : IAgentMessageHandler + { + private readonly IMongoDatabase _database; + + public VideocardHandler(IMongoDatabase database) + { + _database = database; + } + + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage + { + if (message is VideocardList videocards) + { + await OnVideocardsAsync(sender, videocards, cancellationToken); + } + } + + private async ValueTask OnVideocardsAsync(AgentSession session, List? videocards, CancellationToken cancellationToken) + { + var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); + if (agentEntity is null) return; + + var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); + if (hostEntity is null) return; + + var batch = ObjectId.GenerateNewId().ToString(); + var date = DateTime.Now; + + var bulk = new List>(); + + if (videocards is not null && videocards.Any()) + { + foreach (var videocard in videocards) + { + var filterDefinition = Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Eq(x => x.Name, videocard.Model) + }); + + var updateDefinition = Builders.Update + .SetOnInsert(p => p.Insert, date) + .SetOnInsert(p => p.Host, hostEntity.Id) + .SetOnInsert(p => p.Name, videocard.Model) + .Set(p => p.Update, date) + .Set(p => p.Batch, batch) + .Set(p => p.Company, null) + .Set(p => p.Memory, videocard.Memory) + .Set(p => p.Driver, videocard.DriverVersion) + .Set(p => p.Date, videocard.DriverDate); + + bulk.Add(new UpdateOneModel(filterDefinition, updateDefinition) + { + IsUpsert = true + }); + } + + bulk.Add(new DeleteManyModel(Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Ne(x => x.Batch, batch) + }))); + + var result = await _database.HostVideocard().BulkWriteAsync(bulk, cancellationToken: cancellationToken); + } + } + } +} diff --git a/src/Server/Insight.Server/Network/Handlers/Agent/VirtualMaschineHandler.cs b/src/Server/Insight.Server/Network/Handlers/Agent/VirtualMaschineHandler.cs new file mode 100644 index 0000000..a49e08d --- /dev/null +++ b/src/Server/Insight.Server/Network/Handlers/Agent/VirtualMaschineHandler.cs @@ -0,0 +1,173 @@ +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; +using Insight.Infrastructure; +using Insight.Infrastructure.Entities; +using MongoDB.Bson; +using MongoDB.Driver; + +namespace Insight.Server.Network.Handlers.Agent +{ + public class VirtualMaschineHandler : IAgentMessageHandler + { + private readonly IMongoDatabase _database; + + public VirtualMaschineHandler(IMongoDatabase database) + { + _database = database; + } + + public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IAgentMessage + { + if (message is VirtualMaschineList virtualMaschines) + { + await OnVirtualMaschinesAsync(sender, virtualMaschines, cancellationToken); + } + } + + private async ValueTask OnVirtualMaschinesAsync(AgentSession session, List? virtualMaschines, CancellationToken cancellationToken) + { + var agentEntity = await _database.Agent().Find(Builders.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken); + if (agentEntity is null) return; + + var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken); + if (hostEntity is null) return; + + var batch = ObjectId.GenerateNewId().ToString(); + var date = DateTime.Now; + + // virtual maschines + if (virtualMaschines is not null && virtualMaschines.Any()) + { + var virtualMaschineBulk = new List>(); + + foreach (var virtualMaschine in virtualMaschines) + { + var virtualMaschineFilter = Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Eq(x => x.UniqueId, virtualMaschine.Id.ToString()) + }); + + var virtualMaschineUpdate = Builders.Update + .SetOnInsert(p => p.Insert, date) + .SetOnInsert(p => p.Host, hostEntity.Id) + .SetOnInsert(p => p.UniqueId, virtualMaschine.Id.ToString()) + .Set(p => p.Update, date) + .Set(p => p.Batch, batch) + + .Set(p => p.Name, virtualMaschine?.Name) + .Set(p => p.Notes, virtualMaschine?.Notes) + .Set(p => p.Enabled, virtualMaschine?.Enabled?.ToString()) + .Set(p => p.EnabledDefault, virtualMaschine?.EnabledDefault?.ToString()) + .Set(p => p.Health, virtualMaschine?.HealthState?.ToString()) + .Set(p => p.Status, virtualMaschine?.Status) + .Set(p => p.OnTime, virtualMaschine?.OnTime) + .Set(p => p.ReplicationState, virtualMaschine?.ReplicationState?.ToString()) + .Set(p => p.ReplicationHealth, virtualMaschine?.ReplicationHealth?.ToString()) + .Set(p => p.ConfigurationVersion, virtualMaschine?.ConfigurationVersion) + .Set(p => p.IntegrationServicesVersionState, virtualMaschine?.IntegrationServicesVersionState?.ToString()) + .Set(p => p.ProcessId, virtualMaschine?.ProcessId) + .Set(p => p.NumberOfProcessors, virtualMaschine?.NumberOfProcessors) + .Set(p => p.ProcessorLoad, virtualMaschine?.ProcessorLoad) + .Set(p => p.MemoryAvailable, virtualMaschine?.MemoryAvailable) + .Set(p => p.MemoryUsage, virtualMaschine?.MemoryUsage) + .Set(p => p.InstallDate, virtualMaschine?.InstallDate) + .Set(p => p.ConfigurationVersion, virtualMaschine?.ConfigurationVersion) + .Set(p => p.TimeOfLastStateChange, virtualMaschine?.TimeOfLastStateChange) + .Set(p => p.LastReplicationTime, virtualMaschine?.LastReplicationTime) + .Set(p => p.Os, virtualMaschine?.GuestOperatingSystem); + + virtualMaschineBulk.Add(new UpdateOneModel(virtualMaschineFilter, virtualMaschineUpdate) + { + IsUpsert = true + }); + } + + virtualMaschineBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Ne(x => x.Batch, batch) + }))); + + var virtualMaschineResult = await _database.HostHypervisorVirtualMaschine().BulkWriteAsync(virtualMaschineBulk, cancellationToken: cancellationToken); + } + + // virtual maschine configurations + + if (virtualMaschines is not null && virtualMaschines.Any()) + { + var configurationBulk = new List>(); + + foreach (var virtualmaschine in virtualMaschines) + { + var virtualMaschineId = await _database.HostHypervisorVirtualMaschine() + .Find(p => p.Host == hostEntity.Id && p.UniqueId == virtualmaschine.Id.ToString()) + .Project(p => p.Id) + .FirstOrDefaultAsync(); + + if (virtualmaschine.Configurations is not null && virtualmaschine.Configurations.Any()) + { + foreach (var config in virtualmaschine.Configurations) + { + var configFilter = Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Eq(x => x.VirtualMaschine, virtualMaschineId), + Builders.Filter.Eq(x => x.UniqueId, config.Id) + }); + + // custom "notes" concat + string notes = string.Empty; + if (config?.Notes is not null) foreach (var n in config.Notes) notes += n; + + var configUpdate = Builders.Update + .SetOnInsert(p => p.Insert, date) + .SetOnInsert(p => p.Host, hostEntity.Id) + .SetOnInsert(p => p.VirtualMaschine, virtualMaschineId) + .SetOnInsert(p => p.UniqueId, config.Id) + .Set(p => p.Update, date) + .Set(p => p.Batch, batch) + + .Set(p => p.ParentId, config.ParentId) + .Set(p => p.Type, config.Type) + .Set(p => p.Name, config.Name) + .Set(p => p.Notes, notes) + .Set(p => p.CreationTime, config.CreationTime) + .Set(p => p.Generation, config.Generation) + .Set(p => p.Architecture, config.Architecture) + .Set(p => p.SecureBootEnabled, config.SecureBootEnabled) + .Set(p => p.IsAutomaticSnapshot, config.IsAutomaticSnapshot) + .Set(p => p.AutomaticStartupAction, config.AutomaticStartupAction?.ToString()) + .Set(p => p.AutomaticShutdownAction, config.AutomaticShutdownAction?.ToString()) + .Set(p => p.AutomaticRecoveryAction, config.AutomaticRecoveryAction?.ToString()) + .Set(p => p.AutomaticSnapshotsEnabled, config.AutomaticSnapshotsEnabled) + .Set(p => p.BaseBoardSerialNumber, config.BaseBoardSerialNumber) + .Set(p => p.BIOSSerialNumber, config.BIOSSerialNumber) + .Set(p => p.BIOSGUID, config.BIOSGUID) + .Set(p => p.ConfigurationDataRoot, config.ConfigurationDataRoot) + .Set(p => p.ConfigurationFile, config.ConfigurationFile) + .Set(p => p.GuestStateDataRoot, config.GuestStateDataRoot) + .Set(p => p.GuestStateFile, config.GuestStateFile) + .Set(p => p.SnapshotDataRoot, config.SnapshotDataRoot) + .Set(p => p.SuspendDataRoot, config.SuspendDataRoot) + .Set(p => p.SwapFileDataRoot, config.SwapFileDataRoot); + + configurationBulk.Add(new UpdateOneModel(configFilter, configUpdate) + { + IsUpsert = true + }); + } + } + } + + configurationBulk.Add(new DeleteManyModel(Builders.Filter.And(new List> + { + Builders.Filter.Eq(x => x.Host, hostEntity.Id), + Builders.Filter.Ne(x => x.Batch, batch) + }))); + + var configurationResult = await _database.HostVirtualMaschineConfig().BulkWriteAsync(configurationBulk, cancellationToken: cancellationToken); + } + } + } +} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Handlers/Web/ConsoleProxyHandler.cs b/src/Server/Insight.Server/Network/Handlers/Web/ConsoleProxyHandler.cs new file mode 100644 index 0000000..e7cc5c9 --- /dev/null +++ b/src/Server/Insight.Server/Network/Handlers/Web/ConsoleProxyHandler.cs @@ -0,0 +1,103 @@ +using Insight.Agent.Messages; +using Insight.Infrastructure; +using Insight.Infrastructure.Entities; +using Insight.Web.Interfaces; +using Insight.Web.Messages; +using Microsoft.Extensions.Logging; +using MongoDB.Driver; +using Vaitr.MemoryBus; +using Vaitr.Network; + +namespace Insight.Server.Network.Handlers.Web +{ + public class ConsoleProxyHandler : IWebMessageHandler + { + private readonly List _subscriptions = new(); + + private readonly TcpSessionPool _agentPool; + private readonly TcpSessionPool _webPool; + private readonly IMongoDatabase _database; + private readonly IMemoryBus _bus; + private readonly ILogger _logger; + + public ConsoleProxyHandler( + TcpSessionPool agentPool, + TcpSessionPool webPool, + IMongoDatabase database, + IMemoryBus bus, + ILogger logger) + { + _agentPool = agentPool; + _webPool = webPool; + _database = database; + _bus = bus; + _logger = logger; + + _subscriptions.Add(_bus.SubscribeAsync(OnConsoleQueryAsync, null)); + } + + public async ValueTask HandleAsync(WebSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IWebMessage + { + if (message is ConsoleQueryProxyRequest consoleRequest) + { + await OnConsoleQueryRequestAsync(sender, consoleRequest, cancellationToken); + } + } + + private async ValueTask OnConsoleQueryRequestAsync(WebSession session, ConsoleQueryProxyRequest request, CancellationToken cancellationToken) + { + // get host + var hostEntity = await _database.Host() + .Find(Builders + .Filter + .Eq(p => p.Id, request.HostId)) + .FirstOrDefaultAsync(cancellationToken); + + if (hostEntity is null) + { + _logger.LogWarning("hostEntity is null"); + return; + } + + // get agent + var agentEntity = await _database.Agent() + .Find(Builders + .Filter + .Eq(p => p.Id, hostEntity.Agent)) + .FirstOrDefaultAsync(cancellationToken); + + if (agentEntity is null) + { + _logger.LogWarning("agentEntity is null"); + return; + } + + // check if agent online + if (_agentPool.FirstOrDefault(p => p.Value.Id == agentEntity.Id).Value is not AgentSession agent) return; + + // send "real" packet to agent + await agent.SendAsync(new ConsoleQueryRequest + { + Id = request.Id, + HostId = request.HostId, + Query = request.Query + }, cancellationToken); + } + + private async ValueTask OnConsoleQueryAsync(ConsoleQuery query, CancellationToken cancellationToken) + { + // check if web online + if (_webPool.FirstOrDefault().Value is not WebSession web) return; + + await web.SendAsync(new ConsoleQueryProxy + { + Id = query.Id, + HostId = query.HostId, + Query = query.Query, + Data = query.Data, + Errors = query.Errors, + HadErrors = query.HadErrors + }, cancellationToken); + } + } +} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Remote/Handlers/RemoteHandler.cs b/src/Server/Insight.Server/Network/Remote/Handlers/RemoteHandler.cs deleted file mode 100644 index 9e96aa7..0000000 --- a/src/Server/Insight.Server/Network/Remote/Handlers/RemoteHandler.cs +++ /dev/null @@ -1,104 +0,0 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Remote.Messages; -using Microsoft.Extensions.Logging; -using Vaitr.Bus; -using Vaitr.Network; - -namespace Insight.Server.Network.Remote.Handlers; - -public class RemoteHandler(Bus bus, ISessionPool remotePool, ILogger logger) : IMessageHandler -{ - private readonly Bus _bus = bus; - private readonly ISessionPool _remotePool = remotePool; - private readonly ILogger _logger = logger; - - public async ValueTask HandleAsync(RemoteSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage - { - if (message is RemoteSessionRequest sessionRequest) - { - await OnSessionRequest(sender, sessionRequest, cancellationToken); - } - else if (message is CastRequestResponse castRequestResponse) - { - await OnCastRequestResponse(sender, castRequestResponse, cancellationToken); - } - else if (message is CastMetric metricData) - { - await OnMetricData(sender, metricData, cancellationToken); - } - else if (message is CastScreen screenData) - { - await OnScreenData(sender, screenData, cancellationToken); - } - else if (message is CastCursor cursorData) - { - await OnCursorData(sender, cursorData, cancellationToken); - } - else if (message is CastClipboardReceived clipboardData) - { - await OnClipboardData(sender, clipboardData, cancellationToken); - } - else if (message is CastAudio audioData) - { - await OnAudioData(sender, audioData, cancellationToken); - } - } - - private async Task OnSessionRequest(RemoteSession session, RemoteSessionRequest sessionRequest, CancellationToken cancellationToken) - { - _logger.LogInformation("Remote {session} => SessionRequest", session.Id); - - session.Mode = sessionRequest.Mode; - - await session.SendAsync(new RemoteSessionResponse - { - SessionId = session.Id - }, cancellationToken); - } - - private async Task OnCastRequestResponse(RemoteSession session, CastRequestResponse castRequestResponse, CancellationToken cancellationToken) - { - await _bus.PublishAsync(castRequestResponse, cancellationToken); - } - - private async Task OnMetricData(RemoteSession session, CastMetric streamMetrics, CancellationToken cancellationToken) - { - //_logger.LogInformation($"Remote {session.Id} => MetricData"); - - await _bus.PublishAsync(streamMetrics, cancellationToken); - } - - private async Task OnScreenData(RemoteSession session, CastScreen screenData, CancellationToken cancellationToken) - { - //_logger.LogInformation($"Remote {session.Id} => ScreenData"); - - await _bus.PublishAsync(screenData, cancellationToken); - - await session.SendAsync(new CastScreenReceived - { - Timestamp = screenData.Timestamp - }, cancellationToken); - } - - private async Task OnCursorData(RemoteSession session, CastCursor cursorChanged, CancellationToken cancellationToken) - { - //_logger.LogInformation($"Remote {session.Id} => CursorData"); - - await _bus.PublishAsync(cursorChanged, cancellationToken); - } - - private async Task OnClipboardData(RemoteSession session, CastClipboardReceived clipboardChanged, CancellationToken cancellationToken) - { - _logger.LogInformation("Remote {session} => ClipboardData", session.Id); - - await _bus.PublishAsync(clipboardChanged, cancellationToken); - } - - private async Task OnAudioData(RemoteSession session, CastAudio audioSample, CancellationToken cancellationToken) - { - _logger.LogInformation("Remote {session} => AudioData", session.Id); - - await _bus.PublishAsync(audioSample, cancellationToken); - } -} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Remote/RemoteSession.cs b/src/Server/Insight.Server/Network/Remote/RemoteSession.cs deleted file mode 100644 index 1da69a2..0000000 --- a/src/Server/Insight.Server/Network/Remote/RemoteSession.cs +++ /dev/null @@ -1,83 +0,0 @@ -using Insight.Domain.Enums; -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Server.Network.Web; -using Microsoft.Extensions.Logging; -using Vaitr.Network; - -namespace Insight.Server.Network.Remote; - -public class RemoteSession( - ISessionPool webPool, - IEnumerable> handlers, - ISerializer serializer, - ILogger logger) : TcpSession(serializer, logger) -{ - public string Id { get; } = GenerateRandomId(); - public RemoteControlMode Mode { get; set; } - - private readonly ISessionPool _webPool = webPool; - private readonly IEnumerable> _handlers = handlers; - - public async ValueTask ProxyAsync(TMessage message, CancellationToken cancellationToken) - where TMessage : IMessage - { - // check if web online - if (_webPool.FirstOrDefault().Value is not WebSession web) return; - - // proxy-send request packet to web - await web.SendAsync(new Proxy - { - Message = message - }, cancellationToken); - } - - protected override ValueTask OnConnectedAsync(CancellationToken cancellationToken) - { - _logger.LogInformation("Remote ({ep?}) connected", RemoteEndPoint); - return default; - } - - protected override ValueTask OnDisconnectedAsync(CancellationToken cancellationToken) - { - _logger.LogInformation("Remote ({ep?}) disconnected", RemoteEndPoint); - return default; - } - - protected override async ValueTask OnSentAsync(IPacketContext context, CancellationToken cancellationToken) - { - await base.OnSentAsync(context, cancellationToken); - } - - protected override async ValueTask OnReceivedAsync(IPacketContext context, CancellationToken cancellationToken) - { - await base.OnReceivedAsync(context, cancellationToken); - - foreach (var handler in _handlers) - { - try - { - await handler.HandleAsync(this, context.Packet, cancellationToken); - } - catch (Exception ex) - { - _logger.LogWarning("Remote ({ep?}) {ex}", RemoteEndPoint, ex.ToString()); - } - } - } - - protected override ValueTask OnHeartbeatAsync(CancellationToken cancellationToken) - { - _logger.LogInformation("Remote ({ep?}) Heartbeat", RemoteEndPoint); - return default; - } - - private static string GenerateRandomId() - { - var random = new Random(); - string? sessionId = string.Empty; - - for (var i = 0; i < 3; i++) sessionId += random.Next(0, 999).ToString().PadLeft(3, '0'); - return sessionId; - } -} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Shared/ProxyHandler.cs b/src/Server/Insight.Server/Network/Shared/ProxyHandler.cs deleted file mode 100644 index 0a003b3..0000000 --- a/src/Server/Insight.Server/Network/Shared/ProxyHandler.cs +++ /dev/null @@ -1,86 +0,0 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; -using Insight.Infrastructure.Entities; -using Insight.Server.Network.Agent; -using Insight.Server.Network.Web; -using Microsoft.Extensions.Logging; -using MongoDB.Driver; -using Vaitr.Network; - -namespace Insight.Server.Network.Globals; - -public class ProxyHandler( - ISessionPool agentPool, - ISessionPool webPool, - IMongoDatabase database, - ILogger logger) : IMessageHandler, IMessageHandler -{ - private readonly ISessionPool _agentPool = agentPool; - private readonly ISessionPool _webPool = webPool; - private readonly IMongoDatabase _database = database; - private readonly ILogger _logger = logger; - - public async ValueTask HandleAsync(WebSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage - { - switch (message) - { - case Proxy proxyRequest: - await OnProxyRequestAsync(sender, proxyRequest, cancellationToken); - break; - } - } - - public async ValueTask HandleAsync(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage - { - switch (message) - { - case Proxy proxyResponse: - await OnProxyResponseAsync(sender, proxyResponse, cancellationToken); - break; - } - } - - private async ValueTask OnProxyRequestAsync(WebSession session, Proxy request, CancellationToken cancellationToken) - { - // get host - var hostEntity = await _database.Host() - .Find(Builders - .Filter - .Eq(p => p.Id, request.ProxyId)) - .FirstOrDefaultAsync(cancellationToken); - - if (hostEntity is null) - { - _logger.LogWarning("hostEntity is null"); - return; - } - - // get agent - var agentEntity = await _database.Agent() - .Find(Builders - .Filter - .Eq(p => p.Id, hostEntity.Agent)) - .FirstOrDefaultAsync(cancellationToken); - - if (agentEntity is null) - { - _logger.LogWarning("agentEntity is null"); - return; - } - - // check if agent online - if (_agentPool.FirstOrDefault(p => p.Value.Id == agentEntity.Id).Value is not AgentSession agent) return; - - // proxy-send request packet to agent - await agent.SendAsync(request, cancellationToken); - } - - private async ValueTask OnProxyResponseAsync(AgentSession session, Proxy response, CancellationToken cancellationToken) - { - // check if web online - if (_webPool.FirstOrDefault().Value is not WebSession web) return; - - await web.SendAsync(response, cancellationToken); - } -} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/Web/WebSession.cs b/src/Server/Insight.Server/Network/Web/WebSession.cs deleted file mode 100644 index 7603f96..0000000 --- a/src/Server/Insight.Server/Network/Web/WebSession.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Microsoft.Extensions.Logging; -using Vaitr.Network; - -namespace Insight.Server.Network.Web; - -public class WebSession(IEnumerable> handlers, ISerializer serializer, ILogger logger) : TcpSession(serializer, logger) -{ - public string? Id { get; set; } - - private readonly IEnumerable> _handlers = handlers; - - protected override ValueTask OnConnectedAsync(CancellationToken cancellationToken) - { - _logger.LogInformation("Web ({ep?}) connected", RemoteEndPoint); - return default; - } - - protected override ValueTask OnDisconnectedAsync(CancellationToken cancellationToken) - { - _logger.LogInformation("Web ({ep?}) disconnected", RemoteEndPoint); - return default; - } - - protected override async ValueTask OnSentAsync(IPacketContext context, CancellationToken cancellationToken) - { - await base.OnSentAsync(context, cancellationToken); - } - - protected override async ValueTask OnReceivedAsync(IPacketContext context, CancellationToken cancellationToken) - { - await base.OnReceivedAsync(context, cancellationToken); - - foreach (var handler in _handlers) - { - try - { - await handler.HandleAsync(this, context.Packet, cancellationToken); - } - catch (Exception ex) - { - _logger.LogWarning("Web ({ep?}) {ex}", RemoteEndPoint, ex.ToString()); - } - } - } - - protected override ValueTask OnHeartbeatAsync(CancellationToken cancellationToken) - { - _logger.LogInformation("Web ({ep?}) Heartbeat", RemoteEndPoint); - return default; - } -} \ No newline at end of file diff --git a/src/Server/Insight.Server/Network/WebSession.cs b/src/Server/Insight.Server/Network/WebSession.cs new file mode 100644 index 0000000..1a949ac --- /dev/null +++ b/src/Server/Insight.Server/Network/WebSession.cs @@ -0,0 +1,30 @@ +using Insight.Web.Interfaces; +using Insight.Web.Messages; +using Microsoft.Extensions.Logging; +using System.Net.Sockets; +using Vaitr.Network; + +namespace Insight.Server.Network; + +public class WebSession(IEnumerable> handlers, Socket socket, Stream stream, TcpConnectionOptions options, MemPackSerializer serializer, ILogger logger) + : TcpSession(socket, stream, options, serializer, logger) +{ + public string? Id { get; set; } + + private readonly IEnumerable> _handlers = handlers; + + protected override async ValueTask OnReceivedAsync(PacketContext context, CancellationToken cancellationToken) + { + foreach (var handler in _handlers) + { + try + { + await handler.HandleAsync(this, context.Data, cancellationToken); + } + catch (Exception ex) + { + _logger.LogWarning("Web ({ep?}) {ex}", RemoteEndPoint, ex.ToString()); + } + } + } +} \ No newline at end of file diff --git a/src/Server/Insight.Server/Program.cs b/src/Server/Insight.Server/Program.cs index 395f24e..1ee789d 100644 --- a/src/Server/Insight.Server/Program.cs +++ b/src/Server/Insight.Server/Program.cs @@ -1,63 +1,142 @@ +using Insight.Agent.Interfaces; +using Insight.Agent.Messages; using Insight.Domain.Constants; using Insight.Infrastructure; using Insight.Server.Extensions; -using System.Collections; -using System.Diagnostics; +using Insight.Server.Network; +using Insight.Server.Network.Handlers.Agent; +using Insight.Server.Network.Handlers.Web; +using Insight.Server.Services; +using Insight.Web.Interfaces; +using Insight.Web.Messages; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using System.Net; +using Vaitr.MemoryBus.Hosting; +using Vaitr.Network; -namespace Insight.Server; - -internal class Program +namespace Insight.Server { - public static async Task Main(string[] args) + internal class Program { - var builder = WebApplication.CreateBuilder(args); - builder.Host.UseWindowsService(); - builder.Host.UseSystemd(); - - // Configuration - builder.Configuration.Defaults(); - - // Logging - builder.Logging.ClearProviders(); - builder.Logging.SetMinimumLevel(LogLevel.Trace); - builder.Logging.AddFilter("Microsoft.AspNetCore", LogLevel.Warning); - builder.Logging.AddSimpleConsole(options => + public static async Task Main(string[] args) { - options.IncludeScopes = true; - options.SingleLine = true; - options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff "; - }); - builder.Logging.AddFile(Configuration.AppDirectory?.FullName + "/logs/" + Process.GetCurrentProcess().ProcessName + "_{Date}.log", LogLevel.Trace, fileSizeLimitBytes: 104857600, retainedFileCountLimit: 10, outputTemplate: "{Timestamp:o} [{Level:u3}] {Message} {NewLine}{Exception}"); + var builder = Host.CreateDefaultBuilder(args); + builder.UseWindowsService(); + builder.UseSystemd(); - // Services - builder.Services.AddDatabase(builder.Configuration); + builder.ConfigureAppConfiguration(options => + { + options.Defaults(); + }); - // Modules - builder.AddDefaults(); - builder.AddApiDefaults(); - builder.AddMetrics(); - builder.AddSwagger(); - builder.AddAgentBackend(); - builder.AddWebBackend(); + builder.ConfigureLogging(options => + { + options.ClearProviders(); + options.SetMinimumLevel(LogLevel.Trace); - // HTTP Pipeline - var app = builder.Build(); + options.AddSimpleConsole(options => + { + options.IncludeScopes = true; + options.SingleLine = true; + options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff "; + }); - if (app.Environment.IsDevelopment()) - { - + options.AddFile($"{Configuration.AppDirectory?.FullName}/" + "logs/server_{Date}.log", LogLevel.Trace, fileSizeLimitBytes: 104857600, retainedFileCountLimit: 10, outputTemplate: "{Timestamp:o} [{Level:u3}] {Message} {NewLine}{Exception}"); + }); + + builder.ConfigureServices((host, services) => + { + //var databaseLoggerFactory = LoggerFactory.Create(b => + //{ + // b.AddSimpleConsole(); + // b.SetMinimumLevel(LogLevel.Debug); + //}); + + // INFRASTRUCTURE + services.AddDatabase(host.Configuration); + + // AGENT SERVER + services.UseHostedTcpServer(options => + { + options.Address = IPAddress.Any; + options.Port = host.Configuration.GetValue(Appsettings.AgentServerPort) ?? throw new Exception($"{Appsettings.AgentServerPort} value not set (appsettings)"); + options.KeepAlive = 10000; + options.Timeout = 30000; + options.Backlog = 128; + options.Buffer = 1024 * 1024; + options.Parallelism = 0; + options.Certificate = host.Configuration.GetValue(Appsettings.AgentServerCertificate) ?? throw new Exception($"{Appsettings.AgentServerCertificate} value not set (appsettings)"); + options.CertificatePassword = host.Configuration.GetValue(Appsettings.AgentServerCertificatePassword) ?? throw new Exception($"{Appsettings.AgentServerCertificatePassword} value not set (appsettings)"); + options.Compression = Compression.None; + options.Encryption = Encryption.Tls12; + options.SslPolicy = SslPolicy.None; + + //options.InputRateLimit = 1024 * 1024; + //options.OutputRateLimit = 1024 * 1024; + }); + + services.AddSingleton(); + services.AddSingleton, AgentHandler>(); + services.AddSingleton, DriveHandler>(); + services.AddSingleton, Network.Handlers.Agent.EventHandler>(); + services.AddSingleton, InterfaceHandler>(); + services.AddSingleton, MainboardHandler>(); + services.AddSingleton, MemoryHandler>(); + services.AddSingleton, OperationSystemHandler>(); + services.AddSingleton, PrinterHandler>(); + services.AddSingleton, ProcessorHandler>(); + services.AddSingleton, ServiceHandler>(); + services.AddSingleton, SessionHandler>(); + services.AddSingleton, SoftwareHandler>(); + services.AddSingleton, StoragePoolHandler>(); + services.AddSingleton, SystemInfoHandler>(); + services.AddSingleton, TrapHandler>(); + services.AddSingleton, UpdateHandler>(); + services.AddSingleton, UserHandler>(); + services.AddSingleton, VideocardHandler>(); + services.AddSingleton, VirtualMaschineHandler>(); + services.AddSingleton, ConsoleHandler>(); + + // WEB (FRONTEND-PROXY) SERVER + services.UseHostedTcpServer(options => + { + options.Address = IPAddress.Any; + options.Port = host.Configuration.GetValue(Appsettings.WebServerPort) ?? throw new Exception($"{Appsettings.WebServerPort} value not set (appsettings)"); + options.KeepAlive = 10000; + options.Timeout = 30000; + options.Backlog = 128; + options.Buffer = 1024 * 1024; + options.Parallelism = 0; + options.Certificate = host.Configuration.GetValue(Appsettings.WebServerCertificate) ?? throw new Exception($"{Appsettings.WebServerCertificate} value not set (appsettings)"); + options.CertificatePassword = host.Configuration.GetValue(Appsettings.WebServerCertificatePassword) ?? throw new Exception($"{Appsettings.WebServerCertificatePassword} value not set (appsettings)"); + options.Compression = Compression.None; + options.Encryption = Encryption.Tls12; + options.SslPolicy = SslPolicy.None; + + //options.InputRateLimit = 1024 * 1024; + //options.OutputRateLimit = 1024 * 1024; + }); + + services.AddSingleton, ConsoleProxyHandler>(); + + // DISPATCH + services.AddHostedService(); + services.AddHostedService(); + + // GLOBAL DEPENDENCIES + services.AddMemoryBus(); + services.AddTransient(provider => new HttpClient(new HttpClientHandler + { + ClientCertificateOptions = ClientCertificateOption.Manual, + ServerCertificateCustomValidationCallback = (httpRequestMessage, cert, cetChain, policyErrors) => true + })); + }); + + var host = builder.Build(); + await host.RunAsync().ConfigureAwait(false); } - - app.ConfigureSwagger(); - - app.UseCors(x => x - .AllowAnyOrigin() - .AllowAnyMethod() - .AllowAnyHeader()); - - app.UseAuthorization(); - app.MapControllers(); - - await app.RunAsync(); } } \ No newline at end of file diff --git a/src/Server/Insight.Server/Properties/launchSettings.json b/src/Server/Insight.Server/Properties/launchSettings.json index 060a2b2..c95fc24 100644 --- a/src/Server/Insight.Server/Properties/launchSettings.json +++ b/src/Server/Insight.Server/Properties/launchSettings.json @@ -1,19 +1,14 @@ { - "$schema": "http://json.schemastore.org/launchsettings.json", + "$schema": "https://json.schemastore.org/launchsettings.json", "profiles": { "Development": { "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": false, - "launchUrl": "swagger", - "applicationUrl": "http://localhost:5001", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, "Production": { - "commandName": "Project", - "applicationUrl": "http://localhost:5001" + "commandName": "Project" } } -} +} \ No newline at end of file diff --git a/src/Server/Insight.Server/Services/DispatchService.cs b/src/Server/Insight.Server/Services/DispatchService.cs index 6f08467..7d3b6c4 100644 --- a/src/Server/Insight.Server/Services/DispatchService.cs +++ b/src/Server/Insight.Server/Services/DispatchService.cs @@ -1,4 +1,4 @@ -using Insight.Domain.Enums; +using Insight.Agent.Enums; using Insight.Infrastructure; using Insight.Infrastructure.Entities; using Microsoft.Extensions.Configuration; @@ -6,143 +6,153 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using MongoDB.Driver; -namespace Insight.Server.Services; - -internal class DispatchService(HttpClient httpClient, IMongoDatabase database, IConfiguration configuration, ILogger logger) : BackgroundService +namespace Insight.Server.Services { - private readonly HttpClient _httpClient = httpClient; - private readonly IMongoDatabase _database = database; - private readonly IConfiguration _configuration = configuration; - private readonly ILogger _logger = logger; - - protected override async Task ExecuteAsync(CancellationToken cancellationToken) + internal class DispatchService : BackgroundService { - _logger.LogTrace("ExecuteAsync"); + private readonly HttpClient _httpClient; + private readonly IMongoDatabase _database; + private readonly IConfiguration _configuration; + private readonly ILogger _logger; - var enabled = _configuration.GetValue(Appsettings.Dispatch.Webmatic) ?? throw new Exception($"{Appsettings.Dispatch.Webmatic} value not set (appsettings)"); - if (enabled is false) return; - - try + public DispatchService(HttpClient httpClient, IMongoDatabase database, IConfiguration configuration, ILogger logger) { - while (cancellationToken.IsCancellationRequested is false) - { - await DispatchAsync(cancellationToken); - await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); - } + _httpClient = httpClient; + _database = database; + _configuration = configuration; + _logger = logger; } - catch (OperationCanceledException) { } - catch (Exception) { } - } - private async ValueTask DispatchAsync(CancellationToken cancellationToken) - { - _logger.LogTrace($"DispatchAsync"); - - var pendings = await _database.HostLogMonitoring() - .Find(Builders - .Filter.Eq(p => p.Dispatch, DispatchEnum.Pending.ToString())) - .Limit(10) - .ToListAsync(cancellationToken); - - if (pendings is null || pendings.Count == 0) return; - - foreach (var entity in pendings) + protected override async Task ExecuteAsync(CancellationToken cancellationToken) { + _logger.LogTrace("ExecuteAsync"); + + var enabled = _configuration.GetValue(Appsettings.DispatchWebmatic) ?? throw new Exception($"{Appsettings.DispatchWebmatic} value not set (appsettings)"); + if (enabled is false) return; + try { - var result = await SendAsync(entity, default); - - await _database.HostLogMonitoring() - .UpdateOneAsync(Builders.Filter - .Eq(p => p.Id, entity.Id), Builders - .Update - .Set(p => p.Dispatch, result.ToString()), cancellationToken: default); + while (cancellationToken.IsCancellationRequested is false) + { + await DispatchAsync(cancellationToken); + await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); + } } - catch (Exception ex) + catch (OperationCanceledException) { } + catch (Exception) { } + } + + private async ValueTask DispatchAsync(CancellationToken cancellationToken) + { + _logger.LogTrace($"DispatchAsync"); + + var pendings = await _database.HostLogMonitoring() + .Find(Builders + .Filter.Eq(p => p.Dispatch, DispatchEnum.Pending.ToString())) + .Limit(10) + .ToListAsync(cancellationToken); + + if (pendings is null || pendings.Any() is false) return; + + foreach (var entity in pendings) { - _logger.LogError("{exception}", ex.Message); + try + { + var result = await SendAsync(entity, default); + + await _database.HostLogMonitoring() + .UpdateOneAsync(Builders.Filter + .Eq(p => p.Id, entity.Id), Builders + .Update + .Set(p => p.Dispatch, result.ToString()), cancellationToken: default); + } + catch (Exception ex) + { + _logger.LogError(ex.Message); + _logger.LogTrace(ex.StackTrace); + } + finally + { + // webmatic safety offset + await Task.Delay(TimeSpan.FromSeconds(1), default); + } } - finally + } + + private async ValueTask SendAsync(HostLogMonitoringEntity monitoring, CancellationToken cancellationToken) + { + _logger.LogTrace($"SendAsync ({monitoring})"); + + var monitoringApi = Monitoring.LogUri; + var monitoringContent = new List>(); + var monitoringResult = new List>(); + + // adjust by category + if (Enum.TryParse(monitoring.Category, true, out var monitoringCategory) is false) return DispatchEnum.Failure; + + if (monitoringCategory == CategoryEnum.Monitoring) monitoringApi = Monitoring.StatusUri; + + // set category (if log) + if (monitoringApi == Monitoring.LogUri) monitoringContent.Add(new KeyValuePair("category", monitoringCategory.ToString())); + + // host resolve + var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Id, monitoring.Host?.ToString())).FirstOrDefaultAsync(cancellationToken); + if (hostEntity is null) return DispatchEnum.Failure; + + // customer resolve + var customerEntity = await _database.Customer().Find(Builders.Filter.Eq(p => p.Id, hostEntity.Customer)).FirstOrDefaultAsync(cancellationToken); + if (hostEntity is null) return DispatchEnum.Failure; + + // set host name if no remote host set + if (string.IsNullOrEmpty(monitoring.Hostname)) monitoring.Hostname = hostEntity.Name; + + // remove any domain from hostname + if (monitoring.Hostname is not null && monitoring.Hostname.Contains('.')) monitoring.Hostname = monitoring.Hostname.Split(".")[0]; + + // add customer tag to hostname + monitoring.Hostname += $".{customerEntity.Tag}"; + + // if task null, set hostname + if (string.IsNullOrEmpty(monitoring.Task)) monitoring.Task = monitoring.Hostname; + + // insert hostname as computer-name (lowercase) + monitoringContent.Add(new KeyValuePair("computer_name", monitoring.Hostname.ToLower())); + + // insert converted status (api styled) + if (Enum.TryParse(monitoring.Status, true, out var monitoringStatus) is false) return DispatchEnum.Failure; + + monitoringContent.Add(monitoringStatus switch { - // webmatic safety offset - await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken: default); + StatusEnum.Information => new KeyValuePair("status", monitoringApi == Monitoring.StatusUri ? "erfolgreich" : "info"), + StatusEnum.Warning => new KeyValuePair("status", monitoringApi == Monitoring.StatusUri ? "Interaktion" : "warning"), + StatusEnum.Error => new KeyValuePair("status", monitoringApi == Monitoring.StatusUri ? "fehlgeschlagen" : "error"), + _ => throw new NotImplementedException(nameof(monitoringStatus)) + }); + + // insert task, timestamp, message, + monitoringContent.Add(new KeyValuePair("task", monitoring.Task)); + + if (monitoring.Timestamp is not null) + { + monitoringContent.Add(new KeyValuePair("timestamp", monitoring.Timestamp.Value.ToLocalTime().ToString())); } + + if (string.IsNullOrWhiteSpace(monitoring.Message) is false) + { + monitoringContent.Add(new KeyValuePair("message", monitoring.Message)); + } + + // send message + var result = await _httpClient.PostAsync(monitoringApi, new FormUrlEncodedContent(monitoringContent), default); + + monitoringResult.Add(new KeyValuePair("HttpStatusCode", result.StatusCode.ToString())); + monitoringResult.Add(new KeyValuePair("HttpResponseMessage", await result.Content.ReadAsStringAsync(default))); + + // if content != "OK" + if (result is null || result.IsSuccessStatusCode == false) return DispatchEnum.Failure; + + // success + return DispatchEnum.Success; } } - - private async ValueTask SendAsync(HostLogMonitoringEntity monitoring, CancellationToken cancellationToken) - { - _logger.LogTrace("SendAsync ({monitoring})", monitoring); - - var monitoringApi = Monitoring.LogUri; - var monitoringContent = new List>(); - var monitoringResult = new List>(); - - // adjust by category - if (Enum.TryParse(monitoring.Category, true, out var monitoringCategory) is false) return DispatchEnum.Failure; - - if (monitoringCategory == CategoryEnum.Monitoring) monitoringApi = Monitoring.StatusUri; - - // set category (if log) - if (monitoringApi == Monitoring.LogUri) monitoringContent.Add(new KeyValuePair("category", monitoringCategory.ToString())); - - // host resolve - var hostEntity = await _database.Host().Find(Builders.Filter.Eq(p => p.Id, monitoring.Host?.ToString())).FirstOrDefaultAsync(cancellationToken); - if (hostEntity is null) return DispatchEnum.Failure; - - // customer resolve - var customerEntity = await _database.Customer().Find(Builders.Filter.Eq(p => p.Id, hostEntity.Customer)).FirstOrDefaultAsync(cancellationToken); - if (hostEntity is null) return DispatchEnum.Failure; - - // set host name if no remote host set - if (string.IsNullOrEmpty(monitoring.Hostname)) monitoring.Hostname = hostEntity.Name; - - // remove any domain from hostname - if (monitoring.Hostname is not null && monitoring.Hostname.Contains('.')) monitoring.Hostname = monitoring.Hostname.Split(".")[0]; - - // add customer tag to hostname - monitoring.Hostname += $".{customerEntity.Tag}"; - - // if task null, set hostname - if (string.IsNullOrEmpty(monitoring.Task)) monitoring.Task = monitoring.Hostname; - - // insert hostname as computer-name (lowercase) - monitoringContent.Add(new KeyValuePair("computer_name", monitoring.Hostname.ToLower())); - - // insert converted status (api styled) - if (Enum.TryParse(monitoring.Status, true, out var monitoringStatus) is false) return DispatchEnum.Failure; - - monitoringContent.Add(monitoringStatus switch - { - StatusEnum.Information => new KeyValuePair("status", monitoringApi == Monitoring.StatusUri ? "erfolgreich" : "info"), - StatusEnum.Warning => new KeyValuePair("status", monitoringApi == Monitoring.StatusUri ? "Interaktion" : "warning"), - StatusEnum.Error => new KeyValuePair("status", monitoringApi == Monitoring.StatusUri ? "fehlgeschlagen" : "error"), - _ => throw new NotImplementedException(nameof(monitoringStatus)) - }); - - // insert task, timestamp, message, - monitoringContent.Add(new KeyValuePair("task", monitoring.Task)); - - if (monitoring.Timestamp is not null) - { - monitoringContent.Add(new KeyValuePair("timestamp", monitoring.Timestamp.Value.ToLocalTime().ToString())); - } - - if (string.IsNullOrWhiteSpace(monitoring.Message) is false) - { - monitoringContent.Add(new KeyValuePair("message", monitoring.Message)); - } - - // send message - var result = await _httpClient.PostAsync(monitoringApi, new FormUrlEncodedContent(monitoringContent), default); - - monitoringResult.Add(new KeyValuePair("HttpStatusCode", result.StatusCode.ToString())); - monitoringResult.Add(new KeyValuePair("HttpResponseMessage", await result.Content.ReadAsStringAsync(default))); - - // if content != "OK" - if (result is null || result.IsSuccessStatusCode == false) return DispatchEnum.Failure; - - // success - return DispatchEnum.Success; - } } \ No newline at end of file diff --git a/src/Server/Insight.Server/Services/JobService.cs b/src/Server/Insight.Server/Services/JobService.cs new file mode 100644 index 0000000..d692ed4 --- /dev/null +++ b/src/Server/Insight.Server/Services/JobService.cs @@ -0,0 +1,81 @@ +using Insight.Agent.Messages; +using Insight.Infrastructure; +using Insight.Infrastructure.Entities; +using Insight.Server.Extensions; +using Insight.Server.Network; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using MongoDB.Driver; +using Vaitr.Network; + +namespace Insight.Server.Services +{ + internal class JobService : BackgroundService + { + private readonly TcpSessionPool _agentPool; + private readonly IMongoDatabase _database; + private readonly ILogger _logger; + + public JobService(TcpSessionPool agentPool, IMongoDatabase database, ILogger logger) + { + _agentPool = agentPool; + _database = database; + _logger = logger; + } + + protected override async Task ExecuteAsync(CancellationToken cancellationToken) + { + _logger.LogTrace("ExecuteAsync"); + + await Task.Delay(TimeSpan.FromMinutes(1), cancellationToken); + + var jobs = new List + { + Task.Run(async () => + { + while (cancellationToken.IsCancellationRequested is false) + { + try + { + foreach (var agent in await GetAssignedAgentsAsync(cancellationToken)) + { + await agent.SendAsync(new GetInventory(), cancellationToken); + } + } + catch (OperationCanceledException) { } + catch (Exception) { } + finally + { + await Task.Delay(TimeSpan.FromHours(1), cancellationToken); + } + } + }, default) + }; + + try + { + await Task.WhenAll(jobs).ConfigureAwait(false); + } + catch (OperationCanceledException) { } + catch (Exception) { } + } + + private async ValueTask> GetAssignedAgentsAsync(CancellationToken cancellationToken) + { + var valid = new List(); + + await Async.ParallelForEach(_agentPool.Where(p => p.Value.Id is not null), async x => + { + var host = await _database.Host() + .Find(Builders.Filter.Eq(p => p.Agent, x.Value.Id)) + .FirstOrDefaultAsync(cancellationToken) + .ConfigureAwait(false); + + if (host is null) return; + valid.Add(x.Value); + }); + + return valid; + } + } +} \ No newline at end of file diff --git a/src/Server/Insight.Server/appsettings.Development.json b/src/Server/Insight.Server/appsettings.Development.json index c4b7350..17abbae 100644 --- a/src/Server/Insight.Server/appsettings.Development.json +++ b/src/Server/Insight.Server/appsettings.Development.json @@ -1,29 +1,12 @@ { - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - }, - "AllowedHosts": "*", - "Urls": "http://127.0.0.1:5005", + "database": "mongodb://10.22.70.40:32768", + "agent.server.port": 3002, + "agent.server.certificate": "localhost.pfx", + "agent.server.certificate.password": "Webmatic12", - // set in env vars - //"influx.endpoint": "http://127.0.0.1:8086", - //"influx.token": "", - "influx.org": "insight", - "influx.bucket": "insight", - "influx.service": "server", - - "mongo.connection": "mongodb://db.insight.local:27017", - - "agent.port": 3002, - "agent.certificate": "localhost.pfx", - "agent.certificate.password": "Webmatic12", - - "web.port": 3001, - "web.certificate": "localhost.pfx", - "web.certificate.password": "Webmatic12", + "web.server.port": 3001, + "web.server.certificate": "localhost.pfx", + "web.server.certificate.password": "Webmatic12", "dispatch.webmatic": false -} +} \ No newline at end of file diff --git a/src/Server/Insight.Server/appsettings.json b/src/Server/Insight.Server/appsettings.json index 879f162..b0ee8b6 100644 --- a/src/Server/Insight.Server/appsettings.json +++ b/src/Server/Insight.Server/appsettings.json @@ -1,29 +1,12 @@ { - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - }, - "AllowedHosts": "*", - "Urls": "http://127.0.0.1:5005", + "database": "mongodb://127.0.0.1:27017", + "agent.server.port": 3002, + "agent.server.certificate": "localhost.pfx", + "agent.server.certificate.password": "Webmatic12", - // set in env vars - //"influx.endpoint": "http://127.0.0.1:8086", - //"influx.token": "", - "influx.org": "insight", - "influx.bucket": "insight", - "influx.service": "server", + "web.server.port": 3001, + "web.server.certificate": "localhost.pfx", + "web.server.certificate.password": "Webmatic12", - "mongo.connection": "mongodb://127.0.0.1:27017", - - "agent.port": 3002, - "agent.certificate": "localhost.pfx", - "agent.certificate.password": "Webmatic12", - - "web.port": 3001, - "web.certificate": "localhost.pfx", - "web.certificate.password": "Webmatic12", - - "dispatch.webmatic": true -} + "dispatch.webmatic": false +} \ No newline at end of file diff --git a/src/Server/Insight.Server/libman.json b/src/Server/Insight.Server/libman.json deleted file mode 100644 index ceee271..0000000 --- a/src/Server/Insight.Server/libman.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "version": "1.0", - "defaultProvider": "cdnjs", - "libraries": [] -} \ No newline at end of file diff --git a/src/Setup/Insight.Setup.Windows/Constants/Deploy.cs b/src/Setup/Insight.Setup.Windows/Constants/Deploy.cs index d1dffe1..724759b 100644 --- a/src/Setup/Insight.Setup.Windows/Constants/Deploy.cs +++ b/src/Setup/Insight.Setup.Windows/Constants/Deploy.cs @@ -1,48 +1,49 @@ -namespace Insight.Setup.Constants; - -public static class Deploy +namespace Insight.Setup.Constants { - public static class Runtime + public static class Deploy { - public static class Core + public static class Runtime { - public const string Version = "8.0.0"; - public const string Download = "https://download.visualstudio.microsoft.com/download/pr/7f4d5cbc-4449-4ea5-9578-c467821f251f/b9b19f89d0642bf78f4b612c6a741637/dotnet-runtime-8.0.0-win-x64.exe"; + public static class Core + { + public const string Version = "7.0.2"; + public const string Download = "https://download.visualstudio.microsoft.com/download/pr/df7da01f-1f17-4728-92b7-778e9607da8f/7c18246830f8c78591f02f25aa368dcf/dotnet-runtime-7.0.2-win-x64.exe"; - public static DirectoryInfo Directory => new($@"{Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)}/dotnet/shared/Microsoft.NETCore.App"); + public static DirectoryInfo Directory => new DirectoryInfo($@"{Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)}/dotnet/shared/Microsoft.NETCore.App"); + } + + public static class Asp + { + public const string Version = "7.0.2"; + public const string Download = "https://download.visualstudio.microsoft.com/download/pr/3ecad4f7-1342-4688-ae4a-38908c61f4a2/391a9010acad2e312e3d1e766bedfac7/aspnetcore-runtime-7.0.2-win-x64.exe"; + + public static DirectoryInfo Directory => new DirectoryInfo($@"{Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)}/dotnet/shared/Microsoft.AspNetCore.App"); + } } - public static class Asp + public static class Updater { - public const string Version = "8.0.0"; - public const string Download = "https://download.visualstudio.microsoft.com/download/pr/89d3660b-d344-47c5-a1cd-d8343a3f3779/9f55af82923dab7e3dce912f5c5b9d60/aspnetcore-runtime-8.0.0-win-x64.exe"; + public const string Name = "Updater"; + public const string ServiceName = "insight_updater"; + public const string Description = "Insight Updater"; - public static DirectoryInfo Directory => new($@"{Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)}/dotnet/shared/Microsoft.AspNetCore.App"); + public static Uri UpdateHref(Uri api) => new($"{api.AbsoluteUri}/{Name}/windows"); } + + public static class Agent + { + public const string Name = "Agent"; + public const string ServiceName = "insight_agent"; + public const string Description = "Insight Agent"; + } + + public static DirectoryInfo GetAppDirectory(string appName) + => new($"{Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)}/Webmatic/Insight/{appName}"); + + public static FileInfo GetAppExecutable(string appName) + => new($"{GetAppDirectory(appName).FullName}/{appName.ToLower()}.exe"); + + public static Uri GetUpdateHref(Uri api, string appName) + => new($"{api.AbsoluteUri}/update/{appName.ToLower()}/windows"); } - - public static class Updater - { - public const string Name = "Updater"; - public const string ServiceName = "insight_updater"; - public const string Description = "Insight Updater"; - - public static Uri UpdateHref(Uri api) => new($"{api.AbsoluteUri}/{Name}/windows"); - } - - public static class Agent - { - public const string Name = "Agent"; - public const string ServiceName = "insight_agent"; - public const string Description = "Insight Agent"; - } - - public static DirectoryInfo GetAppDirectory(string appName) - => new($"{Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)}/Webmatic/Insight/{appName}"); - - public static FileInfo GetAppExecutable(string appName) - => new($"{GetAppDirectory(appName).FullName}/{appName.ToLower()}.exe"); - - public static Uri GetUpdateHref(Uri api, string appName) - => new($"{api.AbsoluteUri}/update/{appName.ToLower()}/windows"); } \ No newline at end of file diff --git a/src/Setup/Insight.Setup.Windows/Insight.Setup.Windows.csproj b/src/Setup/Insight.Setup.Windows/Insight.Setup.Windows.csproj index b36a2d9..907d9aa 100644 --- a/src/Setup/Insight.Setup.Windows/Insight.Setup.Windows.csproj +++ b/src/Setup/Insight.Setup.Windows/Insight.Setup.Windows.csproj @@ -2,14 +2,14 @@ Exe - net8.0 - latest + net7.0 true enable setup Insight.Setup Insight - 2023.12.14.0 + 2025.2.24.0 + 2025.2.24.0 none true @@ -36,8 +36,8 @@ - - + + diff --git a/src/Setup/Insight.Setup.Windows/Program.cs b/src/Setup/Insight.Setup.Windows/Program.cs index 4450a9a..8c488d7 100644 --- a/src/Setup/Insight.Setup.Windows/Program.cs +++ b/src/Setup/Insight.Setup.Windows/Program.cs @@ -5,53 +5,54 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using System.Runtime.Versioning; -namespace Insight.Setup.Windows; - -[SupportedOSPlatform("windows")] -internal class Program +namespace Insight.Setup.Windows { - public static async Task Main(string[] args) + [SupportedOSPlatform("windows")] + public class Program { - await Host.CreateDefaultBuilder(args) - .ConfigureAppConfiguration(options => - { - options.Sources.Clear(); - options.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true); - options.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true, reloadOnChange: true); - - options.AddCommandLine(args, new Dictionary() + public static async Task Main(string[] args) + { + await Host.CreateDefaultBuilder(args) + .ConfigureAppConfiguration(options => { - { "-deploy", "deploy" }, - { "--deploy", "deploy" } - }); - }) - .ConfigureLogging(options => - { - options.ClearProviders(); - options.SetMinimumLevel(LogLevel.Trace); + options.Sources.Clear(); + options.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true); + options.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true, reloadOnChange: true); - options.AddSimpleConsole(options => + options.AddCommandLine(args, new Dictionary() + { + { "-deploy", "deploy" }, + { "--deploy", "deploy" } + }); + }) + .ConfigureLogging(options => { - options.IncludeScopes = true; - options.SingleLine = true; - options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff "; - }); + options.ClearProviders(); + options.SetMinimumLevel(LogLevel.Trace); - options.AddFilter("Microsoft", LogLevel.Warning); - }) - .ConfigureServices((host, services) => - { - // SERVICES - services.AddHostedService(); + options.AddSimpleConsole(options => + { + options.IncludeScopes = true; + options.SingleLine = true; + options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff "; + }); - // GLOBALS - services.AddTransient(provider => new HttpClient(new HttpClientHandler + options.AddFilter("Microsoft", LogLevel.Warning); + }) + .ConfigureServices((host, services) => { - ClientCertificateOptions = ClientCertificateOption.Manual, - ServerCertificateCustomValidationCallback = (httpRequestMessage, cert, cetChain, policyErrors) => true - })); - }) - .Build() - .RunAsync(); + // SERVICES + services.AddHostedService(); + + // GLOBALS + services.AddTransient(provider => new HttpClient(new HttpClientHandler + { + ClientCertificateOptions = ClientCertificateOption.Manual, + ServerCertificateCustomValidationCallback = (httpRequestMessage, cert, cetChain, policyErrors) => true + })); + }) + .Build() + .RunAsync(); + } } } \ No newline at end of file diff --git a/src/Setup/Insight.Setup.Windows/Services/Deployment.cs b/src/Setup/Insight.Setup.Windows/Services/Deployment.cs index cf4306d..57a8047 100644 --- a/src/Setup/Insight.Setup.Windows/Services/Deployment.cs +++ b/src/Setup/Insight.Setup.Windows/Services/Deployment.cs @@ -6,471 +6,472 @@ using System.Runtime.Versioning; using System.ServiceProcess; using System.Text.Json; -namespace Insight.Setup.Services; - -public static class Deployment +namespace Insight.Setup.Services { - [SupportedOSPlatform("windows")] - public static class Windows + public static class Deployment { - public static class Service + [SupportedOSPlatform("windows")] + public static class Windows { - private static bool ServiceExistence(string serviceName) + public static class Service { - try + private static bool ServiceExistence(string serviceName) { - if (ServiceController.GetServices().Any(s => s.ServiceName.Equals(serviceName, StringComparison.InvariantCultureIgnoreCase))) return true; + try + { + if (ServiceController.GetServices().Any(s => s.ServiceName.Equals(serviceName, StringComparison.InvariantCultureIgnoreCase))) return true; + return false; + } + catch (Exception) { } + return false; } - catch (Exception) { } - return false; - } - - private static bool SetServiceState(string app, ServiceControllerStatus status, TimeSpan timeout) - { - try + private static bool SetServiceState(string app, ServiceControllerStatus status, TimeSpan timeout) { - using var sc = ServiceController.GetServices().FirstOrDefault(s => s.ServiceName.Equals(app, StringComparison.InvariantCultureIgnoreCase)); - if (sc is null) return false; - - if (sc.Status != status) + try { - switch (status) - { - case ServiceControllerStatus.Running: - sc.Start(); - break; + using var sc = ServiceController.GetServices().FirstOrDefault(s => s.ServiceName.Equals(app, StringComparison.InvariantCultureIgnoreCase)); + if (sc is null) return false; - case ServiceControllerStatus.Stopped: - sc.Stop(); - break; + if (sc.Status != status) + { + switch (status) + { + case ServiceControllerStatus.Running: + sc.Start(); + break; + + case ServiceControllerStatus.Stopped: + sc.Stop(); + break; + } + + sc.WaitForStatus(status, timeout); } - sc.WaitForStatus(status, timeout); + return true; } + catch (Exception) { } - return true; + return false; } - catch (Exception) { } - return false; - } - - private static async ValueTask InstallAsync(FileInfo bin, string serviceName, string displayName, string description, bool autorun) - { - if (bin.Exists is false) return false; - if (ServiceExistence(serviceName)) return false; - - var args = @$"/C sc create {serviceName} binPath= ""{bin.FullName}"" DisplayName= ""{displayName}"""; - args += $@" && sc description {serviceName} ""{description}"""; - args += $@" && sc config {serviceName} start= {(autorun ? "auto" : "demand")}"; - args += $@" && sc start {serviceName}"; - - try + private static async ValueTask InstallAsync(FileInfo bin, string serviceName, string displayName, string description, bool autorun) { - using var process = new System.Diagnostics.Process() + if (bin.Exists is false) return false; + if (ServiceExistence(serviceName)) return false; + + var args = @$"/C sc create {serviceName} binPath= ""{bin.FullName}"" DisplayName= ""{displayName}"""; + args += $@" && sc description {serviceName} ""{description}"""; + args += $@" && sc config {serviceName} start= {(autorun ? "auto" : "demand")}"; + args += $@" && sc start {serviceName}"; + + try { - StartInfo = new ProcessStartInfo + using var process = new System.Diagnostics.Process() { - WindowStyle = ProcessWindowStyle.Normal, - FileName = "cmd.exe", - Arguments = args, - Verb = "runas", - RedirectStandardOutput = true, - UseShellExecute = false - } + StartInfo = new ProcessStartInfo + { + WindowStyle = ProcessWindowStyle.Normal, + FileName = "cmd.exe", + Arguments = args, + Verb = "runas", + RedirectStandardOutput = true, + UseShellExecute = false + } + }; + + process.Start(); + + var output = await process.StandardOutput.ReadToEndAsync(); + + if (Directory.GetParent(bin.FullName) is not DirectoryInfo serviceDir) return false; + + return ServiceExistence(serviceName); // may return output as return model if existence false + } + catch (Exception) + { + return false; + } + } + + public static async ValueTask InstallAsync(HttpClient httpClient, Uri api, FileInfo bin, string serviceName, string serviceDisplayName, string serviceDescription, bool autorun, CancellationToken cancellationToken) + { + var result = new InstallResult + { + Api = api?.ToString(), + SourceDirectory = bin.Directory?.FullName, + App = bin.Name, + ServiceName = serviceName, + Autorun = autorun }; - process.Start(); - - var output = await process.StandardOutput.ReadToEndAsync(); - - if (Directory.GetParent(bin.FullName) is not DirectoryInfo serviceDir) return false; - - return ServiceExistence(serviceName); // may return output as return model if existence false - } - catch (Exception) - { - return false; - } - } - - public static async ValueTask InstallAsync(HttpClient httpClient, Uri api, FileInfo bin, string serviceName, string serviceDisplayName, string serviceDescription, bool autorun, CancellationToken cancellationToken) - { - var result = new InstallResult - { - Api = api?.ToString(), - SourceDirectory = bin.Directory?.FullName, - App = bin.Name, - ServiceName = serviceName, - Autorun = autorun - }; - - try - { - if (ServiceExistence(serviceName)) + try { - result.Errors.Add("Service already installed"); - return result; - } + if (ServiceExistence(serviceName)) + { + result.Errors.Add("Service already installed"); + return result; + } - var response = await httpClient.GetFromJsonAsync(api, cancellationToken); - if (response is null) - { - result.ApiErrors.Add("not available / response null"); - return result; - } + var response = await httpClient.GetFromJsonAsync(api, cancellationToken); + if (response is null) + { + result.ApiErrors.Add("not available / response null"); + return result; + } - // get update file (bytes) to memory - using var update = await httpClient.GetAsync(response.Uri, cancellationToken); - if (update is null) - { - result.ApiErrors.Add("update source not available"); - return result; - } + // get update file (bytes) to memory + using var update = await httpClient.GetAsync(response.Uri, cancellationToken); + if (update is null) + { + result.ApiErrors.Add("update source not available"); + return result; + } - result.ApiAvailable = true; + result.ApiAvailable = true; - // read update archive to temp (overwrite) - var temp = Directory.CreateTempSubdirectory(); - var updateFile = new FileInfo($@"{temp.FullName}/{bin.Name}.zip"); + // read update archive to temp (overwrite) + var temp = Directory.CreateTempSubdirectory(); + var updateFile = new FileInfo($@"{temp.FullName}/{bin.Name}.zip"); - await File.WriteAllBytesAsync(updateFile.FullName, await update.Content.ReadAsByteArrayAsync(cancellationToken), cancellationToken); + await File.WriteAllBytesAsync(updateFile.FullName, await update.Content.ReadAsByteArrayAsync(cancellationToken), cancellationToken); - // extract update archive from temp to app dir (overwrite) - ZipFile.ExtractToDirectory(updateFile.FullName, bin.Directory!.FullName, true); + // extract update archive from temp to app dir (overwrite) + ZipFile.ExtractToDirectory(updateFile.FullName, bin.Directory?.FullName, true); - // delete temp folder - if (temp.Exists) temp.Delete(true); + // delete temp folder + if (temp.Exists) temp.Delete(true); - // install service with windows api - if (await InstallAsync(bin, serviceName, serviceDisplayName, serviceDescription, autorun) is false) - { - result.Errors.Add("installation failed"); - return result; - } + // install service with windows api + if (await InstallAsync(bin, serviceName, serviceDisplayName, serviceDescription, autorun) is false) + { + result.Errors.Add("installation failed"); + return result; + } - result.Success = true; - } - catch (Exception ex) - { - result.Errors.Add(ex.Message); - } - - return result; - } - - public static async ValueTask UpdateAsync(HttpClient httpClient, Uri api, FileInfo bin, string serviceName, CancellationToken cancellationToken) - { - var result = new UpdateResult - { - Api = api?.ToString(), - SourceDirectory = bin.Directory?.FullName, - App = bin.Name, - ServiceName = serviceName - }; - - try - { - // check if service exists - if (ServiceExistence(serviceName) is false) - { - result.UpdateErrors.Add("service not found"); - return result; - } - - // get service update details - var response = await httpClient.GetFromJsonAsync(api, cancellationToken); - if (response is null) - { - result.ApiErrors.Add("not available / response null"); - return result; - } - - result.ApiAvailable = true; - - // check if local binary exists - if (bin is null) - { - result.UpdateErrors.Add("source binary not found"); - return result; - } - - // get local file binary version - if (FileVersionInfo.GetVersionInfo(bin.FullName).FileVersion is not string binVersionString) - { - result.UpdateErrors.Add("source binary fileversion not valid"); - return result; - } - - // compare local against update version, skip lower or equal update version - var actualVersion = Version.Parse(binVersionString); - if (actualVersion >= response.Version) - { result.Success = true; - return result; } - else + catch (Exception ex) { - result.UpdateAvailable = true; + result.Errors.Add(ex.Message); } - // get update file (bytes) to memory - using var update = await httpClient.GetAsync(response.Uri, cancellationToken); - if (update is null) - { - result.ApiErrors.Add("update source not available"); - return result; - } - - // stop service - if (SetServiceState(serviceName, ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(10)) is false) - { - result.UpdateErrors.Add("service control failed / failed to stop service"); - return result; - } - - // read update archive to temp (overwrite) - var temp = Directory.CreateTempSubdirectory(); - var updateFile = new FileInfo($@"{temp.FullName}/{bin.Name}.zip"); - - await File.WriteAllBytesAsync(updateFile.FullName, await update.Content.ReadAsByteArrayAsync(cancellationToken), cancellationToken); - - // extract update archive from temp to app dir (overwrite) - ZipFile.ExtractToDirectory(updateFile.FullName, bin.Directory!.FullName, true); - - // delete temp folder - if (temp.Exists) temp.Delete(true); - - // start updateds service - if (SetServiceState(serviceName, ServiceControllerStatus.Running, TimeSpan.FromSeconds(10)) is false) - { - result.UpdateErrors.Add("service control failed / failed to start service"); - return result; - } - - result.Success = true; - } - catch (Exception ex) - { - result.UpdateErrors.Add(ex.Message); + return result; } - return result; - } - - public static async ValueTask UninstallAsync(string serviceName) - { - var result = new UninstallResult + public static async ValueTask UpdateAsync(HttpClient httpClient, Uri api, FileInfo bin, string serviceName, CancellationToken cancellationToken) { - ServiceName = serviceName - }; - - try - { - if (ServiceExistence(serviceName) is false) + var result = new UpdateResult { - result.Errors.Add("service not found"); - return result; - } - - if (SetServiceState(serviceName, ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(60)) is false) - { - result.Errors.Add("service control failed / failed to stop service"); - return result; - } - - using var process = new System.Diagnostics.Process() - { - StartInfo = new ProcessStartInfo - { - WindowStyle = ProcessWindowStyle.Normal, - FileName = "cmd.exe", - Arguments = $"/C sc delete {serviceName}", - Verb = "runas", - RedirectStandardOutput = true, - UseShellExecute = false - } + Api = api?.ToString(), + SourceDirectory = bin.Directory?.FullName, + App = bin.Name, + ServiceName = serviceName }; - process.Start(); - - var output = await process.StandardOutput.ReadToEndAsync(); - - // may return output as return model if existence true - - if (ServiceExistence(serviceName)) + try { - result.Errors.Add("service still existing"); + // check if service exists + if (ServiceExistence(serviceName) is false) + { + result.UpdateErrors.Add("service not found"); + return result; + } + + // get service update details + var response = await httpClient.GetFromJsonAsync(api, cancellationToken); + if (response is null) + { + result.ApiErrors.Add("not available / response null"); + return result; + } + + result.ApiAvailable = true; + + // check if local binary exists + if (bin is null) + { + result.UpdateErrors.Add("source binary not found"); + return result; + } + + // get local file binary version + if (FileVersionInfo.GetVersionInfo(bin.FullName).FileVersion is not string binVersionString) + { + result.UpdateErrors.Add("source binary fileversion not valid"); + return result; + } + + // compare local against update version, skip lower or equal update version + var actualVersion = Version.Parse(binVersionString); + if (actualVersion >= response.Version) + { + result.Success = true; + return result; + } + else + { + result.UpdateAvailable = true; + } + + // get update file (bytes) to memory + using var update = await httpClient.GetAsync(response.Uri, cancellationToken); + if (update is null) + { + result.ApiErrors.Add("update source not available"); + return result; + } + + // stop service + if (SetServiceState(serviceName, ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(10)) is false) + { + result.UpdateErrors.Add("service control failed / failed to stop service"); + return result; + } + + // read update archive to temp (overwrite) + var temp = Directory.CreateTempSubdirectory(); + var updateFile = new FileInfo($@"{temp.FullName}/{bin.Name}.zip"); + + await File.WriteAllBytesAsync(updateFile.FullName, await update.Content.ReadAsByteArrayAsync(cancellationToken), cancellationToken); + + // extract update archive from temp to app dir (overwrite) + ZipFile.ExtractToDirectory(updateFile.FullName, bin.Directory?.FullName, true); + + // delete temp folder + if (temp.Exists) temp.Delete(true); + + // start updateds service + if (SetServiceState(serviceName, ServiceControllerStatus.Running, TimeSpan.FromSeconds(10)) is false) + { + result.UpdateErrors.Add("service control failed / failed to start service"); + return result; + } + + result.Success = true; + } + catch (Exception ex) + { + result.UpdateErrors.Add(ex.Message); } - result.Success = true; - } - catch (Exception ex) - { - result.Errors.Add(ex.Message); + return result; } - return result; - } - } - - public static class Process - { - public static bool IsRunning(FileInfo bin) - { - if (bin.Exists is false) return false; - - var matched = System.Diagnostics.Process.GetProcessesByName(bin.FullName); - - if (matched is null || matched.Length == 0) return false; - - if (matched.Any(p => - p.MainModule is not null && - p.MainModule.FileName is not null && - p.MainModule.FileName.Equals(bin.FullName, - StringComparison.InvariantCultureIgnoreCase))) return true; - - return false; - } - - public static bool Start(FileInfo binary) - { - try + public static async ValueTask UninstallAsync(string serviceName) { - if (IsRunning(binary) is false) return false; + var result = new UninstallResult + { + ServiceName = serviceName + }; - using var process = System.Diagnostics.Process.Start(binary.FullName); - return true; + try + { + if (ServiceExistence(serviceName) is false) + { + result.Errors.Add("service not found"); + return result; + } + + if (SetServiceState(serviceName, ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(60)) is false) + { + result.Errors.Add("service control failed / failed to stop service"); + return result; + } + + using var process = new System.Diagnostics.Process() + { + StartInfo = new ProcessStartInfo + { + WindowStyle = ProcessWindowStyle.Normal, + FileName = "cmd.exe", + Arguments = $"/C sc delete {serviceName}", + Verb = "runas", + RedirectStandardOutput = true, + UseShellExecute = false + } + }; + + process.Start(); + + var output = await process.StandardOutput.ReadToEndAsync(); + + // may return output as return model if existence true + + if (ServiceExistence(serviceName)) + { + result.Errors.Add("service still existing"); + } + + result.Success = true; + } + catch (Exception ex) + { + result.Errors.Add(ex.Message); + } + + return result; } - catch (Exception) { } - - return false; } - public static bool Stop(FileInfo bin, TimeSpan timeout) + public static class Process { - try + public static bool IsRunning(FileInfo bin) { - if (IsRunning(bin) is false) return false; + if (bin.Exists is false) return false; var matched = System.Diagnostics.Process.GetProcessesByName(bin.FullName); - if (matched is null || matched.Length == 0) return true; + if (matched is null || matched.Any() is false) return false; - foreach (var procsInfo in matched.Where(p => + if (matched.Any(p => p.MainModule is not null && p.MainModule.FileName is not null && - p.MainModule.FileName.Equals(bin.FullName, StringComparison.InvariantCultureIgnoreCase))) + p.MainModule.FileName.Equals(bin.FullName, + StringComparison.InvariantCultureIgnoreCase))) return true; + + return false; + } + + public static bool Start(FileInfo binary) + { + try { - if (procsInfo.CloseMainWindow()) procsInfo.WaitForExit((int)timeout.TotalMilliseconds); - if (procsInfo.HasExited is false) procsInfo.Kill(true); + if (IsRunning(binary) is false) return false; + + using var process = System.Diagnostics.Process.Start(binary.FullName); + return true; } + catch (Exception) { } - return true; + return false; } - catch (Exception) { } - return false; - } - - public static async ValueTask UpdateAsync(HttpClient httpClient, Uri api, FileInfo bin, CancellationToken cancellationToken) - { - if (IsRunning(bin) is false) return false; - - var response = await httpClient.GetFromJsonAsync(api.AbsoluteUri, new JsonSerializerOptions + public static bool Stop(FileInfo bin, TimeSpan timeout) { - IncludeFields = true - }, cancellationToken); + try + { + if (IsRunning(bin) is false) return false; - if (response is null) return false; + var matched = System.Diagnostics.Process.GetProcessesByName(bin.FullName); - Version actualVersion; + if (matched is null || matched.Any() is false) return true; - if (FileVersionInfo.GetVersionInfo(bin.FullName).FileVersion is not string binVersionString) return false; + foreach (var procsInfo in matched.Where(p => + p.MainModule is not null && + p.MainModule.FileName is not null && + p.MainModule.FileName.Equals(bin.FullName, StringComparison.InvariantCultureIgnoreCase))) + { + if (procsInfo.CloseMainWindow()) procsInfo.WaitForExit((int)timeout.TotalMilliseconds); + if (procsInfo.HasExited is false) procsInfo.Kill(true); + } - try - { - actualVersion = Version.Parse(binVersionString); - if (actualVersion >= response.Version) return false; + return true; + } + catch (Exception) { } - using var update = await httpClient.GetAsync(response.Uri, cancellationToken); - if (update is null) return false; - - Stop(bin, TimeSpan.FromSeconds(60)); - - // read update archive to temp (overwrite) - var temp = Directory.CreateTempSubdirectory(); - var updateFile = new FileInfo($@"{temp.FullName}/{bin.Name}.zip"); - - await File.WriteAllBytesAsync(updateFile.FullName, await update.Content.ReadAsByteArrayAsync(cancellationToken), cancellationToken); - - // extract update archive from temp to app dir (overwrite) - ZipFile.ExtractToDirectory(updateFile.FullName, bin.Directory!.FullName, true); - - // delete temp folder - if (temp.Exists) temp.Delete(true); - - // rewrite with options to start user session process - //Start(app, directory, TimeSpan.FromSeconds(60)); - - return true; + return false; } - catch (Exception) { } - return false; - } - - public static bool Delete(FileInfo bin, TimeSpan timeout) - { - try + public static async ValueTask UpdateAsync(HttpClient httpClient, Uri api, FileInfo bin, CancellationToken cancellationToken) { - Stop(bin, timeout); - bin.Delete(); + if (IsRunning(bin) is false) return false; - return true; + var response = await httpClient.GetFromJsonAsync(api.AbsoluteUri, new JsonSerializerOptions + { + IncludeFields = true + }, cancellationToken); + + if (response is null) return false; + + Version actualVersion; + + if (FileVersionInfo.GetVersionInfo(bin.FullName).FileVersion is not string binVersionString) return false; + + try + { + actualVersion = Version.Parse(binVersionString); + if (actualVersion >= response.Version) return false; + + using var update = await httpClient.GetAsync(response.Uri, cancellationToken); + if (update is null) return false; + + Stop(bin, TimeSpan.FromSeconds(60)); + + // read update archive to temp (overwrite) + var temp = Directory.CreateTempSubdirectory(); + var updateFile = new FileInfo($@"{temp.FullName}/{bin.Name}.zip"); + + await File.WriteAllBytesAsync(updateFile.FullName, await update.Content.ReadAsByteArrayAsync(cancellationToken), cancellationToken); + + // extract update archive from temp to app dir (overwrite) + ZipFile.ExtractToDirectory(updateFile.FullName, bin.Directory?.FullName, true); + + // delete temp folder + if (temp.Exists) temp.Delete(true); + + // rewrite with options to start user session process + //Start(app, directory, TimeSpan.FromSeconds(60)); + + return true; + } + catch (Exception) { } + + return false; } - catch (Exception) { } - return false; + public static bool Delete(FileInfo bin, TimeSpan timeout) + { + try + { + Stop(bin, timeout); + bin.Delete(); + + return true; + } + catch (Exception) { } + + return false; + } } } - } - public class InstallResult - { - public string? Api { get; set; } - public string? SourceDirectory { get; set; } - public string? App { get; set; } - public string? ServiceName { get; set; } - public bool Autorun { get; set; } + public class InstallResult + { + public string? Api { get; set; } + public string? SourceDirectory { get; set; } + public string? App { get; set; } + public string? ServiceName { get; set; } + public bool Autorun { get; set; } - public bool ApiAvailable { get; set; } = false; - public bool Success { get; set; } = false; - public List ApiErrors { get; } = []; - public List Errors { get; } = []; - } + public bool ApiAvailable { get; set; } = false; + public bool Success { get; set; } = false; + public List ApiErrors { get; } = new(); + public List Errors { get; } = new(); + } - public class UpdateResult - { - public string? Api { get; set; } - public string? SourceDirectory { get; set; } - public string? App { get; set; } - public string? ServiceName { get; set; } + public class UpdateResult + { + public string? Api { get; set; } + public string? SourceDirectory { get; set; } + public string? App { get; set; } + public string? ServiceName { get; set; } - public bool ApiAvailable { get; set; } = false; - public bool UpdateAvailable { get; set; } = false; - public bool Success { get; set; } = false; - public List ApiErrors { get; } = []; - public List UpdateErrors { get; } = []; - } + public bool ApiAvailable { get; set; } = false; + public bool UpdateAvailable { get; set; } = false; + public bool Success { get; set; } = false; + public List ApiErrors { get; } = new(); + public List UpdateErrors { get; } = new(); + } - public class UninstallResult - { - public string? ServiceName { get; set; } + public class UninstallResult + { + public string? ServiceName { get; set; } - public bool Success { get; set; } = false; - public List Errors { get; } = []; + public bool Success { get; set; } = false; + public List Errors { get; } = new(); + } } } \ No newline at end of file diff --git a/src/Setup/Insight.Setup.Windows/Services/SetupService.cs b/src/Setup/Insight.Setup.Windows/Services/SetupService.cs index 0d5bec5..54df73b 100644 --- a/src/Setup/Insight.Setup.Windows/Services/SetupService.cs +++ b/src/Setup/Insight.Setup.Windows/Services/SetupService.cs @@ -5,238 +5,243 @@ using Microsoft.Extensions.Logging; using System.Diagnostics; using System.Runtime.Versioning; -namespace Insight.Setup.Services; - -[SupportedOSPlatform("windows")] -internal class SetupService( - HttpClient httpClient, - IHostApplicationLifetime lifetime, - IConfiguration configuration, - ILogger logger) : BackgroundService +namespace Insight.Setup.Services { - private readonly Uri _uri = configuration.GetValue("api") ?? new Uri("https://insight.webmatic.de/api"); - - private readonly HttpClient _httpClient = httpClient; - private readonly IHostApplicationLifetime _lifetime = lifetime; - private readonly ILogger _logger = logger; - - protected override async Task ExecuteAsync(CancellationToken cancellationToken) + [SupportedOSPlatform("windows")] + internal class SetupService : BackgroundService { - _logger.LogTrace("ExecuteAsync"); + private readonly Uri _uri; - Console.WriteLine("1: Install"); - Console.WriteLine("2: Update"); - Console.WriteLine("3: Uninstall"); + private readonly HttpClient _httpClient; + private readonly IHostApplicationLifetime _lifetime; + private readonly ILogger _logger; - Console.WriteLine("\n"); - - var key = Console.ReadKey(); - - Console.Clear(); - - try + public SetupService(HttpClient httpClient, IHostApplicationLifetime lifetime, IConfiguration configuration, ILogger logger) { - switch (key.Key) + _httpClient = httpClient; + _lifetime = lifetime; + _uri = configuration.GetValue("api") ?? new Uri("https://insight.webmatic.de/api"); //throw new Exception($"api value not set (appsettings)"); + _logger = logger; + } + + protected override async Task ExecuteAsync(CancellationToken cancellationToken) + { + _logger.LogTrace("ExecuteAsync"); + + Console.WriteLine("1: Install"); + Console.WriteLine("2: Update"); + Console.WriteLine("3: Uninstall"); + + Console.WriteLine("\n"); + + var key = Console.ReadKey(); + + Console.Clear(); + + try { - case ConsoleKey.NumPad1: - case ConsoleKey.D1: - { - await InstallAsync(cancellationToken); - break; - } - case ConsoleKey.NumPad2: - case ConsoleKey.D2: - { - await UpdateAsync(cancellationToken); - break; - } - case ConsoleKey.NumPad3: - case ConsoleKey.D3: - { - await UninstallAsync(); - break; - } - default: - { - Console.WriteLine("invalid selection"); - break; - } - } - } - catch (Exception ex) - { - Console.WriteLine(ex); - } - finally - { - _lifetime.StopApplication(); - } - } - - private async ValueTask InstallAsync(CancellationToken cancellationToken) - { - Console.WriteLine("Install Runtime"); - await InstallRuntimeAsync(cancellationToken); - - Console.WriteLine("Install ASP Runtime"); - await InstallAspRuntimeAsync(cancellationToken); - - // UPDATER - Console.WriteLine("Install Updater"); - - var updaterResult = await Deployment.Windows.Service.InstallAsync( - _httpClient, - Deploy.GetUpdateHref(_uri, Deploy.Updater.Name), - Deploy.GetAppExecutable(Deploy.Updater.Name), - Deploy.Updater.ServiceName, - Deploy.Updater.Description, - Deploy.Updater.Description, - true, - cancellationToken); - - Console.WriteLine($"Updater: {updaterResult.Success}"); - Console.WriteLine($"Updater: {string.Concat(updaterResult.Errors)}"); - - // AGENT - Console.WriteLine("Install Agent"); - - var agentResult = await Deployment.Windows.Service.InstallAsync( - _httpClient, - Deploy.GetUpdateHref(_uri, Deploy.Agent.Name), - Deploy.GetAppExecutable(Deploy.Agent.Name), - Deploy.Agent.ServiceName, - Deploy.Agent.Description, - Deploy.Agent.Description, - true, - cancellationToken); - - Console.WriteLine($"Agent: {agentResult}"); - Console.WriteLine($"Agent: {string.Concat(agentResult.Errors)}"); - } - - private async ValueTask UpdateAsync(CancellationToken cancellationToken) - { - // UPDATER - Console.WriteLine("Update Updater"); - - var updateResult = await Deployment.Windows.Service.UpdateAsync( - _httpClient, - Deploy.GetUpdateHref(_uri, Deploy.Updater.Name), - Deploy.GetAppExecutable(Deploy.Updater.Name), - Deploy.Updater.ServiceName, - cancellationToken); - - Console.WriteLine($"Result: {updateResult}"); - - // AGENT - Console.WriteLine("Update Agent"); - - var agentResult = await Deployment.Windows.Service.UpdateAsync( - _httpClient, - Deploy.GetUpdateHref(_uri, Deploy.Agent.Name), - Deploy.GetAppExecutable(Deploy.Agent.Name), - Deploy.Agent.ServiceName, - cancellationToken); - - Console.WriteLine($"Result: {agentResult}"); - } - - private static async ValueTask UninstallAsync() - { - // UPDATER - Console.WriteLine("Uninstall Updater"); - - var updaterResult = await Deployment.Windows.Service.UninstallAsync(Deploy.Updater.ServiceName); - Console.WriteLine($"Result: {updaterResult}"); - - // AGENT - Console.WriteLine("Uninstall Agent"); - - var agentResult = await Deployment.Windows.Service.UninstallAsync(Deploy.Agent.ServiceName); - Console.WriteLine($"Result: {agentResult}"); - } - - private async ValueTask InstallRuntimeAsync(CancellationToken cancellationToken) - { - // try get dotnet folders - var coreDirectory = Deploy.Runtime.Core.Directory; - - // Runtime Installation Check... - if (coreDirectory.Exists && coreDirectory.EnumerateDirectories().Any(x => x.Name == Deploy.Runtime.Core.Version)) return; - - // Downloading Runtime... - var queryResult = await _httpClient.GetAsync(Deploy.Runtime.Core.Download, cancellationToken); - - var tempDir = Directory.CreateTempSubdirectory(); - - await File.WriteAllBytesAsync( - $@"{tempDir.FullName}/runtime.exe", - await queryResult.Content.ReadAsByteArrayAsync(cancellationToken), cancellationToken); - - // Installing Runtime... - var runtimeFile = new FileInfo($@"{tempDir.FullName}/runtime.exe"); - - using var process = new Process() - { - StartInfo = new ProcessStartInfo - { - FileName = runtimeFile.FullName, - ArgumentList = + switch (key.Key) { - @"/install", - @"/quiet", - @"/norestart" - }, - UseShellExecute = false, - RedirectStandardOutput = true + case ConsoleKey.NumPad1: + case ConsoleKey.D1: + { + await InstallAsync(cancellationToken); + break; + } + case ConsoleKey.NumPad2: + case ConsoleKey.D2: + { + await UpdateAsync(cancellationToken); + break; + } + case ConsoleKey.NumPad3: + case ConsoleKey.D3: + { + await UninstallAsync(); + break; + } + default: + { + Console.WriteLine("invalid selection"); + break; + } + } } - }; - - process.Start(); - await process.WaitForExitAsync(cancellationToken); - - if (runtimeFile.Exists) runtimeFile.Delete(); - } - - private async ValueTask InstallAspRuntimeAsync(CancellationToken cancellationToken) - { - // try get dotnet folders - var aspDirectory = Deploy.Runtime.Asp.Directory; - - // Runtime Installation Check... - if (aspDirectory.Exists && aspDirectory.EnumerateDirectories().Any(x => x.Name == Deploy.Runtime.Asp.Version)) return; - - // Downloading Runtime... - var queryResult = await _httpClient.GetAsync(Deploy.Runtime.Asp.Download, cancellationToken); - - var tempDir = Directory.CreateTempSubdirectory(); - - await File.WriteAllBytesAsync( - $@"{tempDir.FullName}/runtime.exe", - await queryResult.Content.ReadAsByteArrayAsync(cancellationToken), cancellationToken); - - // Installing Runtime... - var runtimeFile = new FileInfo($@"{tempDir.FullName}/runtime.exe"); - - using var process = new Process() - { - StartInfo = new ProcessStartInfo + catch (Exception ex) { - FileName = runtimeFile.FullName, - ArgumentList = - { - @"/install", - @"/quiet", - @"/norestart" - }, - UseShellExecute = false, - RedirectStandardOutput = true + Console.WriteLine(ex); } - }; + finally + { + _lifetime.StopApplication(); + } + } - process.Start(); - await process.WaitForExitAsync(cancellationToken); + private async ValueTask InstallAsync(CancellationToken cancellationToken) + { + Console.WriteLine("Install Runtime"); + await InstallRuntimeAsync(cancellationToken); - if (runtimeFile.Exists) runtimeFile.Delete(); + Console.WriteLine("Install ASP Runtime"); + await InstallAspRuntimeAsync(cancellationToken); + + // UPDATER + Console.WriteLine("Install Updater"); + + var updaterResult = await Deployment.Windows.Service.InstallAsync( + _httpClient, + Deploy.GetUpdateHref(_uri, Deploy.Updater.Name), + Deploy.GetAppExecutable(Deploy.Updater.Name), + Deploy.Updater.ServiceName, + Deploy.Updater.Description, + Deploy.Updater.Description, + true, + cancellationToken); + + Console.WriteLine($"Updater: {updaterResult.Success}"); + Console.WriteLine($"Updater: {string.Concat(updaterResult.Errors)}"); + + // AGENT + Console.WriteLine("Install Agent"); + + var agentResult = await Deployment.Windows.Service.InstallAsync( + _httpClient, + Deploy.GetUpdateHref(_uri, Deploy.Agent.Name), + Deploy.GetAppExecutable(Deploy.Agent.Name), + Deploy.Agent.ServiceName, + Deploy.Agent.Description, + Deploy.Agent.Description, + true, + cancellationToken); + + Console.WriteLine($"Agent: {agentResult}"); + Console.WriteLine($"Agent: {string.Concat(agentResult.Errors)}"); + } + + private async ValueTask UpdateAsync(CancellationToken cancellationToken) + { + // UPDATER + Console.WriteLine("Update Updater"); + + var updateResult = await Deployment.Windows.Service.UpdateAsync( + _httpClient, + Deploy.GetUpdateHref(_uri, Deploy.Updater.Name), + Deploy.GetAppExecutable(Deploy.Updater.Name), + Deploy.Updater.ServiceName, + cancellationToken); + + Console.WriteLine($"Result: {updateResult}"); + + // AGENT + Console.WriteLine("Update Agent"); + + var agentResult = await Deployment.Windows.Service.UpdateAsync( + _httpClient, + Deploy.GetUpdateHref(_uri, Deploy.Agent.Name), + Deploy.GetAppExecutable(Deploy.Agent.Name), + Deploy.Agent.ServiceName, + cancellationToken); + + Console.WriteLine($"Result: {agentResult}"); + } + + private static async ValueTask UninstallAsync() + { + // UPDATER + Console.WriteLine("Uninstall Updater"); + + var updaterResult = await Deployment.Windows.Service.UninstallAsync(Deploy.Updater.ServiceName); + Console.WriteLine($"Result: {updaterResult}"); + + // AGENT + Console.WriteLine("Uninstall Agent"); + + var agentResult = await Deployment.Windows.Service.UninstallAsync(Deploy.Agent.ServiceName); + Console.WriteLine($"Result: {agentResult}"); + } + + private async ValueTask InstallRuntimeAsync(CancellationToken cancellationToken) + { + // try get dotnet folders + var coreDirectory = Deploy.Runtime.Core.Directory; + + // Runtime Installation Check... + if (coreDirectory.Exists && coreDirectory.EnumerateDirectories().Any(x => x.Name == Deploy.Runtime.Core.Version)) return; + + // Downloading Runtime... + var queryResult = await _httpClient.GetAsync(Deploy.Runtime.Core.Download, cancellationToken); + + var tempDir = Directory.CreateTempSubdirectory(); + + await File.WriteAllBytesAsync( + $@"{tempDir.FullName}/runtime.exe", + await queryResult.Content.ReadAsByteArrayAsync(cancellationToken), cancellationToken); + + // Installing Runtime... + var runtimeFile = new FileInfo($@"{tempDir.FullName}/runtime.exe"); + + using var process = new Process() + { + StartInfo = new ProcessStartInfo + { + FileName = runtimeFile.FullName, + ArgumentList = + { + @"/install", + @"/quiet", + @"/norestart" + }, + UseShellExecute = false, + RedirectStandardOutput = true + } + }; + + process.Start(); + await process.WaitForExitAsync(cancellationToken); + + if (runtimeFile.Exists) runtimeFile.Delete(); + } + + private async ValueTask InstallAspRuntimeAsync(CancellationToken cancellationToken) + { + // try get dotnet folders + var aspDirectory = Deploy.Runtime.Asp.Directory; + + // Runtime Installation Check... + if (aspDirectory.Exists && aspDirectory.EnumerateDirectories().Any(x => x.Name == Deploy.Runtime.Asp.Version)) return; + + // Downloading Runtime... + var queryResult = await _httpClient.GetAsync(Deploy.Runtime.Asp.Download, cancellationToken); + + var tempDir = Directory.CreateTempSubdirectory(); + + await File.WriteAllBytesAsync( + $@"{tempDir.FullName}/runtime.exe", + await queryResult.Content.ReadAsByteArrayAsync(cancellationToken), cancellationToken); + + // Installing Runtime... + var runtimeFile = new FileInfo($@"{tempDir.FullName}/runtime.exe"); + + using var process = new Process() + { + StartInfo = new ProcessStartInfo + { + FileName = runtimeFile.FullName, + ArgumentList = + { + @"/install", + @"/quiet", + @"/norestart" + }, + UseShellExecute = false, + RedirectStandardOutput = true + } + }; + + process.Start(); + await process.WaitForExitAsync(cancellationToken); + + if (runtimeFile.Exists) runtimeFile.Delete(); + } } } \ No newline at end of file diff --git a/src/Updater/Insight.Updater/Constants/Deploy.cs b/src/Updater/Insight.Updater/Constants/Deploy.cs index 86d9a6d..b285b98 100644 --- a/src/Updater/Insight.Updater/Constants/Deploy.cs +++ b/src/Updater/Insight.Updater/Constants/Deploy.cs @@ -1,20 +1,21 @@ -namespace Insight.Updater.Constants; - -public static class Deploy +namespace Insight.Updater.Constants { - public static class Agent + public static class Deploy { - public const string Name = "Agent"; - public const string ServiceName = "insight_agent"; - public const string Description = "Insight Agent"; + public static class Agent + { + public const string Name = "Agent"; + public const string ServiceName = "insight_agent"; + public const string Description = "Insight Agent"; + } + + public static DirectoryInfo GetAppDirectory(string appName) + => new($"{Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)}/Webmatic/Insight/{appName}"); + + public static FileInfo GetAppExecutable(string appName) + => new($"{GetAppDirectory(appName).FullName}/{appName.ToLower()}.exe"); + + public static Uri GetUpdateHref(Uri api, string appName) + => new($"{api.AbsoluteUri}/update/{appName.ToLower()}/windows"); } - - public static DirectoryInfo GetAppDirectory(string appName) - => new($"{Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)}/Webmatic/Insight/{appName}"); - - public static FileInfo GetAppExecutable(string appName) - => new($"{GetAppDirectory(appName).FullName}/{appName.ToLower()}.exe"); - - public static Uri GetUpdateHref(Uri api, string appName) - => new($"{api.AbsoluteUri}/update/{appName.ToLower()}/windows"); } \ No newline at end of file diff --git a/src/Updater/Insight.Updater/Insight.Updater.csproj b/src/Updater/Insight.Updater/Insight.Updater.csproj index 816226a..88c3b73 100644 --- a/src/Updater/Insight.Updater/Insight.Updater.csproj +++ b/src/Updater/Insight.Updater/Insight.Updater.csproj @@ -2,12 +2,12 @@ Exe - net8.0 - latest + net7.0 Insight Insight.Updater updater - 2023.12.14.0 + 2025.2.24.0 + 2025.2.24.0 enable enable none @@ -42,10 +42,10 @@ - - + + - + diff --git a/src/Updater/Insight.Updater/Program.cs b/src/Updater/Insight.Updater/Program.cs index db97d63..892f807 100644 --- a/src/Updater/Insight.Updater/Program.cs +++ b/src/Updater/Insight.Updater/Program.cs @@ -4,53 +4,54 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using System.Diagnostics; -namespace Insight.Updater.Windows; - -internal class Program +namespace Insight.Updater.Windows { - public static async Task Main(string[] args) + internal class Program { - var builder = Host.CreateDefaultBuilder(args); - builder.UseWindowsService(); - builder.UseSystemd(); - - builder.ConfigureAppConfiguration(options => + public static async Task Main(string[] args) { - options.Sources.Clear(); - options.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true); - options.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true, reloadOnChange: true); - }); + var builder = Host.CreateDefaultBuilder(args); + builder.UseWindowsService(); + builder.UseSystemd(); - builder.ConfigureLogging(options => - { - options.ClearProviders(); - options.SetMinimumLevel(LogLevel.Trace); - - options.AddSimpleConsole(options => + builder.ConfigureAppConfiguration(options => { - options.IncludeScopes = true; - options.SingleLine = true; - options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff "; + options.Sources.Clear(); + options.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true); + options.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true, reloadOnChange: true); }); - options.AddFile(Configuration.AppDirectory?.FullName + "/logs/" + Process.GetCurrentProcess().ProcessName + "_{Date}.log", LogLevel.Trace, fileSizeLimitBytes: 104857600, retainedFileCountLimit: 10, outputTemplate: "{Timestamp:o} [{Level:u3}] {Message} {NewLine}{Exception}"); - }); - builder.ConfigureServices((host, services) => - { - // SERVICES - services.AddHostedService(); - - // GLOBALS - services.AddTransient(provider => new HttpClient(new HttpClientHandler + builder.ConfigureLogging(options => { - ClientCertificateOptions = ClientCertificateOption.Manual, - ServerCertificateCustomValidationCallback = (httpRequestMessage, cert, cetChain, policyErrors) => true - })); - }); + options.ClearProviders(); + options.SetMinimumLevel(LogLevel.Trace); - var host = builder.Build(); - await host.RunAsync().ConfigureAwait(false); + options.AddSimpleConsole(options => + { + options.IncludeScopes = true; + options.SingleLine = true; + options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff "; + }); + + options.AddFile($"{Configuration.AppDirectory?.FullName}/" + "logs/updater_{Date}.log", LogLevel.Trace, fileSizeLimitBytes: 104857600, retainedFileCountLimit: 10, outputTemplate: "{Timestamp:o} [{Level:u3}] {Message} {NewLine}{Exception}"); + }); + + builder.ConfigureServices((host, services) => + { + // SERVICES + services.AddHostedService(); + + // GLOBALS + services.AddTransient(provider => new HttpClient(new HttpClientHandler + { + ClientCertificateOptions = ClientCertificateOption.Manual, + ServerCertificateCustomValidationCallback = (httpRequestMessage, cert, cetChain, policyErrors) => true + })); + }); + + var host = builder.Build(); + await host.RunAsync().ConfigureAwait(false); + } } } \ No newline at end of file diff --git a/src/Updater/Insight.Updater/Services/UpdateService.cs b/src/Updater/Insight.Updater/Services/UpdateService.cs index 402314e..e88c598 100644 --- a/src/Updater/Insight.Updater/Services/UpdateService.cs +++ b/src/Updater/Insight.Updater/Services/UpdateService.cs @@ -10,347 +10,351 @@ using System.Runtime.Versioning; using System.ServiceProcess; using System.Text.Json; -namespace Insight.Updater.Services; - -public class UpdateService( - HttpClient httpClient, - IConfiguration configuration, - ILogger logger) : BackgroundService +namespace Insight.Updater.Services { - private readonly Uri _uri = configuration.GetValue("api") ?? throw new Exception($"api value not set (appsettings)"); - - private readonly HttpClient _httpClient = httpClient; - private readonly ILogger _logger = logger; - - protected override async Task ExecuteAsync(CancellationToken cancellationToken) + public class UpdateService : BackgroundService { - _logger.LogTrace("ExecuteAsync"); + private readonly Uri _uri; - while (cancellationToken.IsCancellationRequested is false) + private readonly HttpClient _httpClient; + private readonly ILogger _logger; + + public UpdateService(HttpClient httpClient, IConfiguration configuration, ILogger logger) { - try - { - UpdateResult? result = null; - - if (OperatingSystem.IsWindows()) result = await WindowsUpdateAsync(cancellationToken); - if (OperatingSystem.IsLinux()) result = await LinuxUpdateAsync(cancellationToken); - - _logger.LogInformation("Update Result: {result}", result?.Success); - - if (result?.UpdateErrors is not null) - { - _logger.LogError("Update Errors: {errors}", string.Concat(result.UpdateErrors)); - } - } - catch (OperationCanceledException) { } - catch (Exception ex) // may inform via client / api about errors - { - _logger.LogError("{ex}", ex.Message); - } - finally - { - await Task.Delay(TimeSpan.FromMinutes(1), cancellationToken); - } + _httpClient = httpClient; + _uri = configuration.GetValue("api") ?? throw new Exception($"api value not set (appsettings)"); + _logger = logger; } - } - [SupportedOSPlatform("windows")] - private async ValueTask WindowsUpdateAsync(CancellationToken cancellationToken) - { - return await Windows.Service.UpdateAsync( - _httpClient, - Deploy.GetUpdateHref(_uri, Deploy.Agent.Name), - Deploy.GetAppExecutable(Deploy.Agent.Name), - Deploy.Agent.ServiceName, - cancellationToken); - } - - [SupportedOSPlatform("linux")] - private ValueTask LinuxUpdateAsync(CancellationToken cancellationToken) - { - throw new NotImplementedException(); - } - - [SupportedOSPlatform("windows")] - private static class Windows - { - public static class Service + protected override async Task ExecuteAsync(CancellationToken cancellationToken) { - private static bool ServiceExistence(string serviceName) + _logger.LogTrace("ExecuteAsync"); + + while (cancellationToken.IsCancellationRequested is false) { try { - if (ServiceController.GetServices().Any(s => s.ServiceName.Equals(serviceName, StringComparison.InvariantCultureIgnoreCase))) return true; + UpdateResult? result = null; + + if (OperatingSystem.IsWindows()) result = await WindowsUpdateAsync(cancellationToken); + if (OperatingSystem.IsLinux()) result = await LinuxUpdateAsync(cancellationToken); + + _logger.LogInformation("Update Result: {result}", result?.Success); + if (result?.UpdateErrors is not null) + { + _logger.LogError("Update Errors: {errors}", string.Concat(result?.UpdateErrors)); + } + } + catch (OperationCanceledException) { } + catch (Exception ex) // may inform via client / api about errors + { + _logger.LogError("{ex}", ex.Message); + } + finally + { + await Task.Delay(TimeSpan.FromMinutes(1), cancellationToken); + } + } + } + + [SupportedOSPlatform("windows")] + private async ValueTask WindowsUpdateAsync(CancellationToken cancellationToken) + { + return await Windows.Service.UpdateAsync( + _httpClient, + Deploy.GetUpdateHref(_uri, Deploy.Agent.Name), + Deploy.GetAppExecutable(Deploy.Agent.Name), + Deploy.Agent.ServiceName, + cancellationToken); + } + + [SupportedOSPlatform("linux")] + private ValueTask LinuxUpdateAsync(CancellationToken cancellationToken) + { + throw new NotImplementedException(); + } + + [SupportedOSPlatform("windows")] + private static class Windows + { + public static class Service + { + private static bool ServiceExistence(string serviceName) + { + try + { + if (ServiceController.GetServices().Any(s => s.ServiceName.Equals(serviceName, StringComparison.InvariantCultureIgnoreCase))) return true; + return false; + } + catch (Exception) { } + return false; } - catch (Exception) { } - return false; - } - - private static bool SetServiceState(string app, ServiceControllerStatus status, TimeSpan timeout) - { - try + private static bool SetServiceState(string app, ServiceControllerStatus status, TimeSpan timeout) { - using var sc = ServiceController.GetServices().FirstOrDefault(s => s.ServiceName.Equals(app, StringComparison.InvariantCultureIgnoreCase)); - if (sc is null) return false; - - if (sc.Status != status) + try { - switch (status) - { - case ServiceControllerStatus.Running: - sc.Start(); - break; + using var sc = ServiceController.GetServices().FirstOrDefault(s => s.ServiceName.Equals(app, StringComparison.InvariantCultureIgnoreCase)); + if (sc is null) return false; - case ServiceControllerStatus.Stopped: - sc.Stop(); - break; + if (sc.Status != status) + { + switch (status) + { + case ServiceControllerStatus.Running: + sc.Start(); + break; + + case ServiceControllerStatus.Stopped: + sc.Stop(); + break; + } + + sc.WaitForStatus(status, timeout); } - sc.WaitForStatus(status, timeout); + return true; } + catch (Exception) { } - return true; + return false; } - catch (Exception) { } - return false; - } - - public static async ValueTask UpdateAsync(HttpClient httpClient, Uri api, FileInfo bin, string serviceName, CancellationToken cancellationToken) - { - var result = new UpdateResult + public static async ValueTask UpdateAsync(HttpClient httpClient, Uri api, FileInfo bin, string serviceName, CancellationToken cancellationToken) { - Api = api?.ToString(), - SourceDirectory = bin.Directory?.FullName, - App = bin.Name, - ServiceName = serviceName - }; - - try - { - // check if service exists - if (ServiceExistence(serviceName) is false) + var result = new UpdateResult { - result.UpdateErrors.Add("service not found"); - return result; - } + Api = api?.ToString(), + SourceDirectory = bin.Directory?.FullName, + App = bin.Name, + ServiceName = serviceName + }; - // get service update details - var response = await httpClient.GetFromJsonAsync(api, cancellationToken); - if (response is null) + try { - result.ApiErrors.Add("not available / response null"); - return result; - } + // check if service exists + if (ServiceExistence(serviceName) is false) + { + result.UpdateErrors.Add("service not found"); + return result; + } - result.ApiAvailable = true; + // get service update details + var response = await httpClient.GetFromJsonAsync(api, cancellationToken); + if (response is null) + { + result.ApiErrors.Add("not available / response null"); + return result; + } - // check if local binary exists - if (bin is null) - { - result.UpdateErrors.Add("source binary not found"); - return result; - } + result.ApiAvailable = true; - // get local file binary version - if (FileVersionInfo.GetVersionInfo(bin.FullName).FileVersion is not string binVersionString) - { - result.UpdateErrors.Add("source binary fileversion not valid"); - return result; - } + // check if local binary exists + if (bin is null) + { + result.UpdateErrors.Add("source binary not found"); + return result; + } + + // get local file binary version + if (FileVersionInfo.GetVersionInfo(bin.FullName).FileVersion is not string binVersionString) + { + result.UpdateErrors.Add("source binary fileversion not valid"); + return result; + } + + // compare local against update version, skip lower or equal update version + var actualVersion = Version.Parse(binVersionString); + if (actualVersion >= response.Version) + { + result.Success = true; + return result; + } + else + { + result.UpdateAvailable = true; + } + + // get update file (bytes) to memory + using var update = await httpClient.GetAsync(response.Uri, cancellationToken); + if (update is null) + { + result.ApiErrors.Add("update source not available"); + return result; + } + + // stop service + if (SetServiceState(serviceName, ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(10)) is false) + { + result.UpdateErrors.Add("service control failed / failed to stop service"); + return result; + } + + // read update archive to temp (overwrite) + var temp = Directory.CreateTempSubdirectory(); + var updateFile = new FileInfo($@"{temp.FullName}/{bin.Name}.zip"); + + await File.WriteAllBytesAsync(updateFile.FullName, await update.Content.ReadAsByteArrayAsync(cancellationToken), cancellationToken); + + // extract update archive from temp to app dir (overwrite) + ZipFile.ExtractToDirectory(updateFile.FullName, bin.Directory?.FullName, true); + + // delete temp folder + if (temp.Exists) temp.Delete(true); + + // start updateds service + if (SetServiceState(serviceName, ServiceControllerStatus.Running, TimeSpan.FromSeconds(10)) is false) + { + result.UpdateErrors.Add("service control failed / failed to start service"); + return result; + } - // compare local against update version, skip lower or equal update version - var actualVersion = Version.Parse(binVersionString); - if (actualVersion >= response.Version) - { result.Success = true; - return result; } - else + catch (Exception ex) { - result.UpdateAvailable = true; + result.UpdateErrors.Add(ex.Message); } - // get update file (bytes) to memory - using var update = await httpClient.GetAsync(response.Uri, cancellationToken); - if (update is null) - { - result.ApiErrors.Add("update source not available"); - return result; - } - - // stop service - if (SetServiceState(serviceName, ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(10)) is false) - { - result.UpdateErrors.Add("service control failed / failed to stop service"); - return result; - } - - // read update archive to temp (overwrite) - var temp = Directory.CreateTempSubdirectory(); - var updateFile = new FileInfo($@"{temp.FullName}/{bin.Name}.zip"); - - await File.WriteAllBytesAsync(updateFile.FullName, await update.Content.ReadAsByteArrayAsync(cancellationToken), cancellationToken); - - // extract update archive from temp to app dir (overwrite) - ZipFile.ExtractToDirectory(updateFile.FullName, bin.Directory!.FullName, true); - - // delete temp folder - if (temp.Exists) temp.Delete(true); - - // start updateds service - if (SetServiceState(serviceName, ServiceControllerStatus.Running, TimeSpan.FromSeconds(10)) is false) - { - result.UpdateErrors.Add("service control failed / failed to start service"); - return result; - } - - result.Success = true; + return result; } - catch (Exception ex) - { - result.UpdateErrors.Add(ex.Message); - } - - return result; - } - } - - public static class Process - { - public static bool IsRunning(FileInfo bin) - { - if (bin.Exists is false) return false; - - var matched = System.Diagnostics.Process.GetProcessesByName(bin.FullName); - - if (matched is null || matched.Length == 0) return false; - - if (matched.Any(p => - p.MainModule is not null && - p.MainModule.FileName is not null && - p.MainModule.FileName.Equals(bin.FullName, - StringComparison.InvariantCultureIgnoreCase))) return true; - - return false; } - public static bool Start(FileInfo binary) + public static class Process { - try + public static bool IsRunning(FileInfo bin) { - if (IsRunning(binary) is false) return false; - - using var process = System.Diagnostics.Process.Start(binary.FullName); - return true; - } - catch (Exception) { } - - return false; - } - - public static bool Stop(FileInfo bin, TimeSpan timeout) - { - try - { - if (IsRunning(bin) is false) return false; + if (bin.Exists is false) return false; var matched = System.Diagnostics.Process.GetProcessesByName(bin.FullName); - if (matched is null || matched.Length == 0) return true; + if (matched is null || matched.Any() is false) return false; - foreach (var procsInfo in matched.Where(p => + if (matched.Any(p => p.MainModule is not null && p.MainModule.FileName is not null && - p.MainModule.FileName.Equals(bin.FullName, StringComparison.InvariantCultureIgnoreCase))) + p.MainModule.FileName.Equals(bin.FullName, + StringComparison.InvariantCultureIgnoreCase))) return true; + + return false; + } + + public static bool Start(FileInfo binary) + { + try { - if (procsInfo.CloseMainWindow()) procsInfo.WaitForExit((int)timeout.TotalMilliseconds); - if (procsInfo.HasExited is false) procsInfo.Kill(true); + if (IsRunning(binary) is false) return false; + + using var process = System.Diagnostics.Process.Start(binary.FullName); + return true; } + catch (Exception) { } - return true; + return false; } - catch (Exception) { } - return false; - } - - public static async ValueTask UpdateAsync(HttpClient httpClient, Uri api, FileInfo bin, CancellationToken cancellationToken) - { - if (IsRunning(bin) is false) return false; - - var response = await httpClient.GetFromJsonAsync(api.AbsoluteUri, new JsonSerializerOptions + public static bool Stop(FileInfo bin, TimeSpan timeout) { - IncludeFields = true - }, cancellationToken); + try + { + if (IsRunning(bin) is false) return false; - if (response is null) return false; + var matched = System.Diagnostics.Process.GetProcessesByName(bin.FullName); - Version actualVersion; + if (matched is null || matched.Any() is false) return true; - if (FileVersionInfo.GetVersionInfo(bin.FullName).FileVersion is not string binVersionString) return false; + foreach (var procsInfo in matched.Where(p => + p.MainModule is not null && + p.MainModule.FileName is not null && + p.MainModule.FileName.Equals(bin.FullName, StringComparison.InvariantCultureIgnoreCase))) + { + if (procsInfo.CloseMainWindow()) procsInfo.WaitForExit((int)timeout.TotalMilliseconds); + if (procsInfo.HasExited is false) procsInfo.Kill(true); + } - try - { - actualVersion = Version.Parse(binVersionString); - if (actualVersion >= response.Version) return false; + return true; + } + catch (Exception) { } - using var update = await httpClient.GetAsync(response.Uri, cancellationToken); - if (update is null) return false; - - Stop(bin, TimeSpan.FromSeconds(60)); - - // read update archive to temp (overwrite) - var temp = Directory.CreateTempSubdirectory(); - var updateFile = new FileInfo($@"{temp.FullName}/{bin.Name}.zip"); - - await File.WriteAllBytesAsync(updateFile.FullName, await update.Content.ReadAsByteArrayAsync(cancellationToken), cancellationToken); - - // extract update archive from temp to app dir (overwrite) - ZipFile.ExtractToDirectory(updateFile.FullName, bin.Directory!.FullName, true); - - // delete temp folder - if (temp.Exists) temp.Delete(true); - - // rewrite with options to start user session process - //Start(app, directory, TimeSpan.FromSeconds(60)); - - return true; + return false; } - catch (Exception) { } - return false; - } - - public static bool Delete(FileInfo bin, TimeSpan timeout) - { - try + public static async ValueTask UpdateAsync(HttpClient httpClient, Uri api, FileInfo bin, CancellationToken cancellationToken) { - Stop(bin, timeout); - bin.Delete(); + if (IsRunning(bin) is false) return false; - return true; + var response = await httpClient.GetFromJsonAsync(api.AbsoluteUri, new JsonSerializerOptions + { + IncludeFields = true + }, cancellationToken); + + if (response is null) return false; + + Version actualVersion; + + if (FileVersionInfo.GetVersionInfo(bin.FullName).FileVersion is not string binVersionString) return false; + + try + { + actualVersion = Version.Parse(binVersionString); + if (actualVersion >= response.Version) return false; + + using var update = await httpClient.GetAsync(response.Uri, cancellationToken); + if (update is null) return false; + + Stop(bin, TimeSpan.FromSeconds(60)); + + // read update archive to temp (overwrite) + var temp = Directory.CreateTempSubdirectory(); + var updateFile = new FileInfo($@"{temp.FullName}/{bin.Name}.zip"); + + await File.WriteAllBytesAsync(updateFile.FullName, await update.Content.ReadAsByteArrayAsync(cancellationToken), cancellationToken); + + // extract update archive from temp to app dir (overwrite) + ZipFile.ExtractToDirectory(updateFile.FullName, bin.Directory?.FullName, true); + + // delete temp folder + if (temp.Exists) temp.Delete(true); + + // rewrite with options to start user session process + //Start(app, directory, TimeSpan.FromSeconds(60)); + + return true; + } + catch (Exception) { } + + return false; } - catch (Exception) { } - return false; + public static bool Delete(FileInfo bin, TimeSpan timeout) + { + try + { + Stop(bin, timeout); + bin.Delete(); + + return true; + } + catch (Exception) { } + + return false; + } } } - } - public class UpdateResult - { - public string? Api { get; set; } - public string? SourceDirectory { get; set; } - public string? App { get; set; } - public string? ServiceName { get; set; } + public class UpdateResult + { + public string? Api { get; set; } + public string? SourceDirectory { get; set; } + public string? App { get; set; } + public string? ServiceName { get; set; } - public bool ApiAvailable { get; set; } = false; - public bool UpdateAvailable { get; set; } = false; - public bool Success { get; set; } = false; - public List ApiErrors { get; } = []; - public List UpdateErrors { get; } = []; + public bool ApiAvailable { get; set; } = false; + public bool UpdateAvailable { get; set; } = false; + public bool Success { get; set; } = false; + public List ApiErrors { get; } = new(); + public List UpdateErrors { get; } = new(); + } } } \ No newline at end of file diff --git a/src/Web/Insight.Web.Assets/Insight.Web.Assets.csproj b/src/Web/Insight.Web.Assets/Insight.Web.Assets.csproj new file mode 100644 index 0000000..4fecff5 --- /dev/null +++ b/src/Web/Insight.Web.Assets/Insight.Web.Assets.csproj @@ -0,0 +1,21 @@ + + + + net7.0 + true + enable + Insight.Web.Assets + Insight.Web + Insight + 2025.2.24.0 + 2025.2.24.0 + none + true + + + + + + + + diff --git a/src/Web/Insight.Web.Assets/Interfaces/IWebMessageHandler.cs b/src/Web/Insight.Web.Assets/Interfaces/IWebMessageHandler.cs new file mode 100644 index 0000000..2609347 --- /dev/null +++ b/src/Web/Insight.Web.Assets/Interfaces/IWebMessageHandler.cs @@ -0,0 +1,9 @@ +using Insight.Web.Messages; + +namespace Insight.Web.Interfaces +{ + public partial interface IWebMessageHandler + { + ValueTask HandleAsync(TSender sender, TMessage message, CancellationToken cancellationToken) where TMessage : IWebMessage; + } +} \ No newline at end of file diff --git a/src/Web/Insight.Web.Assets/Messages/Host/ConsoleProxy.cs b/src/Web/Insight.Web.Assets/Messages/Host/ConsoleProxy.cs new file mode 100644 index 0000000..0a5783f --- /dev/null +++ b/src/Web/Insight.Web.Assets/Messages/Host/ConsoleProxy.cs @@ -0,0 +1,43 @@ +using MemoryPack; + +namespace Insight.Web.Messages +{ + [MemoryPackUnion(1, typeof(ConsoleQueryProxy))] + [MemoryPackUnion(2, typeof(ConsoleQueryProxyRequest))] + public partial interface IWebMessage { } + + [MemoryPackable] + public partial class ConsoleQueryProxy : IWebMessage + { + [MemoryPackOrder(0)] + public string? Id { get; set; } + + [MemoryPackOrder(1)] + public string? HostId { get; set; } + + [MemoryPackOrder(2)] + public string? Query { get; set; } + + [MemoryPackOrder(3)] + public string? Data { get; set; } + + [MemoryPackOrder(4)] + public string? Errors { get; set; } + + [MemoryPackOrder(7)] + public bool HadErrors { get; set; } + } + + [MemoryPackable] + public partial class ConsoleQueryProxyRequest : IWebMessage + { + [MemoryPackOrder(0)] + public string? Id { get; set; } + + [MemoryPackOrder(1)] + public string? HostId { get; set; } + + [MemoryPackOrder(2)] + public string? Query { get; set; } + } +} \ No newline at end of file diff --git a/src/Web/Insight.Web.Assets/Messages/IWebMessage.cs b/src/Web/Insight.Web.Assets/Messages/IWebMessage.cs new file mode 100644 index 0000000..6ac0a66 --- /dev/null +++ b/src/Web/Insight.Web.Assets/Messages/IWebMessage.cs @@ -0,0 +1,7 @@ +using MemoryPack; + +namespace Insight.Web.Messages +{ + [MemoryPackable] + public partial interface IWebMessage { } +} \ No newline at end of file diff --git a/src/Web/Insight.Web/Components/Cards/InfoCard.razor b/src/Web/Insight.Web/Components/Cards/InfoCard.razor index 9b0c1d9..207c6c9 100644 --- a/src/Web/Insight.Web/Components/Cards/InfoCard.razor +++ b/src/Web/Insight.Web/Components/Cards/InfoCard.razor @@ -1,7 +1,4 @@ -@inherits ComponentBase -@implements IDisposable - - + @@ -24,35 +21,27 @@ @code { - [Parameter] public string? Href { get; set; } - [Parameter] public EventCallback OnClick { get; set; } - [Parameter] public string? Icon { get; set; } - [Parameter] public Color? IconColor { get; set; } - [Parameter] public string? Key { get; set; } - [Parameter] public Color? KeyColor { get; set; } - [Parameter] public string? Text { get; set; } - [Parameter] public int Lines { get; set; } = 1; + [Parameter] + public string? Href { get; set; } - private bool _disposed; + [Parameter] + public EventCallback OnClick { get; set; } - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } + [Parameter] + public string? Icon { get; set; } - private void Dispose(bool disposing) - { - if (_disposed is false) return; - if (disposing is false) return; + [Parameter] + public Color? IconColor { get; set; } - try - { + [Parameter] + public string? Key { get; set; } - } - finally - { - _disposed = true; - } - } + [Parameter] + public Color? KeyColor { get; set; } + + [Parameter] + public string? Text { get; set; } + + [Parameter] + public int Lines { get; set; } = 1; } \ No newline at end of file diff --git a/src/Web/Insight.Web/Components/Cards/KeyValueCard.razor b/src/Web/Insight.Web/Components/Cards/KeyValueCard.razor index 70e4120..01a4527 100644 --- a/src/Web/Insight.Web/Components/Cards/KeyValueCard.razor +++ b/src/Web/Insight.Web/Components/Cards/KeyValueCard.razor @@ -1,8 +1,5 @@ @typeparam T -@inherits ComponentBase -@implements IDisposable - @@ -34,35 +31,27 @@ @code{ - [Parameter] public string? Href { get; set; } - [Parameter] public EventCallback OnClick { get; set; } - [Parameter] public string? Icon { get; set; } - [Parameter] public Color? IconColor { get; set; } - [Parameter] public string? Key { get; set; } - [Parameter] public Color? KeyColor { get; set; } - [Parameter] public T? Value { get; set; } - [Parameter] public Color? ValueColor { get; set; } + [Parameter] + public string? Href { get; set; } - private bool _disposed; + [Parameter] + public EventCallback OnClick { get; set; } - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } + [Parameter] + public string? Icon { get; set; } - private void Dispose(bool disposing) - { - if (_disposed is false) return; - if (disposing is false) return; + [Parameter] + public Color? IconColor { get; set; } - try - { + [Parameter] + public string? Key { get; set; } - } - finally - { - _disposed = true; - } - } + [Parameter] + public Color? KeyColor { get; set; } + + [Parameter] + public T? Value { get; set; } + + [Parameter] + public Color? ValueColor { get; set; } } \ No newline at end of file diff --git a/src/Web/Insight.Web/Components/Containers/BaseContainer.razor b/src/Web/Insight.Web/Components/Containers/BaseContainer.razor index eb4a679..5d504ad 100644 --- a/src/Web/Insight.Web/Components/Containers/BaseContainer.razor +++ b/src/Web/Insight.Web/Components/Containers/BaseContainer.razor @@ -1,11 +1,28 @@ -@inherits ComponentBase -@implements IDisposable +@Title -@Title +@*@if (Loading) +{ + -
-
+
+ +
+ + return; +}*@ + +
+
+@* + + + + @item.Text + + + + *@ @@ -26,75 +43,9 @@
-
+
@if (Content is not null) { @Content } -
- -@code{ - [Parameter] public string Title { get; set; } = Global.Name; - [Parameter] public List? Breadcrumbs { get; set; } - [Parameter] public RenderFragment? BreadcrumbAction { get; set; } - [Parameter] public RenderFragment? Content { get; set; } - [Parameter] public Func? LoadData { get; set; } - [Parameter] public bool DisableReload { get; set; } - - private bool _disposed; - - private bool _loading; - private bool Loading - { - get => _loading; - set - { - if (value != _loading) - { - _loading = value; - StateHasChanged(); - } - } - } - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (firstRender) await OnRefreshAsync(); - } - - private async Task OnRefreshAsync() - { - if (LoadData is null || Loading) return; - - try - { - Loading = true; - await LoadData(); - } - finally - { - Loading = false; - } - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private void Dispose(bool disposing) - { - if (_disposed is false) return; - if (disposing is false) return; - - try - { - - } - finally - { - _disposed = true; - } - } -} \ No newline at end of file +
\ No newline at end of file diff --git a/src/Web/Insight.Web/Components/Containers/BaseContainer.razor.cs b/src/Web/Insight.Web/Components/Containers/BaseContainer.razor.cs new file mode 100644 index 0000000..8f5ab44 --- /dev/null +++ b/src/Web/Insight.Web/Components/Containers/BaseContainer.razor.cs @@ -0,0 +1,74 @@ +using Insight.Web.Constants; +using Microsoft.AspNetCore.Components; +using MudBlazor; + +namespace Insight.Web.Components.Containers; + +public partial class BaseContainer +{ + [Parameter] + public string Title { get; set; } = Global.Name; + + [Parameter] + public List? Breadcrumbs { get; set; } + + [Parameter] + public RenderFragment? BreadcrumbAction { get; set; } + + [Parameter] + public RenderFragment? Content { get; set; } + + [Parameter] + public Func? LoadData { get; set; } + + [Parameter] + public bool DisableReload { get; set; } + + + private bool _loading; + private bool Loading + { + get + { + return _loading; + } + set + { + if (value != _loading) + { + _loading = value; + StateHasChanged(); + } + } + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + await OnRefreshAsync(); + } + } + + private async Task OnRefreshAsync() + { + if (LoadData is null || Loading) return; + + Loading = true; + StateHasChanged(); + + //var start = Stopwatch.GetTimestamp(); + + await LoadData(); + + //var time = Stopwatch.GetElapsedTime(start); + + //if (time <= TimeSpan.FromSeconds(1)) + //{ + // await Task.Delay(TimeSpan.FromSeconds(1).Subtract(time)); + //} + + Loading = false; + StateHasChanged(); + } +} \ No newline at end of file diff --git a/src/Web/Insight.Web/Components/Containers/TableContainer.razor b/src/Web/Insight.Web/Components/Containers/TableContainer.razor index faed0f2..a7d06ff 100644 --- a/src/Web/Insight.Web/Components/Containers/TableContainer.razor +++ b/src/Web/Insight.Web/Components/Containers/TableContainer.razor @@ -1,24 +1,17 @@ -@using Insight.Web.Extensions - -@typeparam T - -@inherits ComponentBase -@implements IDisposable - -@inject NavigationManager NavigationManager +@typeparam T @Title -
+
@if (OnAdd.HasDelegate) { - @if (_optionalBreadcrumbs is not null) + @if (AddBreadcrumbs is not null) { - + } @@ -32,7 +25,7 @@
- + @if (Header is not null) { @@ -43,7 +36,7 @@ Filter - + Refresh @@ -70,137 +63,4 @@ - - -@code{ - [Parameter] public string Title { get; set; } = Global.Name; - [Parameter] public List? Breadcrumbs { get; set; } - [Parameter] public Func>>? Data { get; set; } - [Parameter] public RenderFragment? Header { get; set; } - [Parameter] public RenderFragment? RowTemplate { get; set; } - [Parameter] public RenderFragment? ActionTemplate { get; set; } - [Parameter] public bool DisableAction { get; set; } - [Parameter] public bool DisableRefresh { get; set; } - [Parameter] public string? Search - { - get => _search; - set - { - if (_search == value) return; - _search = value; - - SearchChanged.InvokeAsync(value); - } - } - [Parameter] public bool Filtered { get; set; } - [Parameter] public EventCallback SearchChanged { get; set; } - [Parameter] public EventCallback OnFilter { get; set; } - [Parameter] public EventCallback OnAdd { get; set; } - - private List? _optionalBreadcrumbs; - private MudTable? _table; - private string? _search; - private bool _loading; - private bool _disposed; - - private bool Loading - { - get => _loading; - set - { - if (value != _loading) - { - _loading = value; - StateHasChanged(); - } - } - } - - protected override void OnInitialized() - { - if (OnAdd.HasDelegate) - { - _optionalBreadcrumbs = new List() - { - new("", "#", true), - new("", "#", true) - }; - } - - if (NavigationManager.GetQueryString().TryGetValue("search", out var search)) - { - Search = search.ToString(); - } - } - - private async Task> OnLoadDataAsync(TableState state) - { - if (Data is null) throw new MissingMethodException(nameof(Data)); - - try - { - Loading = true; - return await Data(state); - } - finally - { - Loading = false; - } - } - - public async Task RefreshAsync() - { - if (Loading || _table is null) return; - - try - { - Loading = true; - await _table.ReloadServerData(); - } - finally - { - Loading = false; - } - } - - private async Task SearchAsync(string? text) - { - Search = text; - - if (Loading) return; - await RefreshAsync(); - } - - private void OnSearchReleased() => NavigationManager.ChangeQueryStringValue("search", Search); - - private async Task OnFilterClick() - { - if (OnFilter.HasDelegate) await OnFilter.InvokeAsync(this); - } - - private async Task OnAddClick() - { - if (OnAdd.HasDelegate) await OnAdd.InvokeAsync(this); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private void Dispose(bool disposing) - { - if (_disposed is false) return; - if (disposing is false) return; - - try - { - - } - finally - { - _disposed = true; - } - } -} \ No newline at end of file + \ No newline at end of file diff --git a/src/Web/Insight.Web/Components/Containers/TableContainer.razor.cs b/src/Web/Insight.Web/Components/Containers/TableContainer.razor.cs new file mode 100644 index 0000000..bf75e8f --- /dev/null +++ b/src/Web/Insight.Web/Components/Containers/TableContainer.razor.cs @@ -0,0 +1,194 @@ +using Insight.Web.Constants; +using Insight.Web.Extensions; +using Microsoft.AspNetCore.Components; +using MudBlazor; + +namespace Insight.Web.Components.Containers; + +public partial class TableContainer +{ + [Inject] private NavigationManager NavigationManager { get; init; } = default!; + + + [Parameter] + public string Title { get; set; } = Global.Name; + + [Parameter] + public List? Breadcrumbs { get; set; } + + [Parameter] + public Func>>? Data { get; set; } + + [Parameter] + public RenderFragment? Header { get; set; } + + [Parameter] + public RenderFragment? RowTemplate { get; set; } + + [Parameter] + public RenderFragment? ActionTemplate { get; set; } + + [Parameter] + public bool DisableAction { get; set; } + + + private List? AddBreadcrumbs { get; set; } + private MudTable? Table { get; set; } + private bool Loading { get; set; } + + private int CurrentPage { get; set; } + private int CurrentSize { get; set; } + + protected override void OnInitialized() + { + if (OnAdd.HasDelegate) + { + AddBreadcrumbs = new List() + { + new BreadcrumbItem("", "#", true), + new BreadcrumbItem("", "#", true) + }; + } + + if (NavigationManager.GetQueryString().TryGetValue("search", out var search)) + { + Search = search.ToString(); + } + + //if (NavigationManager.GetQueryString().TryGetValue("page", out var pageRaw)) + //{ + // if (int.TryParse(pageRaw, out var page)) + // { + // CurrentPage = page; + // } + //} + + //if (NavigationManager.GetQueryString().TryGetValue("size", out var sizeRaw)) + //{ + // if (int.TryParse(sizeRaw, out var size)) + // { + // CurrentSize = size == 0 ? 100 : size; + // } + //} + } + + private async Task> OnLoadDataAsync(TableState state) + { + if (Data is null) + { + throw new MissingMethodException(nameof(Data)); + } + + try + { + Loading = true; + + //state.Page = CurrentPage; + //Table.SetRowsPerPage(CurrentSize); + + var data = await Data(state); + + //CurrentPage = state.Page; + //CurrentSize = state.PageSize; + + //NavigationManager.ChangeQueryStringValue("page", state.Page.ToString()); + //NavigationManager.ChangeQueryStringValue("size", state.PageSize.ToString()); + + //if (state.SortLabel is not null) NavigationManager.ChangeQueryStringValue("sort", state.SortLabel.ToString()); + //if (state.SortDirection) NavigationManager.ChangeQueryStringValue("direction", state.SortDirection.ToString()); + + return data; + } + finally + { + Loading = false; + } + } + + // + + [Parameter] + public bool DisableRefresh { get; set; } + + private string? _search; + + [Parameter] + public string? Search + { + get => _search; + set + { + if (_search == value) return; + _search = value; + + SearchChanged.InvokeAsync(value); + } + } + + [Parameter] + public EventCallback SearchChanged { get; set; } + + private async Task SearchAsync(string? text) + { + Search = text; + + if (Loading) return; + await RefreshAsync(); + } + + public async Task RefreshAsync() + { + if (Loading || Table is null) return; + + Loading = true; + StateHasChanged(); + + //var start = Stopwatch.GetTimestamp(); + + await Table.ReloadServerData(); + + //var time = Stopwatch.GetElapsedTime(start); + + //if (time <= TimeSpan.FromSeconds(1)) + //{ + // await Task.Delay(TimeSpan.FromSeconds(1).Subtract(time)); + //} + + Loading = false; + StateHasChanged(); + } + + private void OnSearchReleased() + { + NavigationManager.ChangeQueryStringValue("search", Search); + } + + // + + [Parameter] public EventCallback OnFilter { get; set; } + + + [Parameter] + public bool Filtered { get; set; } + + private async Task OnFilterClick() + { + if (OnFilter.HasDelegate) + { + await OnFilter.InvokeAsync(this); + } + } + + // + + [Parameter] + public EventCallback OnAdd { get; set; } + + private async Task OnAddClick() + { + if (OnAdd.HasDelegate) + { + await OnAdd.InvokeAsync(this); + } + } +} \ No newline at end of file diff --git a/src/Web/Insight.Web/Components/Dialogs/ActionDialog.razor b/src/Web/Insight.Web/Components/Dialogs/ActionDialog.razor index 773d039..660fea5 100644 --- a/src/Web/Insight.Web/Components/Dialogs/ActionDialog.razor +++ b/src/Web/Insight.Web/Components/Dialogs/ActionDialog.razor @@ -1,7 +1,4 @@ -@inherits ComponentBase -@implements IDisposable - -@if (@Actions is not null) +@if (@Actions is not null) { @@ -18,59 +15,11 @@ } else { - + @Content -} - -@code{ - [CascadingParameter] public MudDialogInstance MudDialog { get; set; } = default!; - - [Parameter] public bool Visible - { - get => _visible; - set - { - if (_visible == value) return; - _visible = value; - - VisibleChanged.InvokeAsync(value); - } - } - [Parameter] public EventCallback VisibleChanged { get; set; } - [Parameter] public RenderFragment? Content { get; set; } - [Parameter] public RenderFragment? Actions { get; set; } - - private bool _visible; - private bool _disposed; - - protected override void OnAfterRender(bool firstRender) - { - if (firstRender is false) return; - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private void Dispose(bool disposing) - { - if (_disposed is false) return; - if (disposing is false) return; - - try - { - - } - finally - { - _disposed = true; - } - } } \ No newline at end of file diff --git a/src/Web/Insight.Web/Components/Dialogs/ActionDialog.razor.cs b/src/Web/Insight.Web/Components/Dialogs/ActionDialog.razor.cs new file mode 100644 index 0000000..f4734ab --- /dev/null +++ b/src/Web/Insight.Web/Components/Dialogs/ActionDialog.razor.cs @@ -0,0 +1,30 @@ +using Microsoft.AspNetCore.Components; + +namespace Insight.Web.Components.Dialogs; + +public partial class ActionDialog +{ + private bool _visible; + + [Parameter] + public bool Visible + { + get => _visible; + set + { + if (_visible == value) return; + _visible = value; + + VisibleChanged.InvokeAsync(value); + } + } + + [Parameter] + public EventCallback VisibleChanged { get; set; } + + [Parameter] + public RenderFragment? Content { get; set; } + + [Parameter] + public RenderFragment? Actions { get; set; } +} \ No newline at end of file diff --git a/src/Web/Insight.Web/Components/Dialogs/ChatDialog.razor b/src/Web/Insight.Web/Components/Dialogs/ChatDialog.razor index f8a0d44..5aeab56 100644 --- a/src/Web/Insight.Web/Components/Dialogs/ChatDialog.razor +++ b/src/Web/Insight.Web/Components/Dialogs/ChatDialog.razor @@ -11,6 +11,11 @@ + @* + # + contacts + *@ + @foreach (var user in ChatService.Users.Keys.Where(p => p.Uid != SessionHandler.State.Uid).OrderByDescending(p => p.Online)) @@ -85,31 +90,28 @@ { var sender = ChatService.Users.Keys.FirstOrDefault(p => p.Uid == message.SenderId); - @if (sender is not null) - { - -
-
- - - @sender?.Username?.ToUpper().FirstOrDefault() - - -
-
- - @sender?.Username - - - @message.CreatedDate.ToString("dd MMM yyyy - hh:mm tt") - - - @message.Message - -
+ +
+
+ + + @sender?.Username?.ToUpper().FirstOrDefault() + +
- - } +
+ + @sender?.Username + + + @message.CreatedDate.ToString("dd MMM yyyy - hh:mm tt") + + + @message.Message + +
+
+
} } diff --git a/src/Web/Insight.Web/Components/Dialogs/ChatDialog.razor.cs b/src/Web/Insight.Web/Components/Dialogs/ChatDialog.razor.cs index 498e740..b05c974 100644 --- a/src/Web/Insight.Web/Components/Dialogs/ChatDialog.razor.cs +++ b/src/Web/Insight.Web/Components/Dialogs/ChatDialog.razor.cs @@ -8,14 +8,14 @@ using Microsoft.AspNetCore.SignalR.Client; using Microsoft.JSInterop; using MongoDB.Driver; using MudBlazor; -using Vaitr.Bus; +using Vaitr.MemoryBus; using static Insight.Web.Constants.Events.Chat; namespace Insight.Web.Components.Dialogs; -public partial class ChatDialog : IDisposable +public partial class ChatDialog { - [Inject] private Bus Bus { get; init; } = default!; + [Inject] private IMemoryBus Bus { get; init; } = default!; [Inject] private ChatService ChatService { get; init; } = default!; [Inject] private SessionPool SessionCache { get; init; } = default!; [Inject] private SessionHandler SessionHandler { get; init; } = default!; @@ -45,21 +45,19 @@ public partial class ChatDialog : IDisposable private enum Content { Contacts, Chat } private Content _content = Content.Contacts; + private ChatUser? _currentUser; private ChatSession? _currentSession; private string? _currentMessage; - private bool _disposed; - private readonly List _subscriptions = []; + private readonly List _subscriptions = new(); - protected override Task OnInitializedAsync() + protected override async Task OnInitializedAsync() { _subscriptions.Add(Bus.SubscribeAsync(UserConnected, p => p.User.Uid != SessionHandler.State.Uid)); _subscriptions.Add(Bus.SubscribeAsync(UserDisconnected, p => p.User.Uid != SessionHandler.State.Uid)); _subscriptions.Add(Bus.SubscribeAsync(RefreshAsync, null)); _subscriptions.Add(Bus.SubscribeAsync(MessageReceived, p => p.Message.SenderId != SessionHandler.State.Uid)); - - return Task.CompletedTask; } protected override async Task OnAfterRenderAsync(bool firstRender) @@ -84,8 +82,6 @@ public partial class ChatDialog : IDisposable private async Task GetSessionAsync(ChatUser user) { - if (_currentUser is null) return; - var members = new List() { _currentUser, user }; var session = await ChatService.AddOrGetSession(members); @@ -97,7 +93,7 @@ public partial class ChatDialog : IDisposable private async Task SendAsync() { - if (_currentSession is null || _currentUser is null || string.IsNullOrWhiteSpace(_currentMessage)) return; + if (_currentSession is null || string.IsNullOrWhiteSpace(_currentMessage)) return; await _currentSession.SendMessage(_currentUser, _currentMessage, default); _currentMessage = string.Empty; @@ -122,11 +118,11 @@ public partial class ChatDialog : IDisposable options.VisibleStateDuration = 10000; }); - await JSRuntime.InvokeAsync("PlayAudio", "chat_user_online"); + _ = JSRuntime.InvokeAsync("PlayAudio", "chat_user_online"); } catch (Exception ex) { - Logger.LogError("{exception}", ex.Message); + Logger.LogError(ex.Message); } } @@ -145,17 +141,17 @@ public partial class ChatDialog : IDisposable options.VisibleStateDuration = 10000; }); - await JSRuntime.InvokeAsync("PlayAudio", "chat_user_online"); + _ = JSRuntime.InvokeAsync("PlayAudio", "chat_user_online"); } catch (Exception ex) { - Logger.LogError("{exception}", ex.Message); + Logger.LogError(ex.Message); } } private async ValueTask RefreshAsync(ChatRefresh model, CancellationToken cancellationToken) { - await InvokeAsync(StateHasChanged); + _ = InvokeAsync(StateHasChanged); } private async ValueTask MessageReceived(ChatMessageReceived model, CancellationToken cancellationToken) @@ -179,14 +175,14 @@ public partial class ChatDialog : IDisposable if (_content != Content.Chat) { - await JSRuntime.InvokeAsync("PlayAudio", "chat_message"); + _ = JSRuntime.InvokeAsync("PlayAudio", "chat_message"); } - await InvokeAsync(StateHasChanged); + _ = InvokeAsync(StateHasChanged); } catch (Exception ex) { - Logger.LogError("{exception}", ex.ToString()); + Logger.LogError(ex.ToString()); } } @@ -198,25 +194,4 @@ public partial class ChatDialog : IDisposable await InvokeAsync(StateHasChanged); } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private void Dispose(bool disposing) - { - if (_disposed is false) return; - if (disposing is false) return; - - try - { - - } - finally - { - _disposed = true; - } - } } \ No newline at end of file diff --git a/src/Web/Insight.Web/Components/Layouts/LoginLayout.razor b/src/Web/Insight.Web/Components/Layouts/LoginLayout.razor index 35f1c0b..4f71777 100644 --- a/src/Web/Insight.Web/Components/Layouts/LoginLayout.razor +++ b/src/Web/Insight.Web/Components/Layouts/LoginLayout.razor @@ -1,34 +1,8 @@ @inherits LayoutComponentBase -@implements IDisposable - + @Body - - -@code{ - private bool _disposed; - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private void Dispose(bool disposing) - { - if (_disposed is false) return; - if (disposing is false) return; - - try - { - - } - finally - { - _disposed = true; - } - } -} \ No newline at end of file + \ No newline at end of file diff --git a/src/Web/Insight.Web/Components/Layouts/MainLayout.razor b/src/Web/Insight.Web/Components/Layouts/MainLayout.razor index 2c42384..fa4a84f 100644 --- a/src/Web/Insight.Web/Components/Layouts/MainLayout.razor +++ b/src/Web/Insight.Web/Components/Layouts/MainLayout.razor @@ -1,19 +1,10 @@ -@using Vaitr.Bus; -@using Blazored.LocalStorage; -@using Microsoft.AspNetCore.Identity; -@using MongoDB.Driver; -@using Insight.Infrastructure +@using Vaitr.MemoryBus; @inherits LayoutComponentBase @implements IDisposable -@inject AuthenticationStateProvider AuthenticationStateProvider -@inject IServiceScopeFactory ServiceScopeFactory -@inject ILocalStorageService LocalStorageService -@inject IMongoDatabase Database -@inject Bus Bus +@inject IMemoryBus Bus - @@ -28,8 +19,8 @@ - + @@ -47,26 +38,18 @@ @code{ - public IReadOnlyDictionary? RouteValues { get; set; } + public IReadOnlyDictionary? RouteValues { get; set; } - private MudTheme _currentTheme = Themes.Default(); private DrawerProvider? _drawer; - private bool _darkMode; private bool _disposed; - + protected override void OnParametersSet() { - if (Body?.Target as RouteView is RouteView routeView) - RouteValues = routeView.RouteData.RouteValues; + RouteValues = (Body?.Target as RouteView)?.RouteData.RouteValues; base.OnParametersSet(); } - protected override async Task OnInitializedAsync() - { - await LoadDarkModeAsync(); - } - protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) @@ -77,89 +60,22 @@ await Bus.PublishAsync(Events.Layout.Rendered).ConfigureAwait(false); } - private async Task LoadDarkModeAsync() - { - // local storage - var storageDarkMode = await LocalStorageService.GetItemAsync("darkmode"); - if (storageDarkMode is bool darkmodeValue) _darkMode = darkmodeValue; - - // database override - var state = await AuthenticationStateProvider.GetAuthenticationStateAsync(); - - if (state?.User.Identity is not null && state.User.Identity.IsAuthenticated) - { - using var scope = ServiceScopeFactory.CreateScope(); - var userManager = scope.ServiceProvider.GetRequiredService>(); - - if (state.User.Identity?.Name is null) return; - - if (await userManager.FindByNameAsync(state.User.Identity.Name) is not InsightUser user) return; - - var userPrefs = await Database.UserPreference() - .Find(p => p.User == user.Id.ToString()) - .FirstOrDefaultAsync(); - - if (userPrefs is null) return; - - _darkMode = userPrefs.DarkMode; - - await LocalStorageService.SetItemAsync("darkmode", _darkMode); - } - } - - private async Task OnDarkModeToggleAsync() - { - // update current - _darkMode = !_darkMode; - - // update local storage - await LocalStorageService.SetItemAsync("darkmode", _darkMode); - - // update database - var state = await AuthenticationStateProvider.GetAuthenticationStateAsync(); - - if (state?.User.Identity is not null && state.User.Identity.IsAuthenticated) - { - using var scope = ServiceScopeFactory.CreateScope(); - var userManager = scope.ServiceProvider.GetRequiredService>(); - - if (state.User.Identity?.Name is null) return; - - if (await userManager.FindByNameAsync(state.User.Identity.Name) is not InsightUser user) return; - - var date = DateTime.Now; - - var userPrefs = await Database.UserPreference() - .UpdateOneAsync(p => p.User == user.Id.ToString(), Builders.Update - .SetOnInsert(p => p.User, user.Id.ToString()) - .SetOnInsert(p => p.Insert, date) - .Set(p => p.Update, date) - .Set(p => p.DarkMode, _darkMode), new UpdateOptions - { - IsUpsert = true - }); - } - - await InvokeAsync(StateHasChanged); - } - public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } - private void Dispose(bool disposing) + protected virtual void Dispose(bool disposing) { - if (_disposed is false) return; - if (disposing is false) return; - - try + // auto disposed when starved circuit timeouts (disconnects) + if (_disposed is false) { + if (disposing) + { + + } - } - finally - { _disposed = true; } } diff --git a/src/Web/Insight.Web/Components/Navbars/Account.razor b/src/Web/Insight.Web/Components/Navbars/Account.razor index 8180f02..088bc59 100644 --- a/src/Web/Insight.Web/Components/Navbars/Account.razor +++ b/src/Web/Insight.Web/Components/Navbars/Account.razor @@ -1,34 +1,7 @@ @inherits ComponentBase -@implements IDisposable Account -Profile - -@code{ - [CascadingParameter] public IReadOnlyDictionary? RouteValues { get; set; } - - private bool _disposed; - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private void Dispose(bool disposing) - { - if (_disposed || disposing is false) return; - - try - { - - } - finally - { - _disposed = true; - } - } -} \ No newline at end of file +Profile \ No newline at end of file diff --git a/src/Web/Insight.Web/Components/Navbars/Account.razor.cs b/src/Web/Insight.Web/Components/Navbars/Account.razor.cs new file mode 100644 index 0000000..0a34573 --- /dev/null +++ b/src/Web/Insight.Web/Components/Navbars/Account.razor.cs @@ -0,0 +1,28 @@ +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Authorization; + +namespace Insight.Web.Components.Navbars; + +public partial class Account +{ + [CascadingParameter] public IReadOnlyDictionary? RouteValues { get; set; } + + [Inject] private NavigationManager NavigationManager { get; init; } = default!; + [Inject] private AuthenticationStateProvider AuthenticationStateProvider { get; init; } = default!; + + private string Uri { get; set; } = string.Empty; + private string Title { get; set; } = "Account"; + + protected override async Task OnInitializedAsync() + { + var cp = (await AuthenticationStateProvider.GetAuthenticationStateAsync()).User; + //Title = $"Account: {cp?.Identity?.Name}"; + + Uri = NavigationManager.ToBaseRelativePath(NavigationManager.Uri); + } + + protected override void OnAfterRender(bool firstRender) + { + Uri = NavigationManager.ToBaseRelativePath(NavigationManager.Uri); + } +} \ No newline at end of file diff --git a/src/Web/Insight.Web/Components/Navbars/Customer.razor b/src/Web/Insight.Web/Components/Navbars/Customer.razor index 37a6525..5e1ece7 100644 --- a/src/Web/Insight.Web/Components/Navbars/Customer.razor +++ b/src/Web/Insight.Web/Components/Navbars/Customer.razor @@ -1,70 +1,13 @@ -@using MongoDB.Driver -@using Vaitr.Bus +@inherits ComponentBase -@inherits ComponentBase -@implements IDisposable +@* + @Title +*@ -@inject IMongoDatabase Database -@inject Bus Bus - - - @_title + + @Title
- Hosts -
- -@code{ - [CascadingParameter] public IReadOnlyDictionary? RouteValues { get; set; } - - private string? _id; - private string _title = "Customer"; - private IDisposable? _token; - private bool _disposed; - - protected override void OnInitialized() - { - _token = Bus.Subscribe(OnRefresh, p => p == Events.Layout.Rendered); - } - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (RouteValues is not null && _id is null) - { - if (RouteValues.TryGetValue("customerId", out object? rawId) == false) return; - _id = rawId?.ToString(); - - var entity = await Database.Customer() - .Find(p => p.Id == _id) - .FirstOrDefaultAsync(default); - - _title = $"{entity?.Name}"; - - await InvokeAsync(() => StateHasChanged()); - } - } - - public void OnRefresh(string? message) => InvokeAsync(StateHasChanged); - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private void Dispose(bool disposing) - { - if (_disposed) return; - if (disposing is false) return; - - try - { - _token?.Dispose(); - } - finally - { - _disposed = true; - } - } -} \ No newline at end of file + Hosts +
\ No newline at end of file diff --git a/src/Web/Insight.Web/Components/Navbars/Customer.razor.cs b/src/Web/Insight.Web/Components/Navbars/Customer.razor.cs new file mode 100644 index 0000000..23cf3ec --- /dev/null +++ b/src/Web/Insight.Web/Components/Navbars/Customer.razor.cs @@ -0,0 +1,62 @@ +using Insight.Infrastructure; +using Insight.Web.Constants; +using Microsoft.AspNetCore.Components; +using MongoDB.Driver; +using Vaitr.MemoryBus; + +namespace Insight.Web.Components.Navbars; + +public partial class Customer +{ + [CascadingParameter] public IReadOnlyDictionary? RouteValues { get; set; } + + [Inject] private IMongoDatabase Database { get; set; } = default!; + [Inject] private IMemoryBus Bus { get; init; } = default!; + + private string Title { get; set; } = "Customer"; + private string? Id { get; set; } + + private IDisposable? Token { get; set; } + public bool Disposed { get; set; } = false; + + protected override void OnInitialized() + { + Token = Bus.Subscribe(OnRefresh, p => p == Events.Layout.Rendered); + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (RouteValues is not null && Id is null) + { + if (RouteValues.TryGetValue("customerId", out object? rawId) == false) return; + Id = rawId?.ToString(); + + var entity = await Database.Customer() + .Find(p => p.Id == Id) + .FirstOrDefaultAsync(default); + + Title = $"{entity?.Name}"; + + await InvokeAsync(() => StateHasChanged()); + } + } + + public void OnRefresh(string? message) + { + InvokeAsync(() => StateHasChanged()); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (Disposed) return; + if (disposing is false) return; + + Token?.Dispose(); + } +} \ No newline at end of file diff --git a/src/Web/Insight.Web/Components/Navbars/Host.razor b/src/Web/Insight.Web/Components/Navbars/Host.razor index bdf3950..5c394d7 100644 --- a/src/Web/Insight.Web/Components/Navbars/Host.razor +++ b/src/Web/Insight.Web/Components/Navbars/Host.razor @@ -1,127 +1,60 @@ -@using MongoDB.Driver -@using Vaitr.Bus +@inherits ComponentBase -@inherits ComponentBase -@implements IDisposable - -@inject IMongoDatabase Database -@inject Bus Bus - -@*@if (_customer is not null) +@*@if (CustomerEntity is not null) { - @_customer.Name + @CustomerEntity.Name }*@ -@if (_host is not null) +@if (HostEntity is not null) { - - @_host.Name + + @HostEntity.Name }
- Console + Console
- Os + Os - Installed - Pending + Installed + Pending - Sessions - Software - Services - Printers - Volumes - Users - Groups - Storage Pools - Virtual Maschines + Sessions + Software + Services + Printers + Volumes + Users + Groups + Storage Pools + Virtual Maschines - Interfaces - Addresses - Nameservers - Gateways - Routes + Interfaces + Addresses + Nameservers + Gateways + Routes - Mainboard - Processors - Memory - Drives - Videocards + Mainboard + Processors + Memory + Drives + Videocards
- Logs -
- -@code{ - [CascadingParameter] public IReadOnlyDictionary? RouteValues { get; set; } - - private string? _id; - private CustomerEntity? _customer; - private HostEntity? _host; - private IDisposable? _token; - private bool _disposed; - - protected override void OnInitialized() - { - _token = Bus?.Subscribe(OnRefresh, p => p == Events.Layout.Rendered); - } - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (RouteValues is not null && _id is null) - { - if (RouteValues.TryGetValue("hostId", out object? rawId) == false) return; - _id = rawId?.ToString(); - - _host = await Database.Host() - .Find(p => p.Id == _id) - .FirstOrDefaultAsync(default); - - if (_host is not null) - { - _customer = await Database.Customer() - .Find(p => p.Id == _host.Customer) - .FirstOrDefaultAsync(default); - } - - await InvokeAsync(() => StateHasChanged()); - } - } - - public void OnRefresh(string? message) => InvokeAsync(StateHasChanged); - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private void Dispose(bool disposing) - { - if (_disposed) return; - if (disposing is false) return; - - try - { - _token?.Dispose(); - } - finally - { - _disposed = true; - } - } -} \ No newline at end of file + Logs +
\ No newline at end of file diff --git a/src/Web/Insight.Web/Components/Navbars/Host.razor.cs b/src/Web/Insight.Web/Components/Navbars/Host.razor.cs new file mode 100644 index 0000000..ef0b21e --- /dev/null +++ b/src/Web/Insight.Web/Components/Navbars/Host.razor.cs @@ -0,0 +1,69 @@ +using Insight.Infrastructure; +using Insight.Infrastructure.Entities; +using Insight.Web.Constants; +using Microsoft.AspNetCore.Components; +using MongoDB.Driver; +using Vaitr.MemoryBus; + +namespace Insight.Web.Components.Navbars; + +public partial class Host : IDisposable +{ + [CascadingParameter] public IReadOnlyDictionary? RouteValues { get; set; } + + [Inject] private IMongoDatabase Database { get; init; } = default!; + [Inject] private IMemoryBus Bus { get; init; } = default!; + + private CustomerEntity? CustomerEntity { get; set; } + private HostEntity HostEntity { get; set; } + private string? Id { get; set; } + + private IDisposable? Token { get; set; } + public bool Disposed { get; set; } = false; + + protected override void OnInitialized() + { + Token = Bus?.Subscribe(OnRefresh, p => p == Events.Layout.Rendered); + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (RouteValues is not null && Id is null) + { + if (RouteValues.TryGetValue("hostId", out object? rawId) == false) return; + Id = rawId?.ToString(); + + HostEntity = await Database.Host() + .Find(p => p.Id == Id) + .FirstOrDefaultAsync(default); + + if (HostEntity is not null) + { + CustomerEntity = await Database.Customer() + .Find(p => p.Id == HostEntity.Customer) + .FirstOrDefaultAsync(default); + } + + await InvokeAsync(() => StateHasChanged()); + } + } + + public void OnRefresh(string? message) + { + InvokeAsync(() => StateHasChanged()); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (Disposed) return; + if (disposing is false) return; + + Token?.Dispose(); + } +} diff --git a/src/Web/Insight.Web/Components/Navbars/Main.razor b/src/Web/Insight.Web/Components/Navbars/Main.razor index 7281e33..3c61848 100644 --- a/src/Web/Insight.Web/Components/Navbars/Main.razor +++ b/src/Web/Insight.Web/Components/Navbars/Main.razor @@ -1,14 +1,6 @@ -@using MongoDB.Driver -@using Vaitr.Bus +@inherits ComponentBase -@inherits ComponentBase -@implements IDisposable - -@inject NavigationManager NavigationManager -@inject IMongoDatabase Database -@inject Bus Bus - - + @* Dashboard *@ @@ -20,7 +12,7 @@ *@ - + Os @@ -92,7 +84,10 @@ - + + + Overview + Accounts @@ -102,58 +97,16 @@ Hosts - + @* Host Groups - + *@ Agents - - Scheduler - -@code{ - private bool ExpandMonitoring => _uri.StartsWith(Navigation.Monitoring.Index); - private bool ExpandManagement => _uri.StartsWith(Navigation.Management.Index); - private bool ExpandInventory => _uri.StartsWith(Navigation.Inventory.Index); - private bool ExpandInventorySystem => _uri.StartsWith(Navigation.Inventory.Systems.Index); - private bool ExpandInventoryNetwork => _uri.StartsWith(Navigation.Inventory.Network.Index); - private bool ExpandInventoryHardware => _uri.StartsWith(Navigation.Inventory.Hardware.Index); - private string _uri = string.Empty; - private IDisposable? _token; - private bool _disposed; - - protected override void OnInitialized() - { - _token = Bus?.Subscribe(OnRefresh, p => p == Events.Layout.Rendered); - OnRefresh(); - } - - public void OnRefresh(string? message = null) - { - _uri = NavigationManager.ToBaseRelativePath(NavigationManager.Uri); - InvokeAsync(() => StateHasChanged()); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private void Dispose(bool disposing) - { - if (_disposed is false) return; - if (disposing is false) return; - - try - { - _token?.Dispose(); - } - finally - { - _disposed = true; - } - } -} \ No newline at end of file +@* + + Chat + +*@ \ No newline at end of file diff --git a/src/Web/Insight.Web/Components/Navbars/Main.razor.cs b/src/Web/Insight.Web/Components/Navbars/Main.razor.cs new file mode 100644 index 0000000..74374ff --- /dev/null +++ b/src/Web/Insight.Web/Components/Navbars/Main.razor.cs @@ -0,0 +1,136 @@ +using Insight.Web.Constants; +using Microsoft.AspNetCore.Components; +using Vaitr.MemoryBus; + +namespace Insight.Web.Components.Navbars; + +public partial class Main : IDisposable +{ + [Inject] private IMemoryBus Bus { get; init; } = default!; + [Inject] private NavigationManager NavigationManager { get; init; } = default!; + + private string Uri { get; set; } = string.Empty; + private IDisposable? Token { get; set; } + public bool Disposed { get; set; } = false; + + protected override void OnInitialized() + { + Token = Bus?.Subscribe(OnRefresh, p => p == Events.Layout.Rendered); + OnRefresh(); + } + + public void OnRefresh(string? message = null) + { + Uri = NavigationManager.ToBaseRelativePath(NavigationManager.Uri); + InvokeAsync(() => StateHasChanged()); + } + + private bool ExpandMonitoringGroup + { + get + { + if (Uri.StartsWith(Navigation.Monitoring.Index)) return true; + return false; + } + } + + private bool ExpandManagementGroup + { + get + { + if (Uri.StartsWith(Navigation.Management.Overview.Index)) return true; + if (Uri.StartsWith(Navigation.Management.Accounts.Index)) return true; + if (Uri.StartsWith(Navigation.Management.Customers.Index)) return true; + if (Uri.StartsWith(Navigation.Management.Hosts.Index)) return true; + if (Uri.StartsWith(Navigation.Management.HostGroups.Index)) return true; + if (Uri.StartsWith(Navigation.Management.Agents.Index)) return true; + return false; + } + } + + private bool ExpandInventoryGroup + { + get + { + if (ExpandInventorySystem) return true; + if (ExpandInventoryNetwork) return true; + if (ExpandInventoryHardware) return true; + return false; + } + } + + private bool ExpandInventorySystem + { + get + { + if (Uri.StartsWith(Navigation.Inventory.Systems.Os.Index)) return true; + if (Uri.StartsWith(Navigation.Inventory.Systems.Os.Hosts)) return true; + if (Uri.StartsWith(Navigation.Inventory.Systems.Os.Guests)) return true; + if (Uri.StartsWith(Navigation.Inventory.Systems.Updates.Index)) return true; + if (Uri.StartsWith(Navigation.Inventory.Systems.Updates.Hosts)) return true; + if (Uri.StartsWith(Navigation.Inventory.Systems.Software.Index)) return true; + if (Uri.StartsWith(Navigation.Inventory.Systems.Software.Hosts)) return true; + if (Uri.StartsWith(Navigation.Inventory.Systems.Services.Index)) return true; + if (Uri.StartsWith(Navigation.Inventory.Systems.Services.Hosts)) return true; + if (Uri.StartsWith(Navigation.Inventory.Systems.Sessions.Index)) return true; + if (Uri.StartsWith(Navigation.Inventory.Systems.Printers.Index)) return true; + if (Uri.StartsWith(Navigation.Inventory.Systems.Volumes.Index)) return true; + if (Uri.StartsWith(Navigation.Inventory.Systems.Users.Index)) return true; + if (Uri.StartsWith(Navigation.Inventory.Systems.Users.Hosts)) return true; + if (Uri.StartsWith(Navigation.Inventory.Systems.Groups.Index)) return true; + if (Uri.StartsWith(Navigation.Inventory.Systems.Groups.Hosts)) return true; + if (Uri.StartsWith(Navigation.Inventory.Systems.StoragePools.Index)) return true; + if (Uri.StartsWith(Navigation.Inventory.Systems.VirtualMaschines.Index)) return true; + return false; + } + } + + private bool ExpandInventoryNetwork + { + get + { + if (Uri.StartsWith(Navigation.Inventory.Network.Interfaces.Index)) return true; + if (Uri.StartsWith(Navigation.Inventory.Network.Addresses.Index)) return true; + if (Uri.StartsWith(Navigation.Inventory.Network.Addresses.Hosts)) return true; + if (Uri.StartsWith(Navigation.Inventory.Network.Nameservers.Index)) return true; + if (Uri.StartsWith(Navigation.Inventory.Network.Nameservers.Hosts)) return true; + if (Uri.StartsWith(Navigation.Inventory.Network.Gateways.Index)) return true; + if (Uri.StartsWith(Navigation.Inventory.Network.Gateways.Hosts)) return true; + if (Uri.StartsWith(Navigation.Inventory.Network.Routes.Index)) return true; + if (Uri.StartsWith(Navigation.Inventory.Network.Routes.Hosts)) return true; + return false; + } + } + + private bool ExpandInventoryHardware + { + get + { + if (Uri.StartsWith(Navigation.Inventory.Hardware.Mainboards.Index)) return true; + if (Uri.StartsWith(Navigation.Inventory.Hardware.Mainboards.Hosts)) return true; + if (Uri.StartsWith(Navigation.Inventory.Hardware.Processors.Index)) return true; + if (Uri.StartsWith(Navigation.Inventory.Hardware.Processors.Hosts)) return true; + if (Uri.StartsWith(Navigation.Inventory.Hardware.Memory.Index)) return true; + if (Uri.StartsWith(Navigation.Inventory.Hardware.Memory.Hosts)) return true; + if (Uri.StartsWith(Navigation.Inventory.Hardware.Drives.Index)) return true; + if (Uri.StartsWith(Navigation.Inventory.Hardware.Drives.Hosts)) return true; + if (Uri.StartsWith(Navigation.Inventory.Hardware.Videocards.Index)) return true; + if (Uri.StartsWith(Navigation.Inventory.Hardware.Videocards.Hosts)) return true; + return false; + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (Disposed) return; + if (disposing is false) return; + + Token?.Dispose(); + } +} \ No newline at end of file diff --git a/src/Web/Insight.Web/Components/Navbars/NavSwitch.razor b/src/Web/Insight.Web/Components/Navbars/NavSwitch.razor new file mode 100644 index 0000000..9eb23b4 --- /dev/null +++ b/src/Web/Insight.Web/Components/Navbars/NavSwitch.razor @@ -0,0 +1,29 @@ +@using System.Reflection; +@inherits ComponentBase + +
+ + + @if (_content == Content.Account) + { + + } + else if (_content == Content.Host) + { + + } + else if (_content == Content.Customer) + { + + } + else + { +
+ } + + +
+ + + @(Assembly.GetEntryAssembly()?.GetName().Version) + \ No newline at end of file diff --git a/src/Web/Insight.Web/Components/Navbars/NavSwitch.razor.cs b/src/Web/Insight.Web/Components/Navbars/NavSwitch.razor.cs new file mode 100644 index 0000000..bbcc4ab --- /dev/null +++ b/src/Web/Insight.Web/Components/Navbars/NavSwitch.razor.cs @@ -0,0 +1,59 @@ +using Insight.Web.Constants; +using Microsoft.AspNetCore.Components; +using Vaitr.MemoryBus; + +namespace Insight.Web.Components.Navbars; + +public partial class NavSwitch : IDisposable +{ + [CascadingParameter] public IReadOnlyDictionary? RouteValues { get; set; } + + [Inject] private NavigationManager NavigationManager { get; init; } = default!; + [Inject] private IMemoryBus Bus { get; init; } = default!; + + public string Url { get; set; } = string.Empty; + private IDisposable? Token { get; set; } + public bool Disposed { get; set; } = false; + + private enum Content { Main, Account, Customer, Host } + private Content _content = Content.Main; + + protected override void OnInitialized() + { + Token = Bus?.SubscribeAsync(OnRefreshAsync, p => p == Events.Layout.Rendered); + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + await OnRefreshAsync().ConfigureAwait(false); + } + } + + public async ValueTask OnRefreshAsync(string? message = null, CancellationToken cancellationToken = default) + { + Url = NavigationManager.ToBaseRelativePath(NavigationManager.Uri); + + if (Url is null) return; + + if (Url.StartsWith($"{Navigation.Account.Index}/")) _content = Content.Account; + else if (Url.StartsWith($"{Navigation.Management.Customers.Index}/")) _content = Content.Customer; + else if (Url.StartsWith($"{Navigation.Management.Hosts.Index}/")) _content = Content.Host; + else _content = Content.Main; + + await InvokeAsync(StateHasChanged).ConfigureAwait(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (Disposed) return; + Token?.Dispose(); + } +} \ No newline at end of file diff --git a/src/Web/Insight.Web/Components/Navbars/Scheduler.razor b/src/Web/Insight.Web/Components/Navbars/Scheduler.razor deleted file mode 100644 index 024e016..0000000 --- a/src/Web/Insight.Web/Components/Navbars/Scheduler.razor +++ /dev/null @@ -1,37 +0,0 @@ -@inherits ComponentBase -@implements IDisposable - -@inject NavigationManager NavigationManager - - - Scheduler - - -Jobs -Tasks -Triggers - -@code{ - private bool _disposed; - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private void Dispose(bool disposing) - { - if (_disposed is false) return; - if (disposing is false) return; - - try - { - - } - finally - { - _disposed = true; - } - } -} \ No newline at end of file diff --git a/src/Web/Insight.Web/Components/Providers/ChatProvider.razor b/src/Web/Insight.Web/Components/Providers/ChatProvider.razor index c6f231a..b88218b 100644 --- a/src/Web/Insight.Web/Components/Providers/ChatProvider.razor +++ b/src/Web/Insight.Web/Components/Providers/ChatProvider.razor @@ -1,13 +1,12 @@ @using System.Collections.Concurrent; -@using Vaitr.Bus; +@using Vaitr.MemoryBus; @using static Insight.Web.Constants.Events.Chat; -@inherits ComponentBase -@implements IDisposable - -@inject Bus Bus +@inject IMemoryBus Bus @inject SessionHandler SessionHandler +@implements IDisposable + @@ -21,7 +20,7 @@ private readonly ConcurrentBag _subscriptions = new(); - protected override void OnInitialized() + protected override async Task OnInitializedAsync() { _subscriptions.Add(Bus.SubscribeAsync(async (x, c) => await InvokeAsync(StateHasChanged), p => p == Events.Sessions.Changed)); _subscriptions.Add(Bus.SubscribeAsync(async (x, c) => await InvokeAsync(StateHasChanged), p => p.Message.SenderId != SessionHandler.State.Uid)); @@ -29,24 +28,21 @@ public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } - private void Dispose(bool disposing) + protected virtual void Dispose(bool disposing) { // auto disposed when starved circuit timeouts (disconnects) - - if (_disposed is false) return; - if (disposing is false) return; - - try - { - foreach (var sub in _subscriptions) sub.Dispose(); - _subscriptions.Clear(); - } - finally + if (_disposed is false) { + if (disposing) + { + foreach (var sub in _subscriptions) sub.Dispose(); + _subscriptions.Clear(); + } + _disposed = true; } } diff --git a/src/Web/Insight.Web/Components/Providers/DrawerProvider.razor b/src/Web/Insight.Web/Components/Providers/DrawerProvider.razor index 117178d..68a7295 100644 --- a/src/Web/Insight.Web/Components/Providers/DrawerProvider.razor +++ b/src/Web/Insight.Web/Components/Providers/DrawerProvider.razor @@ -1,47 +1,8 @@ -@using System.Reflection; -@using MongoDB.Driver -@using Vaitr.Bus - -@inherits ComponentBase -@implements IDisposable - -@inject NavigationManager NavigationManager -@inject IMongoDatabase Database -@inject Bus Bus - - + -
- - - @if (_content == Content.Account) - { - - } - else if (_content == Content.Customer) - { - - } - else if (_content == Content.Host) - { - - } - else if (_content == Content.Scheduler) - { - - } - else - { -
- } - - -
- - @(Assembly.GetEntryAssembly()?.GetName().Version) - +
@@ -50,57 +11,7 @@ @code { [CascadingParameter] public IReadOnlyDictionary? RouteValues { get; set; } - private string _uri = string.Empty; - private enum Content { Main, Account, Customer, Host, Scheduler } - private Content _content = Content.Main; - private IDisposable? _token; private bool _open = true; - private bool _disposed; - - protected override void OnInitialized() - { - _token = Bus?.SubscribeAsync(OnRefreshAsync, p => p == Events.Layout.Rendered); - } - - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (firstRender) await OnRefreshAsync(); - } public void Toggle() => _open = !_open; - - public async ValueTask OnRefreshAsync(string? message = null, CancellationToken cancellationToken = default) - { - _uri = NavigationManager.ToBaseRelativePath(NavigationManager.Uri); - if (_uri is null) return; - - if (_uri.StartsWith($"{Navigation.Account.Index}/")) _content = Content.Account; - else if (_uri.StartsWith($"{Navigation.Management.Customers.Index}/")) _content = Content.Customer; - else if (_uri.StartsWith($"{Navigation.Management.Hosts.Index}/")) _content = Content.Host; - else if (_uri.StartsWith($"{Navigation.Management.Scheduler.Index}/")) _content = Content.Scheduler; - else _content = Content.Main; - - await InvokeAsync(StateHasChanged); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private void Dispose(bool disposing) - { - if (_disposed is false) return; - if (disposing is false) return; - - try - { - _token?.Dispose(); - } - finally - { - _disposed = true; - } - } } \ No newline at end of file diff --git a/src/Web/Insight.Web/Components/Providers/ProfileProvider.razor b/src/Web/Insight.Web/Components/Providers/ProfileProvider.razor index 5cf99d6..2208e1e 100644 --- a/src/Web/Insight.Web/Components/Providers/ProfileProvider.razor +++ b/src/Web/Insight.Web/Components/Providers/ProfileProvider.razor @@ -1,7 +1,4 @@ -@inherits ComponentBase -@implements IDisposable - -@inject NavigationManager NavigationManager +@inject NavigationManager NavigationManager @@ -52,7 +49,6 @@ @code{ private MudMenu? _menu; - private bool _disposed; private void OnLogin() { @@ -71,25 +67,4 @@ _menu?.CloseMenu(); NavigationManager.NavigateTo(Navigation.Account.Profile, false); } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private void Dispose(bool disposing) - { - if (_disposed is false) return; - if (disposing is false) return; - - try - { - - } - finally - { - _disposed = true; - } - } } \ No newline at end of file diff --git a/src/Web/Insight.Web/Components/Providers/SessionProvider.razor b/src/Web/Insight.Web/Components/Providers/SessionProvider.razor index 7cdbfd5..69357d8 100644 --- a/src/Web/Insight.Web/Components/Providers/SessionProvider.razor +++ b/src/Web/Insight.Web/Components/Providers/SessionProvider.razor @@ -1,37 +1,14 @@ -@using Vaitr.Bus; - -@inherits ComponentBase -@implements IDisposable +@using Vaitr.MemoryBus; @inject SessionHandler SessionHandler -@inject Bus Bus +@inject IMemoryBus Bus @code { - private bool _disposed; - protected override async Task OnAfterRenderAsync(bool firstRender) { - if (firstRender) await SessionHandler.UpdateStateAsync(default); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private void Dispose(bool disposing) - { - if (_disposed is false) return; - if (disposing is false) return; - - try + if (firstRender) { - - } - finally - { - _disposed = true; + await SessionHandler.UpdateStateAsync(default); } } } \ No newline at end of file diff --git a/src/Web/Insight.Web/Components/Providers/ThemeProvider.razor b/src/Web/Insight.Web/Components/Providers/ThemeProvider.razor new file mode 100644 index 0000000..f3549d7 --- /dev/null +++ b/src/Web/Insight.Web/Components/Providers/ThemeProvider.razor @@ -0,0 +1,90 @@ +@using Blazored.LocalStorage; +@using Microsoft.AspNetCore.Identity; +@using MongoDB.Driver; +@using Insight.Infrastructure + +@inject IServiceScopeFactory ServiceScopeFactory +@inject ILocalStorageService LocalStorageService +@inject IMongoDatabase Database +@inject AuthenticationStateProvider AuthenticationStateProvider + + + +@if (DisableIcon is false) +{ + +} + +@code { + [Parameter] public bool DisableIcon { get; set; } + + private MudTheme CurrentTheme { get; } = Themes.Default(); + private bool DarkMode { get; set; } + + protected override async Task OnInitializedAsync() + { + await LoadDarkModeAsync(); + } + + public async Task LoadDarkModeAsync() + { + // local storage + var storageDarkMode = await LocalStorageService.GetItemAsync("darkmode"); + if (storageDarkMode is bool darkmodeValue) DarkMode = darkmodeValue; + + // database override + var state = await AuthenticationStateProvider.GetAuthenticationStateAsync(); + + if (state?.User.Identity is not null && state.User.Identity.IsAuthenticated) + { + using var scope = ServiceScopeFactory.CreateScope(); + var userManager = scope.ServiceProvider.GetRequiredService>(); + + if (await userManager.FindByNameAsync(state.User.Identity.Name) is not InsightUser user) return; + + var userPrefs = await Database.UserPreference() + .Find(p => p.User == user.Id.ToString()) + .FirstOrDefaultAsync(); + + if (userPrefs is null) return; + + DarkMode = userPrefs.DarkMode; + + await LocalStorageService.SetItemAsync("darkmode", DarkMode); + } + } + + private async Task OnDarkModeToggleAsync() + { + // update current + DarkMode = !DarkMode; + + // update local storage + await LocalStorageService.SetItemAsync("darkmode", DarkMode); + + // update database + var state = await AuthenticationStateProvider.GetAuthenticationStateAsync(); + + if (state?.User.Identity is not null && state.User.Identity.IsAuthenticated) + { + using var scope = ServiceScopeFactory.CreateScope(); + var userManager = scope.ServiceProvider.GetRequiredService>(); + + if (await userManager.FindByNameAsync(state.User.Identity.Name) is not InsightUser user) return; + + var date = DateTime.Now; + + var userPrefs = await Database.UserPreference() + .UpdateOneAsync(p => p.User == user.Id.ToString(), Builders.Update + .SetOnInsert(p => p.User, user.Id.ToString()) + .SetOnInsert(p => p.Insert, date) + .Set(p => p.Update, date) + .Set(p => p.DarkMode, DarkMode), new UpdateOptions + { + IsUpsert = true + }); + } + + await InvokeAsync(StateHasChanged); + } +} \ No newline at end of file diff --git a/src/Web/Insight.Web/Constants/Navigation.cs b/src/Web/Insight.Web/Constants/Navigation.cs index 9bea8c5..aadb16b 100644 --- a/src/Web/Insight.Web/Constants/Navigation.cs +++ b/src/Web/Insight.Web/Constants/Navigation.cs @@ -13,22 +13,44 @@ public static class Navigation public static class Account { public const string Index = "account"; - public const string Login = Index + "/login"; - public const string LoginTFA = Login + "/{key:guid}"; - public const string SignIn = Index + "/signin"; - public const string SignInTFA = SignIn + "/2fa"; - public const string Logout = Index + "/logout"; - public const string Lockout = Index + "/lockout"; - public const string Profile = Index + "/profile"; - public const string ChangePassword = Index + "/changepassword"; + public const string Login = "account/login"; + public const string LoginTFA = "account/login/{key:guid}"; + public const string SignIn = "account/signin"; + public const string SignInTFA = "account/signin/2fa"; + public const string Logout = "account/logout"; + public const string Lockout = "account/lockout"; + public const string Profile = "account/profile"; + public const string ChangePassword = "account/changepassword"; - public static string LoginHref(string redirect) => string.IsNullOrWhiteSpace(redirect) ? Login : $"{Login}?redirect={redirect}"; - public static string LoginTFAHref(Guid key) => LoginTFA.Replace("{key:guid}", key.ToString()); + public static string LoginHref(string redirect) + { + if (string.IsNullOrWhiteSpace(redirect)) + { + return Login; + } - public static string SignInHref(Guid key) => $"{SignIn}?key={key}"; - public static string SignInTFAHref(Guid key) => $"{SignInTFA}?key={key}"; + return $"{Login}?redirect={redirect}"; + } - public static string ChangePasswordHref(Guid key) => $"{ChangePassword}?key={key}"; + public static string LoginTFAHref(Guid key) + { + return LoginTFA.Replace("{key:guid}", key.ToString()); + } + + public static string SignInHref(Guid key) + { + return $"{SignIn}?key={key}"; + } + + public static string SignInTFAHref(Guid key) + { + return $"{SignInTFA}?key={key}"; + } + + public static string ChangePasswordHref(Guid key) + { + return $"{ChangePassword}?key={key}"; + } } public static class Monitoring @@ -37,36 +59,36 @@ public static class Navigation public static class Maintenance { - public const string Index = Monitoring.Index + "/maintenance"; + public const string Index = "monitoring/maintenance"; public static class Drives { - public const string Index = Monitoring.Index + "/drives"; + public const string Index = "monitoring/maintenance/drives"; } public static class StoragePools { - public const string Index = Monitoring.Index + "/storagepools"; + public const string Index = "monitoring/maintenance/storagepools"; } public static class Volumes { - public const string Index = Monitoring.Index + "/volumes"; + public const string Index = "monitoring/maintenance/volumes"; } public static class Guests { - public const string Index = Monitoring.Index + "/guests"; + public const string Index = "monitoring/maintenance/guests"; } public static class Snapshots { - public const string Index = Monitoring.Index + "/snapshots"; + public const string Index = "monitoring/maintenance/snapshots"; } public static class Updates { - public const string Index = Monitoring.Index + "/updates"; + public const string Index = "monitoring/maintenance/updates"; } } } @@ -75,58 +97,106 @@ public static class Navigation { public const string Index = "management"; + public static class Overview + { + public const string Index = "management/overview"; + } + public static class Accounts { - public const string Index = Management.Index + "/accounts"; - public const string Details = Index + "/{accountId}"; - - public static string DetailsHref(string? accountId) => Details.Replace("{accountId}", accountId); + public const string Index = "management/accounts"; + public const string Details = "management/accounts/{accountId}"; + + public static string DetailsHref(string? accountId) + { + return Details.Replace("{accountId}", accountId); + } } public static class Customers { - public const string Index = Management.Index + "/customers"; - public const string Details = Index + "/{customerId}"; - public const string Hosts = Details + "/hosts"; - public const string HostsAssign = Hosts + "/assign"; + public const string Index = "management/customers"; + public const string Details = "management/customers/{customerId}"; + public const string Hosts = "management/customers/{customerId}/hosts"; + public const string HostsAssign = "management/customers/{customerId}/hosts/assign"; - public static string DetailsHref(string? customerId) => Details.Replace("{customerId}", customerId); - public static string HostsHref(string? customerId) => Hosts.Replace("{customerId}", customerId); - public static string HostsAssignHref(string? customerId) => HostsAssign.Replace("{customerId}", customerId); + public static string DetailsHref(string? customerId) + { + return Details.Replace("{customerId}", customerId); + } + + public static string HostsHref(string? customerId) + { + return Hosts.Replace("{customerId}", customerId); + } + + public static string HostsAssignHref(string? customerId) + { + return HostsAssign.Replace("{customerId}", customerId); + } } public static class Agents { - public const string Index = Management.Index + "/agents"; - public const string Details = Index + "/{agentId}"; - public const string Logs = Details + "/logs"; - public const string HostAssign = Details + "/assign"; + public const string Index = "management/agents"; + public const string Details = "management/agents/{agentId}"; + public const string Logs = "management/agents/{agentId}/logs"; + public const string HostAssign = "management/agents/{agentId}/assign"; - public static string DetailsHref(string? agentId) => Details.Replace("{agentId}", agentId); - public static string LogsHref(string? agentId) => Logs.Replace("{agentId}", agentId); - public static string HostAssingHref(string? agentId) => HostAssign.Replace("{agentId}", agentId); + public static string DetailsHref(string? agentId) + { + return Details.Replace("{agentId}", agentId); + } + + public static string LogsHref(string? agentId) + { + return Logs.Replace("{agentId}", agentId); + } + + public static string HostAssingHref(string? agentId) + { + return HostAssign.Replace("{agentId}", agentId); + } } public static class Hosts { - public const string Index = Management.Index + "/hosts"; - public const string Details = Index + "/{hostId}"; - public const string Logs = Details + "/logs"; - public const string CustomerAssign = Details + "/customer/assign"; - public const string AgentAssign = Details + "/agent/assign"; + public const string Index = "management/hosts"; + public const string Details = "management/hosts/{hostId}"; + public const string Logs = "management/hosts/{hostId}/logs"; + public const string CustomerAssign = "management/hosts/{hostId}/customer/assign"; + public const string AgentAssign = "management/hosts/{hostId}/agent/assign"; - public static string DetailsHref(string? hostId) => Details.Replace("{hostId}", hostId); - public static string LogsHref(string? hostId) => Logs.Replace("{hostId}", hostId); - public static string CustomerAssingHref(string? hostId) => CustomerAssign.Replace("{hostId}", hostId); - public static string AgentAssingHref(string? hostId) => AgentAssign.Replace("{hostId}", hostId); + public static string DetailsHref(string? hostId) + { + return Details.Replace("{hostId}", hostId); + } + + public static string LogsHref(string? hostId) + { + return Logs.Replace("{hostId}", hostId); + } + + public static string CustomerAssingHref(string? hostId) + { + return CustomerAssign.Replace("{hostId}", hostId); + } + + public static string AgentAssingHref(string? hostId) + { + return AgentAssign.Replace("{hostId}", hostId); + } public static class Actions { public static class Console { - public const string Index = Hosts.Details + "/console"; + public const string Index = "management/hosts/{hostId}/console"; - public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId); + public static string IndexHref(string? hostId) + { + return Index.Replace("{hostId}", hostId); + } } } @@ -134,121 +204,190 @@ public static class Navigation { public static class Os { - public const string Details = Hosts.Details + "/os"; + public const string Details = "management/hosts/{hostId}/os"; - public static string DetailsHref(string? hostId) => Details.Replace("{hostId}", hostId); + public static string DetailsHref(string? hostId) + { + return Details.Replace("{hostId}", hostId); + } } public static class Updates { public static class Installed { - public const string Index = Hosts.Details + "/updates/installed"; + public const string Index = "management/hosts/{hostId}/updates/installed"; - public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId); + public static string IndexHref(string? hostId) + { + return Index.Replace("{hostId}", hostId); + } } public static class Pending { - public const string Index = Hosts.Details + "/updates/pending"; + public const string Index = "management/hosts/{hostId}/updates/pending"; - public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId); + public static string IndexHref(string? hostId) + { + return Index.Replace("{hostId}", hostId); + } } } public static class Sessions { - public const string Index = Hosts.Details + "/sessions"; + public const string Index = "management/hosts/{hostId}/sessions"; - public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId); + public static string IndexHref(string? hostId) + { + return Index.Replace("{hostId}", hostId); + } } public static class Software { - public const string Index = Hosts.Details + "/software"; + public const string Index = "management/hosts/{hostId}/software"; - public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId); + public static string IndexHref(string? hostId) + { + return Index.Replace("{hostId}", hostId); + } } public static class Services { - public const string Index = Hosts.Details + "/services"; + public const string Index = "management/hosts/{hostId}/services"; - public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId); + public static string IndexHref(string? hostId) + { + return Index.Replace("{hostId}", hostId); + } } public static class Printers { - public const string Index = Hosts.Details + "/printers"; + public const string Index = "management/hosts/{hostId}/printers"; - public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId); + public static string IndexHref(string? hostId) + { + return Index.Replace("{hostId}", hostId); + } } public static class Volumes { - public const string Index = Hosts.Details + "/volumes"; - public const string Details = Index + "/{volumeId}"; + public const string Index = "management/hosts/{hostId}/volumes"; + public const string Details = "management/hosts/{hostId}/volumes/{volumeId}"; - public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId); - public static string DetailsHref(string? hostId, string? volumeId) => Details.Replace("{hostId}", hostId).Replace("{volumeId}", volumeId); + public static string IndexHref(string? hostId) + { + return Index.Replace("{hostId}", hostId); + } + + public static string DetailsHref(string? hostId, string? volumeId) + { + return Details.Replace("{hostId}", hostId).Replace("{volumeId}", volumeId); + } } public static class Users { - public const string Index = Hosts.Details + "/users"; - public const string Details = Index + "/{userId}"; + public const string Index = "management/hosts/{hostId}/users"; + public const string Details = "management/hosts/{hostId}/users/{userId}"; - public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId); - public static string DetailsHref(string? hostId, string? userId) => Details.Replace("{hostId}", hostId).Replace("{userId}", userId); + public static string IndexHref(string? hostId) + { + return Index.Replace("{hostId}", hostId); + } + + public static string DetailsHref(string? hostId, string? userId) + { + return Details.Replace("{hostId}", hostId).Replace("{userId}", userId); + } } public static class Groups { - public const string Index = Hosts.Details + "/groups"; + public const string Index = "management/hosts/{hostId}/groups"; - public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId); + public static string IndexHref(string? hostId) + { + return Index.Replace("{hostId}", hostId); + } } public static class StoragePools { - public const string Index = Hosts.Details + "/storagepools"; - public const string Details = Index + "/{storagePoolId}"; + public const string Index = "management/hosts/{hostId}/storagepools"; + public const string Details = "management/hosts/{hostId}/storagepools/{storagePoolId}"; - public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId); - public static string DetailsHref(string? hostId, string? storagePoolId) => Details.Replace("{hostId}", hostId).Replace("{storagePoolId}", storagePoolId); + public static string IndexHref(string? hostId) + { + return Index.Replace("{hostId}", hostId); + } + + public static string DetailsHref(string? hostId, string? storagePoolId) + { + return Details.Replace("{hostId}", hostId).Replace("{storagePoolId}", storagePoolId); + } public static class VirtualDisks { - public const string Index = StoragePools.Details + "/virtualdisks"; - public const string Details = Index + "/{virtualDiskId}"; + public const string Index = "management/hosts/{hostId}/storagepools/{storagePoolId}/virtualdisks"; + public const string Details = "management/hosts/{hostId}/storagepools/{storagePoolId}/virtualdisks/{virtualDiskId}"; - public static string IndexHref(string? hostId, string? storagePoolId) => Index.Replace("{hostId}", hostId).Replace("{storagePoolId}", storagePoolId); - public static string DetailsHref(string? hostId, string? storagePoolId, string? virtualDiskId) => Details.Replace("{hostId}", hostId).Replace("{storagePoolId}", storagePoolId).Replace("{virtualDiskId}", virtualDiskId); + public static string IndexHref(string? hostId, string? storagePoolId) + { + return Index.Replace("{hostId}", hostId).Replace("{storagePoolId}", storagePoolId); + } + + public static string DetailsHref(string? hostId, string? storagePoolId, string? virtualDiskId) + { + return Details.Replace("{hostId}", hostId).Replace("{storagePoolId}", storagePoolId).Replace("{virtualDiskId}", virtualDiskId); + } } public static class PhysicalDisks { - public const string Index = StoragePools.Details + "/physicaldisks"; - public const string Details = Index + "/{physicalDiskId}"; + public const string Index = "management/hosts/{hostId}/storagepools/{storagePoolId}/physicaldisks"; + public const string Details = "management/hosts/{hostId}/storagepools/{storagePoolId}/physicaldisks/{physicalDiskId}"; - public static string IndexHref(string? hostId, string? storagePoolId) => Index.Replace("{hostId}", hostId).Replace("{storagePoolId}", storagePoolId); - public static string DetailsHref(string? hostId, string? storagePoolId, string? physicalDiskId) => Details.Replace("{hostId}", hostId).Replace("{storagePoolId}", storagePoolId).Replace("{physicalDiskId}", physicalDiskId); + public static string IndexHref(string? hostId, string? storagePoolId) + { + return Index.Replace("{hostId}", hostId).Replace("{storagePoolId}", storagePoolId); + } + + public static string DetailsHref(string? hostId, string? storagePoolId, string? physicalDiskId) + { + return Details.Replace("{hostId}", hostId).Replace("{storagePoolId}", storagePoolId).Replace("{physicalDiskId}", physicalDiskId); + } } } public static class VirtualMaschines { - public const string Index = Hosts.Details + "/virtualmaschines"; - public const string Details = Index + "/{virtualMaschineId}"; + public const string Index = "management/hosts/{hostId}/virtualmaschines"; + public const string Details = "management/hosts/{hostId}/virtualmaschines/{virtualMaschineId}"; - public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId); - public static string DetailsHref(string? hostId, string? virtualMaschineId) => Details.Replace("{hostId}", hostId).Replace("{virtualMaschineId}", virtualMaschineId); + public static string IndexHref(string? hostId) + { + return Index.Replace("{hostId}", hostId); + } + + public static string DetailsHref(string? hostId, string? virtualMaschineId) + { + return Details.Replace("{hostId}", hostId).Replace("{virtualMaschineId}", virtualMaschineId); + } public static class Snapshots { - public const string Details = VirtualMaschines.Details + "/snapshots/{snapshotId}"; + public const string Details = "management/hosts/{hostId}/virtualmaschines/{virtualMaschineId}/snapshots/{snapshotId}"; - public static string DetailsHref(string? hostId, string? virtualMaschineId, string? snapshotId) => Details.Replace("{hostId}", hostId).Replace("{virtualMaschineId}", virtualMaschineId).Replace("{snapshotId}", snapshotId); + public static string DetailsHref(string? hostId, string? virtualMaschineId, string? snapshotId) + { + return Details.Replace("{hostId}", hostId).Replace("{virtualMaschineId}", virtualMaschineId).Replace("{snapshotId}", snapshotId); + } } } } @@ -257,44 +396,63 @@ public static class Navigation { public static class Interfaces { - public const string Index = Hosts.Details + "/interfaces"; - public const string Details = Index + "/{interfaceId}"; + public const string Index = "management/hosts/{hostId}/interfaces"; + public const string Details = "management/hosts/{hostId}/interfaces/{interfaceId}"; - public const string Addresses = Details + "/addresses"; - public const string Nameservers = Details + "/nameservers"; - public const string Gateways = Details + "/gateways"; - public const string Routes = Details + "/routes"; + public const string Addresses = "management/hosts/{hostId}/interfaces/{interfaceId}/addresses"; + public const string Nameservers = "management/hosts/{hostId}/interfaces/{interfaceId}/nameservers"; + public const string Gateways = "management/hosts/{hostId}/interfaces/{interfaceId}/gateways"; + public const string Routes = "management/hosts/{hostId}/interfaces/{interfaceId}/routes"; - public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId); - public static string DetailsHref(string? hostId, string? interfaceId) => Details.Replace("{hostId}", hostId).Replace("{interfaceId}", interfaceId); + public static string IndexHref(string? hostId) + { + return Index.Replace("{hostId}", hostId); + } + + public static string DetailsHref(string? hostId, string? interfaceId) + { + return Details.Replace("{hostId}", hostId).Replace("{interfaceId}", interfaceId); + } } public static class Addresses { - public const string Index = Hosts.Details + "/addresses"; + public const string Index = "management/hosts/{hostId}/addresses"; - public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId); + public static string IndexHref(string? hostId) + { + return Index.Replace("{hostId}", hostId); + } } public static class Gateways { - public const string Index = Details + "/gateways"; + public const string Index = "management/hosts/{hostId}/gateways"; - public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId); + public static string IndexHref(string? hostId) + { + return Index.Replace("{hostId}", hostId); + } } public static class Nameservers { - public const string Index = Hosts.Details + "/nameservers"; + public const string Index = "management/hosts/{hostId}/nameservers"; - public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId); + public static string IndexHref(string? hostId) + { + return Index.Replace("{hostId}", hostId); + } } public static class Routes { - public const string Index = Hosts.Details + "/routes"; + public const string Index = "management/hosts/{hostId}/routes"; - public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId); + public static string IndexHref(string? hostId) + { + return Index.Replace("{hostId}", hostId); + } } } @@ -302,264 +460,288 @@ public static class Navigation { public static class Mainboard { - public const string Details = Hosts.Details + "/mainboard"; + public const string Details = "management/hosts/{hostId}/mainboard"; - public static string DetailsHref(string? hostId) => Details.Replace("{hostId}", hostId); + public static string DetailsHref(string? hostId) + { + return Details.Replace("{hostId}", hostId); + } } public static class Processors { - public const string Details = Hosts.Details + "/processors"; + public const string Details = "management/hosts/{hostId}/processors"; - public static string DetailsHref(string? hostId) => Details.Replace("{hostId}", hostId); + public static string DetailsHref(string? hostId) + { + return Details.Replace("{hostId}", hostId); + } } public static class Memory { - public const string Index = Hosts.Details + "/memory"; + public const string Index = "management/hosts/{hostId}/memory"; - public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId); + public static string IndexHref(string? hostId) + { + return Index.Replace("{hostId}", hostId); + } } public static class Drives { - public const string Index = Hosts.Details + "/drives"; + public const string Index = "management/hosts/{hostId}/drives"; - public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId); + public static string IndexHref(string? hostId) + { + return Index.Replace("{hostId}", hostId); + } } public static class Videocards { - public const string Index = Hosts.Details + "/videocards"; + public const string Index = "management/hosts/{hostId}/videocards"; - public static string IndexHref(string? hostId) => Index.Replace("{hostId}", hostId); + public static string IndexHref(string? hostId) + { + return Index.Replace("{hostId}", hostId); + } } } } public static class HostGroups { - public const string Index = Management.Index + "/hostgroups"; - public const string Details = Index + "/{groupId}"; - public const string Hosts = Details + "/hosts"; - public const string HostsAssign = Details + "/assign"; + public const string Index = "management/hostgroups"; + public const string Details = "management/hostgroups/{groupId}"; - public static string DetailsHref(string? groupId) => Details.Replace("{groupId}", groupId); - public static string HostsHref(string? groupId) => Hosts.Replace("{groupId}", groupId); - public static string HostsAssignHref(string? groupId) => HostsAssign.Replace("{groupId}", groupId); - } - - public static class Scheduler - { - public const string Index = Management.Index + "/scheduler"; - - public static class Jobs + public static string DetailsHref(string? groupId) { - public const string Index = Scheduler.Index + "/jobs"; - public const string Details = Index + "/{jobId}"; - public const string Tasks = Details + "/tasks"; - public const string TasksAssign = Tasks + "/assign"; - public const string Triggers = Details + "/triggers"; - public const string TriggersAssign = Triggers + "/assign"; - - public static string DetailsHref(string? jobId) => Details.Replace("{jobId}", jobId); - public static string TasksHref(string? jobId) => Tasks.Replace("{jobId}", jobId); - public static string TasksAssignHref(string? jobId) => TasksAssign.Replace("{jobId}", jobId); - public static string TriggersHref(string? jobId) => Triggers.Replace("{jobId}", jobId); - public static string TriggersAssignHref(string? jobId) => TriggersAssign.Replace("{jobId}", jobId); - } - - public static class Tasks - { - public const string Index = Scheduler.Index + "/tasks"; - public const string Details = Index + "/{taskId}"; - public const string Jobs = Details + "/jobs"; - - public static string DetailsHref(string? taskId) => Details.Replace("{taskId}", taskId); - public static string JobsHref(string? taskId) => Jobs.Replace("{taskId}", taskId); - } - - public static class Triggers - { - public const string Index = Scheduler.Index + "/triggers"; - public const string Details = Index + "/{triggerId}"; - public const string Jobs = Details + "/jobs"; - - public static string DetailsHref(string? triggerId) => Details.Replace("{triggerId}", triggerId); - public static string JobsHref(string? triggerId) => Jobs.Replace("{triggerId}", triggerId); + return Details.Replace("{groupId}", groupId); } } } public static class Inventory { - public const string Index = "inventory"; - public static class Systems { - public const string Index = Inventory.Index + "/system"; - public static class Os { - public const string Index = Systems.Index + "/os"; - public const string Hosts = Index + "/{osName}/hosts"; - public const string Guests = Index + "/{osName}/guests"; + public const string Index = "inventory/os"; + public const string Hosts = "inventory/os/{osName}/hosts"; + public const string Guests = "inventory/os/{osName}/guests"; - public static string HostsHref(string? osName) => Hosts.Replace("{osName}", osName); - public static string GuestsHref(string? osName) => Guests.Replace("{osName}", osName); + public static string HostsHref(string? osName) + { + return Hosts.Replace("{osName}", osName); + } + + public static string GuestsHref(string? osName) + { + return Guests.Replace("{osName}", osName); + } } public static class Updates { - public const string Index = Systems.Index + "/updates"; - public const string Hosts = Index + "/{updateName}/hosts"; + public const string Index = "inventory/updates"; + public const string Hosts = "inventory/updates/{updateName}/hosts"; - public static string HostsHref(string? updateName) => Hosts.Replace("{updateName}", updateName); + public static string HostsHref(string? updateName) + { + return Hosts.Replace("{updateName}", updateName); + } } public static class Software { - public const string Index = Systems.Index + "/software"; - public const string Hosts = Index + "/{softwareName}/hosts"; + public const string Index = "inventory/software"; + public const string Hosts = "inventory/software/{softwareName}/hosts"; - public static string HostsHref(string? software) => Hosts.Replace("{softwareName}", software); + public static string HostsHref(string? software) + { + return Hosts.Replace("{softwareName}", software); + } } public static class Services { - public const string Index = Systems.Index + "/services"; - public const string Hosts = Index + "/{serviceName}/hosts"; + public const string Index = "inventory/services"; + public const string Hosts = "inventory/services/{serviceName}/hosts"; - public static string HostsHref(string? serviceName) => Hosts.Replace("{serviceName}", serviceName); + public static string HostsHref(string? serviceName) + { + return Hosts.Replace("{serviceName}", serviceName); + } } public static class Sessions { - public const string Index = Systems.Index + "/sessions"; + public const string Index = "inventory/sessions"; } public static class Printers { - public const string Index = Systems.Index + "/printers"; + public const string Index = "inventory/printers"; } public static class Volumes { - public const string Index = Systems.Index + "/volumes"; + public const string Index = "inventory/volumes"; } public static class Users { - public const string Index = Systems.Index + "/users"; - public const string Hosts = Index + "/{userName}/hosts"; + public const string Index = "inventory/users"; + public const string Hosts = "inventory/users/{userName}/hosts"; - public static string HostsHref(string? userName) => Hosts.Replace("{userName}", userName); + public static string HostsHref(string? userName) + { + return Hosts.Replace("{userName}", userName); + } } public static class Groups { - public const string Index = Systems.Index + "/groups"; - public const string Hosts = Index + "/{groupName}/hosts"; + public const string Index = "inventory/groups"; + public const string Hosts = "inventory/groups/{groupName}/hosts"; - public static string HostsHref(string? groupName) => Hosts.Replace("{groupName}", groupName); + public static string HostsHref(string? groupName) + { + return Hosts.Replace("{groupName}", groupName); + } } public static class StoragePools { - public const string Index = Systems.Index + "/storagepools"; + public const string Index = "inventory/storagepools"; } public static class VirtualMaschines { - public const string Index = Systems.Index + "/virtualmaschines"; + public const string Index = "inventory/virtualmaschines"; } } public static class Network { - public const string Index = Inventory.Index + "/network"; - public static class Interfaces { - public const string Index = Network.Index + "/interfaces"; + public const string Index = "inventory/interfaces"; } public static class Addresses { - public const string Index = Network.Index + "/addresses"; - public const string Hosts = Index + "/{address}/hosts"; + public const string Index = "inventory/addresses"; + public const string Hosts = "inventory/addresses/{address}/hosts"; - public static string HostsHref(string? address) => Hosts.Replace("{address}", address); + public static string HostsHref(string? address) + { + return Hosts.Replace("{address}", address); + } } public static class Nameservers { - public const string Index = Network.Index + "/nameservers"; - public const string Hosts = Index + "/{nameserverAddress}/hosts"; + public const string Index = "inventory/nameservers"; + public const string Hosts = "inventory/nameservers/{nameserverAddress}/hosts"; - public static string HostsHref(string? nameserverAddress) => Hosts.Replace("{nameserverAddress}", nameserverAddress); + public static string HostsHref(string? nameserverAddress) + { + return Hosts.Replace("{nameserverAddress}", nameserverAddress); + } } public static class Gateways { - public const string Index = Network.Index + "/gateways"; - public const string Hosts = Index + "/{gatewayAddress}/hosts"; + public const string Index = "inventory/gateways"; + public const string Hosts = "inventory/gateways/{gatewayAddress}/hosts"; - public static string HostsHref(string? gatewayAddress) => Hosts.Replace("{gatewayAddress}", gatewayAddress); + public static string HostsHref(string? gatewayAddress) + { + return Hosts.Replace("{gatewayAddress}", gatewayAddress); + } } public static class Routes { - public const string Index = Network.Index + "/routes"; - public const string Hosts = Index + "/{routeAddress}/hosts"; + public const string Index = "inventory/routes"; + public const string Hosts = "inventory/routes/{routeAddress}/hosts"; - public static string HostsHref(string? routeAddress) => Hosts.Replace("{routeAddress}", routeAddress); + public static string HostsHref(string? routeAddress) + { + return Hosts.Replace("{routeAddress}", routeAddress); + } } } public static class Hardware { - public const string Index = Inventory.Index + "/hardware"; - public static class Mainboards { - public const string Index = Hardware.Index + "/mainboards"; - public const string Hosts = Index + "/{mainboardName}/hosts"; + public const string Index = "inventory/mainboards"; + public const string Hosts = "inventory/mainboards/{mainboardName}/hosts"; - public static string HostsHref(string? mainboardName) => Hosts.Replace("{mainboardName}", mainboardName); + public static string HostsHref(string? mainboardName) + { + return Hosts.Replace("{mainboardName}", mainboardName); + } } public static class Processors { - public const string Index = Hardware.Index + "/processors"; - public const string Hosts = Index + "/{processorName}/hosts"; + public const string Index = "inventory/processors"; + public const string Hosts = "inventory/processors/{processorName}/hosts"; - public static string HostsHref(string? processorName) => Hosts.Replace("{processorName}", processorName); + public static string HostsHref(string? processorName) + { + return Hosts.Replace("{processorName}", processorName); + } } public static class Memory { - public const string Index = Hardware.Index + "/memory"; - public const string Hosts = Index + "/{memoryName}/hosts"; + public const string Index = "inventory/memory"; + public const string Hosts = "inventory/memory/{memoryName}/hosts"; - public static string HostsHref(string? memoryName) => Hosts.Replace("{memoryName}", memoryName); + public static string HostsHref(string? memoryName) + { + return Hosts.Replace("{memoryName}", memoryName); + } } public static class Drives { - public const string Index = Hardware.Index + "/drives"; - public const string Hosts = Index + "/{driveName}/hosts"; + public const string Index = "inventory/drives"; + public const string Hosts = "inventory/drives/{driveName}/hosts"; - public static string HostsHref(string? driveName) => Hosts.Replace("{driveName}", driveName); + public static string HostsHref(string? driveName) + { + return Hosts.Replace("{driveName}", driveName); + } } public static class Videocards { - public const string Index = Hardware.Index + "/videocards"; - public const string Hosts = Index + "/{videocardName}/hosts"; + public const string Index = "inventory/videocards"; + public const string Hosts = "inventory/videocards/{videocardName}/hosts"; - public static string HostsHref(string? videocardName) => Hosts.Replace("{videocardName}", videocardName); + public static string HostsHref(string? videocardName) + { + return Hosts.Replace("{videocardName}", videocardName); + } } } } + + public static class Communication + { + public const string Index = "communication"; + + public static class Chat + { + public const string Index = "communication/chat"; + } + } } \ No newline at end of file diff --git a/src/Web/Insight.Web/Constants/Themes.cs b/src/Web/Insight.Web/Constants/Themes.cs index 666b4cb..b90d391 100644 --- a/src/Web/Insight.Web/Constants/Themes.cs +++ b/src/Web/Insight.Web/Constants/Themes.cs @@ -85,7 +85,7 @@ public static class Themes FontWeight = 400, LineHeight = 1.43, LetterSpacing = "normal", - FontFamily = ["Public Sans", "Roboto", "Arial", "sans-serif"] + FontFamily = new string[] { "Public Sans", "Roboto", "Arial", "sans-serif" } }, H1 = new H1 { diff --git a/src/Web/Insight.Web/Extensions/NavigationManagerExtensions.cs b/src/Web/Insight.Web/Extensions/NavigationManagerExtensions.cs index 4c61a23..651f893 100644 --- a/src/Web/Insight.Web/Extensions/NavigationManagerExtensions.cs +++ b/src/Web/Insight.Web/Extensions/NavigationManagerExtensions.cs @@ -10,7 +10,7 @@ public static class NavigationManagerExtensions public static Dictionary GetQueryString(this NavigationManager navigationManager) { var uri = navigationManager.ToAbsoluteUri(navigationManager.Uri); - if (uri is null) return []; + if (uri is null) return new Dictionary(); return QueryHelpers.ParseQuery(uri.Query); } @@ -19,9 +19,9 @@ public static class NavigationManagerExtensions { var queryString = GetQueryString(navigationManager); - if (queryString.TryGetValue(key, out StringValues keyValues)) + if (queryString.ContainsKey(key)) { - if (keyValues == value) return; + if (queryString[key] == value) return; queryString[key] = value; } else @@ -49,10 +49,11 @@ public static class NavigationManagerExtensions url = RemoveQueryStringByKey(url, key); } - var query = new Dictionary(); - + var query = new Dictionary(); foreach (var keys in queryString.Where(x => string.IsNullOrWhiteSpace(x.Value) is false)) - query.Add(keys.Key, keys.Value); + { + query.Add(keys.Key, keys.Value.ToString()); + } return QueryHelpers.AddQueryString(url, query); } diff --git a/src/Web/Insight.Web/Extensions/ServiceExtensions.cs b/src/Web/Insight.Web/Extensions/ServiceExtensions.cs index 79b37e3..46fc119 100644 --- a/src/Web/Insight.Web/Extensions/ServiceExtensions.cs +++ b/src/Web/Insight.Web/Extensions/ServiceExtensions.cs @@ -1,57 +1,13 @@ using Blazored.LocalStorage; using Blazored.SessionStorage; -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Infrastructure; -using Insight.Web.Network.Broker; -using Insight.Web.Network.Broker.Handlers; -using Insight.Web.Network.Remote; -using Insight.Web.Network.Remote.Handlers; using Insight.Web.Services; using Microsoft.AspNetCore.Components.Server.Circuits; using MudBlazor.Services; -using OpenTelemetry.Metrics; -using OpenTelemetry.Resources; -using System.Net; -using Vaitr.Network; -using Vaitr.Network.Hosting; -namespace Insight.Web.Extensions; +namespace Insight.Web.Hosting; public static class ServiceExtensions { - internal static WebApplicationBuilder AddMetrics(this WebApplicationBuilder builder) - { - builder.Services.AddOpenTelemetry() - .WithMetrics(provider => - { - provider.ConfigureResource(configure => - { - configure.Clear(); - configure.AddService(builder.Configuration.GetValue(Appsettings.Influx.Service) ?? throw new Exception($"{Appsettings.Influx.Service} value not set (appsettings)")); - }) - .AddRuntimeInstrumentation() - .AddProcessInstrumentation() - .AddAspNetCoreInstrumentation() - .AddHttpClientInstrumentation() - //.AddMeter("test") - .AddInfluxDBMetricsExporter(configure => - { - configure.Endpoint = builder.Configuration.GetValue(Appsettings.Influx.Endpoint) ?? throw new Exception($"{Appsettings.Influx.Endpoint} value not set (appsettings)"); - configure.Token = builder.Configuration.GetValue(Appsettings.Influx.Token) ?? throw new Exception($"{Appsettings.Influx.Token} value not set (appsettings)"); - configure.Org = builder.Configuration.GetValue(Appsettings.Influx.Organization) ?? throw new Exception($"{Appsettings.Influx.Organization} value not set (appsettings)"); - configure.Bucket = builder.Configuration.GetValue(Appsettings.Influx.Bucket) ?? throw new Exception($"{Appsettings.Influx.Bucket} value not set (appsettings)"); - - configure.MetricExportIntervalMilliseconds = 1000; - }); - } - ); - - //builder.Services.AddSingleton(); - - return builder; - } - internal static IServiceCollection AddWebServices(this IServiceCollection services) { // HOSTS @@ -86,46 +42,4 @@ public static class ServiceExtensions return services; } - - internal static IServiceCollection AddBrokerServices(this IServiceCollection services, IConfiguration configuration) - { - services.UseHostedClient(options => - { - options.Host = configuration.GetValue(Appsettings.Backend.Host) ?? throw new Exception($"{Appsettings.Backend.Host} value not set (appsettings)"); - options.Port = configuration.GetValue(Appsettings.Backend.Port) ?? throw new Exception($"{Appsettings.Backend.Port} value not set (appsettings)"); - options.Keepalive = 10000; - options.Timeout = 30000; - options.Encryption = Encryption.Tls12; - options.Compression = true; - - options.UseSerializer>(); - }); - - services.AddSingleton, AgentHandler>(); - - return services; - } - - internal static IServiceCollection AddRemoteServices(this IServiceCollection services, IConfiguration configuration) - { - services.UseHostedServer(options => - { - options.Address = IPAddress.Any; - options.Port = configuration.GetValue(Appsettings.Remote.Port) ?? throw new Exception($"{Appsettings.Remote.Port} value not set (appsettings)"); - options.Keepalive = 10000; - options.Timeout = 30000; - options.Backlog = 128; - - options.Compression = true; - options.Encryption = Encryption.Tls12; - options.Certificate = configuration.GetValue(Appsettings.Remote.Certificate) ?? throw new Exception($"{Appsettings.Remote.Certificate} value not set (appsettings)"); - options.CertificatePassword = configuration.GetValue(Appsettings.Remote.CertificatePassword) ?? throw new Exception($"{Appsettings.Remote.CertificatePassword} value not set (appsettings)"); - - options.UseSerializer>(); - }); - - services.AddSingleton, RemoteHandler>(); - - return services; - } } \ No newline at end of file diff --git a/src/Web/Insight.Web/Insight.Web.csproj b/src/Web/Insight.Web/Insight.Web.csproj index 0cba988..19ffdd0 100644 --- a/src/Web/Insight.Web/Insight.Web.csproj +++ b/src/Web/Insight.Web/Insight.Web.csproj @@ -1,11 +1,12 @@  - net8.0 + net7.0 latest Insight web - 2023.12.14.0 + 2025.2.24.0 + 2025.2.24.0 Insight.Web enable enable @@ -18,45 +19,40 @@ - none - BL0007 + none - none - BL0007 + none - - - - - - - - - + + - - + + + + + + + + + + + - + + - - - PreserveNewest - - - diff --git a/src/Web/Insight.Web/Messages/RemoteMessages.cs b/src/Web/Insight.Web/Messages/RemoteMessages.cs deleted file mode 100644 index 6feebaa..0000000 --- a/src/Web/Insight.Web/Messages/RemoteMessages.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Insight.Web.Network.Remote; - -namespace Insight.Web.Messages; - -public class RemoteMessages -{ - public record RemoteConnected(RemoteSession RemoteSession); - public record RemoteDisconnected(RemoteSession RemoteSession); -} diff --git a/src/Web/Insight.Web/Middleware/IdentityMiddleware.cs b/src/Web/Insight.Web/Middleware/IdentityMiddleware.cs index f2d3f14..24d8763 100644 --- a/src/Web/Insight.Web/Middleware/IdentityMiddleware.cs +++ b/src/Web/Insight.Web/Middleware/IdentityMiddleware.cs @@ -1,4 +1,5 @@ -using Insight.Infrastructure.Entities; +using Insight.Infrastructure; +using Insight.Infrastructure.Entities; using Insight.Web.Constants; using Insight.Web.Models.Account; using Microsoft.AspNetCore.Authentication; @@ -8,66 +9,72 @@ using System.Collections.Concurrent; namespace Insight.Web.Middleware; -public class IdentityMiddleware(RequestDelegate next, ILogger logger) +public class IdentityMiddleware { public static IDictionary Logins { get; private set; } = new ConcurrentDictionary(); public static IDictionary Passwords { get; private set; } = new ConcurrentDictionary(); - private RequestDelegate Next { get; } = next; - private ILogger Logger { get; } = logger; + private RequestDelegate Next { get; } + private ILogger Logger { get; } + + public IdentityMiddleware(RequestDelegate next, ILogger logger) + { + Next = next; + Logger = logger; + } public async Task Invoke(HttpContext context, IServiceProvider serviceProvider) { try { - if (context.Request.Path.Value is not null) + // skip blazor / internal requests + if (context.Request.Path.Value.StartsWith("/_blazor")) return; + if (context.Request.Path.Value.StartsWith("/_framework")) return; + if (context.Request.Path.Value.StartsWith("/_content")) return; + if (context.Request.Path.Value.StartsWith("/css")) return; + if (context.Request.Path.Value.StartsWith("/fonts")) return; + if (context.Request.Path.Value.StartsWith("/media")) return; + if (context.Request.Path.Value.StartsWith("/js")) return; + if (context.Request.Path.Value.StartsWith("/favicon")) return; + + //Logger.LogWarning($"{context.Request.Path}"); + + // skip hub request (test) + if (context.Request.Path.Value.StartsWith("/hub")) return; + + + // ignore 2fa login request + if (context.Request.Path.Value.StartsWith($"/{Navigation.Account.LoginTFA}")) return; + + // ignore login request + if (context.Request.Path.Value.StartsWith($"/{Navigation.Account.Login}")) return; + + // 2fa signin request + if (context.Request.Path.Value.StartsWith($"/{Navigation.Account.SignInTFA}")) { - // skip blazor / internal requests - if (context.Request.Path.Value.StartsWith("/_blazor")) return; - if (context.Request.Path.Value.StartsWith("/_framework")) return; - if (context.Request.Path.Value.StartsWith("/_content")) return; - if (context.Request.Path.Value.StartsWith("/css")) return; - if (context.Request.Path.Value.StartsWith("/fonts")) return; - if (context.Request.Path.Value.StartsWith("/media")) return; - if (context.Request.Path.Value.StartsWith("/js")) return; - if (context.Request.Path.Value.StartsWith("/favicon")) return; + await OnSignInTFAAsync(context, serviceProvider).ConfigureAwait(false); + return; + } - // skip hub request (test) - if (context.Request.Path.Value.StartsWith("/hub")) return; + // signin request + if (context.Request.Path.Value.StartsWith($"/{Navigation.Account.SignIn}")) + { + await OnSignInAsync(context, serviceProvider).ConfigureAwait(false); + return; + } - // ignore 2fa login request - if (context.Request.Path.Value.StartsWith($"/{Navigation.Account.LoginTFA}")) return; + // logout request + if (context.Request.Path.Value.StartsWith($"/{Navigation.Account.Logout}")) + { + await OnLogoutAsync(context, serviceProvider).ConfigureAwait(false); + return; + } - // ignore login request - if (context.Request.Path.Value.StartsWith($"/{Navigation.Account.Login}")) return; - - // 2fa signin request - if (context.Request.Path.Value.StartsWith($"/{Navigation.Account.SignInTFA}")) - { - await OnSignInTFAAsync(context, serviceProvider).ConfigureAwait(false); - return; - } - - // signin request - if (context.Request.Path.Value.StartsWith($"/{Navigation.Account.SignIn}")) - { - await OnSignInAsync(context, serviceProvider).ConfigureAwait(false); - return; - } - - // logout request - if (context.Request.Path.Value.StartsWith($"/{Navigation.Account.Logout}")) - { - await OnLogoutAsync(context, serviceProvider).ConfigureAwait(false); - return; - } - - //password change request - if (context.Request.Path.Value.StartsWith($"/{Navigation.Account.ChangePassword}")) - { - await OnChangePasswordAsync(context, serviceProvider).ConfigureAwait(false); - return; - } + //password change request + if (context.Request.Path.Value.StartsWith($"/{Navigation.Account.ChangePassword}")) + { + await OnChangePasswordAsync(context, serviceProvider).ConfigureAwait(false); + return; } await OnCatchRoute(context, serviceProvider).ConfigureAwait(false); @@ -81,7 +88,7 @@ public class IdentityMiddleware(RequestDelegate next, ILogger>(); var signInManager = scope.ServiceProvider.GetRequiredService>(); - if (await userManager.FindByEmailAsync(Logins[key].Email ?? string.Empty) is not InsightUser user) + if (await userManager.FindByEmailAsync(Logins[key].Email) is not InsightUser user) { - context.Response.Redirect($"/{Navigation.Account.LoginHref(Logins[key].Redirect ?? string.Empty)}"); + context.Response.Redirect($"/{Navigation.Account.LoginHref(Logins[key].Redirect)}"); return; } - if (Logins[key].Password is not string password || await userManager.CheckPasswordAsync(user, password) is false) + if (await userManager.CheckPasswordAsync(user, Logins[key].Password) is false) { - context.Response.Redirect($"/{Navigation.Account.LoginHref(Logins[key].Redirect ?? string.Empty)}"); + context.Response.Redirect($"/{Navigation.Account.LoginHref(Logins[key].Redirect)}"); return; } if (await userManager.GetTwoFactorEnabledAsync(user)) { - var result = await signInManager.PasswordSignInAsync(user.UserName ?? string.Empty, Logins[key].Password ?? string.Empty, Logins[key].RememberMe, lockoutOnFailure: false).ConfigureAwait(false); + var result = await signInManager.PasswordSignInAsync(user.UserName, Logins[key].Password, Logins[key].RememberMe, lockoutOnFailure: false).ConfigureAwait(false); context.Response.Redirect($"/{Navigation.Account.LoginTFAHref(key)}"); return; } @@ -140,7 +147,7 @@ public class IdentityMiddleware(RequestDelegate next, ILogger>(); var signInManager = scope.ServiceProvider.GetRequiredService>(); - if (Logins[key].Email is not string email) return; + var user = await userManager.FindByEmailAsync(Logins[key].Email).ConfigureAwait(false); - var user = await userManager.FindByEmailAsync(email).ConfigureAwait(false); - if (user is null) return; - - var authenticatorCode = Logins[key].TwoFactorToken?.Replace(" ", string.Empty).Replace("-", string.Empty); - if (authenticatorCode is null) return; + var authenticatorCode = Logins[key].TwoFactorToken.Replace(" ", string.Empty).Replace("-", string.Empty); var valid = await userManager.VerifyTwoFactorTokenAsync(user, userManager.Options.Tokens.AuthenticatorTokenProvider, authenticatorCode).ConfigureAwait(false); if (valid is false) @@ -205,12 +209,12 @@ public class IdentityMiddleware(RequestDelegate next, ILogger>(); @@ -229,23 +233,24 @@ public class IdentityMiddleware(RequestDelegate next, ILogger>(); - // await signInManager.SignOutAsync().ConfigureAwait(false); + using var scope = serviceProvider.CreateScope(); + var signInManager = scope.ServiceProvider.GetRequiredService>(); + await signInManager.SignOutAsync().ConfigureAwait(false); - // context.Abort(); - //} + context.Abort(); + } private async ValueTask OnChangePasswordAsync(HttpContext context, IServiceProvider serviceProvider) { - Logger.LogInformation("OnChangePasswordAsync ({context})", context.Request.Path); + Logger.LogInformation($"OnChangePasswordAsync ({context.Request.Path})"); if (context.Request.Query.ContainsKey("key") is false) return; - if (Guid.TryParse(context.Request.Query["key"], out var key) is false) return; + + var key = Guid.Parse(context.Request.Query["key"]); try { @@ -253,14 +258,11 @@ public class IdentityMiddleware(RequestDelegate next, ILogger>(); var user = await userManager.GetUserAsync(context.User).ConfigureAwait(false); - if (user is null) return; - - if (Passwords[key]?.OldPassword is string pwOld && Passwords[key]?.NewPassword is string pwNew) - _ = await userManager.ChangePasswordAsync(user, pwOld, pwNew).ConfigureAwait(false); + var result = await userManager.ChangePasswordAsync(user, Passwords[key]?.OldPassword, Passwords[key]?.NewPassword).ConfigureAwait(false); } catch (Exception ex) { - Logger.LogError("{exception}", ex.ToString()); + Logger.LogError(ex.ToString()); } finally { @@ -281,9 +283,10 @@ public class IdentityMiddleware(RequestDelegate next, ILogger members, - Func onMessageSent) +public class ChatSession { public ObjectId Id { get; } = ObjectId.GenerateNewId(); - public IEnumerable Members { get; } = members; - public ConcurrentBag Messages { get; } = []; + public IEnumerable Members { get; } + public ConcurrentBag Messages { get; } = new(); - private readonly Func OnMessageSent = onMessageSent; + private readonly Func OnMessageSent; + + public ChatSession(IEnumerable members, Func onMessageSent) + { + Members = members; + OnMessageSent = onMessageSent; + } public async Task SendMessage(ChatUser sender, string message, CancellationToken cancellationToken) { diff --git a/src/Web/Insight.Web/Models/ChatUser.cs b/src/Web/Insight.Web/Models/ChatUser.cs index 9799690..35c9713 100644 --- a/src/Web/Insight.Web/Models/ChatUser.cs +++ b/src/Web/Insight.Web/Models/ChatUser.cs @@ -2,14 +2,19 @@ namespace Insight.Web.Models; -public class ChatUser(ObjectId uid) +public class ChatUser { - public ObjectId Uid { get; set; } = uid; + public ObjectId Uid { get; set; } public bool Online { get; set; } public string? Username { get; set; } public string? Email { get; set; } public byte[]? Avatar { get; set; } + public ChatUser(ObjectId uid) + { + Uid = uid; + } + public override bool Equals(object? obj) { if (obj == null || GetType() != obj.GetType()) return false; diff --git a/src/Web/Insight.Web/Models/RemoteClient.cs b/src/Web/Insight.Web/Models/RemoteClient.cs deleted file mode 100644 index 4a117e5..0000000 --- a/src/Web/Insight.Web/Models/RemoteClient.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Insight.Web.Models; - -public record RemoteClientConnected(string Id); -public record RemoteClientDisconnected(string Id); \ No newline at end of file diff --git a/src/Web/Insight.Web/Network/Broker/Handlers/AgentHandler.cs b/src/Web/Insight.Web/Network/Broker/Handlers/AgentHandler.cs deleted file mode 100644 index 9071353..0000000 --- a/src/Web/Insight.Web/Network/Broker/Handlers/AgentHandler.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Agent.Messages; -using Vaitr.Bus; - -namespace Insight.Web.Network.Broker.Handlers; - -public class AgentHandler(Bus bus) : IMessageHandler -{ - private readonly Bus _bus = bus; - - public async ValueTask HandleAsync(WebSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage - { - if (message is Proxy consoleQuery) - { - await _bus.PublishAsync(consoleQuery, cancellationToken); - } - } -} \ No newline at end of file diff --git a/src/Web/Insight.Web/Network/Broker/WebSession.cs b/src/Web/Insight.Web/Network/Broker/WebSession.cs deleted file mode 100644 index db743ac..0000000 --- a/src/Web/Insight.Web/Network/Broker/WebSession.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Vaitr.Network; - -namespace Insight.Web.Network.Broker; - -public class WebSession( - IEnumerable> handlers, - ISerializer serializer, - ILogger logger) : TcpSession(serializer, logger) -{ - private readonly IEnumerable> _handlers = handlers; - - protected override ValueTask OnConnectedAsync(CancellationToken cancellationToken) - { - _logger.LogInformation("Web ({ep?}) connected", RemoteEndPoint); - return default; - } - - protected override ValueTask OnDisconnectedAsync(CancellationToken cancellationToken) - { - _logger.LogInformation("Web ({ep?}) disconnected", RemoteEndPoint); - return default; - } - - protected override ValueTask OnSentAsync(IPacketContext context, CancellationToken cancellationToken) - { - return base.OnSentAsync(context, cancellationToken); - } - - protected override async ValueTask OnReceivedAsync(IPacketContext context, CancellationToken cancellationToken) - { - await base.OnReceivedAsync(context, cancellationToken); - - foreach (var handler in _handlers) - { - try - { - await handler.HandleAsync(this, context.Packet, cancellationToken); - } - catch (Exception ex) - { - _logger.LogWarning("Web ({ep?}) {ex}", RemoteEndPoint, ex.ToString()); - } - } - } - - protected override ValueTask OnHeartbeatAsync(CancellationToken cancellationToken) - { - _logger.LogInformation("Web ({ep?}) Heartbeat", RemoteEndPoint); - return default; - } -} \ No newline at end of file diff --git a/src/Web/Insight.Web/Network/Handlers/ConsoleHandler.cs b/src/Web/Insight.Web/Network/Handlers/ConsoleHandler.cs new file mode 100644 index 0000000..26cb7df --- /dev/null +++ b/src/Web/Insight.Web/Network/Handlers/ConsoleHandler.cs @@ -0,0 +1,24 @@ +using Insight.Web.Interfaces; +using Insight.Web.Messages; +using Vaitr.MemoryBus; + +namespace Insight.Web.Network.Handlers +{ + public class ConsoleHandler : IWebMessageHandler + { + private readonly IMemoryBus _bus; + + public ConsoleHandler(IMemoryBus bus) + { + _bus = bus; + } + + public async ValueTask HandleAsync(WebSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IWebMessage + { + if (message is ConsoleQueryProxy consoleQuery) + { + await _bus.PublishAsync(consoleQuery, cancellationToken); + } + } + } +} \ No newline at end of file diff --git a/src/Web/Insight.Web/Network/Remote/Handlers/RemoteHandler.cs b/src/Web/Insight.Web/Network/Remote/Handlers/RemoteHandler.cs deleted file mode 100644 index 71d57a0..0000000 --- a/src/Web/Insight.Web/Network/Remote/Handlers/RemoteHandler.cs +++ /dev/null @@ -1,100 +0,0 @@ -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Remote.Messages; -using Vaitr.Bus; - -namespace Insight.Web.Network.Remote.Handlers; - -public class RemoteHandler( - Bus bus, - ILogger logger) : IMessageHandler -{ - private readonly Bus _bus = bus; - private readonly ILogger _logger = logger; - - public async ValueTask HandleAsync(RemoteSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage - { - if (message is RemoteSessionRequest sessionRequest) - { - await OnSessionRequest(sender, sessionRequest, cancellationToken); - } - else if (message is CastRequestResponse castRequestResponse) - { - await OnCastRequestResponse(sender, castRequestResponse, cancellationToken); - } - else if (message is CastMetric metricData) - { - await OnMetricData(sender, metricData, cancellationToken); - } - else if (message is CastScreen screenData) - { - await OnScreenData(sender, screenData, cancellationToken); - } - else if (message is CastCursor cursorData) - { - await OnCursorData(sender, cursorData, cancellationToken); - } - else if (message is CastClipboardReceived clipboardData) - { - await OnClipboardData(sender, clipboardData, cancellationToken); - } - else if (message is CastAudio audioData) - { - await OnAudioData(sender, audioData, cancellationToken); - } - } - - private async Task OnSessionRequest(RemoteSession session, RemoteSessionRequest sessionRequest, CancellationToken cancellationToken) - { - _logger.LogInformation("Remote {session} => SessionRequest", session.Id); - - session.Mode = sessionRequest.Mode; - - await session.SendAsync(new RemoteSessionResponse - { - SessionId = session.Id - }, cancellationToken); - } - - private async Task OnCastRequestResponse(RemoteSession session, CastRequestResponse castRequestResponse, CancellationToken cancellationToken) - { - _logger.LogInformation("Remote {id} => CastRequestResponse", castRequestResponse.Id); - - await _bus.PublishAsync(castRequestResponse, cancellationToken); - } - - private async Task OnMetricData(RemoteSession session, CastMetric streamMetrics, CancellationToken cancellationToken) - { - //_logger.LogInformation($"Remote {streamMetrics.Id} => MetricData"); - - await _bus.PublishAsync(streamMetrics, cancellationToken); - } - - private async Task OnScreenData(RemoteSession session, CastScreen screenData, CancellationToken cancellationToken) - { - //_logger.LogInformation($"Remote {screenData.Id} => ScreenData"); - - await _bus.PublishAsync(screenData, cancellationToken); - } - - private async Task OnCursorData(RemoteSession session, CastCursor cursorChanged, CancellationToken cancellationToken) - { - //_logger.LogInformation($"Remote {cursorChanged.Id} => CursorData"); - - await _bus.PublishAsync(cursorChanged, cancellationToken); - } - - private async Task OnClipboardData(RemoteSession session, CastClipboardReceived clipboardChanged, CancellationToken cancellationToken) - { - _logger.LogInformation("Remote {session} => ClipboardData", session.Id); - - await _bus.PublishAsync(clipboardChanged, cancellationToken); - } - - private async Task OnAudioData(RemoteSession session, CastAudio audioSample, CancellationToken cancellationToken) - { - _logger.LogInformation("Remote {session} => AudioData", session.Id); - - await _bus.PublishAsync(audioSample, cancellationToken); - } -} \ No newline at end of file diff --git a/src/Web/Insight.Web/Network/Remote/RemoteSession.cs b/src/Web/Insight.Web/Network/Remote/RemoteSession.cs deleted file mode 100644 index c9360e6..0000000 --- a/src/Web/Insight.Web/Network/Remote/RemoteSession.cs +++ /dev/null @@ -1,79 +0,0 @@ -using Insight.Domain.Enums; -using Insight.Domain.Interfaces; -using Insight.Domain.Network; -using Insight.Domain.Network.Remote.Messages; -using Vaitr.Bus; -using Vaitr.Network; -using static Insight.Web.Messages.RemoteMessages; - -namespace Insight.Web.Network.Remote; - -public class RemoteSession( - Bus bus, - IEnumerable> handlers, - ISerializer serializer, - ILogger logger) : TcpSession(serializer, logger) -{ - public string Id { get; } = GenerateRandomId(); - public RemoteControlMode Mode { get; set; } - - private readonly Bus _bus = bus; - private readonly IEnumerable> _handlers = handlers; - - protected override async ValueTask OnConnectedAsync(CancellationToken cancellationToken) - { - _logger.LogInformation("Remote ({ep?}) connected", RemoteEndPoint); - - await _bus.PublishAsync(new RemoteDisconnected(this), default); - } - - protected override async ValueTask OnDisconnectedAsync(CancellationToken cancellationToken) - { - _logger.LogInformation("Remote ({ep?}) disconnected", RemoteEndPoint); - - await _bus.PublishAsync(new RemoteDisconnected(this), default); - } - - protected override ValueTask OnSentAsync(IPacketContext context, CancellationToken cancellationToken) - { - //await base.OnSentAsync(context, cancellationToken); - return default; - } - - protected override async ValueTask OnReceivedAsync(IPacketContext context, CancellationToken cancellationToken) - { - //await base.OnReceivedAsync(context, cancellationToken); - - foreach (var handler in _handlers) - { - try - { - await handler.HandleAsync(this, context.Packet, cancellationToken); - } - catch (Exception ex) - { - _logger.LogWarning("Remote ({ep?}) {ex}", RemoteEndPoint, ex.ToString()); - } - } - } - - protected override ValueTask OnHeartbeatAsync(CancellationToken cancellationToken) - { - _logger.LogInformation("Remote ({ep?}) Heartbeat", RemoteEndPoint); - return default; - } - - public async Task ScreenDataAckAsync(CastScreen screenData, CancellationToken cancellationToken) - { - await SendAsync(new CastScreenReceived(screenData), cancellationToken); - } - - private static string GenerateRandomId() - { - var random = new Random(); - string? sessionId = string.Empty; - - for (var i = 0; i < 3; i++) sessionId += random.Next(0, 999).ToString().PadLeft(3, '0'); - return sessionId; - } -} \ No newline at end of file diff --git a/src/Web/Insight.Web/Network/WebSession.cs b/src/Web/Insight.Web/Network/WebSession.cs new file mode 100644 index 0000000..a5fa400 --- /dev/null +++ b/src/Web/Insight.Web/Network/WebSession.cs @@ -0,0 +1,29 @@ +using Insight.Web.Interfaces; +using Insight.Web.Messages; +using System.Net.Sockets; +using Vaitr.Network; + +namespace Insight.Web.Network; + +public class WebSession(IEnumerable> handlers, Socket socket, Stream stream, TcpConnectionOptions options, MemPackSerializer serializer, ILogger logger) + : TcpSession(socket, stream, options, serializer, logger) +{ + private readonly IEnumerable> _handlers = handlers; + + protected override async ValueTask OnReceivedAsync(PacketContext context, CancellationToken cancellationToken) + { + await base.OnReceivedAsync(context, cancellationToken); + + foreach (var handler in _handlers) + { + try + { + await handler.HandleAsync(this, context.Data, cancellationToken); + } + catch (Exception ex) + { + _logger.LogWarning("Web ({ep?}) {ex}", RemoteEndPoint, ex.ToString()); + } + } + } +} \ No newline at end of file diff --git a/src/Web/Insight.Web/Pages/Account/Login.razor.cs b/src/Web/Insight.Web/Pages/Account/Login.razor.cs index 3af234a..f6a9bb2 100644 --- a/src/Web/Insight.Web/Pages/Account/Login.razor.cs +++ b/src/Web/Insight.Web/Pages/Account/Login.razor.cs @@ -62,14 +62,15 @@ public partial class Login return; } - if (Key is null || IdentityMiddleware.Logins[Key.Value] is not LoginModel model) + try + { + IdentityMiddleware.Logins[Key.Value].TwoFactorToken = code; + NavigationManager.NavigateTo(Navigation.Account.SignInTFAHref(Key.Value), true); + } + catch (Exception ex) { Notification.Error(Snackbar, "Invalid Security Token"); - NavigationManager.NavigateTo(Navigation.Account.LoginHref(string.Empty), false); - return; + NavigationManager.NavigateTo(Navigation.Account.LoginHref(null), false); } - - IdentityMiddleware.Logins[Key.Value].TwoFactorToken = code; - NavigationManager.NavigateTo(Navigation.Account.SignInTFAHref(Key.Value), true); } } \ No newline at end of file diff --git a/src/Web/Insight.Web/Pages/Account/LoginTFA.razor b/src/Web/Insight.Web/Pages/Account/LoginTFA.razor new file mode 100644 index 0000000..b0de9e7 --- /dev/null +++ b/src/Web/Insight.Web/Pages/Account/LoginTFA.razor @@ -0,0 +1,32 @@ +@inherits ComponentBase + + + +@if (true) +{ + return; +} + + + +
+
+ + + + + + + Login + + + +
+
+
+
+ +@code{ + private string? _code; +} \ No newline at end of file diff --git a/src/Web/Insight.Web/Pages/Account/LoginTFA.razor.cs b/src/Web/Insight.Web/Pages/Account/LoginTFA.razor.cs new file mode 100644 index 0000000..c9df2e0 --- /dev/null +++ b/src/Web/Insight.Web/Pages/Account/LoginTFA.razor.cs @@ -0,0 +1,29 @@ +using Insight.Web.Constants; +using Insight.Web.Middleware; +using Microsoft.AspNetCore.Components; +using MudBlazor; + +namespace Insight.Web.Pages.Account; + +//[Route(Navigation.Account.LoginTFA)] +public partial class LoginTFA +{ + [Parameter] public Guid Key { get; set; } + + [Inject] private NavigationManager NavigationManager { get; init; } = default!; + [Inject] private ISnackbar Snackbar { get; init; } = default!; + + private readonly string _title = "Login|Insight"; + + private void Submit(string? code) + { + if (string.IsNullOrWhiteSpace(code)) + { + Notification.Information(Snackbar, "Enter Authenticator Code"); + return; + } + + IdentityMiddleware.Logins[Key].TwoFactorToken = code; + NavigationManager.NavigateTo(Navigation.Account.SignInTFAHref(Key), true); + } +} \ No newline at end of file diff --git a/src/Web/Insight.Web/Pages/Account/Profile.razor.cs b/src/Web/Insight.Web/Pages/Account/Profile.razor.cs index 365187a..779882e 100644 --- a/src/Web/Insight.Web/Pages/Account/Profile.razor.cs +++ b/src/Web/Insight.Web/Pages/Account/Profile.razor.cs @@ -16,12 +16,12 @@ public partial class Profile [Inject] private AuthenticationStateProvider AuthenticationStateProvider { get; init; } = default!; private readonly string _title = "Profile|Insight"; - private readonly List _breadcrumbs = - [ + private readonly List _breadcrumbs = new() + { new BreadcrumbItem("Home", href: Navigation.Home), new BreadcrumbItem("Account", href: Navigation.Account.Profile), new BreadcrumbItem("Profile", href: "#", true) - ]; + }; protected override async Task OnInitializedAsync() { diff --git a/src/Web/Insight.Web/Pages/Account/ProfileTwoFactorDialog.razor b/src/Web/Insight.Web/Pages/Account/ProfileTwoFactorDialog.razor index a4a26ae..5aced2c 100644 --- a/src/Web/Insight.Web/Pages/Account/ProfileTwoFactorDialog.razor +++ b/src/Web/Insight.Web/Pages/Account/ProfileTwoFactorDialog.razor @@ -9,11 +9,17 @@