net8, language features, bugfixes

This commit is contained in:
kkb 2023-12-18 16:31:00 +01:00
parent 1591618c2c
commit ce99053a10
353 changed files with 3245 additions and 3944 deletions

View file

@ -39,6 +39,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Insight.Remote.Shared", "sr
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
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -85,6 +87,10 @@ Global
{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
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -100,6 +106,7 @@ Global
{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}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F376A326-7590-4E7E-AB9B-76CED8527AB0}

View file

@ -2,17 +2,24 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<LangVersion>latest</LangVersion>
<RootNamespace>Insight.Agent</RootNamespace>
<Product>Insight</Product>
<AssemblyName>agent</AssemblyName>
<AssemblyVersion>2023.12.14.0</AssemblyVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<SatelliteResourceLanguages>none</SatelliteResourceLanguages>
</PropertyGroup>
<ItemGroup>
<!--WMI / System.Management-->
<RuntimeHostConfigurationOption Include="System.Runtime.Loader.UseRidGraph" Value="true" />
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>none</DebugType>
<DebugType>none</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
@ -20,14 +27,14 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="7.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0" />
<PackageReference Include="Microsoft.PowerShell.SDK" Version="7.3.10" />
<PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0" />
<PackageReference Include="System.Management" Version="7.0.2" />
<PackageReference Include="System.ServiceProcess.ServiceController" Version="7.0.1" />
<PackageReference Include="Vaitr.Snmp" Version="2023.3.3" />
<PackageReference Include="System.Management" Version="8.0.0" />
<PackageReference Include="System.ServiceProcess.ServiceController" Version="8.0.0" />
<PackageReference Include="Vaitr.Snmp" Version="2023.12.15.1" />
</ItemGroup>
<ItemGroup>

View file

@ -5,14 +5,10 @@ using Vaitr.Network;
namespace Insight.Agent.Network;
public class AgentSession : TcpSession<IMessage>
public class AgentSession(IEnumerable<IMessageHandler<AgentSession>> handlers, ISerializer<IMessage> serializer, ILogger<AgentSession> logger)
: TcpSession<IMessage>(serializer, logger)
{
private readonly IEnumerable<IMessageHandler<AgentSession>> _handlers;
public AgentSession(IEnumerable<IMessageHandler<AgentSession>> handlers, ISerializer<IMessage> serializer, ILogger<AgentSession> logger) : base(serializer, logger)
{
_handlers = handlers;
}
private readonly IEnumerable<IMessageHandler<AgentSession>> _handlers = handlers;
protected override ValueTask OnConnectedAsync(CancellationToken cancellationToken)
{

View file

@ -2,20 +2,12 @@
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
using Microsoft.Extensions.Logging;
namespace Insight.Agent.Network.Handlers;
public class CustomHandler : IMessageHandler<AgentSession>
public class CustomHandler(ScriptService scriptService) : IMessageHandler<AgentSession>
{
private readonly ScriptService _scriptService;
private readonly ILogger<CustomHandler> _logger;
public CustomHandler(ScriptService scriptService, ILogger<CustomHandler> logger)
{
_scriptService = scriptService;
_logger = logger;
}
private readonly ScriptService _scriptService = scriptService;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
@ -29,6 +21,7 @@ public class CustomHandler : IMessageHandler<AgentSession>
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)

View file

@ -59,7 +59,7 @@ public class DriveHandler : IMessageHandler<AgentSession>
drive.InterfaceType = @object.GetValue<string>(properties, "interfacetype")?.Trim();
drive.FirmwareRevision = @object.GetValue<string>(properties, "firmwarerevision")?.Trim();
drive.PNPDeviceID = @object.GetValue<string>(properties, "pnpdeviceid")?.Trim();
drive.Volumes = new List<Volume>();
drive.Volumes = [];
var diskpartition = @object.GetRelated("win32_diskpartition");
using (diskpartition)
@ -155,7 +155,7 @@ public class DriveHandler : IMessageHandler<AgentSession>
{
using (collection2)
{
foreach (ManagementObject @object2 in collection2)
foreach (ManagementObject @object2 in collection2.Cast<ManagementObject>())
{
var properties2 = @object2.GetPropertyHashes();

View file

@ -19,7 +19,7 @@ public class InterfaceHandler : IMessageHandler<AgentSession>
case InventoryRequest:
{
var result = new Collection<Interface>();
result.AddRange(GetInterfaces());
if (GetInterfaces() is List<Interface> interfaces) result.AddRange(interfaces);
await sender.SendAsync(result, cancellationToken);
break;
@ -27,10 +27,10 @@ public class InterfaceHandler : IMessageHandler<AgentSession>
}
}
private static List<Interface> GetInterfaces()
private static List<Interface>? GetInterfaces()
{
if (NetworkInterface.GetIsNetworkAvailable() is false) return null;
if (NetworkInterface.GetAllNetworkInterfaces().Any() is false) return null;
if (NetworkInterface.GetAllNetworkInterfaces().Length == 0) return null;
var interfaces = new List<Interface>();
@ -99,7 +99,7 @@ public class InterfaceHandler : IMessageHandler<AgentSession>
using (collection)
{
foreach (ManagementObject @object in collection)
foreach (ManagementObject @object in collection.Cast<ManagementObject>())
{
var properties = @object.GetPropertyHashes();
@ -185,7 +185,7 @@ public class InterfaceHandler : IMessageHandler<AgentSession>
{
var addresses = new List<Unicast>();
if (unicastCollection.Any() is false) return addresses;
if (unicastCollection.Count == 0) return addresses;
foreach (var unicast in unicastCollection)
{
@ -210,7 +210,7 @@ public class InterfaceHandler : IMessageHandler<AgentSession>
{
var addresses = new List<IPAddress2>();
if (addressCollection.Any() is false) return addresses;
if (addressCollection.Count == 0) return addresses;
foreach (var address in addressCollection)
{
@ -224,7 +224,7 @@ public class InterfaceHandler : IMessageHandler<AgentSession>
{
var addresses = new List<IPAddress2>();
if (addressCollection.Any() is false) return addresses;
if (addressCollection.Count == 0) return addresses;
foreach (var address in addressCollection)
{

View file

@ -14,12 +14,12 @@ public class MainboardHandler : IMessageHandler<AgentSession>
switch (message)
{
case InventoryRequest:
await sender.SendAsync(GetMainboard(), cancellationToken);
if (GetMainboard() is Mainboard mainboard) await sender.SendAsync(mainboard, cancellationToken);
break;
}
}
private static Mainboard GetMainboard()
private static Mainboard? GetMainboard()
{
using var searcher = new ManagementObjectSearcher
{

View file

@ -41,7 +41,7 @@ public class OperationSystemHandler : IMessageHandler<AgentSession>
using (collection)
{
foreach (ManagementObject @object in collection)
foreach (ManagementObject @object in collection.Cast<ManagementObject>())
{
var properties = @object.GetPropertyHashes();
@ -51,7 +51,8 @@ public class OperationSystemHandler : IMessageHandler<AgentSession>
if (@object.TryGetValue<string>(properties, "osarchitecture", out var architecture))
{
if (architecture is not null && architecture.ToLower().Contains("64")) os.Architecture = Architecture.X64;
if (architecture is not null && architecture.Contains("64", StringComparison.CurrentCultureIgnoreCase))
os.Architecture = Architecture.X64;
}
else
{

View file

@ -2,20 +2,12 @@
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
using Microsoft.Extensions.Logging;
namespace Insight.Agent.Network.Handlers;
public class ProxyHandler : IMessageHandler<AgentSession>
public class ProxyHandler(ScriptService scriptService) : IMessageHandler<AgentSession>
{
private readonly ScriptService _scriptService;
private readonly ILogger<ProxyHandler> _logger;
public ProxyHandler(ScriptService scriptService, ILogger<ProxyHandler> logger)
{
_scriptService = scriptService;
_logger = logger;
}
private readonly ScriptService _scriptService = scriptService;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
@ -29,6 +21,7 @@ public class ProxyHandler : IMessageHandler<AgentSession>
private async ValueTask OnProxyRequestAsync(AgentSession sender, Proxy<Request> proxyRequest, CancellationToken cancellationToken)
{
if (proxyRequest.Message?.RequestData is null) return;
var result = await _scriptService.QueryAsync(proxyRequest.Message.RequestData);
await sender.SendAsync(new Proxy<Response>()

View file

@ -30,7 +30,7 @@ public class ServiceHandler : IMessageHandler<AgentSession>
var services = new List<Service>();
var serviceControllers = ServiceController.GetServices()?.OrderBy(s => s.DisplayName)?.ToList();
if (serviceControllers is null || serviceControllers.Any() is false) throw new InvalidOperationException("SERVICE Collection NULL");
if (serviceControllers is null || serviceControllers.Count == 0) throw new InvalidOperationException("SERVICE Collection NULL");
foreach (var sc in serviceControllers)
{
@ -102,7 +102,7 @@ public class ServiceHandler : IMessageHandler<AgentSession>
}
}
if (services2.Any() is false) return services;
if (services2.Count == 0) return services;
foreach (var svc in services)
{
@ -117,6 +117,6 @@ public class ServiceHandler : IMessageHandler<AgentSession>
svc.Delay = map.Delay;
}
return services.OrderBy(x => x.Name).ToList();
return [.. services.OrderBy(x => x.Name)];
}
}

View file

@ -48,7 +48,7 @@ public class SessionHandler : IMessageHandler<AgentSession>
//public const int WTS_CURRENT_SESSION = -1;
[DllImport("wtsapi32.dll")]
static extern int WTSEnumerateSessions(
private static extern int WTSEnumerateSessions(
nint pServer,
[MarshalAs(UnmanagedType.U4)] int iReserved,
[MarshalAs(UnmanagedType.U4)] int iVersion,
@ -64,7 +64,7 @@ public class SessionHandler : IMessageHandler<AgentSession>
out uint iBytesReturned);
[DllImport("wtsapi32.dll")]
static extern void WTSFreeMemory(
private static extern void WTSFreeMemory(
nint pMemory);
[StructLayout(LayoutKind.Sequential)]

View file

@ -89,121 +89,6 @@ public class StoragePoolHandler : IMessageHandler<AgentSession>
return pools;
}
private static List<PhysicalDisk> GetPhysicalDisks()
{
using var searcher = new ManagementObjectSearcher
{
Scope = new ManagementScope(@"root\microsoft\windows\storage"),
Query = new ObjectQuery("select objectid, uniqueid, name, friendlyname from msft_physicaldisk")
};
if (searcher.TryGet(out var collection) is false)
{
searcher.Query = new ObjectQuery("select * from msft_physicaldisk");
if (searcher.TryGet(out collection) is false) throw new InvalidOperationException("WMI Collection NULL");
}
var disks = new List<PhysicalDisk>();
using (collection)
{
foreach (ManagementObject @object in collection.Cast<ManagementObject>())
{
var disk = new PhysicalDisk();
var properties = @object.GetPropertyHashes();
disk.UniqueId = @object.GetValue<string>(properties, "uniqueid")?.Trim();
disk.FriendlyName = @object.GetValue<string>(properties, "friendlyname")?.Trim();
disk.Manufacturer = @object.GetValue<string>(properties, "manufacturer")?.Trim();
disk.Model = @object.GetValue<string>(properties, "model")?.Trim();
disk.MediaType = @object.GetValue<ushort>(properties, "mediatype");
disk.BusType = @object.GetValue<ushort>(properties, "bustype");
if (@object.TryGetValue<ushort[]>(properties, "operationalstatus", out var operationals) && operationals is not null)
{
disk.States = operationals.Select(p => (PhysicalDisk.OperationalState)p).ToList();
}
disk.Health = (PhysicalDisk.HealthState)@object.GetValue<ushort>(properties, "healthstatus");
if (@object.TryGetValue<ushort[]>(properties, "supportedusages", out var supportedusages) && supportedusages is not null)
{
disk.SupportedUsages = supportedusages.Select(p => (SupportedUsagesEnum)p).ToList();
}
disk.Usage = @object.GetValue<ushort>(properties, "usage");
disk.PhysicalLocation = @object.GetValue<string>(properties, "physicallocation")?.Trim();
disk.SerialNumber = @object.GetValue<string>(properties, "serialnumber")?.Trim();
disk.FirmwareVersion = @object.GetValue<string>(properties, "firmwareversion")?.Trim();
disk.Size = @object.GetValue<ulong>(properties, "size");
disk.AllocatedSize = @object.GetValue<ulong>(properties, "allocatedsize");
disk.LogicalSectorSize = @object.GetValue<ulong>(properties, "logicalsectorsize");
disk.PhysicalSectorSize = @object.GetValue<ulong>(properties, "physicalsectorsize");
disk.VirtualDiskFootprint = @object.GetValue<ulong>(properties, "virtualdiskfootprint");
disks.Add(disk);
}
}
return disks;
}
private static List<VirtualDisk> 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<VirtualDisk>();
using (collection)
{
foreach (ManagementObject @object in collection.Cast<ManagementObject>())
{
var disk = new VirtualDisk();
var properties = @object.GetPropertyHashes();
disk.UniqueId = @object.GetValue<string>(properties, "uniqueid")?.Trim();
disk.Name = @object.GetValue<string>(properties, "name")?.Trim();
disk.FriendlyName = @object.GetValue<string>(properties, "friendlyname")?.Trim();
disk.AccessType = (AccessTypeEnum)@object.GetValue<ushort>(properties, "access");
disk.ProvisioningType = (ProvisioningTypeEnum)@object.GetValue<ushort>(properties, "provisioningtype");
disk.PhysicalDiskRedundancy = @object.GetValue<ushort>(properties, "physicaldiskredundancy");
disk.ResiliencySettingName = @object.GetValue<string>(properties, "resiliencysettingname")?.Trim();
disk.Deduplication = @object.GetValue<bool>(properties, "isdeduplicationenabled");
disk.IsSnapshot = @object.GetValue<bool>(properties, "issnapshot");
if (@object.TryGetValue<ushort[]>(properties, "operationalstatus", out var operationals) && operationals is not null)
{
disk.States = operationals.Select(p => (VirtualDisk.OperationalState)p).ToList();
}
disk.Health = (VirtualDisk.HealthState)@object.GetValue<ushort>(properties, "healthstatus");
disk.Size = @object.GetValue<ulong>(properties, "size");
disk.AllocatedSize = @object.GetValue<ulong>(properties, "allocatedsize");
disk.FootprintOnPool = @object.GetValue<ulong>(properties, "footprintonpool");
disk.ReadCacheSize = @object.GetValue<ulong>(properties, "readcachesize");
disk.WriteCacheSize = @object.GetValue<ulong>(properties, "writecachesize");
disks.Add(disk);
}
}
return disks;
}
private static List<PhysicalDisk> QueryPhysicalDisksByStoragePool(string storagePoolObjectId)
{
using var searcher = new ManagementObjectSearcher
@ -218,7 +103,7 @@ public class StoragePoolHandler : IMessageHandler<AgentSession>
using (collection)
{
foreach (ManagementObject @object in collection)
foreach (ManagementObject @object in collection.Cast<ManagementObject>())
{
var disk = new PhysicalDisk();
@ -275,7 +160,7 @@ public class StoragePoolHandler : IMessageHandler<AgentSession>
using (collection)
{
foreach (ManagementObject @object in collection)
foreach (ManagementObject @object in collection.Cast<ManagementObject>())
{
var disk = new VirtualDisk();

View file

@ -87,7 +87,6 @@ public class SystemInfoHandler : IMessageHandler<AgentSession>
private static string GetWindowsProductKeyFromDigitalProductId(byte[] digitalProductId, DigitalProductIdVersion digitalProductIdVersion)
{
var productKey = digitalProductIdVersion == DigitalProductIdVersion.Windows8AndUp
? DecodeProductKeyWin8AndUp(digitalProductId)
: DecodeProductKey(digitalProductId);
@ -124,7 +123,7 @@ public class SystemInfoHandler : IMessageHandler<AgentSession>
var digitMapIndex = 0;
for (var j = decodeStringLength - 1; j >= 0; j--)
{
var byteValue = digitMapIndex << 8 | (byte)hexPid[j];
var byteValue = digitMapIndex << 8 | (byte)hexPid[j]!;
hexPid[j] = (byte)(byteValue / 24);
digitMapIndex = byteValue % 24;
decodedChars[i] = digits[digitMapIndex];
@ -148,17 +147,17 @@ public class SystemInfoHandler : IMessageHandler<AgentSession>
var current = 0;
for (var j = 14; j >= 0; j--)
{
current = current * 256;
current *= 256;
current = digitalProductId[j + keyOffset] + current;
digitalProductId[j + keyOffset] = (byte)(current / 24);
current = current % 24;
current %= 24;
last = current;
}
key = digits[current] + key;
}
var keypart1 = key.Substring(1, last);
var keypart2 = key.Substring(last + 1, key.Length - (last + 1));
var keypart2 = key[(last + 1)..];
key = keypart1 + "N" + keypart2;
for (var i = 5; i < key.Length; i += 6)

View file

@ -10,7 +10,7 @@ using UpdateCollection = Insight.Domain.Network.Agent.Messages.UpdateCollection;
namespace Insight.Agent.Network.Handlers;
[SupportedOSPlatform("windows")]
public class UpdateHandler : IMessageHandler<AgentSession>
public partial class UpdateHandler : IMessageHandler<AgentSession>
{
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
@ -60,7 +60,7 @@ public class UpdateHandler : IMessageHandler<AgentSession>
try
{
var rx = new Regex(@"KB(\d+)");
var rx = KnowledgeBaseRegex();
update.Hotfix = rx.Match(wupdate.Title).Value;
}
catch (Exception)
@ -125,4 +125,7 @@ public class UpdateHandler : IMessageHandler<AgentSession>
return updates;
}
[GeneratedRegex(@"KB(\d+)")]
private static partial Regex KnowledgeBaseRegex();
}

View file

@ -32,7 +32,7 @@ public class UserHandler : IMessageHandler<AgentSession>
foreach (var u in users)
{
u.Groups = new List<Group>();
u.Groups = [];
foreach (var ug in usergrouping.Where(ug => ug.UserDomain == u.Domain && ug.UserName == u.Name))
{
@ -67,7 +67,7 @@ public class UserHandler : IMessageHandler<AgentSession>
using (collection)
{
foreach (ManagementObject @object in collection)
foreach (ManagementObject @object in collection.Cast<ManagementObject>())
{
var group = new Group();
@ -83,7 +83,7 @@ public class UserHandler : IMessageHandler<AgentSession>
}
}
return groups.OrderBy(x => x.Name)?.ToList();
return [.. groups.OrderBy(x => x.Name)];
}
private static List<User> QueryUsers()
@ -105,7 +105,7 @@ public class UserHandler : IMessageHandler<AgentSession>
using (collection)
{
foreach (ManagementObject @object in collection)
foreach (ManagementObject @object in collection.Cast<ManagementObject>())
{
var user = new User();
@ -150,7 +150,7 @@ public class UserHandler : IMessageHandler<AgentSession>
using (collection)
{
foreach (ManagementObject @object in collection)
foreach (ManagementObject @object in collection.Cast<ManagementObject>())
{
var usergroup = new UserGroupMap();

View file

@ -341,7 +341,7 @@ public class VirtualMaschineHandler : IMessageHandler<AgentSession>
{
conf.ParentId = parentGuid.ToString();
parentConfig.Childs ??= new List<VirtualMaschineConfiguration>();
parentConfig.Childs ??= [];
parentConfig.Childs.Add(conf);
}
else

View file

@ -9,6 +9,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System.Runtime.Versioning;
using Vaitr.Network;
using Vaitr.Network.Hosting;
@ -66,29 +67,13 @@ internal class Program
options.UseSerializer<AgentSession, IMessage, MemPackSerializer<IMessage>>();
});
services.AddSingleton<IMessageHandler<AgentSession>, CustomHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, ProxyHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, AuthenticationHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, DriveHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, InterfaceHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, MainboardHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, MemoryHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, OperationSystemHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, PrinterHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, ProcessorHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, ServiceHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, SessionHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, SoftwareHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, StoragePoolHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, SystemInfoHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, UpdateHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, UserHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, VideocardHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, VirtualMaschineHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, ProxyHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, CustomHandler>();
if (OperatingSystem.IsWindows()) ServiceCollectionExtensions.InjectWindowsHandler(services);
// GLOBAL DEPENDENCIES
//services.AddSingleton<Bus>();
services.AddTransient(provider => new HttpClient(new HttpClientHandler
{
ClientCertificateOptions = ClientCertificateOption.Manual,
@ -100,3 +85,29 @@ internal class Program
await host.RunAsync().ConfigureAwait(false);
}
}
internal static class ServiceCollectionExtensions
{
[SupportedOSPlatform("windows")]
internal static IServiceCollection InjectWindowsHandler(this IServiceCollection services)
{
services.AddSingleton<IMessageHandler<AgentSession>, DriveHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, InterfaceHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, MainboardHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, MemoryHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, OperationSystemHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, PrinterHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, ProcessorHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, ServiceHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, SessionHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, SoftwareHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, StoragePoolHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, SystemInfoHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, UpdateHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, UserHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, VideocardHandler>();
services.AddSingleton<IMessageHandler<AgentSession>, VirtualMaschineHandler>();
return services;
}
}

View file

@ -5,12 +5,7 @@ using System.Runtime.Versioning;
namespace Insight.Agent.Services;
[SupportedOSPlatform("linux")]
public partial class CollectorService
public partial class CollectorService(ILogger<CollectorService>? logger = null)
{
public ILogger<CollectorService> Logger { get; }
public CollectorService(ILogger<CollectorService>? logger = null)
{
Logger = logger ?? NullLogger<CollectorService>.Instance;
}
public ILogger<CollectorService> Logger { get; } = logger ?? NullLogger<CollectorService>.Instance;
}

View file

@ -4,12 +4,14 @@ namespace Insight.Agent.Services;
public static class Configurator
{
private static readonly JsonSerializerOptions _serializerOptions = new() { PropertyNameCaseInsensitive = true, WriteIndented = true };
public static async ValueTask<TConfig> ReadAsync<TConfig>(string file, CancellationToken cancellationToken = default)
where TConfig : class
{
var json = await File.ReadAllTextAsync(file, cancellationToken);
if (JsonSerializer.Deserialize<TConfig>(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true, WriteIndented = true }) is not TConfig config)
if (JsonSerializer.Deserialize<TConfig>(json, _serializerOptions) is not TConfig config)
{
throw new InvalidDataException($"Failed to deserialize ({file})");
}
@ -31,7 +33,7 @@ public static class Configurator
{
var json = await File.ReadAllTextAsync(file, cancellationToken);
if (JsonSerializer.Deserialize<IDictionary<string, object>>(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true, WriteIndented = true }) is not IDictionary<string, object> config)
if (JsonSerializer.Deserialize<IDictionary<string, object>>(json, _serializerOptions) is not IDictionary<string, object> config)
{
throw new InvalidDataException($"Failed to deserialize ({file})");
}
@ -89,7 +91,7 @@ public static class Configurator
private static async ValueTask WriteToFileAsync<TData>(TData data, string file, CancellationToken cancellationToken)
{
var json = JsonSerializer.Serialize(data, new JsonSerializerOptions { WriteIndented = true });
var json = JsonSerializer.Serialize(data, _serializerOptions);
await File.WriteAllTextAsync(file, json, cancellationToken);
}

View file

@ -163,7 +163,7 @@ internal class EventService : BackgroundService
};
}
_queue.Writer.WriteAsync(@event, default);
_ = _queue.Writer.WriteAsync(@event, default);
}
catch (Exception) { } // app crash
}

View file

@ -4,17 +4,14 @@ using System.Management.Automation.Runspaces;
namespace Insight.Agent.Services;
public class ScriptService
public class ScriptService(ILogger<ScriptService> logger)
{
private readonly ILogger<ScriptService> _logger;
public ScriptService(ILogger<ScriptService> logger)
{
_logger = logger;
}
private readonly ILogger<ScriptService> _logger = logger;
public async Task<QueryResult> QueryAsync(string query)
{
_logger.LogDebug("QueryAsync ({query})", query);
var result = new QueryResult();
var errors = new List<string>();

View file

@ -12,19 +12,12 @@ using System.Text.Json;
namespace Insight.Agent.Services;
internal class UpdateService : BackgroundService
internal class UpdateService(HttpClient httpClient, IConfiguration configuration, ILogger<UpdateService> logger) : BackgroundService
{
private readonly Uri _uri;
private readonly Uri _uri = configuration.GetValue<Uri?>("api") ?? throw new Exception($"api value not set (appsettings)");
private readonly HttpClient _httpClient;
private readonly ILogger<UpdateService> _logger;
public UpdateService(HttpClient httpClient, IConfiguration configuration, ILogger<UpdateService> logger)
{
_httpClient = httpClient;
_uri = configuration.GetValue<Uri?>("api") ?? throw new Exception($"api value not set (appsettings)");
_logger = logger;
}
private readonly HttpClient _httpClient = httpClient;
private readonly ILogger<UpdateService> _logger = logger;
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
{
@ -42,7 +35,7 @@ internal class UpdateService : BackgroundService
_logger.LogInformation("Update Result: {result}", result?.Success);
if (result?.UpdateErrors is not null)
{
_logger.LogError("Update Errors: {errors}", string.Concat(result?.UpdateErrors));
_logger.LogError("Update Errors: {errors}", string.Concat(result.UpdateErrors));
}
}
catch (OperationCanceledException) { }
@ -198,7 +191,7 @@ internal class UpdateService : BackgroundService
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);
ZipFile.ExtractToDirectory(updateFile.FullName, bin.Directory!.FullName, true);
// delete temp folder
if (temp.Exists) temp.Delete(true);
@ -229,7 +222,7 @@ internal class UpdateService : BackgroundService
var matched = System.Diagnostics.Process.GetProcessesByName(bin.FullName);
if (matched is null || matched.Any() is false) return false;
if (matched is null || matched.Length == 0) return false;
if (matched.Any(p =>
p.MainModule is not null &&
@ -262,7 +255,7 @@ internal class UpdateService : BackgroundService
var matched = System.Diagnostics.Process.GetProcessesByName(bin.FullName);
if (matched is null || matched.Any() is false) return true;
if (matched is null || matched.Length == 0) return true;
foreach (var procsInfo in matched.Where(p =>
p.MainModule is not null &&
@ -312,7 +305,7 @@ internal class UpdateService : BackgroundService
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);
ZipFile.ExtractToDirectory(updateFile.FullName, bin.Directory!.FullName, true);
// delete temp folder
if (temp.Exists) temp.Delete(true);
@ -353,7 +346,7 @@ internal class UpdateService : BackgroundService
public bool ApiAvailable { get; set; } = false;
public bool UpdateAvailable { get; set; } = false;
public bool Success { get; set; } = false;
public List<string> ApiErrors { get; } = new();
public List<string> UpdateErrors { get; } = new();
public List<string> ApiErrors { get; } = [];
public List<string> UpdateErrors { get; } = [];
}
}

View file

@ -21,10 +21,9 @@ public partial class CollectorService
output = stream.ReadToEnd();
// clean output
var clean = Regex
.Replace(output
var clean = CleanRegex().Replace(output
.Trim()
.Replace("\t", " "), @"[ ]{2,}", " ");
.Replace("\t", " "), " ");
var elements = clean.Split(Array.Empty<char>(), StringSplitOptions.RemoveEmptyEntries);
@ -36,13 +35,12 @@ public partial class CollectorService
// linebreak list conversion
var lines = new List<string>(output
.Split(new string[] { "\n", "\r\n" }, StringSplitOptions.RemoveEmptyEntries))
.Split(separator, StringSplitOptions.RemoveEmptyEntries))
.Select(l =>
{
return Regex
.Replace(l
return CleanRegex().Replace(l
.Trim()
.Replace("\t", " "), @"[ ]{2,}", " ");
.Replace("\t", " "), " ");
})
.ToList();
@ -62,13 +60,12 @@ public partial class CollectorService
// linebreak list conversion
lines = new List<string>(output
.Split(new string[] { "\n", "\r\n" }, StringSplitOptions.RemoveEmptyEntries))
.Split(separator, StringSplitOptions.RemoveEmptyEntries))
.Select(l =>
{
return Regex
.Replace(l
return CleanRegex().Replace(l
.Trim()
.Replace("\t", " "), @"[ ]{2,}", " ");
.Replace("\t", " "), " ");
})
.ToList();
@ -102,4 +99,9 @@ public partial class CollectorService
return os;
}
private static readonly string[] separator = ["\n", "\r\n"];
[GeneratedRegex(@"[ ]{2,}")]
private static partial Regex CleanRegex();
}

View file

@ -17,11 +17,11 @@ public partial class CollectorService
var output = "w".Bash();
// linebreak list conversion
var lines = output.Split(new string[] { "\n", "\r\n" }, StringSplitOptions.RemoveEmptyEntries).ToList();
var lines = output.Split(separatorArray, StringSplitOptions.RemoveEmptyEntries).ToList();
lines = lines.Select(l =>
{
return Regex.Replace(l.Trim().Replace("\t", " "), @"[ ]{2,}", " ");
return CleanOutputRegex().Replace(l.Trim().Replace("\t", " "), " ");
}).ToList();
// cleaning
@ -46,4 +46,9 @@ public partial class CollectorService
return sessions;
}
private static readonly string[] separatorArray = ["\n", "\r\n"];
[GeneratedRegex(@"[ ]{2,}")]
private static partial Regex CleanOutputRegex();
}

View file

@ -1,31 +1,29 @@
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 : ControllerBase
public class AccountController(IdentityService identityService, IServiceScopeFactory scopeFactory) : ControllerBase
{
private readonly IdentityService _identityService;
private readonly AccountService _accountService;
private readonly ILogger<AccountController> _logger;
public AccountController(IdentityService identityService, AccountService accountService, ILogger<AccountController> logger)
{
_identityService = identityService;
_accountService = accountService;
_logger = logger;
}
private readonly IdentityService _identityService = identityService;
private readonly IServiceScopeFactory _scopeFactory = scopeFactory;
[HttpGet, Authorize]
public async Task<IActionResult> Get([FromQuery] PagedDataRequest request, CancellationToken cancellationToken)
{
using var scope = _scopeFactory.CreateScope();
var collection = scope.ServiceProvider.GetRequiredService<IMongoDatabase>().User();
try
{
var result = await _accountService.GetAsync(
var result = await collection.GetPagedAsync(
offset: request.Offset,
limit: request.Limit,
request: Request,

View file

@ -1,28 +1,26 @@
using Insight.Infrastructure.Models;
using Insight.Infrastructure.Services;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Models;
using Insight.Infrastructure.Web;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using MongoDB.Driver;
namespace Insight.Api.Controllers;
[ApiController, Route("api/agents")]
public class AgentController : ControllerBase
public class AgentController(IServiceScopeFactory scopeFactory) : ControllerBase
{
private readonly AgentService _agentService;
private readonly ILogger<AgentController> _logger;
public AgentController(AgentService agentService, ILogger<AgentController> logger)
{
_agentService = agentService;
_logger = logger;
}
private readonly IServiceScopeFactory _scopeFactory = scopeFactory;
[HttpGet, Authorize]
public async Task<IActionResult> Get([FromQuery] PagedDataRequest request, CancellationToken cancellationToken)
{
using var scope = _scopeFactory.CreateScope();
var collection = scope.ServiceProvider.GetRequiredService<IMongoDatabase>().Agent();
try
{
var result = await _agentService.GetAsync(
var result = await collection.GetPagedAsync(
offset: request.Offset,
limit: request.Limit,
request: Request,

View file

@ -1,28 +1,26 @@
using Insight.Infrastructure.Models;
using Insight.Infrastructure.Services;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Models;
using Insight.Infrastructure.Web;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using MongoDB.Driver;
namespace Insight.Api.Controllers;
[ApiController, Route("api/customers")]
public class CustomerController : ControllerBase
public class CustomerController(IServiceScopeFactory scopeFactory) : ControllerBase
{
private readonly CustomerService _customerService;
private readonly ILogger<CustomerController> _logger;
public CustomerController(CustomerService customerService, ILogger<CustomerController> logger)
{
_customerService = customerService;
_logger = logger;
}
private readonly IServiceScopeFactory _scopeFactory = scopeFactory;
[HttpGet, Authorize]
public async Task<IActionResult> Get([FromQuery] PagedDataRequest request, CancellationToken cancellationToken)
{
using var scope = _scopeFactory.CreateScope();
var collection = scope.ServiceProvider.GetRequiredService<IMongoDatabase>().Customer();
try
{
var result = await _customerService.GetAsync(
var result = await collection.GetPagedAsync(
offset: request.Offset,
limit: request.Limit,
request: Request,

View file

@ -1,28 +1,26 @@
using Insight.Infrastructure.Models;
using Insight.Infrastructure.Services;
using Insight.Infrastructure.Entities;
using Insight.Infrastructure.Models;
using Insight.Infrastructure.Web;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using MongoDB.Driver;
namespace Insight.Api.Controllers;
[ApiController, Route("api/hosts")]
public class HostController : ControllerBase
public class HostController(IServiceScopeFactory scopeFactory) : ControllerBase
{
private readonly HostService _hostService;
private readonly ILogger<HostController> _logger;
public HostController(HostService hostService, ILogger<HostController> logger)
{
_hostService = hostService;
_logger = logger;
}
private readonly IServiceScopeFactory _scopeFactory = scopeFactory;
[HttpGet, Authorize]
public async Task<IActionResult> Get([FromQuery] PagedDataRequest request, CancellationToken cancellationToken)
{
using var scope = _scopeFactory.CreateScope();
var collection = scope.ServiceProvider.GetRequiredService<IMongoDatabase>().Host();
try
{
var result = await _hostService.GetAsync(
var result = await collection.GetPagedAsync(
offset: request.Offset,
limit: request.Limit,
request: Request,

View file

@ -1,6 +1,6 @@
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.Bson;
@ -11,20 +11,16 @@ using System.Text.RegularExpressions;
namespace Insight.Api.Controllers;
[ApiController, Route("api/inventory")]
public class InventoryController : ControllerBase
public class InventoryController(IServiceScopeFactory scopeFactory) : ControllerBase
{
private readonly InventoryService _inventoryService;
private readonly ILogger<InventoryController> _logger;
public InventoryController(InventoryService inventoryService, ILogger<InventoryController> logger)
{
_inventoryService = inventoryService;
_logger = logger;
}
private readonly IServiceScopeFactory _scopeFactory = scopeFactory;
[HttpGet, Authorize]
public async Task<IActionResult> Get([FromQuery] HostApplicationEntity request, [FromQuery] PagedDataRequest meta, CancellationToken cancellationToken)
{
using var scope = _scopeFactory.CreateScope();
var collection = scope.ServiceProvider.GetRequiredService<IMongoDatabase>().HostApplication();
try
{
var filter = Builders<HostApplicationEntity>.Filter.Empty;
@ -38,7 +34,7 @@ public class InventoryController : ControllerBase
if (request.Name is not null)
filter &= Builders<HostApplicationEntity>.Filter.Regex(p => p.Name, new BsonRegularExpression(new Regex(request.Name, RegexOptions.IgnoreCase)));
var result = await _inventoryService.GetAsync(
var result = await collection.GetPagedAsync(
filter: filter,
offset: meta.Offset,
limit: meta.Limit,

View file

@ -3,14 +3,9 @@
namespace Insight.Server.Controllers;
[ApiController, Route("api/setup")]
public class SetupController : ControllerBase
public class SetupController(ILogger<SetupController> logger) : ControllerBase
{
private readonly ILogger<SetupController> _logger;
public SetupController(ILogger<SetupController> logger)
{
_logger = logger;
}
private readonly ILogger<SetupController> _logger = logger;
[HttpGet("windows")]
public async Task<IActionResult> GetAsync(CancellationToken cancellationToken)

View file

@ -6,14 +6,9 @@ using Microsoft.AspNetCore.Mvc;
namespace Insight.Api.Controllers;
[ApiController, Route("api/token", Order = 0)]
public class TokenController : ControllerBase
public class TokenController(TokenService tokenService) : ControllerBase
{
private readonly TokenService _tokenService;
public TokenController(TokenService tokenService)
{
_tokenService = tokenService;
}
private readonly TokenService _tokenService = tokenService;
/// <remarks>
/// Access Token Request
@ -21,6 +16,9 @@ public class TokenController : ControllerBase
[HttpPost, AllowAnonymous]
public async Task<IActionResult> Authentication([FromBody] TokenRequest request)
{
if (request.Username is null) return BadRequest("username is null");
if (request.Password is null) return BadRequest("password is null");
try
{
var result = await _tokenService.GetAsync(request.Username, request.Password, request.Code, HttpContext.Connection.RemoteIpAddress).ConfigureAwait(false);

View file

@ -5,14 +5,9 @@ using Microsoft.AspNetCore.Mvc;
namespace Insight.Server.Controllers;
[ApiController, Route("api/update")]
public class UpdateController : ControllerBase
public class UpdateController(ILogger<UpdateController> logger) : ControllerBase
{
private readonly ILogger<UpdateController> _logger;
public UpdateController(ILogger<UpdateController> logger)
{
_logger = logger;
}
private readonly ILogger<UpdateController> _logger = logger;
[HttpGet("updater/windows")]
public IActionResult UpdaterWindows()
@ -35,7 +30,7 @@ public class UpdateController : ControllerBase
var versions = updateDir.GetFiles("*.zip", SearchOption.TopDirectoryOnly);
if (versions is null || versions.Any() is false) return NotFound();
if (versions is null || versions.Length == 0) return NotFound();
var latest = versions.OrderBy(x => x.Name).FirstOrDefault();
@ -73,7 +68,7 @@ public class UpdateController : ControllerBase
var versions = updateDir.GetFiles("*.zip", SearchOption.TopDirectoryOnly);
if (versions is null || versions.Any() is false) return NotFound();
if (versions is null || versions.Length == 0) return NotFound();
var latest = versions.OrderBy(x => x.Name).FirstOrDefault();

View file

@ -6,7 +6,7 @@ namespace Insight.Api.Hosting;
public static class ServiceExtensions
{
internal static IServiceCollection AddSwaggerServices(this IServiceCollection services, IConfiguration configuration)
internal static IServiceCollection AddSwaggerServices(this IServiceCollection services)
{
services.AddEndpointsApiExplorer();
services.AddSwaggerGen(options =>

View file

@ -1,42 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Product>Insight</Product>
<AssemblyName>api</AssemblyName>
<AssemblyVersion>2023.12.14.0</AssemblyVersion>
<RootNamespace>Insight.Api</RootNamespace>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>4ae1d3bf-869e-4963-8a19-35634507d3b3</UserSecretsId>
<PublishAot>false</PublishAot>
<PublishTrimmed>false</PublishTrimmed>
<!--<ServerGarbageCollection>false</ServerGarbageCollection>
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<LangVersion>latest</LangVersion>
<Product>Insight</Product>
<AssemblyName>api</AssemblyName>
<AssemblyVersion>2023.12.15.0</AssemblyVersion>
<RootNamespace>Insight.Api</RootNamespace>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>4ae1d3bf-869e-4963-8a19-35634507d3b3</UserSecretsId>
<PublishAot>false</PublishAot>
<PublishTrimmed>false</PublishTrimmed>
<!--<ServerGarbageCollection>false</ServerGarbageCollection>
<ConcurrentGarbageCollection>false</ConcurrentGarbageCollection>-->
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>none</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DebugType>none</DebugType>
</PropertyGroup>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn>
<SatelliteResourceLanguages>none</SatelliteResourceLanguages>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="7.0.1" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.13" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0" />
<!--Unix Serilog stuff-->
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0" />
<!--Unix Serilog stuff-->
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Core\Insight.Infrastructure.Web\Insight.Infrastructure.Web.csproj" />
<ProjectReference Include="..\..\Core\Insight.Infrastructure\Insight.Infrastructure.csproj" />
</ItemGroup>

View file

@ -40,12 +40,12 @@ internal class Program
builder.Services.AddAuthorization();
// WEBSERVICES
builder.Services.AddProxyServices(builder.Configuration);
builder.Services.AddRoutingServices(builder.Configuration);
builder.Services.AddProxyServices();
builder.Services.AddRoutingServices();
builder.Services.AddControllers();
// SWAGGER
builder.Services.AddSwaggerServices(builder.Configuration);
builder.Services.AddSwaggerServices();
//builder.Services.AddControllers();
//builder.Services.AddEndpointsApiExplorer();

View file

@ -1,4 +1,5 @@
using System.Net;
using System.Diagnostics;
using System.Net;
using System.Reflection;
namespace Insight.Domain.Constants;
@ -7,6 +8,14 @@ public static class Configuration
{
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 DirectoryInfo? AppDirectory => AppDirectoryHelper();
public static string DefaultConfig => Path.Combine(AppDirectory?.FullName ?? string.Empty, "config.json");
private static DirectoryInfo? AppDirectoryHelper()
{
using var proc = Process.GetCurrentProcess();
if (proc?.MainModule?.FileName is null) throw new InvalidOperationException("MainModule not found");
return new DirectoryInfo(proc.MainModule.FileName).Parent;
}
}

View file

@ -2,6 +2,7 @@
public enum CategoryEnum
{
None = 0,
Network = 1,
System = 2,
Application = 3,

View file

@ -1,25 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>true</ImplicitUsings>
<TargetFramework>net8.0</TargetFramework>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>Insight.Domain</RootNamespace>
<Product>Insight</Product>
<AssemblyVersion>2023.12.14.0</AssemblyVersion>
<AssemblyVersion>2023.12.15.0</AssemblyVersion>
<SatelliteResourceLanguages>none</SatelliteResourceLanguages>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<!--Ignore MemoryPack Warning-->
<NoWarn>9193</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Vaitr.Bus" Version="2023.12.13" />
<PackageReference Include="Vaitr.Network" Version="2023.12.14" />
<PackageReference Include="System.Text.Json" Version="8.0.0" />
<PackageReference Include="Vaitr.Bus" Version="2023.12.15.1" />
<PackageReference Include="Vaitr.Network" Version="2023.12.16" />
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>none</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DebugType>none</DebugType>
</PropertyGroup>
</Project>

View file

@ -1,5 +1,4 @@
using MessagePack;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.Serialization;
using System.Text.Json.Serialization;
@ -31,17 +30,17 @@ public class Result
}
[IgnoreDataMember]
public Exception? Exception { get; init; }
public Exception? Exception { get; set; }
[IgnoreDataMember]
[MemberNotNullWhen(true, nameof(Exception))]
//[MemberNotNullWhen(true, nameof(Exception))]
public bool HadException => Exception is not null;
[DataMember]
public bool IsSuccess { get; init; }
public bool IsSuccess { get; set; }
[DataMember]
public string Reason { get; init; } = string.Empty;
public string Reason { get; set; } = string.Empty;
public static Result Fail(string reason)
@ -130,19 +129,19 @@ public class Result<T>
}
[IgnoreDataMember]
public Exception? Exception { get; init; }
public Exception? Exception { get; set; }
[IgnoreDataMember]
[MemberNotNullWhen(true, nameof(Exception))]
//[MemberNotNullWhen(true, nameof(Exception))]
public bool HadException => Exception is not null;
[DataMember]
[MemberNotNullWhen(true, nameof(Value))]
public bool IsSuccess { get; init; }
//[MemberNotNullWhen(true, nameof(Value))]
public bool IsSuccess { get; set; }
[DataMember]
public string Reason { get; init; } = string.Empty;
public string Reason { get; set; } = string.Empty;
[DataMember]
public T? Value { get; init; }
public T? Value { get; set; }
}

View file

@ -27,28 +27,17 @@ public class TokenResponse
public string? RefreshToken { get; set; }
}
public class TokenRevokeRequest
public class TokenRevokeRequest(string token, string? reason)
{
[JsonPropertyName("token"), Required]
public string? Token { get; set; }
public string? Token { get; set; } = token;
[JsonPropertyName("reason")]
public string? Reason { get; set; }
public TokenRevokeRequest(string token, string? reason)
{
Token = token;
Reason = reason;
}
public string? Reason { get; set; } = reason;
}
public class TokenRefreshRequest
public class TokenRefreshRequest(string token)
{
[JsonPropertyName("token"), Required]
public string? Token { get; set; }
public TokenRefreshRequest(string token)
{
Token = token;
}
public string? Token { get; set; } = token;
}

View file

@ -182,6 +182,6 @@ public partial class IPAddress2 : IMessage
IsIPv6Multicast = address.IsIPv6Multicast;
IsIPv6SiteLocal = address.IsIPv6SiteLocal;
IsIPv6Teredo = address.IsIPv6Teredo;
IsIPv6UniqueLocal = address.IsIPv6UniqueLocal;
//IsIPv6UniqueLocal = address.IsIPv6UniqueLocal;
}
}

View file

@ -6,10 +6,6 @@ namespace Insight.Domain.Network;
[MemoryPackUnion(0, typeof(Agent.Messages.AuthenticationRequest))]
[MemoryPackUnion(1, typeof(Agent.Messages.AuthenticationResponse))]
[MemoryPackUnion(2, typeof(Agent.Messages.InventoryRequest))]
//[MemoryPackUnion(3, typeof(Agent.Messages.ConsoleQueryRequest))]
//[MemoryPackUnion(4, typeof(Agent.Messages.ConsoleQueryResponse))]
//[MemoryPackUnion(5, typeof(Proxy<Agent.Messages.ConsoleQueryResponse>))]
//[MemoryPackUnion(6, typeof(Proxy<Agent.Messages.ConsoleQueryRequest>))]
[MemoryPackUnion(7, typeof(Agent.Messages.Event))]
[MemoryPackUnion(8, typeof(Agent.Messages.Trap))]
[MemoryPackUnion(9, typeof(Agent.Messages.Mainboard))]

View file

@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Http.Extensions;
namespace Insight.Infrastructure;
public static class HttpRequestExtensions
public static partial class HttpRequestExtensions
{
public static void AddPagination<TData>(this HttpRequest request, PagedList<TData> pagelist)
{

View file

@ -0,0 +1,18 @@
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<TData>(this HttpResponse response, PagedList<TData> pagelist)
{
response.Headers.Append("X-Pagination", JsonSerializer.Serialize(pagelist.Meta as PagedHeaderData, _options));
}
}

View file

@ -0,0 +1,44 @@
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<PagedList<TData>> GetPagedAsync<TData>(
this IMongoCollection<TData> collection,
HttpRequest request,
HttpResponse response,
FilterDefinition<TData>? filter = null,
SortDefinition<TData>? 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<PagedList<TResult>> GetPagedAsync<TData, TResult>(
this IMongoCollection<TData> collection,
HttpRequest request,
HttpResponse response,
IAggregateFluent<BsonDocument> query,
int offset = 0,
int limit = 10,
CancellationToken cancellationToken = default)
{
var result = await Infrastructure.MongoCollectionExtensions.GetPagedAsync<TData, TResult>(collection, query, offset, limit, cancellationToken).ConfigureAwait(false);
request?.AddPagination(result);
response?.AddPagination(result);
return result;
}
}

View file

@ -0,0 +1,229 @@
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.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 IServiceCollection AddTokenServices(this IServiceCollection services, IConfiguration configuration)
{
var options = new Models.TokenOptions(
key: configuration.GetValue<string?>(Appsettings.JwtKey) ?? throw new Exception($"{Appsettings.JwtKey} value not set (appsettings)"),
expires: configuration.GetValue<int?>(Appsettings.JwtExp) ?? throw new Exception($"{Appsettings.JwtExp} value not set (appsettings)"),
audience: configuration.GetValue<Uri?>(Appsettings.JwtAudience) ?? throw new Exception($"{Appsettings.JwtAudience} value not set (appsettings)"),
issuer: configuration.GetValue<Uri?>(Appsettings.JwtIssuer) ?? throw new Exception($"{Appsettings.JwtIssuer} value not set (appsettings)"));
services.AddSingleton(options);
services.AddTransient<TokenService>();
return services;
}
public static IServiceCollection AddProxyServices(this IServiceCollection services)
{
// add before routing
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
return services;
}
public static IServiceCollection AddRoutingServices(this IServiceCollection services)
{
// add after proxy
services.AddRouting(options =>
{
options.LowercaseUrls = true;
});
return services;
}
public static IServiceCollection AddIdentityServices(this IServiceCollection services, IConfiguration configuration)
{
var connectionString = configuration.GetValue<string?>(Appsettings.Database) ?? throw new Exception($"{Appsettings.Database} value not set (appsettings)");
services.AddIdentity<InsightUser, InsightRole>(options =>
{
})
.AddMongoDbStores<InsightUser, InsightRole, ObjectId>(connectionString, Settings.Database)
.AddDefaultTokenProviders()
.AddSignInManager();
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<string?>(Appsettings.JwtAudience) ?? throw new Exception($"{Appsettings.JwtAudience} value not set (appsettings)");
options.TokenValidationParameters.ValidateAudience = true;
options.TokenValidationParameters.ValidIssuer = configuration.GetValue<string?>(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<string?>(Appsettings.JwtKey) ?? throw new Exception($"{Appsettings.JwtKey} 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<InsightUser, InsightRole, ObjectId>(identityOptions)
// .AddDefaultTokenProviders()
// .AddSignInManager<InsightUser>();
// 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;
//}
}

View file

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>Insight.Infrastructure.Web</RootNamespace>
<Product>Insight</Product>
<AssemblyVersion>2023.12.15.0</AssemblyVersion>
<SatelliteResourceLanguages>none</SatelliteResourceLanguages>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http.Extensions" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.0" />
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="7.0.3" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Insight.Infrastructure\Insight.Infrastructure.csproj" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,9 @@
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;
}

View file

@ -10,24 +10,17 @@ using System.Text;
namespace Insight.Infrastructure.Services;
public class TokenService
public class TokenService(TokenOptions options, IdentityService identityService, IMongoDatabase database)
{
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;
}
private readonly TokenOptions _options = options;
private readonly IdentityService _identityService = identityService;
private readonly IMongoDatabase _database = database;
public async Task<TokenResponse> 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 accessToken = await CreateAccessTokenAsync(user).ConfigureAwait(false);
var refreshToken = await CreateRefreshTokenAsync(user, ipa).ConfigureAwait(false);
return new TokenResponse
@ -42,7 +35,7 @@ public class TokenService
{
if (string.IsNullOrWhiteSpace(refreshToken)) throw new ArgumentNullException(nameof(refreshToken));
var user = await _database.User().Find(p => p.RefreshTokens.Any(t => t.Token == refreshToken)).FirstOrDefaultAsync();
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);
@ -73,7 +66,7 @@ public class TokenService
var newRefreshToken = await CreateRefreshTokenAsync(user, ipa).ConfigureAwait(false);
// create access token
var accessToken = await CreateAccessTokenAsync(user, ipa).ConfigureAwait(false);
var accessToken = await CreateAccessTokenAsync(user).ConfigureAwait(false);
return new TokenResponse
{
@ -87,7 +80,7 @@ public class TokenService
{
if (string.IsNullOrWhiteSpace(refreshToken)) throw new ArgumentNullException(nameof(refreshToken));
var user = await _database.User().Find(p => p.RefreshTokens.Any(t => t.Token == refreshToken)).FirstOrDefaultAsync();
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);
@ -102,7 +95,7 @@ public class TokenService
token.ReasonRevoked = reason;
}
private async Task<(string, int)> CreateAccessTokenAsync(InsightUser user, IPAddress? ipa = null)
private async Task<(string, int)> CreateAccessTokenAsync(InsightUser user)
{
var claims = await _identityService.GetClaimsAsync(user).ConfigureAwait(false);

View file

@ -1,16 +0,0 @@
using Insight.Infrastructure.Models;
using Microsoft.AspNetCore.Http;
using System.Text.Json;
namespace Insight.Infrastructure;
public static class HttpResponseExtensions
{
public static void AddPagination<TData>(this HttpResponse response, PagedList<TData> pagelist)
{
response.Headers.Add("X-Pagination", JsonSerializer.Serialize(pagelist.Meta as PagedHeaderData, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
}));
}
}

View file

@ -1,12 +1,11 @@
using Insight.Infrastructure.Models;
using Microsoft.AspNetCore.Http;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Driver;
namespace Insight.Infrastructure;
public static class MongoCollectionExtensions
public static partial class MongoCollectionExtensions
{
private const int _maximumLimit = 100;
@ -30,24 +29,6 @@ public static class MongoCollectionExtensions
return new PagedList<TData>(data, offset, limit, total);
}
public static async Task<PagedList<TData>> GetPagedAsync<TData>(
this IMongoCollection<TData> collection,
HttpRequest request,
HttpResponse response,
FilterDefinition<TData>? filter = null,
SortDefinition<TData>? sort = null,
int offset = 0,
int limit = 10,
CancellationToken cancellationToken = default)
{
var result = await GetPagedAsync(collection, filter, sort, offset, limit, cancellationToken).ConfigureAwait(false);
request?.AddPagination(result);
response?.AddPagination(result);
return result;
}
public static async Task<PagedList<TResult>> GetPagedAsync<TData, TResult>(
this IMongoCollection<TData> collection,
IAggregateFluent<BsonDocument> query,
@ -62,21 +43,4 @@ public static class MongoCollectionExtensions
return new PagedList<TResult>(data.Select(x => BsonSerializer.Deserialize<TResult>(x)), offset, limit, total);
}
public static async Task<PagedList<TResult>> GetPagedAsync<TData, TResult>(
this IMongoCollection<TData> collection,
HttpRequest request,
HttpResponse response,
IAggregateFluent<BsonDocument> query,
int offset = 0,
int limit = 10,
CancellationToken cancellationToken = default)
{
var result = await GetPagedAsync<TData, TResult>(collection, query, offset, limit, cancellationToken).ConfigureAwait(false);
request?.AddPagination(result);
response?.AddPagination(result);
return result;
}
}

View file

@ -1,24 +1,13 @@
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 Insight.Infrastructure.Services;
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 class ServiceExtensions
public static partial class ServiceExtensions
{
public static IServiceCollection AddDatabase(this IServiceCollection services, IConfiguration configuration, ILoggerFactory? loggerFactory = null)
{
@ -42,221 +31,6 @@ public static class ServiceExtensions
{
services.AddTransient<IdentityService>();
services.AddTransient<AuthenticatorService>();
services.AddTransient<AccountService>();
services.AddTransient<CustomerService>();
services.AddTransient<HostService>();
services.AddTransient<AgentService>();
services.AddTransient<InventoryService>();
return services;
}
public static IServiceCollection AddIdentityServices(this IServiceCollection services, IConfiguration configuration)
{
var connectionString = configuration.GetValue<string?>(Appsettings.Database) ?? throw new Exception($"{Appsettings.Database} value not set (appsettings)");
services.AddIdentity<InsightUser, InsightRole>(options =>
{
})
.AddMongoDbStores<InsightUser, InsightRole, ObjectId>(connectionString, Settings.Database)
.AddDefaultTokenProviders()
.AddSignInManager();
return services;
}
public static IServiceCollection AddTokenServices(this IServiceCollection services, IConfiguration configuration)
{
var options = new Models.TokenOptions(
key: configuration.GetValue<string?>(Appsettings.JwtKey) ?? throw new Exception($"{Appsettings.JwtKey} value not set (appsettings)"),
expires: configuration.GetValue<int?>(Appsettings.JwtExp) ?? throw new Exception($"{Appsettings.JwtExp} value not set (appsettings)"),
audience: configuration.GetValue<Uri?>(Appsettings.JwtAudience) ?? throw new Exception($"{Appsettings.JwtAudience} value not set (appsettings)"),
issuer: configuration.GetValue<Uri?>(Appsettings.JwtIssuer) ?? throw new Exception($"{Appsettings.JwtIssuer} value not set (appsettings)"));
services.AddSingleton(options);
services.AddTransient<TokenService>();
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<string?>(Appsettings.JwtAudience) ?? throw new Exception($"{Appsettings.JwtAudience} value not set (appsettings)");
options.TokenValidationParameters.ValidateAudience = true;
options.TokenValidationParameters.ValidIssuer = configuration.GetValue<string?>(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<string?>(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<ForwardedHeadersOptions>(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<InsightUser, InsightRole, ObjectId>(identityOptions)
.AddDefaultTokenProviders()
.AddSignInManager<InsightUser>();
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;
}
}

View file

@ -1,28 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>Insight.Infrastructure</RootNamespace>
<Product>Insight</Product>
<AssemblyVersion>2023.12.14.0</AssemblyVersion>
<ImplicitUsings>true</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>none</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DebugType>none</DebugType>
<AssemblyVersion>2023.12.15.0</AssemblyVersion>
<SatelliteResourceLanguages>none</SatelliteResourceLanguages>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.13" />
<PackageReference Include="MongoDB.Driver" Version="2.23.0" />
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
<PackageReference Include="AspNetCore.Identity.MongoDbCore" Version="3.1.2" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.0.3" />
<PackageReference Include="Vaitr.Scheduler" Version="2023.12.6" />
<PackageReference Include="MongoDB.Driver" Version="2.23.1" />
<PackageReference Include="Vaitr.Scheduler" Version="2023.12.15.1" />
</ItemGroup>
<ItemGroup>

View file

@ -1,17 +0,0 @@
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;
}
}

View file

@ -1,35 +0,0 @@
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<AccountService> _logger;
public AccountService(IMongoDatabase database, ILogger<AccountService> logger)
{
_database = database;
_logger = logger;
}
public Task<PagedList<InsightUser>> GetAsync(
FilterDefinition<InsightUser>? filter = null,
SortDefinition<InsightUser>? sort = null,
int offset = 0,
int limit = 10,
CancellationToken cancellationToken = default) => _database.User().GetPagedAsync(filter, sort, offset, limit, cancellationToken);
public Task<PagedList<InsightUser>> GetAsync(
HttpRequest request,
HttpResponse response,
FilterDefinition<InsightUser>? filter = null,
SortDefinition<InsightUser>? sort = null,
int offset = 0,
int limit = 10,
CancellationToken cancellationToken = default) => _database.User().GetPagedAsync(request, response, filter, sort, offset, limit, cancellationToken);
}

View file

@ -1,35 +0,0 @@
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<AgentService> _logger;
public AgentService(IMongoDatabase database, ILogger<AgentService> logger)
{
_database = database;
_logger = logger;
}
public Task<PagedList<AgentEntity>> GetAsync(
FilterDefinition<AgentEntity>? filter = null,
SortDefinition<AgentEntity>? sort = null,
int offset = 0,
int limit = 10,
CancellationToken cancellationToken = default) => _database.Agent().GetPagedAsync(filter, sort, offset, limit, cancellationToken);
public Task<PagedList<AgentEntity>> GetAsync(
HttpRequest request,
HttpResponse response,
FilterDefinition<AgentEntity>? filter = null,
SortDefinition<AgentEntity>? sort = null,
int offset = 0,
int limit = 10,
CancellationToken cancellationToken = default) => _database.Agent().GetPagedAsync(request, response, filter, sort, offset, limit, cancellationToken);
}

View file

@ -7,16 +7,9 @@ using System.Text.Encodings.Web;
namespace Insight.Infrastructure.Services;
public class AuthenticatorService
public class AuthenticatorService(UserManager<InsightUser> userManager)
{
private readonly IMongoDatabase _database;
private readonly UserManager<InsightUser> _userManager;
public AuthenticatorService(IMongoDatabase database, UserManager<InsightUser> userManager)
{
_database = database;
_userManager = userManager;
}
private readonly UserManager<InsightUser> _userManager = userManager;
public async Task<bool> GetStatusAsync(InsightUser user)
{
@ -79,7 +72,7 @@ public class AuthenticatorService
return await _userManager.GenerateNewTwoFactorRecoveryCodesAsync(user, count).ConfigureAwait(false);
}
public string GenerateQrCode(string email, string unformattedKey)
public static string GenerateQrCode(string email, string unformattedKey)
{
var encoder = UrlEncoder.Default;

View file

@ -1,35 +0,0 @@
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<CustomerService> _logger;
public CustomerService(IMongoDatabase database, ILogger<CustomerService> logger)
{
_database = database;
_logger = logger;
}
public Task<PagedList<CustomerEntity>> GetAsync(
FilterDefinition<CustomerEntity>? filter = null,
SortDefinition<CustomerEntity>? sort = null,
int offset = 0,
int limit = 10,
CancellationToken cancellationToken = default) => _database.Customer().GetPagedAsync(filter, sort, offset, limit, cancellationToken);
public Task<PagedList<CustomerEntity>> GetAsync(
HttpRequest request,
HttpResponse response,
FilterDefinition<CustomerEntity>? filter = null,
SortDefinition<CustomerEntity>? sort = null,
int offset = 0,
int limit = 10,
CancellationToken cancellationToken = default) => _database.Customer().GetPagedAsync(request, response, filter, sort, offset, limit, cancellationToken);
}

View file

@ -1,35 +0,0 @@
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<HostService> _logger;
public HostService(IMongoDatabase database, ILogger<HostService> logger)
{
_database = database;
_logger = logger;
}
public Task<PagedList<HostEntity>> GetAsync(
FilterDefinition<HostEntity>? filter = null,
SortDefinition<HostEntity>? sort = null,
int offset = 0,
int limit = 10,
CancellationToken cancellationToken = default) => _database.Host().GetPagedAsync(filter, sort, offset, limit, cancellationToken);
public Task<PagedList<HostEntity>> GetAsync(
HttpRequest request,
HttpResponse response,
FilterDefinition<HostEntity>? filter = null,
SortDefinition<HostEntity>? sort = null,
int offset = 0,
int limit = 10,
CancellationToken cancellationToken = default) => _database.Host().GetPagedAsync(request, response, filter, sort, offset, limit, cancellationToken);
}

View file

@ -5,18 +5,10 @@ using System.Security.Claims;
namespace Insight.Infrastructure.Services;
public class IdentityService
public class IdentityService(UserManager<InsightUser> userManager, RoleManager<InsightRole> roleManager)
{
private readonly UserManager<InsightUser> _userManager;
private readonly RoleManager<InsightRole> _roleManager;
private readonly ILogger<IdentityService> _logger;
public IdentityService(UserManager<InsightUser> userManager, RoleManager<InsightRole> roleManager, ILogger<IdentityService> logger)
{
_userManager = userManager;
_roleManager = roleManager;
_logger = logger;
}
private readonly UserManager<InsightUser> _userManager = userManager;
private readonly RoleManager<InsightRole> _roleManager = roleManager;
public async Task SeedAsync()
{

View file

@ -1,35 +0,0 @@
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<InventoryService> _logger;
public InventoryService(IMongoDatabase database, ILogger<InventoryService> logger)
{
_database = database;
_logger = logger;
}
public Task<PagedList<HostApplicationEntity>> GetAsync(
FilterDefinition<HostApplicationEntity>? filter = null,
SortDefinition<HostApplicationEntity>? sort = null,
int offset = 0,
int limit = 10,
CancellationToken cancellationToken = default) => _database.HostApplication().GetPagedAsync(filter, sort, offset, limit, cancellationToken);
public Task<PagedList<HostApplicationEntity>> GetAsync(
HttpRequest request,
HttpResponse response,
FilterDefinition<HostApplicationEntity>? filter = null,
SortDefinition<HostApplicationEntity>? sort = null,
int offset = 0,
int limit = 10,
CancellationToken cancellationToken = default) => _database.HostApplication().GetPagedAsync(request, response, filter, sort, offset, limit, cancellationToken);
}

View file

@ -1,20 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<LangVersion>latest</LangVersion>
<RootNamespace>Insight.Remote.Shared</RootNamespace>
<Product>Insight</Product>
<AssemblyName>Insight.Remote.Shared</AssemblyName>
<AssemblyVersion>2023.12.14.0</AssemblyVersion>
<AssemblyVersion>2023.12.15.0</AssemblyVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<SatelliteResourceLanguages>none</SatelliteResourceLanguages>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.0" />
<PackageReference Include="System.ServiceProcess.ServiceController" Version="7.0.1" />
<PackageReference Include="System.ServiceProcess.ServiceController" Version="8.0.0" />
<PackageReference Include="SkiaSharp.Views.Desktop.Common" Version="2.88.6" />
</ItemGroup>

View file

@ -2,16 +2,9 @@
namespace Insight.Remote.Shared.Models;
public class CursorInfo
public class CursorInfo(byte[] imageBytes, Point hotspot, string cssOverride = "")
{
public byte[] ImageBytes { get; set; }
public Point HotSpot { get; set; }
public string CssOverride { get; set; }
public CursorInfo(byte[] imageBytes, Point hotspot, string cssOverride = "")
{
ImageBytes = imageBytes;
HotSpot = hotspot;
CssOverride = cssOverride;
}
public byte[] ImageBytes { get; set; } = imageBytes;
public Point HotSpot { get; set; } = hotspot;
public string CssOverride { get; set; } = cssOverride;
}

View file

@ -1,13 +1,7 @@
namespace Insight.Remote.Shared.Models;
public readonly struct SentFrame
public readonly struct SentFrame(int frameSize, DateTimeOffset timestamp)
{
public SentFrame(int frameSize, DateTimeOffset timestamp)
{
FrameSize = frameSize;
Timestamp = timestamp;
}
public DateTimeOffset Timestamp { get; }
public int FrameSize { get; }
public DateTimeOffset Timestamp { get; } = timestamp;
public int FrameSize { get; } = frameSize;
}

View file

@ -235,7 +235,7 @@ public static class SECUR32
MaxTokenInfoClass
}
[StructLayout(LayoutKind.Sequential)]
public struct QUOTA_LIMITS
public readonly struct QUOTA_LIMITS
{
readonly UInt32 PagedPoolLimit;
readonly UInt32 NonPagedPoolLimit;

View file

@ -9,18 +9,11 @@ using Vaitr.Bus;
namespace Insight.Remote.Shared.Network.Handlers;
public class RemoteHandler : IMessageHandler<RemoteSession>
public class RemoteHandler(Bus bus, Streamer streamer, ILogger<RemoteHandler> logger) : IMessageHandler<RemoteSession>
{
private readonly Bus _bus;
private readonly Streamer _streamer;
private readonly ILogger<RemoteHandler> _logger;
public RemoteHandler(Bus bus, Streamer streamer, ILogger<RemoteHandler> logger)
{
_bus = bus;
_streamer = streamer;
_logger = logger;
}
private readonly Bus _bus = bus;
private readonly Streamer _streamer = streamer;
private readonly ILogger<RemoteHandler> _logger = logger;
public async ValueTask HandleAsync<TMessage>(RemoteSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
@ -48,16 +41,18 @@ public class RemoteHandler : IMessageHandler<RemoteSession>
private async Task OnSessionResponse(RemoteSession session, RemoteSessionResponse sessionResponse, CancellationToken cancellationToken)
{
_logger.LogInformation($"Remote {session.Id} => SessionResponse");
if (session.Id is not string sessionId) return;
_logger.LogInformation("Remote {session} => SessionResponse", sessionId);
session.Id = sessionResponse.SessionId;
await _bus.PublishAsync(new IdentityChanged(session.Id));
await _bus.PublishAsync(new IdentityChanged(sessionId), cancellationToken);
}
private async Task OnCastRequest(RemoteSession session, CastRequest castRequest, CancellationToken cancellationToken)
{
_logger.LogInformation($"Remote {session.Id} => CastRequest");
_logger.LogInformation("Remote {session.Id} => CastRequest", session.Id);
//if (request.RequesterName is null || request.ConnectionId is null) return;
@ -105,7 +100,7 @@ public class RemoteHandler : IMessageHandler<RemoteSession>
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
_logger.LogError("{exception}", ex.Message);
}
//DesktopStream? viewer = _viewerPool.Values.FirstOrDefault(p => p.ConnectionId == request.ConnectionId);
@ -121,7 +116,7 @@ public class RemoteHandler : IMessageHandler<RemoteSession>
private async Task OnCastAbort(RemoteSession session, CastAbort castAbort, CancellationToken cancellationToken)
{
_logger.LogInformation($"Remote {session.Id} => CastAbort");
_logger.LogInformation("Remote {session} => CastAbort", session.Id);
await _streamer.CancelAsync(castAbort, cancellationToken);
}
@ -148,7 +143,7 @@ public class RemoteHandler : IMessageHandler<RemoteSession>
}
catch (Exception ex)
{
_logger.LogError(ex.ToString());
_logger.LogError("{exception}", ex.ToString());
}
}
}

View file

@ -4,26 +4,23 @@ using Insight.Domain.Network;
using Insight.Domain.Network.Remote.Messages;
using Insight.Remote.Shared.Messages;
using Microsoft.Extensions.Logging;
using System.ServiceProcess;
using Vaitr.Bus;
using Vaitr.Network;
namespace Insight.Remote.Shared.Network;
public class RemoteSession : TcpSession<IMessage>
public class RemoteSession(
Bus bus,
IEnumerable<IMessageHandler<RemoteSession>> handlers,
ISerializer<IMessage> serializer,
ILogger<RemoteSession> logger) : TcpSession<IMessage>(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;
private readonly IEnumerable<IMessageHandler<RemoteSession>> _handlers;
public RemoteSession(Bus bus, IEnumerable<IMessageHandler<RemoteSession>> handlers, ISerializer<IMessage> serializer, ILogger<RemoteSession> logger) : base(serializer, logger)
{
_bus = bus;
_handlers = handlers;
}
private readonly Bus _bus = bus;
private readonly IEnumerable<IMessageHandler<RemoteSession>> _handlers = handlers;
protected override async ValueTask OnConnectedAsync(CancellationToken cancellationToken)
{
@ -45,9 +42,10 @@ public class RemoteSession : TcpSession<IMessage>
await _bus.PublishAsync(new ConnectionStateChanged(ConnectionState.Disconnected));
}
protected override async ValueTask OnSentAsync(IPacketContext<IMessage> context, CancellationToken cancellationToken)
protected override ValueTask OnSentAsync(IPacketContext<IMessage> context, CancellationToken cancellationToken)
{
//await base.OnSentAsync(context, cancellationToken);
return default;
}
protected override async ValueTask OnReceivedAsync(IPacketContext<IMessage> context, CancellationToken cancellationToken)
@ -67,12 +65,14 @@ public class RemoteSession : TcpSession<IMessage>
}
}
protected override async ValueTask OnHeartbeatAsync(CancellationToken cancellationToken)
protected override ValueTask OnHeartbeatAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Remote ({ep?}) Heartbeat", RemoteEndPoint);
return default;
}
private async ValueTask OnWindowsSessionSwitchedAsync(WindowsSessionSwitched message, CancellationToken cancellationToken)
private ValueTask OnWindowsSessionSwitchedAsync(WindowsSessionSwitched message, CancellationToken cancellationToken)
{
try
{
@ -80,23 +80,24 @@ public class RemoteSession : TcpSession<IMessage>
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
_logger.LogError("{exception}", ex.Message);
}
return default;
}
private async ValueTask OnWindowsSessionEndingAsync(WindowsSessionEnding message, CancellationToken cancellationToken)
private static ValueTask OnWindowsSessionEndingAsync(WindowsSessionEnding message, CancellationToken cancellationToken)
{
//await DisconnectViewersAsync();
return default;
}
private static bool RunningAsService()
{
return false;
if (OperatingSystem.IsWindows())
{
return ServiceController.GetServices().Any(serviceController => serviceController.ServiceName.Equals("remotecontrol"));
}
//if (OperatingSystem.IsWindows())
//{
// return ServiceController.GetServices().Any(serviceController => serviceController.ServiceName.Equals("remotecontrol"));
//}
return false;
}

View file

@ -10,7 +10,7 @@ public class Runtime : IHostedService
private readonly CancellationTokenSource _cts = new();
private Task? _desktopTask;
private Thread? _uiThread;
private readonly Thread? _uiThread;
private readonly IDesktopApp _desktopApp;
private readonly IDispatcher _dispatcher;
@ -31,20 +31,21 @@ public class Runtime : IHostedService
_lifetime.ApplicationStopping.Register(_cts.Cancel);
}
public async Task StartAsync(CancellationToken cancellationToken)
public Task StartAsync(CancellationToken cancellationToken)
{
// init app (os specific providers)
_desktopTask = _desktopApp.InitAsync(RemoteControlMode.Attended, _cts.Token);
// init dispatcher
if (false) // if mode is attended (interactive)
{
// init ui thread
_uiThread = await _dispatcher.RunAsync(_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)

View file

@ -14,7 +14,16 @@ using Vaitr.Network;
namespace Insight.Remote.Shared.Services;
public class Streamer : IDisposable
public class Streamer(
Bus bus,
ISessionPool<RemoteSession, IMessage> remotePool,
IFileProvider fileProvider,
IClipboardProvider clipboardProvider,
IAudioProvider audioProvider,
IInputProvider inputProvider,
ICursorProvider cursorProvider,
IScreenProvider screenProvider,
ILogger<Streamer> logger) : IDisposable
{
public int ImageQuality { get; set; } = 50;
public bool HasControl { get; set; } = true;
@ -34,37 +43,15 @@ public class Streamer : IDisposable
private readonly ConcurrentQueue<DateTimeOffset> _fpsQueue = new();
private readonly ConcurrentQueue<SentFrame> _sentFrames = new();
private readonly Bus _bus;
private readonly ISessionPool<RemoteSession, IMessage> _remotePool;
private readonly IFileProvider _fileProvider;
private readonly IClipboardProvider _clipboardProvider;
private readonly IAudioProvider _audioProvider;
private readonly IInputProvider _inputProvider;
private readonly ICursorProvider _cursorProvider;
private readonly IScreenProvider _screenProvider;
private readonly ILogger<Streamer> _logger;
public Streamer(
Bus bus,
ISessionPool<RemoteSession, IMessage> remotePool,
IFileProvider fileProvider,
IClipboardProvider clipboardProvider,
IAudioProvider audioProvider,
IInputProvider inputProvider,
ICursorProvider cursorProvider,
IScreenProvider screenProvider,
ILogger<Streamer> logger)
{
_bus = bus;
_remotePool = remotePool;
_fileProvider = fileProvider;
_clipboardProvider = clipboardProvider;
_audioProvider = audioProvider;
_inputProvider = inputProvider;
_cursorProvider = cursorProvider;
_screenProvider = screenProvider;
_logger = logger;
}
private readonly Bus _bus = bus;
private readonly ISessionPool<RemoteSession, IMessage> _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<Streamer> _logger = logger;
public async Task InitAsync(CastRequest request, CancellationToken cancellationToken)
{
@ -108,7 +95,7 @@ public class Streamer : IDisposable
catch (OperationCanceledException) { }
catch (Exception ex)
{
_logger.LogError(ex.Message);
_logger.LogError("{exception}", ex.Message);
}
finally
{
@ -268,7 +255,7 @@ public class Streamer : IDisposable
}
catch (Exception ex)
{
_logger.LogError("{exception}", ex.Message);
}
finally
{
@ -331,15 +318,20 @@ public class Streamer : IDisposable
// }
//}
public async Task CancelAsync(CastAbort castAbort, CancellationToken cancellationToken)
public Task CancelAsync(CastAbort castAbort, CancellationToken cancellationToken)
{
_cts?.Cancel();
return Task.CompletedTask;
}
public async Task FrameReceivedAsync(CastScreenReceived screenDataReceived, CancellationToken cancellationToken)
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)

View file

@ -2,7 +2,8 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0-windows</TargetFramework>
<TargetFramework>net8.0-windows</TargetFramework>
<LangVersion>latest</LangVersion>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
<Product>Remote Control</Product>
@ -12,10 +13,11 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<SatelliteResourceLanguages>none</SatelliteResourceLanguages>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="7.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0" />
<PackageReference Include="NAudio.Wasapi" Version="2.2.1" />
<PackageReference Include="SharpDX.Direct3D11" Version="4.2.0" />
</ItemGroup>

View file

@ -4,28 +4,18 @@ using SharpDX.DXGI;
namespace Insight.Remote.Windows.Models;
public class DirectXOutput : IDisposable
public class DirectXOutput(Adapter1 adapter,
SharpDX.Direct3D11.Device device,
OutputDuplication outputDuplication,
Texture2D texture2D,
DisplayModeRotation rotation) : IDisposable
{
public DirectXOutput(Adapter1 adapter,
SharpDX.Direct3D11.Device device,
OutputDuplication outputDuplication,
Texture2D texture2D,
DisplayModeRotation rotation)
{
Adapter = adapter;
Device = device;
OutputDuplication = outputDuplication;
Texture2D = texture2D;
Rotation = rotation;
Bounds = new Rectangle(0, 0, texture2D.Description.Width, texture2D.Description.Height);
}
public Adapter1 Adapter { get; }
public Rectangle Bounds { get; set; }
public SharpDX.Direct3D11.Device Device { get; }
public OutputDuplication OutputDuplication { get; }
public DisplayModeRotation Rotation { get; }
public Texture2D Texture2D { get; }
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()
{

View file

@ -9,44 +9,33 @@ using Microsoft.Extensions.Logging;
using Microsoft.Win32;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Windows;
using System.Runtime.Versioning;
using Vaitr.Bus;
namespace Insight.Remote.Windows.Services;
internal class WinApp : IDesktopApp
[SupportedOSPlatform("windows")]
internal class WinApp(
IInputProvider inputProvider,
ICursorProvider cursorProvider,
IAudioProvider audioProvider,
IClipboardProvider clipboardProvider,
IDispatcher dispatcher,
MainViewModel mainViewModel,
Bus bus,
ILogger<WinApp> logger) : IDesktopApp
{
private MainWindow? _mainWindow;
private bool _disposed;
private readonly IInputProvider _inputProvider;
private readonly ICursorProvider _cursorProvider;
private readonly IAudioProvider _audioProvider;
private readonly IClipboardProvider _clipboardProvider;
private readonly IDispatcher _dispatcher;
private readonly MainViewModel _maiViewModel;
private readonly Bus _bus;
private readonly ILogger<WinApp> _logger;
public WinApp(
IInputProvider inputProvider,
ICursorProvider cursorProvider,
IAudioProvider audioProvider,
IClipboardProvider clipboardProvider,
IDispatcher dispatcher,
MainViewModel mainViewModel,
Bus bus,
ILogger<WinApp> logger)
{
_inputProvider = inputProvider;
_cursorProvider = cursorProvider;
_audioProvider = audioProvider;
_clipboardProvider = clipboardProvider;
_dispatcher = dispatcher;
_maiViewModel = mainViewModel;
_bus = bus;
_logger = logger;
}
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<WinApp> _logger = logger;
public async Task InitAsync(RemoteControlMode mode, CancellationToken cancellationToken)
{
@ -100,7 +89,7 @@ internal class WinApp : IDesktopApp
catch (TaskCanceledException) { }
catch (Exception ex)
{
_logger.LogError(ex.Message);
_logger.LogError("{exception}", ex.Message);
}
}
}
@ -143,7 +132,7 @@ internal class WinApp : IDesktopApp
catch (TaskCanceledException) { }
catch (Exception ex)
{
_logger.LogError(ex.Message);
_logger.LogError("{exception}", ex.Message);
}
}
@ -153,26 +142,21 @@ internal class WinApp : IDesktopApp
private async ValueTask OnCastRequestAsync(CastRequest request, CancellationToken cancellationToken)
{
if (true) // test
{
await _bus.PublishAsync(new CastRequestDemand(request, true), cancellationToken);
return;
}
// 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);
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;
}
}
// switch (result)
// {
// case MessageBoxResult.No: await _bus.PublishAsync(new CastRequestDemand(request, false), cancellationToken); return;
// }
//}
await _bus.PublishAsync(new CastRequestDemand(request, true), cancellationToken);
}

View file

@ -7,19 +7,13 @@ using Vaitr.Bus;
namespace Insight.Remote.Windows.Services;
internal class WinAudioProvider : IAudioProvider
internal class WinAudioProvider(Bus bus, ILogger<WinAudioProvider> logger) : IAudioProvider
{
private WasapiLoopbackCapture? _capturer;
private WaveFormat? _targetFormat;
private readonly Bus _bus;
private readonly ILogger<WinAudioProvider> _logger;
public WinAudioProvider(Bus bus, ILogger<WinAudioProvider> logger)
{
_bus = bus;
_logger = logger;
}
private readonly Bus _bus = bus;
private readonly ILogger<WinAudioProvider> _logger = logger;
public async Task InitAsync(CancellationToken cancellationToken)
{

View file

@ -8,18 +8,12 @@ using Clipboard = System.Windows.Clipboard;
namespace Insight.Remote.Windows.Services;
internal class WinClipboardProvider : IClipboardProvider
internal class WinClipboardProvider(Bus bus, ILogger<WinClipboardProvider> logger) : IClipboardProvider
{
private readonly ConcurrentQueue<string> _setQueue = new();
private readonly Bus _bus;
private readonly ILogger<WinClipboardProvider> _logger;
public WinClipboardProvider(Bus bus, ILogger<WinClipboardProvider> logger)
{
_bus = bus;
_logger = logger;
}
private readonly Bus _bus = bus;
private readonly ILogger<WinClipboardProvider> _logger = logger;
public async Task InitAsync(CancellationToken cancellationToken)
{
@ -79,7 +73,7 @@ internal class WinClipboardProvider : IClipboardProvider
catch (TaskCanceledException) { }
catch (Exception ex)
{
_logger.LogError(ex.Message);
_logger.LogError("{exception}", ex.Message);
}
}
}

View file

@ -8,20 +8,15 @@ using System.Runtime.InteropServices;
namespace Insight.Remote.Windows.Services;
internal class WinCursorProvider : ICursorProvider
internal class WinCursorProvider(ILogger<WinCursorProvider> logger) : ICursorProvider
{
private readonly SemaphoreSlim _semaphore = new(1, 1);
private readonly ILogger<WinCursorProvider> _logger;
private readonly ILogger<WinCursorProvider> _logger = logger;
private User32.CursorInfo _cursor = new();
private CastCursor _lastCursor = new();
private nint _lastHandle = 0;
private byte[] _lastIconBytes = Array.Empty<byte>();
public WinCursorProvider(ILogger<WinCursorProvider> logger)
{
_logger = logger;
}
private byte[] _lastIconBytes = [];
public async Task<CastCursor?> GetAsync(CancellationToken cancellationToken)
{
@ -73,7 +68,7 @@ internal class WinCursorProvider : ICursorProvider
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
_logger.LogError("{exception}", ex.Message);
return null;
}
finally
@ -92,10 +87,10 @@ internal class WinCursorProvider : ICursorProvider
User32.SetCursorPos(x, y);
}
catch (TaskCanceledException) { }
catch (OperationCanceledException) { }
catch (Exception ex)
{
_logger.LogError(ex.Message);
_logger.LogError("{exception}", ex.Message);
}
finally
{
@ -107,6 +102,6 @@ internal class WinCursorProvider : ICursorProvider
{
X = 0,
Y = 0,
Icon = Array.Empty<byte>()
Icon = []
};
}

View file

@ -6,20 +6,14 @@ using Application = System.Windows.Application;
namespace Insight.Remote.Windows.Services;
internal class WinDispatcher : IDispatcher
internal class WinDispatcher(IHostApplicationLifetime lifetime, ILogger<WinDispatcher> logger) : IDispatcher
{
private Application? _app;
private readonly ManualResetEvent _appSignal = new(false);
private readonly IHostApplicationLifetime _lifetime;
private readonly ILogger<WinDispatcher> _logger;
public WinDispatcher(IHostApplicationLifetime lifetime, ILogger<WinDispatcher> logger)
{
_lifetime = lifetime;
_logger = logger;
}
private readonly IHostApplicationLifetime _lifetime = lifetime;
private readonly ILogger<WinDispatcher> _logger = logger;
public async Task<Thread> RunAsync(CancellationToken cancellationToken)
{
@ -56,7 +50,7 @@ internal class WinDispatcher : IDispatcher
catch (TaskCanceledException) { }
catch (Exception ex)
{
_logger.LogError(ex.Message);
_logger.LogError("{exception}", ex.Message);
}
}

View file

@ -5,6 +5,7 @@ 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;
@ -12,17 +13,13 @@ using MessageBoxOptions = System.Windows.MessageBoxOptions;
namespace Insight.Remote.Windows.Services;
internal class WinFileProvider : IFileProvider
[SupportedOSPlatform("windows")]
internal class WinFileProvider(ILogger<WinFileProvider> logger) : IFileProvider
{
private static MessageBoxResult? _result;
private static readonly ConcurrentDictionary<string, FileStream> _partialTransfers = new();
private static readonly SemaphoreSlim _writeLock = new(1, 1);
private readonly ILogger<WinFileProvider> _logger;
public WinFileProvider(ILogger<WinFileProvider> logger)
{
_logger = logger;
}
private readonly ILogger<WinFileProvider> _logger = logger;
public string GetBaseDirectory()
{
@ -89,7 +86,7 @@ internal class WinFileProvider : IFileProvider
}
}
public async Task UploadFile(FileUpload fileUpload, Streamer viewer, Action<double> progressUpdateCallback, CancellationToken cancelToken)
public Task UploadFile(FileUpload fileUpload, Streamer viewer, Action<double> progressUpdateCallback, CancellationToken cancelToken)
{
try
{
@ -99,9 +96,11 @@ internal class WinFileProvider : IFileProvider
{
_logger.LogError(ex, "Error while uploading file.");
}
return Task.CompletedTask;
}
private void SetFileOrFolderPermissions(string path)
private static void SetFileOrFolderPermissions(string path)
{
FileSystemSecurity ds;

View file

@ -6,20 +6,14 @@ using System.Threading.Channels;
namespace Insight.Remote.Windows.Services;
internal class WinInputProvider : IInputProvider
internal class WinInputProvider(IScreenProvider screenProvider, ILogger<WinInputProvider> logger) : IInputProvider
{
private volatile bool _inputBlocked;
private readonly Channel<Action> _inputs = Channel.CreateUnbounded<Action>(new UnboundedChannelOptions { AllowSynchronousContinuations = false });
private readonly IScreenProvider _screenProvider;
private readonly ILogger<WinInputProvider> _logger;
public WinInputProvider(IScreenProvider screenProvider, ILogger<WinInputProvider> logger)
{
_screenProvider = screenProvider;
_logger = logger;
}
private readonly IScreenProvider _screenProvider = screenProvider;
private readonly ILogger<WinInputProvider> _logger = logger;
public async Task InitAsync(CancellationToken cancellationToken)
{
@ -31,10 +25,10 @@ internal class WinInputProvider : IInputProvider
await Task.Delay(1000, cancellationToken);
}
}
catch (TaskCanceledException) { }
catch (OperationCanceledException) { }
catch (Exception ex)
{
_logger.LogError(ex.ToString());
_logger.LogError("{exception}", ex.ToString());
}
}
@ -68,7 +62,7 @@ internal class WinInputProvider : IInputProvider
catch (OperationCanceledException) { }
catch (Exception ex)
{
_logger.LogError(ex.Message);
_logger.LogError("{exception}", ex.Message);
}
}
@ -83,10 +77,10 @@ internal class WinInputProvider : IInputProvider
{
await semaphore.WaitAsync(cancellationToken);
}
catch (TaskCanceledException) { }
catch (OperationCanceledException) { }
catch (Exception ex)
{
_logger.LogError(ex.ToString());
_logger.LogError("{exception}", ex.ToString());
}
}
@ -110,13 +104,13 @@ internal class WinInputProvider : IInputProvider
};
var input = new User32.INPUT() { type = User32.InputType.KEYBOARD, U = union };
_ = User32.SendInput(1, new User32.INPUT[] { input }, User32.INPUT.Size);
_ = User32.SendInput(1, [input], User32.INPUT.Size);
}, cancellationToken);
}
catch (TaskCanceledException) { }
catch (OperationCanceledException) { }
catch (Exception ex)
{
_logger.LogError(ex.ToString());
_logger.LogError("{exception}", ex.ToString());
}
}
@ -140,13 +134,13 @@ internal class WinInputProvider : IInputProvider
}
};
var input = new User32.INPUT() { type = User32.InputType.KEYBOARD, U = union };
_ = User32.SendInput(1, new User32.INPUT[] { input }, User32.INPUT.Size);
_ = User32.SendInput(1, [input], User32.INPUT.Size);
}, cancellationToken);
}
catch (TaskCanceledException) { }
catch (OperationCanceledException) { }
catch (Exception ex)
{
_logger.LogError(ex.ToString());
_logger.LogError("{exception}", ex.ToString());
}
}
@ -209,13 +203,13 @@ internal class WinInputProvider : IInputProvider
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, new User32.INPUT[] { input }, User32.INPUT.Size);
_ = User32.SendInput(1, [input], User32.INPUT.Size);
}, cancellationToken);
}
catch (TaskCanceledException) { }
catch (OperationCanceledException) { }
catch (Exception ex)
{
_logger.LogError(ex.ToString());
_logger.LogError("{exception}", ex.ToString());
}
}
@ -231,13 +225,13 @@ internal class WinInputProvider : IInputProvider
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, new User32.INPUT[] { input }, User32.INPUT.Size);
_ = User32.SendInput(1, [input], User32.INPUT.Size);
}, cancellationToken);
}
catch (TaskCanceledException) { }
catch (OperationCanceledException) { }
catch (Exception ex)
{
_logger.LogError(ex.ToString());
_logger.LogError("{exception}", ex.ToString());
}
}
@ -257,13 +251,13 @@ internal class WinInputProvider : IInputProvider
}
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, new User32.INPUT[] { input }, User32.INPUT.Size);
_ = User32.SendInput(1, [input], User32.INPUT.Size);
}, cancellationToken);
}
catch (TaskCanceledException) { }
catch (OperationCanceledException) { }
catch (Exception ex)
{
_logger.LogError(ex.ToString());
_logger.LogError("{exception}", ex.ToString());
}
}
@ -276,10 +270,10 @@ internal class WinInputProvider : IInputProvider
SendKeys.SendWait(transferText);
}, cancellationToken);
}
catch (TaskCanceledException) { }
catch (OperationCanceledException) { }
catch (Exception ex)
{
_logger.LogError(ex.ToString());
_logger.LogError("{exception}", ex.ToString());
}
}
@ -308,7 +302,7 @@ internal class WinInputProvider : IInputProvider
}
};
var input = new User32.INPUT() { type = User32.InputType.KEYBOARD, U = union };
_ = User32.SendInput(1, new User32.INPUT[] { input }, User32.INPUT.Size);
_ = User32.SendInput(1, [input], User32.INPUT.Size);
}
}
catch { }
@ -318,7 +312,7 @@ internal class WinInputProvider : IInputProvider
catch (TaskCanceledException) { }
catch (Exception ex)
{
_logger.LogError(ex.ToString());
_logger.LogError("{exception}", ex.ToString());
}
}
@ -337,7 +331,7 @@ internal class WinInputProvider : IInputProvider
catch (TaskCanceledException) { }
catch (Exception ex)
{
_logger.LogError(ex.ToString());
_logger.LogError("{exception}", ex.ToString());
}
}

View file

@ -37,11 +37,13 @@ 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<Rectangle>? ScreenChanged;
@ -72,8 +74,8 @@ internal class WinScreenCapturer : IScreenProvider
private bool _initialized;
private readonly SemaphoreSlim _semaphore = new(1, 1);
private readonly Dictionary<string, int> _bitBltScreens = new();
private readonly Dictionary<string, DirectXOutput> _directxScreens = new();
private readonly Dictionary<string, int> _bitBltScreens = [];
private readonly Dictionary<string, DirectXOutput> _directxScreens = [];
private readonly Bus _bus;
private readonly ILogger<WinScreenCapturer> _logger;
@ -86,7 +88,7 @@ internal class WinScreenCapturer : IScreenProvider
SystemEvents.DisplaySettingsChanged += SystemEvents_DisplaySettingsChanged;
}
public async Task InitAsync(CancellationToken cancellationToken)
public Task InitAsync(CancellationToken cancellationToken)
{
Win32Interop.SwitchToInputDesktop();
@ -94,6 +96,8 @@ internal class WinScreenCapturer : IScreenProvider
InitDirectX();
_initialized = true;
return Task.CompletedTask;
}
public void SetSelectedScreen(string displayName)

View file

@ -2,9 +2,7 @@
using Insight.Remote.Shared.Messages;
using Insight.Remote.Shared.Native.Windows;
using Insight.Remote.Shared.Reactive;
using Insight.Remote.Shared.Services;
using Microsoft.Extensions.Logging;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Security.Principal;
using Vaitr.Bus;
@ -28,7 +26,7 @@ public class MainViewModel : ViewModelBase
private string? _lastId;
private readonly List<IDisposable> _subscriptions = new();
private readonly List<IDisposable> _subscriptions = [];
private readonly Bus _bus;
private readonly IDispatcher _dispatcher;
@ -152,6 +150,6 @@ public class FakeMainViewModel : ViewModelBase
public RelayCommand ElevateToAdminCommand { get; } = new(() => { });
public RelayCommand ElevateToServiceCommand { get; } = new(() => { });
public bool IsAdministrator => false;
public static bool IsAdministrator => false;
public string StatusMessage { get; set; } = "test";
}

View file

@ -25,7 +25,7 @@ public partial class MainWindow : Window
private void Window_Loaded(object sender, RoutedEventArgs e)
{
if (DesignerProperties.GetIsInDesignMode(this)) return;
if (DataContext is not MainViewModel vm) return;
if (DataContext is not MainViewModel) return;
}
private void Window_Closing(object sender, CancelEventArgs e)

View file

@ -8,7 +8,7 @@ public static class Async
this IAsyncEnumerable<T> source,
Func<T, Task> body,
int maxDegreeOfParallelism = DataflowBlockOptions.Unbounded,
TaskScheduler scheduler = null)
TaskScheduler? scheduler = null)
{
var options = new ExecutionDataflowBlockOptions
{
@ -31,7 +31,7 @@ public static class Async
this IEnumerable<T> source,
Func<T, Task> body,
int maxDegreeOfParallelism = DataflowBlockOptions.Unbounded,
TaskScheduler scheduler = null)
TaskScheduler? scheduler = null)
{
var options = new ExecutionDataflowBlockOptions
{

View file

@ -2,13 +2,15 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<LangVersion>latest</LangVersion>
<Product>Insight</Product>
<AssemblyName>server</AssemblyName>
<AssemblyVersion>2023.12.14.0</AssemblyVersion>
<RootNamespace>Insight.Server</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<SatelliteResourceLanguages>none</SatelliteResourceLanguages>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
@ -38,8 +40,8 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="7.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0" />
<PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0" />
<!--Unix Serilog stuff-->
</ItemGroup>

View file

@ -7,18 +7,16 @@ using Vaitr.Network;
namespace Insight.Server.Network.Agent;
public class AgentSession : TcpSession<IMessage>
public class AgentSession(
AgentHandler agentHandler,
IEnumerable<IMessageHandler<AgentSession>> handlers,
ISerializer<IMessage> serializer,
ILogger<AgentSession> logger) : TcpSession<IMessage>(serializer, logger)
{
public string? Id { get; set; }
private readonly AgentHandler _agentHandler;
private readonly IEnumerable<IMessageHandler<AgentSession>> _handlers;
public AgentSession(AgentHandler agentHandler, IEnumerable<IMessageHandler<AgentSession>> handlers, ISerializer<IMessage> serializer, ILogger<AgentSession> logger) : base(serializer, logger)
{
_agentHandler = agentHandler;
_handlers = handlers;
}
private readonly AgentHandler _agentHandler = agentHandler;
private readonly IEnumerable<IMessageHandler<AgentSession>> _handlers = handlers;
protected override async ValueTask OnConnectedAsync(CancellationToken cancellationToken)
{

View file

@ -8,16 +8,10 @@ using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class AgentHandler : IMessageHandler<AgentSession>
public class AgentHandler(IMongoDatabase database, ILogger<AgentHandler> logger) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database;
private readonly ILogger<AgentHandler> _logger;
public AgentHandler(IMongoDatabase database, ILogger<AgentHandler> logger)
{
_database = database;
_logger = logger;
}
private readonly IMongoDatabase _database = database;
private readonly ILogger<AgentHandler> _logger = logger;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{

View file

@ -5,14 +5,9 @@ using Microsoft.Extensions.Logging;
namespace Insight.Server.Network.Agent.Handlers;
public class CustomHandler : IMessageHandler<AgentSession>
public class CustomHandler(ILogger<CustomHandler> logger) : IMessageHandler<AgentSession>
{
private readonly ILogger<CustomHandler> _logger;
public CustomHandler(ILogger<CustomHandler> logger)
{
_logger = logger;
}
private readonly ILogger<CustomHandler> _logger = logger;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
@ -24,8 +19,9 @@ public class CustomHandler : IMessageHandler<AgentSession>
}
}
private async ValueTask OnResponseAsync(AgentSession sender, Response response, CancellationToken cancellationToken)
private ValueTask OnResponseAsync(AgentSession sender, Response response, CancellationToken cancellationToken)
{
_logger.LogWarning($"Response: {response.ResponseData}");
_logger.LogWarning("Response: {response}", response.ResponseData);
return default;
}
}

View file

@ -7,14 +7,9 @@ using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class DriveHandler : IMessageHandler<AgentSession>
public class DriveHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database;
public DriveHandler(IMongoDatabase database)
{
_database = database;
}
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
@ -39,7 +34,7 @@ public class DriveHandler : IMessageHandler<AgentSession>
var driveBulk = new List<WriteModel<HostDriveEntity>>();
if (drives is not null && drives.Any())
if (drives is not null && drives.Count != 0)
{
foreach (var drive in drives)
{
@ -83,16 +78,16 @@ public class DriveHandler : IMessageHandler<AgentSession>
var volumeBulk = new List<WriteModel<HostVolumeEntity>>();
if (drives is not null && drives.Any())
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();
.FirstOrDefaultAsync(cancellationToken: default);
if (drive.Volumes is not null && drive.Volumes.Any())
if (drive.Volumes is not null && drive.Volumes.Count != 0)
{
foreach (var volume in drive.Volumes)
{

View file

@ -3,22 +3,14 @@ using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
using Insight.Infrastructure.Entities;
using Microsoft.Extensions.Logging;
using MongoDB.Driver;
using static Insight.Domain.Network.Agent.Messages.Event;
namespace Insight.Server.Network.Agent.Handlers;
public class EventHandler : IMessageHandler<AgentSession>
public class EventHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database;
private readonly ILogger<EventHandler> _logger;
public EventHandler(IMongoDatabase database, ILogger<EventHandler> logger)
{
_database = database;
_logger = logger;
}
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
@ -75,13 +67,13 @@ public class EventHandler : IMessageHandler<AgentSession>
_ => null
};
CategoryEnum? category = @event.Category.ToLower() switch
CategoryEnum? category = @event.Category?.ToLower() switch
{
"network" => CategoryEnum.Network,
"application" => CategoryEnum.Application,
"security" => CategoryEnum.Security,
"system" => CategoryEnum.System,
_ => null
_ => CategoryEnum.None
};
var date = DateTime.Now;
@ -114,55 +106,59 @@ public class EventHandler : IMessageHandler<AgentSession>
_ => null
};
CategoryEnum? category = null;
switch (@event.Category)
var category = CategoryEnum.None;
if (@event.Category is not null)
{
case var _ when @event.Category.Contains("network", StringComparison.InvariantCultureIgnoreCase):
category = CategoryEnum.Network;
break;
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("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("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("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("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("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("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("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("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("storagespaces", StringComparison.InvariantCultureIgnoreCase):
category = CategoryEnum.System;
break;
case var _ when @event.Category.Contains("diagnostics", StringComparison.InvariantCultureIgnoreCase):
category = CategoryEnum.System;
break;
case var _ when @event.Category.Contains("diagnostics", StringComparison.InvariantCultureIgnoreCase):
category = CategoryEnum.System;
break;
default:
break;
default:
break;
}
}
var date = DateTime.Now;
@ -175,7 +171,7 @@ public class EventHandler : IMessageHandler<AgentSession>
EventId = @event.EventId.ToString(),
Status = status.ToString(),
Source = @event.Source,
Category = category?.ToString(),
Category = category.ToString(),
Message = @event.Message
};
@ -183,7 +179,7 @@ public class EventHandler : IMessageHandler<AgentSession>
return log;
}
private bool FilterEventId(Event @event)
private static bool FilterEventId(Event @event)
{
var filter = new List<int>
{
@ -234,10 +230,8 @@ public class EventHandler : IMessageHandler<AgentSession>
return false;
}
private bool FilterMonitoringHostLog(HostLogEntity hostLog)
private static 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())

View file

@ -7,14 +7,9 @@ using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class InterfaceHandler : IMessageHandler<AgentSession>
public class InterfaceHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database;
public InterfaceHandler(IMongoDatabase database)
{
_database = database;
}
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
@ -39,7 +34,7 @@ public class InterfaceHandler : IMessageHandler<AgentSession>
// interfaces
if (interfaces is not null && interfaces.Any())
if (interfaces is not null && interfaces.Count != 0)
{
var interfaceBulk = new List<WriteModel<HostInterfaceEntity>>();
@ -95,7 +90,7 @@ public class InterfaceHandler : IMessageHandler<AgentSession>
// addresses
if (interfaces is not null && interfaces.Any())
if (interfaces is not null && interfaces.Count != 0)
{
var addressBulk = new List<WriteModel<HostInterfaceAddressEntity>>();
@ -104,9 +99,9 @@ public class InterfaceHandler : IMessageHandler<AgentSession>
var interfaceId = await _database.HostInterface()
.Find(p => p.Host == hostEntity.Id && p.Index == @interface.Index)
.Project(p => p.Id)
.FirstOrDefaultAsync();
.FirstOrDefaultAsync(cancellationToken: default);
if (@interface.Addresses is not null && @interface.Addresses.Any())
if (@interface.Addresses is not null && @interface.Addresses.Count != 0)
{
foreach (var address in @interface.Addresses)
{
@ -146,7 +141,7 @@ public class InterfaceHandler : IMessageHandler<AgentSession>
// gateways
if (interfaces is not null && interfaces.Any())
if (interfaces is not null && interfaces.Count != 0)
{
var gatewayBulk = new List<WriteModel<HostInterfaceGatewayEntity>>();
@ -155,9 +150,9 @@ public class InterfaceHandler : IMessageHandler<AgentSession>
var interfaceId = await _database.HostInterface()
.Find(p => p.Host == hostEntity.Id && p.Index == @interface.Index)
.Project(p => p.Id)
.FirstOrDefaultAsync();
.FirstOrDefaultAsync(cancellationToken: default);
if (@interface.Gateways is not null && @interface.Gateways.Any())
if (@interface.Gateways is not null && @interface.Gateways.Count != 0)
{
foreach (var gateway in @interface.Gateways)
{
@ -195,7 +190,7 @@ public class InterfaceHandler : IMessageHandler<AgentSession>
// nameservers
if (interfaces is not null && interfaces.Any())
if (interfaces is not null && interfaces.Count != 0)
{
var nameserverBulk = new List<WriteModel<HostInterfaceNameserverEntity>>();
@ -204,9 +199,9 @@ public class InterfaceHandler : IMessageHandler<AgentSession>
var interfaceId = await _database.HostInterface()
.Find(p => p.Host == hostEntity.Id && p.Index == @interface.Index)
.Project(p => p.Id)
.FirstOrDefaultAsync();
.FirstOrDefaultAsync(cancellationToken: default);
if (@interface.Dns is not null && @interface.Dns.Any())
if (@interface.Dns is not null && @interface.Dns.Count != 0)
{
foreach (var nameserver in @interface.Dns)
{
@ -244,7 +239,7 @@ public class InterfaceHandler : IMessageHandler<AgentSession>
// routes
if (interfaces is not null && interfaces.Any())
if (interfaces is not null && interfaces.Count != 0)
{
var routeBulk = new List<WriteModel<HostInterfaceRouteEntity>>();
@ -253,9 +248,9 @@ public class InterfaceHandler : IMessageHandler<AgentSession>
var interfaceId = await _database.HostInterface()
.Find(p => p.Host == hostEntity.Id && p.Index == @interface.Index)
.Project(p => p.Id)
.FirstOrDefaultAsync();
.FirstOrDefaultAsync(cancellationToken: default);
if (@interface.Routes is not null && @interface.Routes.Any())
if (@interface.Routes is not null && @interface.Routes.Count != 0)
{
foreach (var route in @interface.Routes)
{

View file

@ -6,14 +6,9 @@ using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers
{
public class MainboardHandler : IMessageHandler<AgentSession>
public class MainboardHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database;
public MainboardHandler(IMongoDatabase database)
{
_database = database;
}
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{

View file

@ -7,14 +7,9 @@ using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class MemoryHandler : IMessageHandler<AgentSession>
public class MemoryHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database;
public MemoryHandler(IMongoDatabase database)
{
_database = database;
}
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
@ -39,7 +34,7 @@ public class MemoryHandler : IMessageHandler<AgentSession>
var bulk = new List<WriteModel<HostMemoryEntity>>();
if (memory is not null && memory.Any())
if (memory is not null && memory.Count != 0)
{
foreach (var mem in memory)
{

View file

@ -6,14 +6,9 @@ using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class OperationSystemHandler : IMessageHandler<AgentSession>
public class OperationSystemHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database;
public OperationSystemHandler(IMongoDatabase database)
{
_database = database;
}
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{

View file

@ -7,14 +7,9 @@ using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class PrinterHandler : IMessageHandler<AgentSession>
public class PrinterHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database;
public PrinterHandler(IMongoDatabase database)
{
_database = database;
}
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
@ -39,7 +34,7 @@ public class PrinterHandler : IMessageHandler<AgentSession>
var bulk = new List<WriteModel<HostPrinterEntity>>();
if (printers is not null && printers.Any())
if (printers is not null && printers.Count != 0)
{
foreach (var printer in printers)
{

View file

@ -7,14 +7,9 @@ using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class ProcessorHandler : IMessageHandler<AgentSession>
public class ProcessorHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database;
public ProcessorHandler(IMongoDatabase database)
{
_database = database;
}
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
@ -39,7 +34,7 @@ public class ProcessorHandler : IMessageHandler<AgentSession>
var bulk = new List<WriteModel<HostProcessorEntity>>();
if (processors is not null && processors.Any())
if (processors is not null && processors.Count != 0)
{
foreach (var processor in processors)
{

View file

@ -7,14 +7,9 @@ using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class ServiceHandler : IMessageHandler<AgentSession>
public class ServiceHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database;
public ServiceHandler(IMongoDatabase database)
{
_database = database;
}
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
@ -39,7 +34,7 @@ public class ServiceHandler : IMessageHandler<AgentSession>
var bulk = new List<WriteModel<HostServiceEntity>>();
if (services is not null && services.Any())
if (services is not null && services.Count != 0)
{
foreach (var service in services)
{

View file

@ -7,14 +7,9 @@ using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class SessionHandler : IMessageHandler<AgentSession>
public class SessionHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database;
public SessionHandler(IMongoDatabase database)
{
_database = database;
}
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
@ -39,7 +34,7 @@ public class SessionHandler : IMessageHandler<AgentSession>
var bulk = new List<WriteModel<HostSessionEntity>>();
if (sessions is not null && sessions.Any())
if (sessions is not null && sessions.Count != 0)
{
foreach (var sess in sessions)
{

View file

@ -7,14 +7,9 @@ using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class SoftwareHandler : IMessageHandler<AgentSession>
public class SoftwareHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database;
public SoftwareHandler(IMongoDatabase database)
{
_database = database;
}
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
@ -39,7 +34,7 @@ public class SoftwareHandler : IMessageHandler<AgentSession>
var bulk = new List<WriteModel<HostApplicationEntity>>();
if (applications is not null && applications.Any())
if (applications is not null && applications.Count != 0)
{
foreach (var app in applications)
{

View file

@ -7,14 +7,9 @@ using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class StoragePoolHandler : IMessageHandler<AgentSession>
public class StoragePoolHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database;
public StoragePoolHandler(IMongoDatabase database)
{
_database = database;
}
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
@ -39,7 +34,7 @@ public class StoragePoolHandler : IMessageHandler<AgentSession>
// storagepools
if (storagePools is not null && storagePools.Any())
if (storagePools is not null && storagePools.Count != 0)
{
var storagepoolBulk = new List<WriteModel<HostStoragePoolEntity>>();
@ -55,12 +50,10 @@ public class StoragePoolHandler : IMessageHandler<AgentSession>
if (storagePool.States is not null)
{
states = new List<string>();
states = [];
foreach (var state in storagePool.States)
{
states.Add(state.ToString());
}
}
var storagePoolUpdate = Builders<HostStoragePoolEntity>.Update
@ -98,7 +91,7 @@ public class StoragePoolHandler : IMessageHandler<AgentSession>
// physicaldisks
if (storagePools is not null && storagePools.Any())
if (storagePools is not null && storagePools.Count != 0)
{
var physicalDiskBulk = new List<WriteModel<HostStoragePoolPhysicalDiskEntity>>();
@ -107,9 +100,9 @@ public class StoragePoolHandler : IMessageHandler<AgentSession>
var storagePoolId = await _database.HostStoragePool()
.Find(p => p.Host == hostEntity.Id && p.UniqueId == storagePool.UniqueId)
.Project(p => p.Id)
.FirstOrDefaultAsync();
.FirstOrDefaultAsync(cancellationToken: default);
if (storagePool.PhysicalDisks is not null && storagePool.PhysicalDisks.Any())
if (storagePool.PhysicalDisks is not null && storagePool.PhysicalDisks.Count != 0)
{
foreach (var physicalDisk in storagePool.PhysicalDisks)
{
@ -124,12 +117,10 @@ public class StoragePoolHandler : IMessageHandler<AgentSession>
if (physicalDisk.States is not null)
{
states = new List<string>();
states = [];
foreach (var state in physicalDisk.States)
{
states.Add(state.ToString());
}
}
var physicalDiskUpdate = Builders<HostStoragePoolPhysicalDiskEntity>.Update
@ -177,20 +168,20 @@ public class StoragePoolHandler : IMessageHandler<AgentSession>
// virtual disks
if (storagePools is not null && storagePools.Any())
if (storagePools is not null && storagePools.Count != 0)
{
var virtualDiskBulk = new List<WriteModel<HostStoragePoolVirtualDiskEntity>>();
foreach (var storagePool in storagePools)
{
if (storagePool.VirtualDisks is not null && storagePool.VirtualDisks.Any())
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();
.FirstOrDefaultAsync(cancellationToken: default);
var virtualDiskFilter = Builders<HostStoragePoolVirtualDiskEntity>.Filter.And(new List<FilterDefinition<HostStoragePoolVirtualDiskEntity>>
{
@ -203,12 +194,10 @@ public class StoragePoolHandler : IMessageHandler<AgentSession>
if (virtualDisk.States is not null)
{
states = new List<string>();
states = [];
foreach (var state in virtualDisk.States)
{
states.Add(state.ToString());
}
}
var virtualDiskUpdate = Builders<HostStoragePoolVirtualDiskEntity>.Update

View file

@ -6,14 +6,9 @@ using MongoDB.Driver;
namespace Insight.Server.Network.Agent.Handlers;
public class SystemInfoHandler : IMessageHandler<AgentSession>
public class SystemInfoHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database;
public SystemInfoHandler(IMongoDatabase database)
{
_database = database;
}
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
@ -27,22 +22,24 @@ public class SystemInfoHandler : IMessageHandler<AgentSession>
private async ValueTask OnSystemInfoAsync(AgentSession session, SystemInfo? system, CancellationToken cancellationToken)
{
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session.Id)).FirstOrDefaultAsync(cancellationToken);
var agentEntity = await _database.Agent().Find(Builders<AgentEntity>.Filter.Eq(p => p.Id, session?.Id)).FirstOrDefaultAsync(cancellationToken);
if (agentEntity is null) return;
var hostEntity = await _database.Host().Find(Builders<HostEntity>.Filter.Eq(p => p.Agent, agentEntity.Id)).FirstOrDefaultAsync(cancellationToken);
var hostEntity = await _database.Host().Find(Builders<HostEntity>.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<HostSystemEntity>.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
.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);

View file

@ -11,14 +11,9 @@ using static Insight.Server.Models.MonitorMessage;
namespace Insight.Server.Network.Agent.Handlers;
public class TrapHandler : IMessageHandler<AgentSession>
public partial class TrapHandler(IMongoDatabase database) : IMessageHandler<AgentSession>
{
private readonly IMongoDatabase _database;
public TrapHandler(IMongoDatabase database)
{
_database = database;
}
private readonly IMongoDatabase _database = database;
public async ValueTask HandleAsync<TMessage>(AgentSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
{
@ -85,7 +80,8 @@ public class TrapHandler : IMessageHandler<AgentSession>
{
monitoring = null;
if (packet is null || packet.Data is null || packet.Data.Any() is false) return false;
if (packet is null || packet.Data is null || packet.Data.Count == 0)
return false;
monitoring = new MonitorMessage
{
@ -96,9 +92,7 @@ public class TrapHandler : IMessageHandler<AgentSession>
};
if (Enum.TryParse<ApplicationEnum>(packet.Community, true, out var application))
{
monitoring.Application = application;
}
StatusEnum? status;
string? task;
@ -131,9 +125,12 @@ public class TrapHandler : IMessageHandler<AgentSession>
return true;
}
private static bool ParseAcronis(List<KeyValuePair<string, string>> data, out StatusEnum? status, out string? task, out string? message)
[GeneratedRegex(@"\s+")]
private static partial Regex AcronisRegex();
private static bool ParseAcronis(List<KeyValuePair<string, string?>> data, out StatusEnum? status, out string? task, out string? message)
{
status = data[0].Value.ToLower() switch
status = data[0].Value?.ToLower() switch
{
"erfolgreich" => StatusEnum.Information,
"success" => StatusEnum.Information,
@ -149,49 +146,32 @@ public class TrapHandler : IMessageHandler<AgentSession>
task = null;
message = null;
var parsed = false;
var trim = data[1].Value?.Split(':', StringSplitOptions.None);
if (trim is null || trim.Length == 0) return 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();
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;
parsed = true;
}
catch (Exception)
{
// skipped for base64 parse
}
if (data[1].Value is not string val) return false;
if (parsed) return true;
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();
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);
content = Encoding.UTF8.GetString(bytes);
trim = content.Split(':', StringSplitOptions.None);
if (trim is null || trim.Length == 0) return false;
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;
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<KeyValuePair<string, string>> data, out StatusEnum? status, out string? task, out string? message)
private static bool ParseVeeam(List<KeyValuePair<string, string?>> data, out StatusEnum? status, out string? task, out string? message)
{
status = null;
task = null;
@ -206,10 +186,10 @@ public class TrapHandler : IMessageHandler<AgentSession>
if (Guid.TryParse(data[0].Value, out _))
summary = true;
if (data[1].Value.ToLower() == "backup configuration job")
if (data[1].Value?.ToLower() == "backup configuration job")
return false;
status = (summary ? data[2].Value.ToLower() : data[3].Value.ToLower()) switch
status = (summary ? data[2].Value?.ToLower() : data[3].Value?.ToLower()) switch
{
"success" => StatusEnum.Information,
"warning" => StatusEnum.Warning,
@ -230,7 +210,7 @@ public class TrapHandler : IMessageHandler<AgentSession>
return false;
}
private static bool ParseQnap(List<KeyValuePair<string, string>> data, out StatusEnum? status, out string? task, out string? message)
private static bool ParseQnap(List<KeyValuePair<string, string?>> data, out StatusEnum? status, out string? task, out string? message)
{
status = StatusEnum.Information;
task = null;
@ -265,21 +245,15 @@ public class TrapHandler : IMessageHandler<AgentSession>
};
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)
catch (Exception)
{
//_logger.LogError("{ex}", ex);
}

Some files were not shown because too many files have changed in this diff Show more