using System; using System.Collections.Generic; using System.Data.Common; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Security.Claims; using System.Security.Cryptography; using System.Security.Principal; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Xml.Linq; using System.IdentityModel.Tokens.Jwt; using System.DirectoryServices.AccountManagement; using System.DirectoryServices.ActiveDirectory; using System.IO; using Microsoft.IdentityModel.Tokens; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using C4IT.Configuration; using C4IT.FASD.Base; using C4IT.FASD.Licensing; using C4IT.Logging; using C4IT.Security; using C4IT.XML; using C4IT.Matrix42.WebClient; using C4IT_DataHistoryProvider_Base; using C4IT_DataHistoryProvider_Base.DataSources; using C4IT_DataHistoryProvider_Base.Services; using static C4IT.Logging.cLogManager; namespace C4IT.DataHistoryProvider { public delegate void DataHistoryUiMessageFunc(cDataHistoryUiStatusMessage Message); public abstract class cDataHistoryCollectorModule { public cDataHistoryCollector Collector { get; protected set; } public readonly List Origins; public readonly string Name = ""; public readonly Guid LicenseId = Guid.Empty; public cDataHistoryCollectorModule(cDataHistoryCollector Collector, eDataHistoryOrigin Origin, string Name, string LicenseId) { this.Name = Name; Guid.TryParse(LicenseId, out this.LicenseId); this.Collector = Collector; this.Origins = new List() { Origin }; } public cDataHistoryCollectorModule(cDataHistoryCollector Collector, List Origin, string Name, string LicenseId) { this.Name = Name; Guid.TryParse(LicenseId, out this.LicenseId); this.Collector = Collector; this.Origins = Origin; } public override string ToString() { return Name; } public abstract Task GetScanTimeInfoAsync(cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token); public async Task GetScanTimeInfoAsync(cDataHistoryScanTiming ScanTiming, string ScanName, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; var LastScan = await Collector.GetLastScanTime(ScanName, requestInfo, LogDeep + 1, Token); if (LastScan == null || LastScan == new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)) return null; var retVal = new cScanTimeInfo((DateTime)LastScan); try { retVal.NextScan = retVal.GetScanTime(DateTime.UtcNow, ScanTiming); } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return retVal; } public abstract Task DoScanAsync(bool Always, bool Rescan, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token, bool EnhancedDebug = false); public abstract Task> GetIds(cF4sdConnectorIds IdEntry, enumFasdInformationClass InfoClass, cF4sdWebRequestInfo requestInfo, int LogDeep); public virtual List GetFilterValues(List IDs, enumFasdInformationClass InfoClass) { return IDs; } public virtual async Task> GetQuickActionList() { await Task.CompletedTask; var result = new List(); return result; } public virtual bool CheckIfLateDelivery(cDataHistoryConfigTable Table) { return false; } public void AddTableResultVirtualSuccessorTasks(List Tables, Dictionary Identities, DateTime RefTime, int MaxAge, List UsageInfo, Guid CacheId, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var lstTables = new List(); var myTables = new List(); foreach (var Table in Tables) { if (!this.Origins.Contains(Table.ParentCluster.Origin)) continue; if (!CheckIfLateDelivery(Table)) continue; myTables.Add(Table); lstTables.Add(Table.Name); } if (lstTables.Count > 0) { var ct = new CancellationTokenSource().Token; var tsk = GetTableResultsVirtualAsync(myTables, Identities, RefTime, MaxAge, false, CacheId, ct, requestInfo, LogDeep + 1); SuccessorCache.AddTask(CacheId, lstTables, tsk, UsageInfo, ct); } } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } } public virtual async Task> GetTableResultsVirtualAsync(List Tables, Dictionary Identities, DateTime RefTime, int MaxAge, bool instantly, Guid? CacheId, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { await Task.CompletedTask; return null; } public virtual async Task> GetDetailsTableResultsVirtualAsync(List Tables, Dictionary Identities, DateTime RefTime, int MaxAge, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { await Task.CompletedTask; return null; } public virtual async Task GetSelectionTableResultCountAsync(cDataHistoryConfigTable Table, List Identities, string search, cF4sdWebRequestInfo requestInfo, CancellationToken Token, bool resetFilter = false, List filterParams = null) { await Task.CompletedTask; return -1; } public virtual async Task GetSelectionTableResultAsync(cDataHistoryConfigTable Table, List Identities, string search, int PageSize, int Page, cF4sdWebRequestInfo requestInfo, CancellationToken Token, bool resetFilter = false, List filterParams = null) { await Task.CompletedTask; return null; } public virtual async Task ValidateMainTablesAsync(cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { await Task.CompletedTask; return true; } public virtual async Task ColumnUpatePostProcessingAsync(cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { await Task.CompletedTask; return false; } public virtual void TablePostConfig(cDataHistoryConfigTable Table) { } public virtual async Task WritePropertyAsync(cF4SDWriteParameters PropertiesToWrite, cF4sdWebRequestInfo requestInfo, CancellationToken Token) { await Task.CompletedTask; return false; } public virtual async Task ValidateTokenAsync(cF4SDTokenRegistration TokenRegistration, cF4sdWebRequestInfo RequestInfo, int LogDeep, CancellationToken Token) { await Task.CompletedTask; return null; } public virtual async Task GetAdditionalUserInfo(enumAdditionalAuthentication Type, cF4sdWebRequestInfo RequestInfo, int LogDeep, CancellationToken Token) { await Task.CompletedTask; return null; } } public class cDataHistoryCollector : cDataHistoryCollectorModule, IConfigNodeValidation, ISearchResultRelationProvider { public const string constConnectorName = "F4SD collector"; public const string constLicenseId = "00000000-0000-0000-0000-000000000000"; public const int constMinutesUntilTokenIsInvalid = 5; public static readonly Guid ConfigId = new Guid("0FCE8005-81BD-4F06-82FF-55DD9364FBE5"); public static readonly string JwtTokenIssuer = "https://login.f4sdcockpit.consulting4it.de"; public static readonly string JwtTokenAudience = "urn:Cockpit.F4SD"; public Guid getId() { return ConfigId; } public const string constFileNameClusterConfig = "F4SD-DataClusters-Configuration.xml"; public const string constFileNameInfrastructureConfig = "F4SD-Infrastructure-Configuration.xml"; public bool IsValid { get; private set; } = false; public cDataHistoryConfigClusters ClusterConfig { get; private set; } = null; public cDataHistoryConfigInfrastructure InfrastructureConfig { get; private set; } = null; private cDataHistoryConfigGolabalParameters GlobalParametersConfigFile = null; private cF4sdGlobalConfig GlobalConfig { get; set; } = null; private DateTime GlobalParametersConfigTimestamp = DateTime.MinValue; private object GlobalParametersConfigLock = new object(); public readonly Dictionary Connectors = new Dictionary(); public readonly cDataHistoryCollectorActiveDirectory ActiveDirectory = null; public readonly cDataHistoryCollectorClientAgent F4sdAgent = null; public cDataHistoryCollectorM42Wpm M42WpmCollector { get; private set; } = null; public cDataHistoryCollectorNxql NxqlCollector { get; private set; } = null; public cDataHistoryCollectorCitrix CitrixCollector { get; private set; } = null; public bool F4SDAnalyticsValid = false; public cF4SDAnalyticsConfigDatabase F4SDAnalyticsDb { get; private set; } = null; public event DataHistoryUiMessageFunc ProcessUiMessage; public readonly bool autoConnectionCheck = false; public Dictionary ClientConfigs = null; public Dictionary GlobalConfigValues = new Dictionary(); public readonly JwtSecurityTokenHandler JwtTokenHandler = new JwtSecurityTokenHandler(); public SymmetricSecurityKey BearerSecurityKey { get; private set; } = null; public TokenValidationParameters JwtTokenValidationParameters { get; private set; } = null; public Dictionary SessionValues = new Dictionary(); public Dictionary CaseValues = new Dictionary(); public cDataHistoryCollectorTokenCache TokenCache; public enumWebServerStatus ServerStatus = enumWebServerStatus.starting; private readonly List _searchResultRelationProviders = new List(); public bool RunningInIISExpress = false; #region Services private IStagedRelationService _stagedRelationService; public IStagedRelationService GetStagedRelationService() { if (_stagedRelationService is null) _stagedRelationService = new StagedRelationService(_searchResultRelationProviders); return _stagedRelationService; } #endregion internal class cDetailsComputationInfo { internal cDataHistoryConfigComputationBase Computation; internal int[] ValueIndexes; } public cDataHistoryConfigSqlConnection mainDbConnection { get; private set; } = null; public cDataHistoryCollector(bool autoConnectionCheck, cF4sdWebRequestInfo requestInfo, int LogDeep) : base(null, eDataHistoryOrigin.Main, constConnectorName, constLicenseId) { this.Collector = this; this.autoConnectionCheck = autoConnectionCheck; TokenCache = new cDataHistoryCollectorTokenCache(this, requestInfo, LogDeep + 1); Connectors.Add(eDataHistoryOrigin.Main, this); try { var _process = Process.GetCurrentProcess(); if (_process?.ProcessName != null && _process.ProcessName.ToLower().StartsWith("iisexpress")) RunningInIISExpress = true; } catch (Exception e1) { LogException(e1); } var _ActiveDirectory = new cDataHistoryCollectorActiveDirectory(this); if (cF4SDLicense.Instance?.Modules != null) { if (cF4SDLicense.Instance.Modules.ContainsKey(_ActiveDirectory.LicenseId)) { ActiveDirectory = _ActiveDirectory; Connectors.Add(eDataHistoryOrigin.ActiveDirectory, ActiveDirectory); } var _F4sdAgent = new cDataHistoryCollectorClientAgent(this); if (cF4SDLicense.Instance.Modules.ContainsKey(_F4sdAgent.LicenseId)) { F4sdAgent = _F4sdAgent; Connectors.Add(eDataHistoryOrigin.F4sdAgent, F4sdAgent); } } } public List GetConnectors() { var _connectors = Connectors.Values.Distinct().ToList(); return _connectors; } public bool RefreshGlobalConfigurationParameters() { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { lock (GlobalParametersConfigLock) { var _currentTimeStamp = DateTime.MaxValue; if (GlobalParametersConfigFile != null) _currentTimeStamp = File.GetLastWriteTimeUtc(GlobalParametersConfigFile.FilePath); if (_currentTimeStamp <= GlobalParametersConfigTimestamp) { DoProcessUiMessage(0, ""); DoProcessUiMessage(1, "Global parameters are already loaded and are up to date..."); return true; } DoProcessUiMessage(0, ""); DoProcessUiMessage(1, "loading the global parameters..."); var _cfgGlobalParameters = new cDataHistoryConfigGolabalParameters(this.InfrastructureConfig); _cfgGlobalParameters.LoadFromFile(out var PMs); if (PMs != null && PMs.Count > 0) DoProcessUiMessage(2, PMs); if (_cfgGlobalParameters == null || !_cfgGlobalParameters.IsValid) { DoProcessUiMessage(1, "error on loading the global parameters."); return false; } GlobalParametersConfigFile = _cfgGlobalParameters; GlobalConfig = new cF4sdGlobalConfig(regPath: null); if (GlobalParametersConfigFile.Parameters != null) GlobalConfig.Load(CentralParameters: GlobalParametersConfigFile.Parameters); } return true; } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } return false; } public async Task LoadConfigurationAsync(bool checkServerEnvironment, bool checkCurrentUser, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep, Assembly ExecutingAssembly = null) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { IsValid = false; DoProcessUiMessage(0, "start loading the collector configuration..."); // load the SqlHelper if (!DataHistorySqlHelper.LoadWellKnownSqlStatements(out var PMs, ExecutingAssembly)) { if (PMs != null && PMs.Count > 0) { DoProcessUiMessage(1, "loading the well defined SQL statements..."); DoProcessUiMessage(2, PMs); DoProcessUiMessage(1, "error on loading the well defined SQL statement."); } return false; } // load the infrastructure DoProcessUiMessage(0, ""); DoProcessUiMessage(1, "loading the the infrastructure definitions..."); var _cfgInfrastructure = new cDataHistoryConfigInfrastructure(); _cfgInfrastructure.LoadFromFile(out PMs); if (PMs != null && PMs.Count > 0) DoProcessUiMessage(2, PMs); if (_cfgInfrastructure == null || !_cfgInfrastructure.IsValid) { DoProcessUiMessage(1, "error on loading the infrastructure definitions."); return false; } InfrastructureConfig = _cfgInfrastructure; DoProcessUiMessage(1, "the infrastructure configuration loaded successful."); DoProcessUiMessage(0, ""); var HasM42Config = _cfgInfrastructure.M42Wpm != null; var HasIntuneConfig = (_cfgInfrastructure.AzureTenants?.Values.Any(t => t.ScanIntuneDevices) == true); var HasMobileDeviceConfig = (_cfgInfrastructure.AzureTenants?.Values.Any(t => t.WithMobileDevices) == true); var HasCitrixConfig = (InfrastructureConfig.Citrix != null); DoProcessUiMessage(1, "resolving the ad membership groups"); ActiveDirectory.ResolveWinAuthenticationGroups(); // check the server environment if (checkServerEnvironment) await CheckServerEnvironmentAsync(checkCurrentUser, Token, requestInfo, LogDeep + 1); // load the data clusters DoProcessUiMessage(0, ""); DoProcessUiMessage(1, "loading the data cluster definitions..."); var _cfgDataClusters = new cDataHistoryConfigClusters(); _cfgDataClusters.LoadFromFile(out PMs, withM42Config: HasM42Config, withIntuneConfig: HasIntuneConfig,withMobileDeviceConfig:HasMobileDeviceConfig,withCitrixConfig:HasCitrixConfig); if (PMs != null && PMs.Count > 0) DoProcessUiMessage(2, PMs); if (_cfgDataClusters == null || !_cfgDataClusters.IsValid) { DoProcessUiMessage(1, "error on loading the data cluster definitions."); return false; } ClusterConfig = _cfgDataClusters; DoProcessUiMessage(1, "the data cluster configuration loaded successful."); DoProcessUiMessage(0, ""); // load the global parameters if (!RefreshGlobalConfigurationParameters()) return false; mainDbConnection = InfrastructureConfig.HistoryDB.Connection; if (InfrastructureConfig.M42Wpm != null) { var _M42WpmCollector = new cDataHistoryCollectorM42Wpm(this); if (cF4SDLicense.Instance?.Modules != null) if (cF4SDLicense.Instance.Modules.ContainsKey(_M42WpmCollector.LicenseId)) { M42WpmCollector = _M42WpmCollector; Connectors.Add(eDataHistoryOrigin.M42Wpm, M42WpmCollector); RegisterSearchRelationProvider(_M42WpmCollector); } } if (InfrastructureConfig.Nexthink != null) { var _NxqlCollector = new cDataHistoryCollectorNxql(this); if (cF4SDLicense.Instance?.Modules != null) if (cF4SDLicense.Instance.Modules.ContainsKey(_NxqlCollector.LicenseId)) { NxqlCollector = _NxqlCollector; Connectors.Add(eDataHistoryOrigin.NexthinkNxql, NxqlCollector); } } if (HasCitrixConfig) { var _CitrixCollector = new cDataHistoryCollectorCitrix(this); if (cF4SDLicense.Instance?.Modules != null) //if (cF4SDLicense.Instance.Modules.ContainsKey(_CitrixCollector.LicenseId)) //{ CitrixCollector = _CitrixCollector; Connectors.Add(eDataHistoryOrigin.Citrix, _CitrixCollector); RegisterSearchRelationProvider(_CitrixCollector); //} } if(HasIntuneConfig) { Connectors.Add(eDataHistoryOrigin.Intune, ActiveDirectory); RegisterSearchRelationProvider(ActiveDirectory); } // do the post configuration tasks afer the infrastructure was loaded DoProcessUiMessage(1, "processing post configuration tasks"); foreach (var Table in _cfgDataClusters.Tables.Values) { if (Connectors.TryGetValue(Table.ParentCluster.Origin, out var _module)) _module?.TablePostConfig(Table); } RegisterSearchRelationProvider(this); DoProcessUiMessage(0, ""); DoProcessUiMessage(0, "the collector configuration loaded successful."); IsValid = true; return true; } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return false; } private void RegisterSearchRelationProvider(ISearchResultRelationProvider provider) { _searchResultRelationProviders.Add(provider); } public cF4sdGlobalConfig GetGlobalConfig() { RefreshGlobalConfigurationParameters(); cF4sdGlobalConfig _result = null; lock (GlobalParametersConfigLock) { _result = GlobalConfig; } return GlobalConfig; } private void RegisterSearchRelationProviders(IEnumerable providers) { _searchResultRelationProviders.AddRange(providers); } public async Task CheckServerEnvironmentAsync(bool CheckCurrentUser, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { DoProcessUiMessage(1, ""); DoProcessUiMessage(1, "checking the server environment..."); var _issConfig = IisConfigHelper.CheckIISConfiguration(); if (!_issConfig.IsWebSocketInstalled) DoProcessUiMessage(2, " Warning: The IIS feature 'WebSocket' is not installed. This is needed for use of direct connections.", LogLevels.Warning); if (!_issConfig.IsIssWindowsAuthenticationInstalled) DoProcessUiMessage(2, " Warning: The IIS feature 'WindowsAuthentication' is not installed. This is mandatory for the use of authorization.", LogLevels.Warning); if (!_issConfig.IsIssWindowsAuthenticationEnabled) DoProcessUiMessage(2, " Warning: The 'WindowsAuthentication' is not enabled for the WEB application F4SDCockpit. This is mandatory for the use of authorization.", LogLevels.Warning); await CheckAuthorisationConfigurationAsync(CheckCurrentUser, Token, requestInfo, LogDeep + 1); DoProcessUiMessage(1, "server environment check finished."); } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } } public async Task CheckAuthorisationConfigurationAsync(bool CheckCurrentUser, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { if (InfrastructureConfig?.Authorisation == null || !InfrastructureConfig.Authorisation.IsValid) { DoProcessUiMessage(2, " Warning: Authentication is not configured properly in the file 'F4SD-Infrastructure-Configuration.xml'. It is strongly recommended not to use F4SD Cockpit without configured authentication.", LogLevels.Warning); return; } if (CheckCurrentUser) { var _userInfo = await GetCurrentUserInfoAsync(Token, requestInfo, LogDeep + 1); if (_userInfo?.Roles == null || _userInfo.Roles.Count == 0) { DoProcessUiMessage(2, $" Warning: The current user {_userInfo?.AdAccount} is not member of any F4SD role. Please check the authentication configuration and the ad group memberships.", LogLevels.Warning); } else { if (!_userInfo.Roles.Contains("Cockpit.User")) DoProcessUiMessage(2, $" Warning: The current user {_userInfo.AdAccount} is not member of the F4SD role 'Cockpit.User'. Please check the authentication configuration and the ad group memberships.", LogLevels.Warning); } } } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } } public void ValidateClientConfiguration() { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { DoProcessUiMessage(0, "start validating the client configuration files..."); DoProcessUiMessage(0, ""); var _Configs = new Dictionary(); var _lst = Enum.GetValues(typeof(enumFasdConfigurationType)).Cast(); foreach (var _item in _lst) { if (_item != enumFasdConfigurationType.unknown) { var _msg = new List(); var HasM42Config = InfrastructureConfig.M42Wpm != null; var HasIntuneConfig = (InfrastructureConfig.AzureTenants?.Values.Any(t => t.ScanIntuneDevices) == true); var HasMobileDeviceConfig = (InfrastructureConfig.AzureTenants?.Values.Any(t => t.WithMobileDevices) == true); var HasCitrixConfig = (InfrastructureConfig.Citrix != null); var _cfg = cFasdBaseConfig.GetConfigByType(_item, null, _msg, withM42Config: HasM42Config, withIntuneConfig: HasIntuneConfig, withMobileDeviceConfig: HasMobileDeviceConfig, withCitrixConfig:HasCitrixConfig); if (_cfg.IsValid) { _Configs[_item] = _cfg; if (_msg.Count == 0) DoProcessUiMessage(1, $"the {_item} configuration is valid."); else DoProcessUiMessage(1, $"the {_item} configuration is valid but has some annotations:"); } else DoProcessUiMessage(1, $"the the {_item} configuration is invalid!"); if (_msg.Count > 0) DoProcessUiMessage(2, _msg); DoProcessUiMessage(0, ""); } } ClientConfigs = _Configs; DoProcessUiMessage(0, "the validation of the client configuration files finished."); } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } } public async Task UpdateF4SDAnalyticsConfigInfosAsync(cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken _token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { if (this.F4SDAnalyticsValid && this.F4SDAnalyticsDb?.Connection != null) { if (ClientConfigs != null && ClientConfigs.TryGetValue(enumFasdConfigurationType.quickActions, out var _quickActionsBase)) { if (_quickActionsBase is cFasdQuickActionConfig _quickActions) { if (DataHistorySqlHelper.GetWellKnownSqlStatement("UpdateQActionInfo", out var Query)) if (DataHistorySqlHelper.GetWellKnownSqlStatement("UpdateQActionInfoLang", out var Query2)) { using (var Conn = new cDbConnection(this.F4SDAnalyticsDb.Connection)) { foreach (var _quickAction in _quickActions.F4SDQuickActions.QuickActions.Values) { if (_quickAction.Id == Guid.Empty) continue; var _params = new Dictionary() { { "Id", _quickAction.Id}, { "Name", _quickAction.Name}, { "Type", _quickAction.GetTypeName()} }; await DataHistorySqlHelper.ExecuteAsync(Conn, Query, _params, requestInfo, _token); foreach (var _langEntry in _quickAction.Names) { _params = new Dictionary() { { "Id", _quickAction.Id}, { "Name", _langEntry.Value}, { "Lang", _langEntry.Key.ToUpperInvariant()} }; await DataHistorySqlHelper.ExecuteAsync(Conn, Query2, _params, requestInfo, _token); } } } } } } } } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } } private async Task ValidateDatabaseAsync(cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var DbName = InfrastructureConfig.HistoryDB.Connection.Database; DoProcessUiMessage(0, ""); DoProcessUiMessage(1, $"start validating the data history database '{DbName}' itself..."); using (var DbConn = new cDbConnection(mainDbConnection, Timeout: 10, WithoutDatabase: true)) if (DbConn.IsOpen) { if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Validate_Database", out var Query)) return; var Params = new Dictionary() { { "DbName", DbName } }; var n = await DataHistorySqlHelper.GetScalarResultAsync(DbConn, Query, Params, requestInfo, Token); if (n >= 1) { DoProcessUiMessage(1, $"the validation of the data history database '{DbName}' itself finished successful."); } else { DoProcessUiMessage(2, $"the database {DbName} coud not be found."); if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Create_Database", out Query)) return; var Query2 = Query.Clone(string.Format(Query.Query, mainDbConnection.Database)); var n2 = await DataHistorySqlHelper.ExecuteAsync(DbConn, Query2, null, requestInfo, Token); if (n2 == null) { DoProcessUiMessage(2, $"the data history database '{DbName}' could not be created."); return; } DoProcessUiMessage(2, $"the database {DbName} is created successful."); } if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Validate_DbCollation", out Query)) return; var strQuery = string.Format(Query.Query, DbName); var _startTime2 = DateTime.UtcNow; n = await DataHistorySqlHelper.GetScalarResultAsync(DbConn.Connection, strQuery, null, Token); if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(Query.Name, _startTime2, DbName, 0, requestInfo?.requestName); if (n != 1) DoProcessUiMessage(2, $"Warning: the collation of database {DbName} is not 'Latin1_General_CI_AI'"); } } catch (Exception E) { DoProcessUiMessage(1, $"the validation of the data history database itself aborted with an exceptional error."); LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } } public override async Task ValidateMainTablesAsync(cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { // validate if fulltext search is enabled for the server instance DoProcessUiMessage(1, $"start validating the full text feature..."); if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Validate_Fulltext_Installed", out var Query)) return false; if (await DataHistorySqlHelper.GetScalarResultAsync(DbConn, Query, null, requestInfo, Token) != 1) { DoProcessUiMessage(1, $"the sql server instance {DbConn.Connection.DataSource} is not enabled for full text."); return false; } // validate if fulltext search is enabled for the database if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Validate_Fulltext", out Query)) return false; if (!(await DataHistorySqlHelper.GetScalarResultAsync(DbConn, Query, null, requestInfo, Token) == true)) { DoProcessUiMessage(1, $"the database '{DbConn.Connection.Database}' is not enabled for full text."); return false; } DoProcessUiMessage(1, $"the full text feature is activated for the database."); DoProcessUiMessage(1, ""); // validate the main tables DoProcessUiMessage(1, $"start validating the main tables..."); if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Validate_MainTables", out Query)) return false; var n = await DataHistorySqlHelper.GetScalarResultAsync(DbConn, Query, null, requestInfo, Token); if (n > 0) { DoProcessUiMessage(1, $"the validation of the main tables finished successful."); return true; } // create the main tables DoProcessUiMessage(2, $"the main tables are not complete, creating them..."); if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Create_MainTables", out Query)) return false; var n2 = await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, null, requestInfo, Token); // validate the creates main tables if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Validate_MainTables", out Query)) return false; n = await DataHistorySqlHelper.GetScalarResultAsync(DbConn, Query, null, requestInfo, Token); if (n > 0) { DoProcessUiMessage(2, $"the main tables were created successfull."); return true; } DoProcessUiMessage(2, "An error occurred when creating the main tables."); } catch (Exception E) { DoProcessUiMessage(1, $"the validation of the main tables aborted with an exceptional error."); LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return false; } private async Task ValidateF4SDAnalyticsDatabaseAsync(CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep, bool ForceCreate = false) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var DbConnection = InfrastructureConfig.F4SDAnalyticsDB?.Connection; if (DbConnection == null) return false; DoProcessUiMessage(0, ""); DoProcessUiMessage(1, $"start validating the data database '{DbConnection.Database}' itself..."); using (var DbConn = new cDbConnection(DbConnection, WithoutDatabase: true)) if (DbConn.IsOpen) { if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Validate_Database", out var Query)) return false; var Params = new Dictionary() { { "DbName", DbConnection.Database } }; var n = await DataHistorySqlHelper.GetScalarResultAsync(DbConn, Query, Params, requestInfo, Token); if (n >= 1) { DoProcessUiMessage(1, $"the validation of the data F4SDAnalytics database '{DbConnection.Database}' itself finished successful."); return true; } DoProcessUiMessage(2, $"the database {DbConnection.Database} coud not be found."); if (ForceCreate) { if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Create_Database", out Query)) return false; var Query2 = Query.Clone(string.Format(Query.Query, DbConnection.Database)); var n2 = await DataHistorySqlHelper.ExecuteAsync(DbConn, Query2, null, requestInfo, Token); if (n2 != null) { DoProcessUiMessage(2, $"the database {DbConnection.Database} is created successful."); return true; } DoProcessUiMessage(2, $"Error: the database '{DbConnection.Database}' could not be created."); return false; } } DoProcessUiMessage(1, $"Error: the connection on the database '{DbConnection.Database}' is not available."); return false; } catch (Exception E) { DoProcessUiMessage(0, ""); DoProcessUiMessage(0, $"the validation of the data F4SDAnalytics database itself aborted with an exceptional error."); LogException(E); return false; } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } } private async Task ValidateF4SDAnalyticsMainTablesAsync(cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token, bool ForceCreate) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { // validate the main tables DoProcessUiMessage(1, $"start validating the main tables..."); if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Validate_F4SDAnalyticsMainTables", out var Query)) return false; var n = await DataHistorySqlHelper.GetScalarResultAsync(DbConn, Query, null, requestInfo, Token); if (n > 0) { DoProcessUiMessage(1, $"the validation of the main tables finished successful."); DoProcessUiMessage(0, ""); return true; } if (!ForceCreate && n < 1) { DoProcessUiMessage(2, $"the main tables are not complete..."); return false; } if (ForceCreate) { // create the main tables DoProcessUiMessage(2, $"the main tables are not complete, creating them..."); if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Create_F4SDAnalyticsMainTables", out Query)) return false; await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, null, requestInfo, Token); // validate the creates main tables if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Validate_F4SDAnalyticsMainTables", out Query)) return false; n = await DataHistorySqlHelper.GetScalarResultAsync(DbConn, Query, null, requestInfo, Token); if (n > 0) { DoProcessUiMessage(2, $"the main tables were created successfull."); DoProcessUiMessage(0, ""); return true; } DoProcessUiMessage(2, "An error occurred when creating the main tables."); } } catch (Exception E) { DoProcessUiMessage(1, $"the validation of the main tables aborted with an exceptional error."); LogException(E); return false; } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return false; } private async Task ValidateF4SDAnalyticsFunctionsAsync(cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token, bool ForceCreate) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { // validate the functions DoProcessUiMessage(1, $"start validating the functions..."); if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Validate_F4SDAnalyticsFunctions", out var Query)) return false; var n = await DataHistorySqlHelper.GetScalarResultAsync(DbConn, Query, null, requestInfo, Token); if (n > 0) { DoProcessUiMessage(1, $"the validation of the functions finished successful."); DoProcessUiMessage(0, ""); return true; } if (!ForceCreate && n < 1) { DoProcessUiMessage(2, $"the functions are not complete..."); return false; } if (ForceCreate) { // create the functions DoProcessUiMessage(2, $"the functions are not complete, creating them..."); if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Create_F4SDAnalyticsFunctions", out Query)) return false; await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, null, requestInfo, Token); // validate the creates functions if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Validate_F4SDAnalyticsFunctions", out Query)) return false; n = await DataHistorySqlHelper.GetScalarResultAsync(DbConn, Query, null, requestInfo, Token); if (n > 0) { DoProcessUiMessage(2, $"the functions were created successfull."); DoProcessUiMessage(0, ""); return true; } DoProcessUiMessage(2, "An error occurred when creating the functions."); } } catch (Exception E) { DoProcessUiMessage(1, $"the validation of the funtions aborted with an exceptional error."); LogException(E); return false; } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return false; } private async Task ValidateF4SDAnalyticsViewsAsync(cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token, bool ForceCreate) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { // validate the view tables DoProcessUiMessage(1, $"start validating the view tables..."); if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Validate_F4SDAnalyticsViews", out var Query)) return false; var n = await DataHistorySqlHelper.GetScalarResultAsync(DbConn, Query, null, requestInfo, Token); if (n > 0) { DoProcessUiMessage(1, $"the validation of the view tables finished successful."); DoProcessUiMessage(0, ""); return true; } if (!ForceCreate && n < 1) { DoProcessUiMessage(2, $"the view tables are not complete..."); return false; } if (ForceCreate) { // create the view tables DoProcessUiMessage(2, $"the view tables are not complete, creating them..."); if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Create_F4SDAnalyticsViews", out Query)) return false; Query.Query = Query.Query.Replace("$DatabaseHistory$", InfrastructureConfig.HistoryDB.Connection.Database); await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, null, requestInfo, Token); // validate the creates view tables if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Validate_F4SDAnalyticsViews", out Query)) return false; n = await DataHistorySqlHelper.GetScalarResultAsync(DbConn, Query, null, requestInfo, Token); if (n > 0) { DoProcessUiMessage(2, $"the view tables were created successfull."); return true; } DoProcessUiMessage(2, "An error occurred when creating the view tables."); } } catch (Exception E) { DoProcessUiMessage(1, $"the validation of the view tables aborted with an exceptional error."); LogException(E); return false; } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return false; } private async Task UpdateF4SDAnalyticsMainTablesAsync(cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token, bool ForceCreate) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { // validate the main tables DoProcessUiMessage(1, $"start update the main tables..."); if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Update_F4SDAnalyticsMainTables", out var Query)) return false; var n = await DataHistorySqlHelper.GetScalarResultAsync(DbConn, Query, null, requestInfo, Token); if (n == 0) { DoProcessUiMessage(1, $"the update of the main tables was successfull, nothing updated."); return true; } if (n > 0) { DoProcessUiMessage(1, $"the update of the main tables finished successful."); DoProcessUiMessage(0, ""); return true; } else { DoProcessUiMessage(2, $"the main tables could not be updated."); LogEntry($"the main tables could not be updated.", LogLevels.Fatal); return false; } } catch (Exception E) { DoProcessUiMessage(1, $"the validation of the main tables aborted with an exceptional error."); LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return false; } private async Task UpdateF4SDAnalyticsViewsAsync(cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token, bool ForceCreate) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { // validate the main tables DoProcessUiMessage(1, $"start update the views..."); if (!DataHistorySqlHelper.GetWellKnownSqlStatement("Update_F4SDAnalyticsViews", out var Query)) return false; Query.Query = Query.Query.Replace("$DatabaseHistory$", InfrastructureConfig.HistoryDB.Connection.Database); var n = await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, null, requestInfo, Token); if (n != null) { DoProcessUiMessage(1, $"the update of the view tables finished successful."); DoProcessUiMessage(0, ""); return true; } DoProcessUiMessage(1, $"the view tables could not be updated."); return false; } catch (Exception E) { DoProcessUiMessage(1, $"the update of the views aborted with an exceptional error."); LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return false; } private async Task GetDatabaseTableVersion(cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; if (!DataHistorySqlHelper.GetWellKnownSqlStatement("GetDbTablesVersion", out var Query)) return null; int apiError = 0; try { using (var Reader = await DataHistorySqlHelper.GetDataReaderAsync(DbConn, Query, null, Token)) { if (Reader != null) try { if (Reader.HasRows) { if (await Reader.ReadAsync()) { try { var iVersion = Reader.GetInt32(0); var iRevision = Reader.GetInt32(1); var RetVal = new Version(iVersion, iRevision); return RetVal; } catch (Exception E) { cLogManager.DefaultLogger.LogException(E); } } } } catch (Exception E) { cLogManager.DefaultLogger.LogException(E); } } } catch (Exception E) { apiError = E.HResult; LogException(E); } finally { if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(Query.Name, _startTime, "", apiError, requestInfo?.requestName); if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } private async Task InsertDbVersionAsync(cDbConnection DbConn, Version version, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { if (!DataHistorySqlHelper.GetWellKnownSqlStatement("UpdateDbVersion", out var Query)) return; var Params = new Dictionary(2) { { "version", version.Major }, { "revision", version.Minor } }; await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, Params, requestInfo, Token); } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } } private async Task ValidatePostUpdates(cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { // get the actual db table version var currentVersion = await GetDatabaseTableVersion(DbConn, requestInfo, LogDeep + 1, Token); // get all db table updates not done var Updates = new SortedList(); foreach (var Entry in DataHistorySqlHelper.wellDefinedSqlStatements.Values) { const string constUpdateName = "UpdateDbTablesV"; if (Entry.Name.StartsWith(constUpdateName)) { var strVersion = Entry.Name.Remove(0, constUpdateName.Length); if (Version.TryParse(strVersion, out var entryVersion)) if (entryVersion > currentVersion) Updates.Add(entryVersion, Entry); } } // do the updates var IsOk = true; foreach (var updateQuery in Updates) { var n = await DataHistorySqlHelper.GetScalarResultAsync(DbConn, updateQuery.Value, null, requestInfo, Token); if (n == 0) { DoProcessUiMessage(1, $"the validation of the post update V{updateQuery.Key} was successfull, nothing updated."); await InsertDbVersionAsync(DbConn, updateQuery.Key, requestInfo, LogDeep + 1, Token); } else if (n > 0) { DoProcessUiMessage(1, $"{n} updates where processed by post update V{updateQuery.Key}."); } else { LogEntry($"the post update V01 is not successful.", LogLevels.Fatal); IsOk = false; } } if (IsOk) return true; } catch (Exception E) { DoProcessUiMessage(1, $"the validation of the post updates aborted with an exceptional error."); LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } LogEntry($"the post updates could not be validated sucessfull.", LogLevels.Fatal); return false; } private async Task ValidateAgentApiConnection() { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { const int maxRetryCount = 3; TimeSpan delay = TimeSpan.FromSeconds(5); bool loggedInToAgentApi = false; for (int i = 0; i < maxRetryCount; i++) { loggedInToAgentApi = await F4sdAgent.LogonToAgentApiAsync(); if (loggedInToAgentApi) break; LogEntry("Logon to agent API failed.", LogLevels.Warning); await Task.Delay(delay); } if (!loggedInToAgentApi) { DoProcessUiMessage(0, $"ERROR: Could not connect to the F4SD Agent API. Maybe there are invalid credentials configured.", LogLevels.Error); return; } var _remoteScript = await F4sdAgent.GetRemoteScriptsAsync(); if (_remoteScript == null) { DoProcessUiMessage(0, $"ERROR: Retrieve remote scripts from Agent API.", LogLevels.Error); return; } DoProcessUiMessage(0, $"Successful connection to the F4SD Agent API established. {_remoteScript.Count} remote scripts found.", LogLevels.Info); } catch (Exception E) { DoProcessUiMessage(0, $"ERROR: Unknown error while validating Agent API.", LogLevels.Error); LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } } public async Task ValidateHistoryDatabasesAsync(bool isWebservice, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; var RetVal = true; var DbName = InfrastructureConfig.HistoryDB.Connection.Database; try { DoProcessUiMessage(0, $"start validating the data history database '{DbName}'..."); DoProcessUiMessage(0, ""); await ValidateDatabaseAsync(requestInfo, LogDeep + 1, Token); if (Token.IsCancellationRequested) return false; using (var DbConn = new cDbConnection(mainDbConnection, Timeout: 3 * 60 * 60)) { if (!DbConn.IsOpen) return false; //DoProcessUiMessage(0, ""); //RetVal = await ValidateMainTablesAsync(DbConn, requestInfo, LogDeep + 1, Token); //if (Token.IsCancellationRequested || !RetVal) return false; DoProcessUiMessage(0, ""); foreach (var Connector in GetConnectors()) { RetVal = await Connector.ValidateMainTablesAsync(DbConn, requestInfo, LogDeep + 1, Token); if (Token.IsCancellationRequested || !RetVal) return false; DoProcessUiMessage(0, ""); } RetVal = await ValidatePostUpdates(DbConn, requestInfo, LogDeep + 1, Token); DoProcessUiMessage(0, ""); var _Ok = true; // check the existance of the tables and create them foreach (var DbTable in ClusterConfig.Tables.Values) { if (DbTable.IsVirtual && DbTable.Cached != eDataHistoryTableCached.Yes) continue; _Ok &= await ValidateDbTableAsync(DbConn, DbTable, requestInfo, LogDeep + 1, Token); } // check the table references and create them var lst = ""; foreach (var DbTable in ClusterConfig.Tables.Values) { if (DbTable.IsVirtual && DbTable.Cached != eDataHistoryTableCached.Yes) continue; var _sqlRefs = await DataHistorySqlHelper.GetTableReferences(DbConn.Connection, DbTable.SourceName, Token); if (DbTable.HasScanId) { lst += DbTable.Name + "\n"; _Ok &= await ValidateDbTableReferenceScanHistoryAsync(DbConn, DbTable, _sqlRefs, requestInfo, LogDeep + 1, Token); } foreach (var Ref in DbTable.References.Values) _Ok &= await ValidateDbTableReferencesAsync(DbConn, DbTable, Ref, _sqlRefs, requestInfo, LogDeep + 1, Token); } if (Token.IsCancellationRequested || !RetVal) return false; await LoadGloablConfigValuesAsync(DbConn, requestInfo, LogDeep + 1, Token); if (isWebservice) await TokenCache.LoadAsync(DbConn, Token, requestInfo, LogDeep + 1); } DoProcessUiMessage(0, $"the validation of the data history database '{DbName}' finished."); if (!await F4sdAgent.CheckAndInitializeDbAccess(requestInfo, LogDeep + 1, CancellationToken.None)) { DoProcessUiMessage(0, $"Could not initialize the F4SD agent database correctly '{InfrastructureConfig.ClientAgent.Organization}'."); return false; } await ValidateAgentApiConnection(); } catch (Exception E) { DoProcessUiMessage(1, $"the validation of the data history database '{DbName}' aborted with an exceptional error."); RetVal = false; LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return RetVal; } private async Task ValidateDbTableAsync(cDbConnection DbConn, cDataHistoryConfigTable DbTable, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var _TableExist = await DataHistorySqlHelper.CheckIfTableExistAsync(DbConn.Connection, DbTable.SourceName, requestInfo, LogDeep + 1); if (_TableExist) LogEntry($"The database '{DbTable.SourceName}' already exist.", LogLevels.Debug); else { LogEntry($"The database '{DbTable.SourceName}' does not exist, creating it...", LogLevels.Debug); var Query = DataHistorySqlHelper.GetSqlCreateStatement(DbTable, cDataHistoryConfigClusters.confUseBinValuesAsPrimaryKey, true); var _startTime2 = DateTime.UtcNow; var CRes = await DataHistorySqlHelper.ExecuteAsync(DbConn.Connection, Query, null, Token); if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry("ValidateDbTableAsync.CreateTable", _startTime2, DbTable.SourceName, 0, requestInfo?.requestName); } // validate & create additional table columns if (!DataHistorySqlHelper.GetWellKnownSqlStatement("CheckAndCreateTableColumn", out var Query2)) return false; if (!DataHistorySqlHelper.GetWellKnownSqlStatement("CheckScanIdTableColumn", out var QueryScanId)) return false; bool ColumnCreated = false; foreach (var Column in DbTable.Columns.Values) { try { var strNull = "NULL"; if (!DbTable.IsNullable(Column)) strNull = "NOT " + strNull; var strQuery = string.Format(Query2.Query, DbTable.SourceName, Column.Name, Column.SqlType, strNull); var _startTime2 = DateTime.UtcNow; var RV = await DataHistorySqlHelper.GetScalarResultAsync(DbConn.Connection, strQuery, null, Token); if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(Query2.Name, _startTime2, DbTable.SourceName + "." + Column.Name, 0, requestInfo?.requestName); if (RV == 1) ColumnCreated = true; if (Column.SqlTypeBin != null) { strQuery = string.Format(Query2.Query, DbTable.SourceName, Column.Name + DataHistorySqlHelper.constBinValueNameAdd, Column.SqlTypeBin, strNull); _startTime2 = DateTime.UtcNow; RV = await DataHistorySqlHelper.GetScalarResultAsync(DbConn.Connection, strQuery, null, Token); if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(Query2.Name, _startTime2, DbTable.SourceName + "." + Column.Name + DataHistorySqlHelper.constBinValueNameAdd, 0, requestInfo?.requestName); if (RV == 1) ColumnCreated = true; } } catch (Exception E) { LogException(E); } } var strQueryScanId = string.Format(QueryScanId.Query, DbTable.SourceName); var _startTime3 = DateTime.UtcNow; var _n = await DataHistorySqlHelper.GetScalarResultAsync(DbConn.Connection, strQueryScanId, null, Token); if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(QueryScanId.Name, _startTime3, DbTable.SourceName, 0, requestInfo?.requestName); DbTable.HasScanId = _n == 1; if (ColumnCreated) { var isOk = await Connectors[DbTable.ParentCluster.Origin].ColumnUpatePostProcessingAsync(DbConn, requestInfo, LogDeep + 1, Token); } } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return false; } private async Task ValidateDbTableReferenceScanHistoryAsync(cDbConnection DbConn, cDataHistoryConfigTable DbTable, Dictionary _sqlRefs, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { if (DbTable.Type != eDataHistoryTableType.Events && DbTable.Type != eDataHistoryTableType.History) return true; MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { if (_sqlRefs.ContainsKey($"FK_{DbTable.SourceName}_scan-history")) return true; var sqlCmd = $"ALTER TABLE [{DbTable.SourceName}] WITH CHECK ADD CONSTRAINT [FK_{DbTable.SourceName}_scan-history] FOREIGN KEY([ScanId]) REFERENCES [main-scan-history] ([ScanId]) ON DELETE CASCADE;"; var _Res = await DataHistorySqlHelper.ExecuteAsync(DbConn.Connection, sqlCmd, null, Token); return (_Res == -1); } catch (Exception E) { LogException(E); } finally { if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry("ValidateDbTableReferenceScanHistoryAsync", _startTime, "DbTable.SourceName", 0, requestInfo?.requestName); if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return false; } private async Task ValidateDbTableReferencesAsync(cDbConnection DbConn, cDataHistoryConfigTable DbTable, cDataHistoryConfigTableReferenceInfo Ref, Dictionary _sqlRefs, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var RetVal = true; var _RefName = DataHistorySqlHelper.GetReferencingName(DbTable, Ref); var _exists = false; foreach (var _refInfo in _sqlRefs.Values) { if (_refInfo.Name == _RefName) { _exists = true; break; } } if (!_exists) { var _Query = DataHistorySqlHelper.GetReferencingStatements(DbTable, Ref); var _Res = await DataHistorySqlHelper.ExecuteAsync(DbConn.Connection, _Query, null, Token); if (_Res != -1) RetVal = false; } return RetVal; } catch (Exception E) { LogException(E); } finally { if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry("ValidateDbTableReferencesAsync", _startTime, "DbTable.SourceName", 0, requestInfo?.requestName); if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return false; } public async Task ValidateAgentDbUpdates(cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { var cmdList = DataHistorySqlHelper.wellDefinedSqlStatements.Where(v => v.Key.StartsWith("AgentDbUpdate")).ToDictionary(v => v.Key, v => v.Value); var cmdSorted = new SortedList(cmdList); DoProcessUiMessage(0, ""); DoProcessUiMessage(0, "Start validating Agent DB"); using (var DbConn = new cDbConnection(this.InfrastructureConfig.ClientAgent.Connection, Timeout: 3 * 60 * 60)) { foreach (var DbCmd in cmdSorted.Values) { try { if (String.IsNullOrWhiteSpace(DbCmd.Description)) DoProcessUiMessage(1, $"Processing SQL query {DbCmd.Name}..."); else DoProcessUiMessage(1, DbCmd.Description + "..."); var resInt = await DataHistorySqlHelper.ExecuteAsync(DbConn, DbCmd, null, requestInfo, Token, Timeout: 3 * 60 * 60); DoProcessUiMessage(2, $"...finished."); } catch (Exception E) { LogException(E); } } } DoProcessUiMessage(0, "Validating Agent DB finished."); } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } return false; } public async Task ValidateF4SDAnalyticsDBAsync(cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token, bool ForceCreate = false) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; var RetVal = true; F4SDAnalyticsValid = false; var DbConnection = InfrastructureConfig.F4SDAnalyticsDB?.Connection; if (DbConnection == null) return false; try { DoProcessUiMessage(0, ""); DoProcessUiMessage(0, $"start validating the data '{DbConnection.Database}' database..."); var isValid = await ValidateF4SDAnalyticsDatabaseAsync(Token, requestInfo, LogDeep + 1, ForceCreate); if (!isValid) { DoProcessUiMessage(0, ""); DoProcessUiMessage(0, $"the validation of the data database '{DbConnection.Database}' finished."); return false; } if (Token.IsCancellationRequested) return false; using (var DbConn = new cDbConnection(DbConnection, Timeout: 3 * 60 * 60)) { if (!DbConn.IsOpen) { return false; } DoProcessUiMessage(0, ""); RetVal = await ValidateF4SDAnalyticsMainTablesAsync(DbConn, requestInfo, LogDeep + 1, Token, ForceCreate); if (Token.IsCancellationRequested || !RetVal) { return false; } RetVal = await ValidateF4SDAnalyticsFunctionsAsync(DbConn, requestInfo, LogDeep + 1, Token, ForceCreate); if (Token.IsCancellationRequested || !RetVal) { return false; } RetVal = await ValidateF4SDAnalyticsViewsAsync(DbConn, requestInfo, LogDeep + 1, Token, ForceCreate); if (Token.IsCancellationRequested || !RetVal) { return false; } RetVal = await UpdateF4SDAnalyticsViewsAsync(DbConn, requestInfo, LogDeep + 1, Token, ForceCreate); if (Token.IsCancellationRequested || !RetVal) { return false; } DoProcessUiMessage(0, ""); F4SDAnalyticsValid = true; F4SDAnalyticsDb = InfrastructureConfig.F4SDAnalyticsDB; } DoProcessUiMessage(0, $"the validation of the data analytics database '{DbConnection.Database}' finished."); } catch (Exception E) { DoProcessUiMessage(1, $"the validation of the data analytics database '{DbConnection.Database}' aborted with an exceptional error."); RetVal = false; LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return RetVal; } public async void CheckSessionsAsync(object sender, System.Timers.ElapsedEventArgs e) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { var currentTimeStamp = DateTime.UtcNow; var _toClose = new List(); lock (SessionValues) { foreach (var v in SessionValues) { var diff = (int)currentTimeStamp.Subtract(SessionValues[v.Key]).TotalMinutes; if (diff >= F4SDAnalyticsDb.SessionTimeout) { var userSessions = new cF4SDUserSessionParameters(); userSessions.SessionId = v.Key; userSessions.SessionDate = currentTimeStamp; _toClose.Add(userSessions); } } } foreach (var s in _toClose) { var _requestInfo = new cF4sdWebRequestInfo("CheckSessionsAsync", s.SessionId.ToString()); await CloseUserSessionAsync(s, _requestInfo, 1, CancellationToken.None); } } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } } public async void CheckCasesAsync(object sender, System.Timers.ElapsedEventArgs e) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } var requestInfo = new cF4sdWebRequestInfo("CheckCasesAsync", null); if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceStart(0, requestInfo.requestName, requestInfo.id, requestInfo.created); } var apiError = 0; try { var currentTimeStamp = DateTime.UtcNow; var _toClose = new List(); lock (CaseValues) { foreach (var v in CaseValues) { var diff = (int)currentTimeStamp.Subtract(CaseValues[v.Key]).TotalMinutes; if (diff > F4SDAnalyticsDb.CaseTimeout) { var caseData = new cF4SDCaseTimeParameters(); caseData.CaseId = v.Key; caseData.StatusId = CaseStatus.Canceled; _toClose.Add(caseData); } } } foreach (var s in _toClose) { var requestInfo2 = new cF4sdWebRequestInfo("CheckCasesAsync", s.CaseId?.ToString()); await UpdateCaseStateAsync(s, requestInfo2, 1, CancellationToken.None); } } catch (Exception E) { apiError = E.HResult; LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(0, requestInfo.requestName, requestInfo.id, requestInfo.created, requestInfo.created, ErrorCode: apiError); } if (CM != null) LogMethodEnd(CM); } } private async Task LoadGloablConfigValuesAsync(cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { DoProcessUiMessage(1, $"start loading database config values..."); if (!DataHistorySqlHelper.GetWellKnownSqlStatement("GetConfigValues", out var Query)) return; GlobalConfigValues.Clear(); int apiError = 0; try { using (var _reader = await DataHistorySqlHelper.GetDataReaderAsync(DbConn, Query, null, Token)) { if (_reader != null) try { if (_reader.HasRows) { while (await _reader.ReadAsync()) { try { var Key = _reader.GetString(0); var Value = _reader.GetString(1); GlobalConfigValues[Key] = Value; } catch (Exception E) { cLogManager.DefaultLogger.LogException(E); } if (Token.IsCancellationRequested) return; } } } catch (Exception E) { cLogManager.DefaultLogger.LogException(E); } } } catch (Exception E) { apiError = E.HResult; LogException(E); } finally { if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(Query.Name, _startTime, "", apiError, requestInfo?.requestName); } await GetSecTokenKeyAsync(DbConn, requestInfo, LogDeep + 1, Token); DoProcessUiMessage(1, "loading database config values finished."); DoProcessUiMessage(0, ""); } catch (Exception E) { DoProcessUiMessage(1, $"loading global configuraton aborted with an exceptional error."); LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } } private async Task GetSecTokenKeyAsync(cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { if (GlobalConfigValues.TryGetValue("Security.AccessTokenKey", out var _encKey)) { var _sec = cSecurePassword.Instance.Decode(_encKey); BearerSecurityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_sec)); } else { var _sec = Guid.NewGuid().ToString() + Guid.NewGuid().ToString() + Guid.NewGuid().ToString() + Guid.NewGuid().ToString(); _sec = _sec.Replace("-", ""); BearerSecurityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_sec)); _sec = cSecurePassword.Instance.Encode(_sec); await UpdateConfigValueAsync("Security.AccessTokenKey", _sec, DbConn, requestInfo, LogDeep + 1, Token); } JwtTokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, ValidateIssuer = true, ValidateAudience = true, ValidIssuer = JwtTokenIssuer, ValidAudience = JwtTokenAudience, IssuerSigningKey = BearerSecurityKey }; } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } } public string GenerateJsonWebToken(cF4sdUserInfo UserInfo) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { if (BearerSecurityKey == null) return null; var credentials = new SigningCredentials(BearerSecurityKey, SecurityAlgorithms.HmacSha256); var claims = new List { new Claim(JwtRegisteredClaimNames.NameId, UserInfo.Id.ToString()), new Claim(JwtRegisteredClaimNames.UniqueName, UserInfo.Name), new Claim(JwtRegisteredClaimNames.AuthTime, UserInfo.LogonTime.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'z'")), new Claim("login_method", UserInfo.AccountType.ToString()), new Claim("login_account", UserInfo.AdAccount.ToString()), new Claim("account_sid", UserInfo.AdSid), new Claim("language", UserInfo.Language ?? "") }; if (UserInfo.Roles?.Count > 0) foreach (var _roleEntry in UserInfo.Roles) claims.Add(new Claim("roles", _roleEntry)); UserInfo.LogonTime = DateTime.UtcNow; UserInfo.RenewUntil = UserInfo.LogonTime.AddMinutes(90); UserInfo.ValidUntil = UserInfo.LogonTime.AddMinutes(120); var token = new JwtSecurityToken(JwtTokenIssuer, JwtTokenAudience, claims, notBefore: UserInfo.LogonTime.AddMinutes(-1), expires: UserInfo.ValidUntil, signingCredentials: credentials); var retVal2 = JwtTokenHandler.WriteToken(token); return retVal2; } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } return null; } private async Task UpdateConfigValueAsync(string Key, string Value, cDbConnection DbConn, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { if (!DataHistorySqlHelper.GetWellKnownSqlStatement("UpdateConfigValue", out var Query)) return; var _params = new Dictionary() { { "Key", Key}, { "Value", Value}, }; await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, _params, requestInfo, Token); } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } } public async Task CreateCaseAsync(cF4SDCaseParameters Param, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var anonymous = InfrastructureConfig.F4SDAnalyticsDB?.AnonymousUser; var DbConnection = InfrastructureConfig.F4SDAnalyticsDB?.Connection; if (DbConnection == null) return false; if (!DataHistorySqlHelper.GetWellKnownSqlStatement("CreateCase", out var Query)) return false; using (var DbConn = new cDbConnection(DbConnection)) if (DbConn.IsOpen) { if (anonymous != null && (bool)anonymous) { Param.UserId = GetUserHashGuid((Guid)Param.UserId); } if (Param.SessionId != null && Param.SessionId != Guid.Empty) { if (Param.CaseId != null && Param.CaseId != Guid.Empty) { var Params = new Dictionary() { { "SessionId", Param.SessionId }, { "CaseId", Param.CaseId }, { "UserId", Param.UserId } }; var n = await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, Params, requestInfo, Token); if (n >= 1) { DoProcessUiMessage(2, $"Case is started. CaseId: " + Param.CaseId.ToString(), LogLevels.Debug); lock (CaseValues) CaseValues.Add((Guid)Param.CaseId, DateTime.UtcNow); return true; } DoProcessUiMessage(2, $"the insert of the Case-data into F4SDAnalytics database with exception error.", LogLevels.Warning); return false; } DoProcessUiMessage(2, $"API Call - CreateCase Invalid CaseId: 00000000-0000-0000-0000-000000000000 of the Case-data into F4SDAnalytics database.", LogLevels.Warning); return false; } DoProcessUiMessage(2, $"API Call - CreateCase - Invalid SessionId: 00000000-0000-0000-0000-000000000000 of the Case-data into F4SDAnalytics database.", LogLevels.Warning); return false; } return false; } catch (Exception E) { LogException(E); return false; } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } } public async Task UpdateCaseStateAsync(cF4SDCaseTimeParameters Param, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var DbConnection = InfrastructureConfig.F4SDAnalyticsDB?.Connection; if (DbConnection == null) return false; if (!DataHistorySqlHelper.GetWellKnownSqlStatement("UpdateCaseState", out var Query)) return false; using (var DbConn = new cDbConnection(DbConnection)) if (DbConn.IsOpen) { if (Param.CaseId != null && Param.CaseId != Guid.Empty) { XElement ParamState = null; if (Param.CaseTimes != null && Param.CaseTimes.Count > 0) { ParamState = new XElement("Root", from prm in Param.CaseTimes select new XElement("Item", new XElement("StatusId", (int)prm.StatusId), new XElement("TimeStamp", prm.CaseTime) )); } var Params = new Dictionary() { { "CaseId", Param.CaseId }, { "StatusId", Param.StatusId }, { "ActiveTime", Param.ActiveTime }, { "StatusXML", ParamState?.ToString() ?? String.Empty } }; var n = await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, Params, requestInfo, Token); if (n >= 1) { if (Param.StatusId == CaseStatus.Canceled || Param.StatusId == CaseStatus.Finished) { DoProcessUiMessage(2, $"Case is closed. CaseId: " + Param.CaseId.ToString(), LogLevels.Debug); lock (CaseValues) CaseValues.Remove((Guid)Param.CaseId); } return true; } DoProcessUiMessage(2, $"Current CaseId: " + Param.CaseId.ToString() + " could not be found", LogLevels.Debug); return false; } DoProcessUiMessage(2, $"API Call UpdateCaseState - Invalid CaseId: 00000000-0000-0000-0000-000000000000 of the Case-data into F4SDAnalytics database.", LogLevels.Warning); return false; } return false; } catch (Exception E) { LogException(E); return false; } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } } public async Task ReportQuickActionExecutionAsync(cF4SDQuickActionParameters Param, cDataHistoryConfigSqlConnection DBConnection, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { if (DBConnection != null && DBConnection.Database == InfrastructureConfig.F4SDAnalyticsDB?.Connection.Database && DataHistorySqlHelper.GetWellKnownSqlStatement("AnalyticsReportQuickActionExecution", out var Query)) { using (var DbConn = new cDbConnection(DBConnection)) if (DbConn.IsOpen) { if (Param.CaseId != null && Param.CaseId != Guid.Empty) { var Params = new Dictionary() { { "CaseId", Param.CaseId }, { "QActionId", Param.QuickActionId }, { "DeviceId", Param.DeviceId }, { "Start", Param.Start }, { "Finish", Param.Finish }, { "Parameters", Param.Paramaters }, { "Result", Param.Result }, { "ErrorCode", Param.ErrorCode }, { "ErrorDescription", Param.ErrorDescription }, { "ExecutionType", Param.ExecutionType.ToString() },{ "ResultType", Param.ResultType.ToString() }}; var n = await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, Params, requestInfo, Token); if (n >= 1) { return true; } DoProcessUiMessage(2, $"the insert of the QuickActionExecution-data into F4SDAnalytics database with exception error.", LogLevels.Warning); return false; } DoProcessUiMessage(2, $"API Call ReportQuickActionExecution - Invalid CaseId: 00000000-0000-0000-0000-000000000000 of the QuickActionExecution-data into F4SDAnalytics database.", LogLevels.Warning); return false; } } if (DBConnection != null && DBConnection.Database == InfrastructureConfig.HistoryDB.Connection.Database && DataHistorySqlHelper.GetWellKnownSqlStatement("ReportQuickActionExecution", out var Query2)) { using (var DbConn = new cDbConnection(DBConnection)) if (DbConn.IsOpen) { var Params = new Dictionary() { { "UserId", Param.UserId }, { "QActionId", Param.QuickActionId }, { "DeviceId", Param.DeviceId },{ "QActionName", Param.QuickActionName }, { "Start", Param.Start }, { "Finish", Param.Finish }, { "Parameters", Param.Paramaters }, { "Result", Param.Result }, { "ErrorCode", Param.ErrorCode }, { "ErrorDescription", Param.ErrorDescription }, { "ExecutionType", Param.ExecutionType.ToString() },{ "ResultType", Param.ResultType.ToString() }}; var n = await DataHistorySqlHelper.ExecuteAsync(DbConn, Query2, Params, requestInfo, Token); if (n >= 1) { return true; } DoProcessUiMessage(2, $"the insert of the QuickActionExecution-data into History database with exception error."); return false; } } return false; } catch (Exception E) { LogException(E); return false; } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } } public async Task CreateUserSessionAsync(cF4SDUserSessionParameters Param, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var anonymous = InfrastructureConfig.F4SDAnalyticsDB?.AnonymousUser; var DbConnection = InfrastructureConfig.F4SDAnalyticsDB?.Connection; if (anonymous != null && (bool)anonymous) { Param.UserId = GetUserHashGuid((Guid)Param.UserId); } if (DbConnection == null) return false; if (!DataHistorySqlHelper.GetWellKnownSqlStatement("CreateUserSession", out var Query)) return false; using (var DbConn = new cDbConnection(DbConnection)) if (DbConn.IsOpen) { if (Param.SessionId != null && Param.SessionId != Guid.Empty) { var Params = new Dictionary() { { "SessionId", Param.SessionId }, { "UserId", Param.UserId }, { "SessionDate", Param.SessionDate } }; var n = await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, Params, requestInfo, Token); if (n >= 1) { DoProcessUiMessage(2, $"Session is started. SessionId: " + Param.SessionId.ToString(), LogLevels.Debug); lock (SessionValues) SessionValues[(Guid)Param.SessionId] = DateTime.UtcNow; return true; } DoProcessUiMessage(2, $"the insert of the Usersession-data into F4SDAnalytics database with exception error.", LogLevels.Warning); return false; } DoProcessUiMessage(2, $"API Call CreateUserSession - Invalid SessionId: 00000000-0000-0000-0000-000000000000 of the Usersession-data into F4SDAnalytics database.", LogLevels.Warning); return false; } return false; } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return false; } public async Task CloseUserSessionAsync(cF4SDUserSessionParameters Param, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var DbConnection = InfrastructureConfig.F4SDAnalyticsDB?.Connection; if (DbConnection == null) return false; if (!DataHistorySqlHelper.GetWellKnownSqlStatement("CloseUserSession", out var Query)) return false; using (var DbConn = new cDbConnection(DbConnection)) if (DbConn.IsOpen) { if (Param.SessionId != null && Param.SessionId != Guid.Empty) { var Params = new Dictionary() { { "SessionId", Param.SessionId }, { "SessionDate", Param.SessionDate } }; var n = await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, Params, requestInfo, Token); if (n >= 1) { DoProcessUiMessage(2, $"Session is closed. SessionId: " + Param.SessionId.ToString(), LogLevels.Debug); lock (SessionValues) SessionValues.Remove((Guid)Param.SessionId); return true; } DoProcessUiMessage(2, $"the update of the Usersession-data into F4SDAnalytics database with exception error.", LogLevels.Warning); if (cLogManager.DefaultLogger.IsDebug) { var _msg = new List() { $"query: {Query}", $"session id: {Param.SessionId}", $"session date: {Param.SessionDate}", }; cLogManager.DefaultLogger.LogList(LogLevels.Debug, _msg); } return false; } DoProcessUiMessage(2, $"API Call CreateUserSession - Invalid SessionId: 00000000-0000-0000-0000-000000000000 of the Usersession-data into F4SDAnalytics database.", LogLevels.Warning); return false; } return false; } catch (Exception E) { LogException(E); return false; } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } } public async Task UpdateCaseAsync(Guid CaseId, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var DbConnection = InfrastructureConfig.F4SDAnalyticsDB?.Connection; if (DbConnection == null) return false; if (!DataHistorySqlHelper.GetWellKnownSqlStatement("UpdateCases", out var Query)) return false; using (var DbConn = new cDbConnection(DbConnection)) if (DbConn.IsOpen) { if (CaseId != null && CaseId != Guid.Empty) { var Params = new Dictionary() { { "CaseId", CaseId } }; var n = await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, Params, requestInfo, Token); if (n >= 1) { DoProcessUiMessage(2, $"Casestatus is updated. CaseId: " + CaseId.ToString(), LogLevels.Debug); lock (CaseValues) CaseValues.Add(CaseId, DateTime.UtcNow); return true; } DoProcessUiMessage(2, $"the update of the CaseStatus with CaseId '{CaseId}' into F4SDAnalytics database returned no legal update count ({n}).", LogLevels.Warning); return false; } DoProcessUiMessage(2, $"API Call KeepAliveCase - Invalid CaseId: 00000000-0000-0000-0000-000000000000 to update of the CaseStatus into F4SDAnalytics database.", LogLevels.Warning); return false; } return false; } catch (Exception E) { LogException(E); return false; } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } } public async Task ReportTicketAsync(cApiM42Ticket Param, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var anonymous = InfrastructureConfig.F4SDAnalyticsDB?.AnonymousUser; Guid.TryParse(requestInfo.userInfo?.Id.ToString(), out Guid userGuid); if (anonymous != null && (bool)anonymous) Param.User = GetUserHashGuid(userGuid).ToString(); else Param.User = userGuid.ToString(); var DbConnection = InfrastructureConfig.F4SDAnalyticsDB?.Connection; if (DbConnection == null) return false; if (!DataHistorySqlHelper.GetWellKnownSqlStatement("InsertTicket", out var Query)) return false; using (var DbConn = new cDbConnection(DbConnection)) if (DbConn.IsOpen) { if (Param.Ticket != null && Param.Ticket != Guid.Empty) { if (Param.CaseId != null && Param.CaseId != Guid.Empty) { var startTime = Param.workTimes.FirstOrDefault(x => x.Key == "StartTime").Value; var endTime = Param.workTimes.FirstOrDefault(x => x.Key == "EndTime").Value; var workingTime = Param.workTimes.FirstOrDefault(x => x.Key == "NettoWorkingTime").Value; var Params = new Dictionary() { { "TicketId", Param.Ticket }, { "Status", Param.StatusIdValue }, { "CaseId", Param.CaseId }, { "UserId", Param.User }, { "Start", startTime }, { "Finish", endTime }, { "ActiveTime", workingTime } }; var n = await DataHistorySqlHelper.ExecuteAsync(DbConn, Query, Params, requestInfo, Token); if (n >= 1) { DoProcessUiMessage(2, $"Ticket-Data is saved . TicketNumber: " + Param.Ticket, LogLevels.Debug); lock (CaseValues) CaseValues.Add((Guid)Param.CaseId, DateTime.UtcNow); return true; } DoProcessUiMessage(2, $"the insert of the Ticket-data into F4SDAnalytics database with exception error.", LogLevels.Warning); return false; } DoProcessUiMessage(2, $"API Call - InsertTicket Invalid CaseId: 00000000-0000-0000-0000-000000000000 of the Ticket-data into F4SDAnalytics database.", LogLevels.Warning); return false; } DoProcessUiMessage(2, $"API Call - InsertTicket - Invalid TicketId: 00000000-0000-0000-0000-000000000000 of the Ticket-data into F4SDAnalytics database.", LogLevels.Warning); return false; } return false; } catch (Exception E) { LogException(E); return false; } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } } public bool KeepAliveSession(Guid SessionId, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { if (SessionId != null && SessionId != Guid.Empty) { lock (SessionValues) SessionValues[SessionId] = DateTime.UtcNow; return true; } if (cLogManager.DefaultLogger.IsDebug) LogEntry($"API Call KeepAliveCase - Invalid CaseId: 00000000-0000-0000-0000-000000000000 ", LogLevels.Warning); return false; } catch (Exception E) { LogException(E); return false; } finally { if (CM != null) LogMethodEnd(CM); } } public async Task KeepAliveCase(Guid CaseId, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { if (CaseId != null && CaseId != Guid.Empty) { if (CaseValues.ContainsKey(CaseId)) { lock (CaseValues) CaseValues[CaseId] = DateTime.UtcNow; } else { await UpdateCaseAsync(CaseId, requestInfo, LogDeep + 1, Token); } return true; } if (cLogManager.DefaultLogger.IsDebug) LogEntry($"API Call KeepAliveCase - Invalid CaseId: 00000000-0000-0000-0000-000000000000 ", LogLevels.Warning); return false; } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return false; } public void DoProcessUiMessage(int Indent, string Message, LogLevels logLevel = LogLevels.Info) { try { var strIndent = new string(' ', Indent * 2); cLogManager.DefaultLogger.LogEntry(logLevel, strIndent + Message); ProcessUiMessage?.Invoke(cDataHistoryUiStatusMessage.Create(Indent, Message)); } catch { } } public void DoProcessUiMessage(int Indent, cXmlParserNodeMessage Message) { DoProcessUiMessage(Indent, cXmlParser.GetMessageString(Message)); } public void DoProcessUiMessage(int Indent, List Messages) { foreach (var Entry in Messages) DoProcessUiMessage(Indent, Entry); } public void CleanupUiMessageHandler() { if (ProcessUiMessage != null) { foreach (var Entry in ProcessUiMessage.GetInvocationList()) try { ProcessUiMessage -= Entry as DataHistoryUiMessageFunc; } catch { } ProcessUiMessage = null; } } internal class cFasdApiSearchResultExt { internal cFasdApiSearchResultEntry Result = new cFasdApiSearchResultEntry(); internal string upn_internal = null; internal int? IdAgent; } public class cUsageData { internal Int32 id; internal Int64 duration; internal DateTime lastEvent; } public async Task GetCurrentUserInfoAsync(CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var _user = WindowsIdentity.GetCurrent(); var _res = await GetWinUserInfoAsync(_user, CultureInfo.CurrentCulture.DisplayName, true, Token, requestInfo, LogDeep + 1); return _res; } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public async Task GetWinUserInfoAsync(IIdentity Identity, string Language, bool justWinRoles, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { if (Identity == null) return null; if (!(Identity is WindowsIdentity _winUser)) { LogEntry($"could not logon with specified identity due to incompatible authentication type (name={Identity.Name}, type={Identity.AuthenticationType}"); return null; } if (!_winUser.IsAuthenticated) { LogEntry($"the specified winuser is not authenticated (name={Identity.Name}, type={Identity.AuthenticationType}"); return null; } var _sid = _winUser.User.ToString(); var _retVal = new cF4sdUserInfo() { Id = Guid.Empty, LogonTime = DateTime.UtcNow, AccountType = cF4sdUserInfo.enumAccountType.AdUser, AdAccount = _winUser.Name, Name = _winUser.Name, AdSid = _sid, Language = Language }; LogEntry($"The authenticated user is: name={Identity.Name}, type={Identity.AuthenticationType}"); bool IsEntraIdDevelop = false; if (!justWinRoles) { if (!string.IsNullOrEmpty(_sid)) { Dictionary> _ids = null; if (RunningInIISExpress) { // check if we are in EntraID develop mode (running in IIS Express and the user is an Entra ID User) Guid azureId = Guid.Empty; azureId = cDataHistoryCollectorActiveDirectory.ConvertAzureSidToGuid(_sid); if (azureId != Guid.Empty) _ids = await UserSearchByEntraIdDevelopAsync(azureId, Token, requestInfo, LogDeep + 1); } if (_ids == null || _ids.Count == 0) _ids = await UserSearchBySidsAsync(new List { _sid }, Token, requestInfo, LogDeep + 1); else IsEntraIdDevelop = true; if (Token.IsCancellationRequested) return null; if (_ids?.Count > 0) { var _entry = _ids?.First().Value; if (_entry?.Count > 0) { var _result = _entry.First().Result; if (_result != null) { _retVal.Name = _result.Name; _retVal.Id = _result.id; } } } } if (_retVal.Id == Guid.Empty) { LogEntry($"Could not find user {_winUser.Name} with SID {_sid} for authentication in table 'main-user'.", LogLevels.Warning); LogEntry($"Please check, if at least one of the defined AD user scan nodes contains this user.", LogLevels.Warning); return null; } } var _membershipGroups = InfrastructureConfig?.Authorisation?.MembershipGroups?.GroupsAd; var _resMembershipGroups = new List(); if (IsEntraIdDevelop) { // if we are in EntraID develop mode, we have fake all ad group memberships if (_membershipGroups != null) foreach (var _entryDom in _membershipGroups.Values) foreach (var _entryGroup in _entryDom.Values) _resMembershipGroups.Add(_entryGroup); } else { var _dom = Domain.GetComputerDomain(); var _pc = new PrincipalContext(ContextType.Domain); var _groups = _winUser.Groups; var _msgLog = new List(); if (cLogManager.DefaultLogger.IsDebug) { _msgLog.Add($"the winuser {_retVal.AdAccount} logged on"); _msgLog.Add($" is member of ad security groups:"); } foreach (var _group in _groups) { if (Token.IsCancellationRequested) return null; if (_group is SecurityIdentifier _si) { cF4SDMembershipGroupAd _memGrp = null; if (_membershipGroups != null) foreach (var _entryDom in _membershipGroups.Values) { foreach (var _entryGroup in _entryDom.Values) { if (_si.Value == _entryGroup.SID) { _resMembershipGroups.Add(_entryGroup); _memGrp = _entryGroup; } } } if (DefaultLogger.IsDebug) { try { var _gp = GroupPrincipal.FindByIdentity(_pc, IdentityType.Sid, _si.Value); if (_gp != null) { if (_memGrp != null) _msgLog.Add($" {_gp.SamAccountName} ({_gp.DistinguishedName}) is member of '{_memGrp.Name}'"); else _msgLog.Add($" {_gp.SamAccountName} ({_gp.DistinguishedName})"); } else _msgLog.Add($" could not find group {_si.Value}"); } catch (Exception E) { LogException(E); } } } } if (cLogManager.DefaultLogger.IsDebug) cLogManager.DefaultLogger.LogList(LogLevels.Debug, _msgLog); } if (_membershipGroups?.Count > 0) AddRolesByMembership(_retVal, _resMembershipGroups); if (Token.IsCancellationRequested) return null; if (!string.IsNullOrEmpty(_retVal.AdSid) && (M42WpmCollector != null)) await M42WpmCollector.AddM42UserInfosAsync(_retVal, Token, requestInfo, LogDeep + 1); var _token = GenerateJsonWebToken(_retVal); _retVal.Token = _token; return _retVal; } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } private async Task>> searchSqlAsync(string strQuery, Dictionary SqlParam, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep, string QueryName, string PhoneSearch = null, bool SupportCancellation = false) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; int apiError = 0; try { if (strQuery == null) return null; using (var DbConn = new cDbConnection(mainDbConnection, Timeout: 10)) { if (!DbConn.IsOpen) return null; using (var Reader = await DataHistorySqlHelper.GetTableResultAsync(DbConn.Connection, strQuery, SqlParam, Token, SupportCancellation: SupportCancellation)) { var output = new Dictionary>(); if (Reader != null) try { if (Reader.HasRows) { var maxStateVal = Enum.GetValues(typeof(enumF4sdSearchResultStatus)).Cast().Max(); var minStateVal = Enum.GetValues(typeof(enumF4sdSearchResultStatus)).Cast().Min(); while (await Reader.ReadAsync(Token)) { try { var Entry = new cFasdApiSearchResultExt(); var intType = Reader.GetInt32(0); Entry.Result.Type = (enumF4sdSearchResultClass)intType; Entry.upn_internal = Reader.IsDBNull(4) ? null : Reader.GetString(4); Entry.IdAgent = Reader.IsDBNull(5) ? (int?)null : Reader.GetInt32(5); var strName = Reader.GetString(1); if (PhoneSearch != null && Entry.Result.Type == enumF4sdSearchResultClass.Phone) // phone type { string strPhone = null; var strPh = Reader.IsDBNull(8) ? null : Reader.GetString(8); if (strPh != null) { var arrPh = strPh.Split(' '); foreach (var str in arrPh) { if (str.EndsWith(PhoneSearch)) { strPhone = str; break; } } } if (strPhone != null) { Entry.Result.Name = strName + " (" + strPhone + ")"; Entry.Result.DisplayName = strName + " (" + strPhone + ")"; } else { Entry.Result.Name = strName; Entry.Result.DisplayName = strName; } } else { Entry.Result.Name = strName; Entry.Result.DisplayName = strName; } Entry.Result.id = Reader.GetFieldValue(2); if (!Reader.IsDBNull(3)) { var intStatus = Reader.GetInt32(3); if (intStatus <= maxStateVal && intStatus >= minStateVal) Entry.Result.Status = (enumF4sdSearchResultStatus)intStatus; } var account = Reader.IsDBNull(6) ? null : Reader.GetString(6); var domain = Reader.IsDBNull(7) ? null : Reader.GetString(7); Entry.Result.Infos = new Dictionary(2) { {"account", account }, {"domain", domain }, }; if (output.TryGetValue(strName, out var lst)) { lst.Add(Entry); } else { if (output.Count > 11) break; lst = new List { Entry }; output.Add(strName, lst); } } catch (Exception E) { cLogManager.DefaultLogger.LogException(E); } } } } catch (Exception E) { if (!Token.IsCancellationRequested || !SupportCancellation) cLogManager.DefaultLogger.LogException(E); } return output; } } } catch (Exception E) { apiError = E.HResult; LogException(E); } finally { if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(QueryName, _startTime, SqlParam, apiError, requestInfo?.requestName); if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } private async Task>> searchStringAsync(string search, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep, string Field = null, bool Reverse = false) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var IsPhone = this.InfrastructureConfig.HistoryDB.SearchForPhoneNumbers && isDigits(search); string strQuery = null; if (Field == null) { if (IsPhone) { strQuery = "SearchFulltextRev"; Reverse = true; } else #if SIMULATE_SLOW_SEARCH strQuery = "SearchFulltextWithDelay"; #else strQuery = "SearchFulltext"; #endif } else { if (Reverse) strQuery = "SearchByFieldRev"; else strQuery = "SearchByField"; } var SqlParam = new Dictionary(); if (Field == null || !Reverse) { var searchMask = $"\"{search}*\""; SqlParam.Add("SEARCH", searchMask); } if (Reverse) { char[] arrRev = (search + 'x').ToArray(); Array.Reverse(arrRev); var strRev = new string(arrRev); strRev = $"\"{strRev}*\""; SqlParam.Add("REV", strRev); } SqlParam.Add("DAYS", this.InfrastructureConfig.ClientAgent.MaxDeviceAge); if (strQuery == null) return null; if (!DataHistorySqlHelper.GetWellKnownSqlStatement(strQuery, out var Query)) return null; strQuery = Query.Query; if (Field != null) strQuery = string.Format(strQuery, Field); string strPhoneSearch = null; if (IsPhone) strPhoneSearch = search; return await searchSqlAsync(strQuery, SqlParam, Token, requestInfo, LogDeep + 1, Query.Name, strPhoneSearch, true); } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } private async Task>> searchComputerNameAsync(string search, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep, string Field = null, bool Reverse = false) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { string strQuery = "SearchComputerByName"; var SqlParam = new Dictionary(); if (Field == null || !Reverse) { var searchMask = $"\'{search}%\'"; SqlParam.Add("name", search + "%"); } if (!DataHistorySqlHelper.GetWellKnownSqlStatement(strQuery, out var Query)) return null; strQuery = Query.Query; if (Field != null) strQuery = string.Format(strQuery, Field); return await searchSqlAsync(strQuery, SqlParam, Token, requestInfo, LogDeep + 1, Query.Name, SupportCancellation: true); } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public async Task> DefaultSearchAsync(string search, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { List> taskList = new List>(); var RetVal = new List(); var SearchWithLike = this.InfrastructureConfig.HistoryDB.SearchWithLike; if (SearchWithLike) { var T1 = Task.Run(() => { return searchComputerNameAsync(search, Token, requestInfo, LogDeep + 1); }); var T2 = Task.Run(() => { return searchStringAsync(search, Token, requestInfo, LogDeep + 1); }); var output = await Task.WhenAll(T1, T2); foreach (var Entry in output[0].Values) { if (Entry.Count == 1) RetVal.Add(Entry[0].Result); else if (Entry.Count > 1) { foreach (var Entry2 in Entry) { CompleteSearchEntry(Entry2); RetVal.Add(Entry2.Result); } } } foreach (var Entry in output[1].Values) { if (RetVal.Count >= 11) break; bool alreadyExists = RetVal.Any(x => x.id == Entry[0].Result.id); if (!alreadyExists) { if (Entry.Count == 1) RetVal.Add(Entry[0].Result); else if (Entry.Count > 1) { foreach (var Entry2 in Entry) { CompleteSearchEntry(Entry2); RetVal.Add(Entry2.Result); } } } } } else { var output = await searchStringAsync(search, Token, requestInfo, LogDeep + 1); foreach (var Entry in output.Values) { if (Entry.Count == 1) RetVal.Add(Entry[0].Result); else if (Entry.Count > 1) { foreach (var Entry2 in Entry) { CompleteSearchEntry(Entry2); RetVal.Add(Entry2.Result); } } } } return RetVal; } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } internal cFasdApiSearchResultExt CompleteSearchEntry(cFasdApiSearchResultExt entry) { var strDomain = ""; if (entry.upn_internal != null) { var arr1 = entry.upn_internal.Split('@'); if (arr1.Length > 1) { var arr2 = arr1[1].Split('.'); if (arr2.Length > 0) strDomain = arr2[0]; } } var strDead = ""; if (entry.IdAgent == null) strDead = "⚠ "; if (!string.IsNullOrEmpty(strDomain)) { string c = strDomain[0].ToString().ToUpperInvariant(); strDomain = c + strDomain.Remove(0, 1); entry.Result.Name += $" (" + strDead + strDomain + ")"; entry.Result.DisplayName += $" (" + strDead + strDomain + ")"; } return entry; } public Guid? DetailedSearchStart(string search, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { var cancellationToken = new CancellationTokenSource(); var _task = Task.Run(async () => { return await DetailedSearchAsync(search, cancellationToken.Token, requestInfo, LogDeep); }); var RetVal = cDataHistoryCollectorSearchTaskCache.AddTask(cancellationToken, _task); return RetVal; } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } return null; } public async Task DetailedSearchResultAsync(Guid taskID, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { var _result = await cDataHistoryCollectorSearchTaskCache.GetResultAsync(taskID); return _result; } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } return null; } public async Task DetailedSearchAsync(string search, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { var RetVal = new cFasdApiSearchResultCollection(); var SearchWithLike = this.InfrastructureConfig.HistoryDB.SearchWithLike; if (SearchWithLike) { var T1 = Task.Run(() => { return searchComputerNameAsync(search, Token, requestInfo, LogDeep + 1); }); var T2 = Task.Run(() => { return searchStringAsync(search, Token, requestInfo, LogDeep + 1); }); var output = await Task.WhenAll(T1, T2); foreach (var Entry in output[0]) { if (!RetVal.TryGetValue(Entry.Key, out var lst)) { lst = new List(); RetVal.Add(Entry.Key, lst); } foreach (var Entry2 in Entry.Value) lst.Add(Entry2.Result); } foreach (var Entry in output[1]) { if (RetVal.Count >= 11) break; if (!RetVal.TryGetValue(Entry.Key, out var lst)) { lst = new List(); RetVal.Add(Entry.Key, lst); foreach (var Entry2 in Entry.Value) lst.Add(Entry2.Result); } } } else { var output = await searchStringAsync(search, Token, requestInfo, LogDeep + 1); foreach (var Entry in output) { if (!RetVal.TryGetValue(Entry.Key, out var lst)) { lst = new List(); RetVal.Add(Entry.Key, lst); } foreach (var Entry2 in Entry.Value) lst.Add(Entry2.Result); } } return RetVal; } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } return null; } public async Task PhoneSearchAsync(string searchPhone, string searchName, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { Dictionary>[] output; if (string.IsNullOrEmpty(searchName)) { var res1 = await searchStringAsync(searchPhone, Token, requestInfo, LogDeep + 1, "phone_rev", true); output = new Dictionary>[] { res1 }; } else { var T1 = Task.Run(() => { return searchStringAsync(searchPhone, Token, requestInfo, LogDeep + 1, "phone_rev", true); }); var T2 = Task.Run(() => { return searchStringAsync(searchName, Token, requestInfo, LogDeep + 1, "full_name", false); }); output = await Task.WhenAll(T1, T2); } var _tmpRetVal = new Dictionary>(); foreach (var Entry3 in output) foreach (var Entry in Entry3) { if (!_tmpRetVal.TryGetValue(Entry.Key, out var lst)) { lst = new Dictionary(); _tmpRetVal.Add(Entry.Key, lst); } foreach (var Entry2 in Entry.Value) { bool replace = true; if (lst.TryGetValue(Entry2.Result.id, out var _e)) { if (_e.Type > Entry2.Result.Type) replace = false; } if (replace) lst[Entry2.Result.id] = Entry2.Result; } } var RetVal = new cFasdApiSearchResultCollection(); foreach (var Entry in _tmpRetVal) { var lst = Entry.Value.Values.ToList(); RetVal[Entry.Key] = lst; } return RetVal; } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public async Task>> ComputerSearchByNameAsync(string Name, string Domain, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { string strQuery = null; var SqlParams = new Dictionary(2) { { "name", Name } }; if (string.IsNullOrWhiteSpace(Domain)) strQuery = "SearchComputerByName"; else { strQuery = "SearchComputerByNameAndDomain"; SqlParams.Add("domain", Domain); } if (!DataHistorySqlHelper.GetWellKnownSqlStatement(strQuery, out var Query)) return null; var output = await searchSqlAsync(Query.Query, SqlParams, Token, requestInfo, LogDeep + 1, Query.Name, SupportCancellation: false); var RetVal = new Dictionary>(); foreach (var Entry in output) { if (!RetVal.TryGetValue(Entry.Key, out var lst)) { lst = new List(); RetVal.Add(Entry.Key, lst); } foreach (var Entry2 in Entry.Value) lst.Add(Entry2.Result); } return RetVal; } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } internal async Task>> UserSearchByEntraIdDevelopAsync(Guid AzureId, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var SqlParams = new Dictionary { { "AzureId", AzureId } }; if (!DataHistorySqlHelper.GetWellKnownSqlStatement("SearchUserByAzureIdDevelop", out var Query)) return null; var res = await searchSqlAsync(Query.Query, SqlParams, Token, requestInfo, LogDeep + 1, Query.Name, SupportCancellation: false); return res; } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } internal async Task>> UserSearchBySidsAsync(List Sids, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var SqlParams = new Dictionary(Sids.Count); var strIn = ""; int i = 0; foreach (var Entry in Sids) { var objSid = new SecurityIdentifier(Entry); var arrB = new byte[objSid.BinaryLength]; objSid.GetBinaryForm(arrB, 0); if (strIn != "") strIn += ","; strIn += "@SID" + i.ToString(); SqlParams.Add("SID" + i.ToString(), arrB); i++; } if (!DataHistorySqlHelper.GetWellKnownSqlStatement("SearchUserBySid", out var Query)) return null; var strQuery = string.Format(Query.Query, strIn); var res = await searchSqlAsync(strQuery, SqlParams, Token, requestInfo, LogDeep + 1, Query.Name, SupportCancellation: false); return res; } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public async Task GetUserIdFromAccountAsync(string Account, string Domain, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { if (string.IsNullOrEmpty(Account) || string.IsNullOrEmpty(Domain)) return null; if (!DataHistorySqlHelper.GetWellKnownSqlStatement("GetUserIdFromAccount", out var Query)) return null; var Params = new Dictionary() { { "account", Account}, { "domain", Domain} }; using (var Conn = new cDbConnection(mainDbConnection)) { if (!Conn.IsOpen) { LogEntry($"Could not open main sql database '{mainDbConnection.Database}', aborting scan...'", LogLevels.Error); return null; } var res = await DataHistorySqlHelper.GetScalarResultAsync(Conn, Query, Params, requestInfo, Token); return res; } } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public async Task UserSearchByNameAndSidsAsync(string Name, List SIDs, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { Dictionary> output = null; if (SIDs != null && SIDs.Count != 0) output = await UserSearchBySidsAsync(SIDs, Token, requestInfo, LogDeep + 1); if (output == null || output.Count == 0) output = await searchStringAsync(Name, Token, requestInfo, LogDeep + 1); var RetVal = new cFasdApiSearchResultCollection(); foreach (var Entry in output) { if (!RetVal.TryGetValue(Entry.Key, out var lst)) { lst = new List(); RetVal.Add(Entry.Key, lst); } foreach (var Entry2 in Entry.Value) lst.Add(Entry2.Result); } return RetVal; } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool isDigits(string s) { if (s == null || s == "") return false; for (int i = 0; i < s.Length; i++) if ((s[i] ^ '0') > 9) return false; return true; } public async Task> GetInfoClassListTest(enumFasdInformationClass infoClass, bool filtered, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; var IsValid = false; var RetVal = new List(); try { DoProcessUiMessage(0, $"Retrieving the {infoClass} list for testing purposes."); var queryName = $"Get{infoClass}ListTest"; if (filtered) queryName += "Filtered"; if (!DataHistorySqlHelper.GetWellKnownSqlStatement(queryName, out var Query)) return RetVal; using (var Conn = new cDbConnection(mainDbConnection)) { if (!Conn.IsOpen) { LogEntry($"Could not open main sql database '{mainDbConnection.Database}', aborting scan...'", LogLevels.Error); return RetVal; } int apiError = 0; try { using (var Reader = await DataHistorySqlHelper.GetTableResultAsync(Conn, Query, null, Token)) { if (Reader != null) try { IsValid = true; if (Reader.HasRows) { while (await Reader.ReadAsync()) { try { var Entry = new cDataHistoryInfoClassListEntry { Name = Reader.GetString(0), id = Reader.GetGuid(1) }; if (!string.IsNullOrWhiteSpace(Entry.Name) && (Entry.id != Guid.Empty)) RetVal.Add(Entry); } catch (Exception E) { cLogManager.DefaultLogger.LogException(E); } } } } catch (Exception E) { IsValid = false; cLogManager.DefaultLogger.LogException(E); } } } catch (Exception E) { apiError = E.HResult; LogException(E); } finally { if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(Query.Name, _startTime, "", apiError, requestInfo?.requestName); } } } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } if (!IsValid) DoProcessUiMessage(1, $"Error while retrieving the {infoClass} list for testing purposes."); else DoProcessUiMessage(1, $"{RetVal.Count} {infoClass} entries found."); return RetVal; } public async Task> GetUsageFromAgentData(enumFasdInformationClass infoClass, List Ids, int Age, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var Age2 = Age; if (Ids.Count == 1) Age2 = 365; var AgentLimit = DateTime.UtcNow + TimeSpan.FromDays(-Age2); var idInput = Ids.Select(v => new cF4sdIdentityEntry() { Id = v, Class = infoClass }).ToList(); var listIds = await getConnectorIdList(idInput, Token, requestInfo, LogDeep + 1); if (listIds == null || listIds.Count == 0) return null; var lstAgentIds = new Dictionary(Ids.Count); var lstTicketIds = new List(Ids.Count); foreach (var Entry in listIds) { if (M42WpmCollector != null && infoClass == enumFasdInformationClass.User) { if (Entry.sid != null) lstTicketIds.Add(Entry); } if (Entry.lastSeenByAgent != null && Entry.lastSeenByAgent >= AgentLimit) { if (Entry.agentId2 != null) lstAgentIds[(int)Entry.agentId2] = new cDataHistoryUsageIdInfo() { Id = Entry.Id, AccountType = enumAccountType.Azure }; if (Entry.agentId != null) lstAgentIds[(int)Entry.agentId] = new cDataHistoryUsageIdInfo() { Id = Entry.Id, AccountType = enumAccountType.AD }; } if (Entry.localAgentIds != null) { foreach (var entryLocal in Entry.localAgentIds) { if (entryLocal.lastSeenByAgent >= AgentLimit) lstAgentIds[entryLocal.agentId] = new cDataHistoryUsageIdInfo() { Id = Entry.Id, AccountType = enumAccountType.Local, account = entryLocal.account, domain = "" }; } } } if (DefaultLogger.IsDebug) { var _msgDebug = new List() { $"{lstAgentIds?.Count} agent ids found by usage determination:" }; foreach (var dbgEntry in lstAgentIds) _msgDebug.Add($"{dbgEntry.Key}: accountType={dbgEntry.Value.AccountType}, account={dbgEntry.Value.account}, domain={dbgEntry.Value.domain}, id={dbgEntry.Value.Id}"); DefaultLogger.LogList(LogLevels.Debug, _msgDebug); } var taskList = new List>>(2); if (lstAgentIds.Count > 0) taskList.Add(Task.Run>(async () => { return await GetUsedInfoFromAgentData(infoClass, lstAgentIds, Age, Token, requestInfo, LogDeep + 1); })); if (lstTicketIds.Count > 0) taskList.Add(Task.Run>(async () => { return await getTicketUsage(infoClass, lstTicketIds, Age, Token, requestInfo, LogDeep + 1); })); if (taskList.Count == 0) return null; var arrTask = taskList.ToArray(); var RetVal = await Task.WhenAll>(arrTask); var RetVal2 = new List(); foreach (var Entry in RetVal) { if (Entry != null) RetVal2.AddRange(Entry); } if (RetVal2.Count > 0) return RetVal2; } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public async Task> GetUsageFromOnlyAgentData(enumFasdInformationClass infoClass, List Ids, int Age, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var Age2 = Age; if (Ids.Count == 1) Age2 = 365; var AgentLimit = DateTime.UtcNow + TimeSpan.FromDays(-Age2); var idInput = Ids.Select(v => new cF4sdIdentityEntry() { Id = v, Class = infoClass }).ToList(); var listIds = await getConnectorIdList(idInput, Token, requestInfo, LogDeep + 1); if (listIds == null || listIds.Count == 0) return null; var lstAgentIds = new Dictionary(Ids.Count); foreach (var Entry in listIds) { if (Entry.lastSeenByAgent != null && Entry.lastSeenByAgent >= AgentLimit) { if (Entry.agentId2 != null) lstAgentIds[(int)Entry.agentId2] = new cDataHistoryUsageIdInfo() { Id = Entry.Id, AccountType = enumAccountType.Azure }; if (Entry.agentId != null) lstAgentIds[(int)Entry.agentId] = new cDataHistoryUsageIdInfo() { Id = Entry.Id, AccountType = enumAccountType.AD }; } if (Entry.localAgentIds != null) { foreach (var entryLocal in Entry.localAgentIds) { if (entryLocal.lastSeenByAgent >= AgentLimit) lstAgentIds[entryLocal.agentId] = new cDataHistoryUsageIdInfo() { Id = Entry.Id, AccountType = enumAccountType.Local, account = entryLocal.account, domain = "" }; } } } if (DefaultLogger.IsDebug) { var _msgDebug = new List() { $"{lstAgentIds?.Count} agent ids found by usage determination:" }; foreach (var dbgEntry in lstAgentIds) _msgDebug.Add($"{dbgEntry.Key}: accountType={dbgEntry.Value.AccountType}, account={dbgEntry.Value.account}, domain={dbgEntry.Value.domain}, id={dbgEntry.Value.Id}"); DefaultLogger.LogList(LogLevels.Debug, _msgDebug); } var taskList = new List>>(2); if (lstAgentIds.Count > 0) taskList.Add(Task.Run>(async () => { return await GetUsedInfoFromAgentData(infoClass, lstAgentIds, Age, Token, requestInfo, LogDeep + 1); })); if (taskList.Count == 0) return null; var arrTask = taskList.ToArray(); var RetVal = await Task.WhenAll>(arrTask); var RetVal2 = new List(); foreach (var Entry in RetVal) { if (Entry != null) RetVal2.AddRange(Entry); } if (RetVal2.Count > 0) return RetVal2; } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } private async Task> getTicketUsage(enumFasdInformationClass infoClass, List lstTicketIds, int Age, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { return await M42WpmCollector?.getTicketUsage(lstTicketIds, Token, requestInfo, LogDeep); } private enumFasdInformationClass getResultClassForAgentUsage(enumFasdInformationClass infoClass) { switch (infoClass) { case enumFasdInformationClass.User: return enumFasdInformationClass.Computer; case enumFasdInformationClass.Computer: return enumFasdInformationClass.User; } return enumFasdInformationClass.Unknown; } private async Task> GetUsedInfoFromAgentData(enumFasdInformationClass infoClass, Dictionary AgentIdInfos, int Age, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var lstTasks = new List>>(AgentIdInfos.Count); foreach (var AgentId in AgentIdInfos) lstTasks.Add(GetSingleUsedInfoFromAgentData(infoClass, AgentId.Value, AgentId.Key, Age, Token, requestInfo, LogDeep + 1)); var res = await Task.WhenAll(lstTasks.ToArray()); var RetVal = new List(); double _sumDuration = 0; for (int i = 0; i < res.Length; i++) { var Entry = res[i]; if (Entry == null) continue; foreach (var Entry2 in Entry) { if (Entry2 == null) continue; RetVal.Add(Entry2); _sumDuration += Entry2.UsingLevel; } } if (_sumDuration == 0) _sumDuration = 1; foreach (var Entry in RetVal) Entry.UsingLevel /= _sumDuration; return RetVal; } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } private async Task> GetSingleUsedInfoFromAgentData(enumFasdInformationClass infoClass, cDataHistoryUsageIdInfo Id, int AgentId, int Age, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var _usageData = await F4sdAgent.GetSingleUsedInfoFromAgentData(infoClass, AgentId, Age, Token, requestInfo, LogDeep + 1); if (_usageData == null) return null; var _infoClass = getResultClassForAgentUsage(infoClass); var RetVal = new List(); foreach (var _entry in _usageData) { var deviceInfo = await GetMainInfoFromAgentId(_infoClass, _entry.id, requestInfo, LogDeep + 1, Token); if (deviceInfo == null && infoClass == enumFasdInformationClass.Computer && _infoClass == enumFasdInformationClass.User && InfrastructureConfig.ClientAgent?.localAccountAssignments != null) deviceInfo = await GetLocalUserInfoFromAgentId(_entry.id, requestInfo, LogDeep + 1, Token); if (deviceInfo != null) { var _at = enumAccountType.unknow; if (infoClass == enumFasdInformationClass.User) _at = Id.AccountType; deviceInfo.Identities?.Add(new cF4sdIdentityEntry() { Class = infoClass, Id = Id.Id, agentId = AgentId, AccountType = _at }); deviceInfo.UsingLevel = (double)_entry.duration; deviceInfo.LastUsed = _entry.lastEvent; if (deviceInfo.Infos == null) deviceInfo.Infos = new Dictionary(); if (!deviceInfo.Infos.ContainsKey("UserAccountType")) deviceInfo.Infos.Add("UserAccountType", Id.AccountType.ToString()); if (infoClass == enumFasdInformationClass.User) { if (!string.IsNullOrEmpty(Id.account)) deviceInfo.Infos.Add("UserAccount", Id.account); if (!string.IsNullOrEmpty(Id.domain)) deviceInfo.Infos.Add("UserDommain", Id.domain); } RetVal.Add(deviceInfo); if (DefaultLogger.IsDebug) deviceInfo.LogIt(LogLevels.Debug); } } if (RetVal.Count > 0) return RetVal; } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } private async Task GetMainInfoFromAgentId(enumFasdInformationClass infoClass, int agentID, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token, cF4sdApiSearchResultRelation SearchEntry = null) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; if (!DataHistorySqlHelper.GetWellKnownSqlStatement($"Get{infoClass}InfoFromAgentId", out var Query)) return null; var Params = new Dictionary() { { "id", agentID } }; int apiError = 0; try { using (var ConnMain = new cDbConnection(mainDbConnection)) using (var Reader = await DataHistorySqlHelper.GetDataReaderAsync(ConnMain, Query, Params, Token)) { if (Reader != null) try { if (Reader.HasRows) { var maxStateVal = Enum.GetValues(typeof(enumF4sdSearchResultStatus)).Cast().Max(); var minStateVal = Enum.GetValues(typeof(enumF4sdSearchResultStatus)).Cast().Min(); if (await Reader.ReadAsync()) { try { var Id = Reader.GetGuid(0); var Name = Reader.GetString(1); var Status = enumF4sdSearchResultStatus.Unknown; if (!Reader.IsDBNull(2)) { var intStatus = Reader.GetInt32(2); if (intStatus <= maxStateVal && intStatus >= minStateVal) Status = (enumF4sdSearchResultStatus)intStatus; } var account = Reader.IsDBNull(3) ? null : Reader.GetString(3); var domain = Reader.IsDBNull(4) ? null : Reader.GetString(4); var IsAzure = Reader.GetInt32(5); var AccountType = enumAccountType.unknow; if (infoClass == enumFasdInformationClass.User) { if (IsAzure == 1) AccountType = enumAccountType.Azure; else AccountType = enumAccountType.AD; } var RetVal = new cF4sdApiSearchResultRelation() { Type = cFasdApiSearchResultEntry.getSearchClass(infoClass), id = Id, Name = Name, DisplayName = Name, Status = Status, LastUsed = DateTime.UtcNow, UsingLevel = 1.0, }; RetVal.Identities = new cF4sdIdentityList { new cF4sdIdentityEntry() { Class = infoClass, Id = RetVal.id, agentId = agentID, AccountType = AccountType } }; RetVal.Infos = new Dictionary { ["account"] = account, ["domain"] = domain }; if (infoClass == enumFasdInformationClass.User) RetVal.Infos["UserAccountType"] = AccountType.ToString(); if (SearchEntry != null) { RetVal.UsingLevel = SearchEntry.UsingLevel; RetVal.LastUsed = SearchEntry.LastUsed; if (SearchEntry.Identities != null) RetVal.Identities?.AddRange(SearchEntry.Identities); } return RetVal; } catch (Exception E) { cLogManager.DefaultLogger.LogException(E); } } } } catch (Exception E) { cLogManager.DefaultLogger.LogException(E); } } } catch (Exception E) { apiError = E.HResult; LogException(E); } finally { if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(Query.Name, _startTime, Params, apiError, requestInfo?.requestName); if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } private async Task GetLocalUserInfoFromAgentId(int agentID, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); LogEntry($"agentId={agentID}", LogLevels.Debug); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; if (!DataHistorySqlHelper.GetWellKnownSqlStatement($"GetLocalUserInfoFromAgentId", out var Query)) return null; var Params = new Dictionary() { { "id", agentID } }; int apiError = 0; try { using (var ConnMain = new cDbConnection(mainDbConnection)) using (var Reader = await DataHistorySqlHelper.GetDataReaderAsync(ConnMain, Query, Params, Token)) { if (Reader != null) try { if (Reader.HasRows) { var maxStateVal = Enum.GetValues(typeof(enumF4sdSearchResultStatus)).Cast().Max(); var minStateVal = Enum.GetValues(typeof(enumF4sdSearchResultStatus)).Cast().Min(); if (await Reader.ReadAsync()) { try { var Id = Reader.GetGuid(0); var Name = Reader.GetString(1); var Status = enumF4sdSearchResultStatus.Unknown; if (!Reader.IsDBNull(2)) { var intStatus = Reader.GetInt32(2); if (intStatus <= maxStateVal && intStatus >= minStateVal) Status = (enumF4sdSearchResultStatus)intStatus; } var account = Reader.IsDBNull(3) ? null : Reader.GetString(3); var RetVal = new cF4sdApiSearchResultRelation() { Type = enumF4sdSearchResultClass.User, id = Id, Name = Name, DisplayName = Name, Status = Status, LastUsed = DateTime.UtcNow, UsingLevel = 1.0, }; RetVal.Identities = new cF4sdIdentityList() { new cF4sdIdentityEntry() { Class = enumFasdInformationClass.User, Id = Id, agentId = agentID, AccountType = enumAccountType.Local } }; RetVal.Infos = new Dictionary { ["account"] = account, ["UserAccountType"] = "Local" }; LogEntry($"Local account info found: id={Id}, account={account} ", LogLevels.Debug); return RetVal; } catch (Exception E) { cLogManager.DefaultLogger.LogException(E); } } } } catch (Exception E) { cLogManager.DefaultLogger.LogException(E); } } } catch (Exception E) { apiError = E.HResult; LogException(E); } finally { if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(Query.Name, _startTime, Params, apiError, requestInfo?.requestName); if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public async Task> GetTableResultsMainDb(List Tables, Dictionary Identities, DateTime RefTime, int MaxAge, bool instantly, bool IsSecondCall, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { Task>[] tasks = new Task>[Tables.Count]; for (int i = 0; i < Tables.Count; i++) { tasks[i] = getTableRawData(Tables[i], Identities, RefTime, MaxAge, instantly, IsSecondCall, Token, requestInfo, LogDeep + 1); } var Results = await Task.WhenAll(tasks).ConfigureAwait(false); var RetVal = new List(); foreach (var Entry in Results) { if (Entry == null) continue; RetVal.AddRange(Entry); } return RetVal; } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public async Task GetDetailsTableSingleResultMainDb(cDataHistoryConfigTable Table, Dictionary Identities, DateTime RefTime, int MaxAge, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { using (var Conn = new cDbConnection(mainDbConnection)) { if (!Conn.IsOpen) { LogEntry($"Could not open main sql database '{mainDbConnection.Database}', aborting scan...'", LogLevels.Error); return null; } var Cols = new List(); foreach (var col in Table.Columns.Values) { Cols.Add(col.Name); if (col.SqlTypeBin != null) Cols.Add(col.Name + "_bin"); } if (!Identities.TryGetValue(Table.ParentCluster.InformationClass, out var _ids)) return null; var _valId = _ids.Id; var _rowId = Table.KeyColumns.First()?.SourceName; var _rowTime = Table.EventTimeColumn?.SourceName; if (string.IsNullOrEmpty(_rowId) || string.IsNullOrEmpty(_rowTime)) return null; var Filter = new Dictionary(1) { { _rowId, _valId } }; using (var _reader = await DataHistorySqlHelper.getDbReaderDetailTable(Conn, Table.SourceName, Filter, _rowTime, MaxAge, Token)) { if (_reader == null) return null; if (_reader.HasRows) { var retVal = new cF4SDHealthCardRawData.cHealthCardDetailsTable { Name = Table.Name, Columns = Table.Columns.Values.Select(v => v.Name).ToList(), Values = new Dictionary>() }; var _colInfos = Table.Columns.Values.ToList(); Dictionary _dic = new Dictionary(Table.Columns.Count); var _idx = 0; foreach (var _colInfo in Table.Columns.Values) { _dic[_colInfo.SourceName] = _idx; _idx++; } var _arrIdxAssign = Enumerable.Repeat(-1, Table.Columns.Count).ToArray(); for (int i = 0; i < _reader.FieldCount; i++) { var _n = _reader.GetName(i); if (_dic.TryGetValue(_n, out var _ix)) _arrIdxAssign[_ix] = i; } while (await _reader.ReadAsync(Token)) { if (Token.IsCancellationRequested) return null; var _row = Enumerable.Repeat(null, Table.Columns.Count).ToArray(); DateTime? EventTime = null; for (int i = 0; i < Table.Columns.Count; i++) { var _n = _arrIdxAssign[i]; if (_n >= 0) { var obj = _reader.GetValue(_n); var _obj2 = DataHistorySqlHelper.GetSqlDataValueFromHistoryType(obj, _colInfos[i].ValueType, _colInfos[i].Cardinal); _row[i] = _obj2[0]; if (_reader.GetName(_n) == Table.EventTimeColumn.SourceName) if (_row[i] is DateTime dt) EventTime = dt; } } if (EventTime != null) { var indexDay = cDataHistoryCollector.getDayIndex((DateTime)EventTime, RefTime, MaxAge + 1); if (!retVal.Values.TryGetValue(indexDay, out var entryDay)) { entryDay = new List(); retVal.Values.Add(indexDay, entryDay); } entryDay.Add(_row); } } return retVal; } } } } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } return null; } public async Task> GetDetailsTableResultsMainDb(List Tables, Dictionary Identities, DateTime RefTime, int MaxAge, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var _lstTsk = new List>(Tables.Count); foreach (var _table in Tables) _lstTsk.Add(GetDetailsTableSingleResultMainDb(_table, Identities, RefTime, MaxAge, Token)); var arrRet = await Task.WhenAll(_lstTsk); return arrRet.Where(v => v != null).ToList(); } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public static void CorrectUsage(cDataHistoryCollector Collector, cF4SDHealthCardRawData data, List Usage) { try { if (data?.Tables == null || Usage == null) return; foreach (var _table in data.Tables.Values) { if (_table.IsStatic) continue; if (Collector.ClusterConfig.Tables.TryGetValue(_table.Name, out var _configTable) && _configTable.Type != eDataHistoryTableType.History) continue; foreach (var _column in _table.Columns.Values) { if (_column.Values == null || _column.Values.Count == 0) continue; int _l = 0; if (_table.StartingIndex < 0) _l = Math.Min(_column.Values.Count + _table.StartingIndex, Usage.Count); else _l = Math.Min(_column.Values.Count, Usage.Count - _table.StartingIndex); for (int i = 0; i < _l; i++) { int i1 = 0; int i2 = 0; if (_table.StartingIndex < 0) { i1 = i; i2 = i - _table.StartingIndex; } else { i1 = i + _table.StartingIndex; i2 = i; } if (Usage[i1] <= 0) _column.Values[i2] = null; } } } } catch (Exception E) { LogException(E); } } public async Task GetTableResults(List Tables, List Identities, DateTime RefTime, int MaxAge, bool instantly, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var _tables = new List(); foreach (var t in Tables) { if (!_tables.Contains(t)) _tables.Add(t); } var Ids = await getConntectorIds(Identities, Token, requestInfo, LogDeep + 1).ConfigureAwait(false); var dicVirtualTables = new Dictionary>(); var lstDbTables = new List(); foreach (var strTable in _tables) { var tableConfig = this.GetTableFromName(strTable); if (tableConfig == null) { LogEntry($"The table '{strTable}' could not be found in the data clusters definitions", LogLevels.Warning); continue; } if (lstDbTables.Contains(tableConfig)) continue; if (tableConfig.Type == eDataHistoryTableType.Events || tableConfig.Type == eDataHistoryTableType.Selection) continue; if (tableConfig.IsVirtual) { if (Connectors.ContainsKey(tableConfig.ParentCluster.Origin)) { if (!dicVirtualTables.TryGetValue(tableConfig.ParentCluster.Origin, out var lstTables)) { lstTables = new List(); dicVirtualTables.Add(tableConfig.ParentCluster.Origin, lstTables); } if (!lstTables.Contains(tableConfig)) lstTables.Add(tableConfig); } } else { lstDbTables.Add(tableConfig); } } var c = dicVirtualTables.Count; var idx = 0; if (lstDbTables.Count > 0) { c++; idx = 1; } Task>[] tasks = new Task>[c]; if (lstDbTables.Count > 0) tasks[0] = GetTableResultsMainDb(lstDbTables, Ids, RefTime, MaxAge, instantly, false, Token, requestInfo, LogDeep + 1); foreach (var Entry in dicVirtualTables) { var C = Connectors[Entry.Key]; tasks[idx] = Task.Run(() => { return C.GetTableResultsVirtualAsync(Entry.Value, Ids, RefTime, MaxAge, instantly, null, Token, requestInfo, LogDeep + 1); }); idx++; } var Results = await Task.WhenAll(tasks).ConfigureAwait(false); var RetVal = new cF4SDHealthCardRawData(); var IsIncompleted = false; foreach (var Entry in Results) { if (Entry == null) continue; foreach (var subEntry in Entry) if (!RetVal.Tables.ContainsKey(subEntry.Name)) { RetVal.Tables.Add(subEntry.Name, subEntry); if (instantly) subEntry.IsIncomplete = false; else IsIncompleted |= subEntry.IsIncomplete; } } // detect the usage information List _usage = null; if (RetVal.Tables.TryGetValue("agnt-computer-event-numerical", out var usageTable)) { cF4SDHealthCardRawData.cHealthCardTableColumn usageCol1; if (!usageTable.Columns.TryGetValue("DeviceActivity", out usageCol1)) usageCol1 = null; cF4SDHealthCardRawData.cHealthCardTableColumn usageCol2; if (!usageTable.Columns.TryGetValue("UserActivity", out usageCol2)) usageCol2 = null; if (usageCol1 == null) { usageCol1 = usageCol2; usageCol2 = null; } if (usageCol1?.Values != null) { var _l = usageCol1.Values.Count; if (usageCol2?.Values != null) _l = Math.Max(_l, usageCol2.Values.Count); _usage = new List(_l); foreach (var _entry in usageCol1.Values) { Int64 _v = 0; try { _v = Convert.ToInt64(_entry); } catch { } _usage.Add(_v); } if (usageCol2?.Values != null) { var _i = 0; foreach (var _entry in usageCol1.Values) { Int64 _v = 0; try { _v = Convert.ToInt64(_entry); } catch { } if (_i < _usage.Count) _usage[_i] = Math.Max(_usage[_i], _v); else _usage.Add(_v); _i++; } } CorrectUsage(this, RetVal, _usage); } } if (IsIncompleted && !instantly) { RetVal.Id = Guid.NewGuid(); foreach (var Entry in dicVirtualTables) { var C = Connectors[Entry.Key]; C.AddTableResultVirtualSuccessorTasks(Entry.Value, Ids, RefTime, MaxAge, _usage, RetVal.Id, requestInfo, LogDeep + 1); } AddTableResultSuccessorTasks(lstDbTables, Ids, RefTime, MaxAge, _usage, RetVal.Id, requestInfo, LogDeep + 1); } return RetVal; } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public cDataHistoryConfigTable GetTableFromName(string Name) { try { if (ClusterConfig.AlternateTableNames.TryGetValue(Name, out var _aln)) Name = _aln; if (ClusterConfig.Tables.TryGetValue(Name, out var _retVal)) return _retVal; } catch (Exception E) { LogException(E); } finally { } return null; } public async Task> GetDetailsTableResultsAsync(List Tables, List Identities, DateTime RefTime, int MaxAge, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var Ids = await getConntectorIds(Identities, Token, requestInfo, LogDeep + 1).ConfigureAwait(false); var dicVirtualTables = new Dictionary>(); var lstDbTables = new List(); foreach (var strTable in Tables) { var tableConfig = GetTableFromName(strTable); if (tableConfig == null) { LogEntry($"The table '{strTable}' could not be found in the data clusters definitions", LogLevels.Warning); continue; } if (lstDbTables.Contains(tableConfig)) continue; if (tableConfig.Type != eDataHistoryTableType.Events && tableConfig.Type != eDataHistoryTableType.StaticDetails) continue; if (tableConfig.IsVirtual) { if (Connectors.ContainsKey(tableConfig.ParentCluster.Origin)) { if (!dicVirtualTables.TryGetValue(tableConfig.ParentCluster.Origin, out var lstTables)) { lstTables = new List(); dicVirtualTables.Add(tableConfig.ParentCluster.Origin, lstTables); } lstTables.Add(tableConfig); } } else { lstDbTables.Add(tableConfig); } } var c = dicVirtualTables.Count; var idx = 0; if (lstDbTables.Count > 0) { c++; idx = 1; } Task>[] tasks = new Task>[c]; if (lstDbTables.Count > 0) tasks[0] = GetDetailsTableResultsMainDb(lstDbTables, Ids, RefTime, MaxAge, Token, requestInfo, LogDeep + 1); foreach (var Entry in dicVirtualTables) { var C = Connectors[Entry.Key]; tasks[idx] = C.GetDetailsTableResultsVirtualAsync(Entry.Value, Ids, RefTime, MaxAge, Token, requestInfo, LogDeep + 1); idx++; } var Results = await Task.WhenAll(tasks).ConfigureAwait(false); var RetVal = new List(); foreach (var Entry in Results) { if (Entry == null) continue; RetVal.AddRange(Entry); } return RetVal; } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public async Task GetSelectionTableResultCountAsync(string Table, List Identities, string search, cF4sdWebRequestInfo requestInfo, CancellationToken Token, bool resetFilter = false, List filterParams = null) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { if (!ClusterConfig.Tables.TryGetValue(Table, out var _table)) { LogEntry($"Could not find table '{Table}' in table list.", LogLevels.Warning); return -1; } if (!this.Connectors.TryGetValue(_table.ParentCluster.Origin, out var _module)) { LogEntry($"Could not find module '{_table.ParentCluster.Origin}' in module list.", LogLevels.Warning); return -1; } var _retVal = await _module.GetSelectionTableResultCountAsync(_table, Identities, search, requestInfo, Token, resetFilter, filterParams); return _retVal; } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } return -1; } public async Task GetSelectionTableResultAsync(string Table, List Identities, string search, int PageSize, int Page, cF4sdWebRequestInfo requestInfo, CancellationToken Token, bool resetFilter = false, List filterParams = null) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { if (!ClusterConfig.Tables.TryGetValue(Table, out var _table)) return null; if (!this.Connectors.TryGetValue(_table.ParentCluster.Origin, out var _module)) return null; var _retVal = await _module.GetSelectionTableResultAsync(_table, Identities, search, PageSize, Page, requestInfo, Token, resetFilter, filterParams); return _retVal; } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } return null; } public async Task> GetCachedHistoricTable(cDataHistoryConfigTable tableConfig, Dictionary Filter, DateTime RefTime, int MaxAge, cDataHistoryScanTiming Timing, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { using (var Conn = new cDbConnection(mainDbConnection)) { if (!Conn.IsOpen) { LogEntry($"Could not open main sql database '{mainDbConnection.Database}', aborting scan...'", LogLevels.Error); return null; } using (var _reader = await DataHistorySqlHelper.getDbReaderHistoricTable(Conn, tableConfig.SourceName, Filter, RefTime + TimeSpan.FromDays(-MaxAge - 1), Token)) { if (_reader == null) return null; if (_reader.FieldCount > 2) { var retVal = new cF4SDHealthCardRawData.cHealthCardTable { Name = tableConfig.Name, InformationClass = tableConfig.ParentCluster.InformationClass, StartingIndex = int.MaxValue, IsStatic = false, TableType = tableConfig.Type }; var maxIndex = int.MinValue; var Cols = new Dictionary(_reader.FieldCount); for (int i = 0; i < _reader.FieldCount; i++) { var _propName = _reader.GetName(i); if (tableConfig.Columns.TryGetValue(_propName, out var _col)) { var _ci = new cF4SDHealthCardRawData.cHealthCardTableColumn() { ColumnName = _col.Name }; Cols[i] = _ci; retVal.Columns[_col.Name] = _ci; } if (tableConfig.Columns.TryGetValue(_propName + "_bin", out var _col2)) { var _ci = new cF4SDHealthCardRawData.cHealthCardTableColumn() { ColumnName = _col.Name + "_bin" }; Cols[i] = _ci; retVal.Columns[_col.Name + "_bin"] = _ci; } } var TimeFrames = new Dictionary>(); if (_reader.HasRows) { while (await _reader.ReadAsync()) { DateTime timeFrom = _reader.GetDateTime(0); DateTime timeTo = _reader.GetDateTime(1); var indexTimeFrame = cScanTimeInfo.GetScanIntervalIndex(RefTime, timeFrom, timeTo, Timing); if (maxIndex == int.MinValue) { maxIndex = indexTimeFrame - 1; } if (TimeFrames.ContainsKey(indexTimeFrame)) continue; TimeFrames.Add(indexTimeFrame, new KeyValuePair(timeFrom, timeTo)); foreach (var entryCol in Cols) { var colInfo = entryCol.Value; var colIndex = entryCol.Key; var objValue = _reader[colIndex]; objValue = objValue == DBNull.Value ? null : objValue; if (Cols.TryGetValue(colIndex, out var _col)) { if (indexTimeFrame > maxIndex) { for (int j = maxIndex + 1; j < indexTimeFrame; j++) _col.Values.Add(null); _col.Values.Add(objValue); } else if (indexTimeFrame < retVal.StartingIndex) { for (int j = indexTimeFrame + 1; j < retVal.StartingIndex; j++) _col.Values.Insert(0, null); _col.Values.Insert(0, objValue); } else { _col.Values[indexTimeFrame - retVal.StartingIndex] = objValue; } } } retVal.StartingIndex = Math.Min(retVal.StartingIndex, indexTimeFrame); maxIndex = Math.Max(maxIndex, indexTimeFrame); } } if (maxIndex >= retVal.StartingIndex) { retVal.TimeFrames = new DateTime[maxIndex - retVal.StartingIndex + 1, 2]; for (int i = retVal.StartingIndex; i <= maxIndex; i++) { if (TimeFrames.TryGetValue(i, out var _tf)) { retVal.TimeFrames[i - retVal.StartingIndex, 0] = _tf.Key; retVal.TimeFrames[i - retVal.StartingIndex, 1] = _tf.Value; } else { retVal.TimeFrames[i - retVal.StartingIndex, 0] = DateTime.MinValue; retVal.TimeFrames[i - retVal.StartingIndex, 1] = DateTime.MinValue; } } } return new List() { retVal }; } } } } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } private async Task> getTableRawDataStatic(DbDataReader _reader, cDataHistoryConfigTable tableConfig, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { if (await _reader.ReadAsync(Token)) { if (Token.IsCancellationRequested) return null; var objValues = new object[_reader.FieldCount]; var n = _reader.GetValues(objValues); var ColNames = new string[_reader.FieldCount]; if (ColNames.Length == _reader.FieldCount) { var RetVal = new cF4SDHealthCardRawData.cHealthCardTable(); for (int i = 0; i < _reader.FieldCount; i++) { var objVal = objValues[i] == DBNull.Value ? null : objValues[i]; var strCol = _reader.GetName(i); RetVal.Columns.Add(strCol, new cF4SDHealthCardRawData.cHealthCardTableColumn() { ColumnName = strCol, Values = new List() { objVal } }); } RetVal.Name = tableConfig.Name; RetVal.InformationClass = tableConfig.ParentCluster.InformationClass; RetVal.IsStatic = tableConfig.Type == eDataHistoryTableType.Static; RetVal.TableType = tableConfig.Type; return new List() { RetVal }; } } } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } return null; } private async Task> getTableRawDataHistoric(DbDataReader _reader, cDataHistoryConfigTable tableConfig, DateTime RefTime, int MaxAge, bool instantly, bool IsSecondCall, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { if (tableConfig.EventTimeColumn == null) return null; cHistoricAggregationEntry[] arrColAgg = new cHistoricAggregationEntry[tableConfig.Columns.Count]; var i = 0; foreach (var col in tableConfig.Columns.Values) { if (col is cDataHistoryConfigColumn _colInfo) arrColAgg[i] = new cHistoricAggregationEntry(_colInfo, MaxAge + 1, null); i++; } var _colInfos = tableConfig.Columns.Values.ToList(); Dictionary _dic = new Dictionary(tableConfig.Columns.Count); var _idx = 0; foreach (var _colInfo in tableConfig.Columns.Values) { _dic[_colInfo.SourceName] = _idx; _idx++; } var _idxTimeCol = -1; var _arrIdxAssign = Enumerable.Repeat(-1, tableConfig.Columns.Count).ToArray(); for (i = 0; i < _reader.FieldCount; i++) { var _n = _reader.GetName(i); if (_dic.TryGetValue(_n, out var _ix)) _arrIdxAssign[_ix] = i; if (_n == tableConfig.EventTimeColumn.SourceName) _idxTimeCol = i; } if (_idxTimeCol < 0) return null; while (await _reader.ReadAsync(Token)) { if (Token.IsCancellationRequested) return null; var _eventTime = _reader.GetDateTime(_idxTimeCol); for (i = 0; i < tableConfig.Columns.Count; i++) { var _n = _arrIdxAssign[i]; if (_n >= 0) { var obj = _reader.GetValue(_n); var _obj2 = DataHistorySqlHelper.GetSqlDataValueFromHistoryType(obj, _colInfos[i].ValueType, _colInfos[i].Cardinal); arrColAgg[i].addValue(_obj2[0], _eventTime, RefTime, 0); } } } var RetValHistoric = new cF4SDHealthCardRawData.cHealthCardTable { Name = tableConfig.Name, InformationClass = tableConfig.ParentCluster.InformationClass, IsStatic = false, TableType = eDataHistoryTableType.History }; i = 0; foreach (var Entry in tableConfig.Columns.Values) { var agg = arrColAgg[i]; var col = new cF4SDHealthCardRawData.cHealthCardTableColumn() { ColumnName = agg.Column.Name, Values = agg.getValues() }; RetValHistoric.Columns[agg.Column.Name] = col; i++; } return new List() { RetValHistoric }; } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } return null; } public void AddTableResultSuccessorTasks(List Tables, Dictionary Identities, DateTime RefTime, int MaxAge, List UsageInfo, Guid CacheId, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var lstTables = new List(); var myTables = new List(); foreach (var Table in Tables) { if (Table.ParentCluster.Origin != eDataHistoryOrigin.Main) continue; if (!Table.LateDelivery) continue; if (Table.Cached != eDataHistoryTableCached.Yes) continue; myTables.Add(Table); lstTables.Add(Table.Name); } if (lstTables.Count > 0) { var ct = new CancellationTokenSource().Token; var tsk = GetTableResultsMainDb(myTables, Identities, RefTime, MaxAge, false, true, ct, requestInfo, LogDeep + 1); SuccessorCache.AddTask(CacheId, lstTables, tsk, UsageInfo, ct); } } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } } private async Task> getTableRawData(cDataHistoryConfigTable tableConfig, Dictionary Identities, DateTime RefTime, int MaxAge, bool instantly, bool IsSecondCall, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (tableConfig.LateDelivery && !instantly && !IsSecondCall) { return new List() { new cF4SDHealthCardRawData.cHealthCardTable() { Name = tableConfig.Name, InformationClass = enumFasdInformationClass.Ticket, IsIncomplete = true } }; } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var Cols = new List(); foreach (var col in tableConfig.Columns.Values) { Cols.Add(col.Name); if (col.SqlTypeBin != null) Cols.Add(col.Name + "_bin"); } if (Identities.TryGetValue(tableConfig.ParentCluster.InformationClass, out var Identity)) if (Connectors.TryGetValue(tableConfig.ParentCluster.Origin, out var C)) { var IdValues = await C.GetIds(Identity, tableConfig.ParentCluster.InformationClass, requestInfo, LogDeep + 1); if (IdValues != null && tableConfig.KeyColumns.Count == IdValues.Count) { var Filters = new Dictionary(); for (int i = 0; i < IdValues.Count; i++) { if (IdValues[i] == null) { LogEntry($"Empty filter value used on getting raw data for table {tableConfig.Name}.", LogLevels.Warning); return null; } var Col = tableConfig.KeyColumns[i]; var ColName = Col.Name; if (Col.SqlTypeBin != null) ColName += "_bin"; Filters.Add(ColName, IdValues[i]); } using (var Conn = new cDbConnection(mainDbConnection)) { if (!Conn.IsOpen) { LogEntry($"Could not open main sql database '{mainDbConnection.Database}', aborting scan...'", LogLevels.Error); return null; } using (var _reader = await DataHistorySqlHelper.getDbReaderSelectAsync(Conn, tableConfig.SourceName, Cols, Filters, Token).ConfigureAwait(false)) { if (_reader.HasRows) switch (tableConfig.Type) { case eDataHistoryTableType.Static: return await getTableRawDataStatic(_reader, tableConfig, Token); case eDataHistoryTableType.History: return await getTableRawDataHistoric(_reader, tableConfig, RefTime, MaxAge, instantly, IsSecondCall, Token); } } } } } } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public async Task> getConntectorIds(List Identities, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var tasks = new Task[Identities.Count]; for (int i = 0; i < Identities.Count; i++) { tasks[i] = getConnectorIds(Identities[i].Class, Identities[i], Token, requestInfo, LogDeep + 1); } var Result = await Task.WhenAll(tasks).ConfigureAwait(false); var RetVal = Result.Where(v => v != null).ToDictionary(x => x.infoClass); return RetVal; } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public async Task> getConnectorIdList(List Identities, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var tasks = new Task[Identities.Count]; for (int i = 0; i < Identities.Count; i++) { tasks[i] = getConnectorIds(Identities[i].Class, Identities[i], Token, requestInfo, LogDeep + 1, WithLocalAccounts: true); } var Result = await Task.WhenAll(tasks).ConfigureAwait(false); var RetVal = Result.Where(v => v != null).ToList(); return RetVal; } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } private async Task getConnectorIds(enumFasdInformationClass infoClass, cF4sdIdentityEntry Identity, CancellationToken Token, cF4sdWebRequestInfo requestInfo, int LogDeep, bool WithLocalAccounts = false) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; int apiError = 0; try { if (infoClass == enumFasdInformationClass.Ticket) return new cF4sdConnectorIds() { Id = Identity.Id, infoClass = enumFasdInformationClass.Ticket }; if (infoClass == enumFasdInformationClass.VirtualSession) return new cF4sdConnectorIds() { Id = Identity.Id, infoClass = enumFasdInformationClass.VirtualSession }; if (infoClass == enumFasdInformationClass.MobileDevice) return new cF4sdConnectorIds() { Id = Identity.Id, infoClass = enumFasdInformationClass.MobileDevice }; if (!DataHistorySqlHelper.GetWellKnownSqlStatement($"GetConnectorIdsFrom{infoClass}Id", out var Query)) return null; var Params = new Dictionary() { { "id", Identity.Id } }; using (var conn = new cDbConnection(mainDbConnection)) { if (!conn.IsOpen) { LogEntry($"Could not open main sql database '{mainDbConnection.Database}', aborting scan...'", LogLevels.Error); return null; } cF4sdConnectorIds RetVal = null; try { using (var Reader = await DataHistorySqlHelper.GetDataReaderAsync(conn, Query, Params, Token)) { if (Reader != null) try { if (Reader.HasRows) { if (await Reader.ReadAsync()) { var Entry = new cF4sdConnectorIds() { infoClass = infoClass, Id = Identity.Id }; Entry.sid = Reader.IsDBNull(0) ? null : (byte[])Reader.GetValue(0); Entry.agentId = Reader.IsDBNull(1) ? (int?)null : Reader.GetInt32(1); Entry.agentId2 = Reader.IsDBNull(4) ? (int?)null : Reader.GetInt32(4); Entry.name = Reader.GetString(2); Entry.lastSeenByAgent = Reader.IsDBNull(3) ? (DateTime?)null : Reader.GetDateTime(3); Entry.tenantId = Reader.IsDBNull(5) ? Guid.Empty : Reader.GetGuid(5); Entry.intuneId = Reader.IsDBNull(6) ? Guid.Empty : Reader.GetGuid(6); Entry.azureDeviceId = Reader.IsDBNull(7) ? Guid.Empty : Reader.GetGuid(7); Entry.citrixUserId = Reader.IsDBNull(8) ? (int?)null : Reader.GetInt32(8); Entry.citrixTenantId = Reader.IsDBNull(9) ? String.Empty : Reader.GetString(9); if (Identity.agentId != null) Entry.agentId = Identity.agentId; Entry.accountType = Identity.AccountType; RetVal = Entry; } } } catch (Exception E) { LogException(E); } } } catch (Exception E) { apiError = E.HResult; LogException(E); } finally { if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(Query.Name, _startTime, Params, apiError, requestInfo?.requestName); } var _doLocalAccounts = WithLocalAccounts && RetVal != null && infoClass == enumFasdInformationClass.User && InfrastructureConfig.ClientAgent?.localAccountAssignments != null; if (DefaultLogger.IsDebug) { var _msgDebug = new List() { "local account lookup infos:", $"with local accounts: {WithLocalAccounts}", $"RetVal agent id: {RetVal?.agentId}", $"info class: {infoClass}", $"Local account assignments count: {InfrastructureConfig.ClientAgent?.localAccountAssignments?.Count}", $"do local accounts: {_doLocalAccounts}" }; DefaultLogger.LogList(LogLevels.Debug, _msgDebug); } if (_doLocalAccounts) { var lst = new List(); Params = new Dictionary() { { "ID", Identity.Id } }; var _count = 0; var _startTime2 = DateTime.UtcNow; apiError = 0; if (DataHistorySqlHelper.GetWellKnownSqlStatement("GetLocalUserFromId", out Query)) try { using (var Reader = await DataHistorySqlHelper.GetDataReaderAsync(conn, Query, Params, Token)) { if (Reader != null) try { if (Reader.HasRows) { while (await Reader.ReadAsync()) { _count++; var localAgentId = Reader.GetInt32(0); var lastSeen = Reader.IsDBNull(1) ? (DateTime?)null : Reader.GetDateTime(1); var localAccount = Reader.GetString(2); if (lastSeen != null) { if (RetVal.localAgentIds == null) RetVal.localAgentIds = new List(); RetVal.localAgentIds.Add(new cF4sdConnectorIds.localIdEntry() { agentId = localAgentId, lastSeenByAgent = (DateTime)lastSeen, account = localAccount }); } } } } catch (Exception E) { LogException(E); } } } catch (Exception E) { apiError = E.HResult; LogException(E); } finally { if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(Query.Name, _startTime, Params, apiError, requestInfo?.requestName); } LogEntry($"local account assignement for id={Identity.Id} found: {_count}, {RetVal?.localAgentIds?.Count} of them are valid.", LogLevels.Debug); } return RetVal; } } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public static object getJsonValueFromString(string strValue, enumFasdValueType ValueType) { try { switch (ValueType) { default: string RetVal0 = null; try { RetVal0 = JsonConvert.DeserializeObject(strValue); } catch { } if (RetVal0 == null) RetVal0 = strValue; return RetVal0; case enumFasdValueType.INT: return JsonConvert.DeserializeObject(strValue); case enumFasdValueType.BIGINT: return JsonConvert.DeserializeObject(strValue); case enumFasdValueType.FLOAT: return JsonConvert.DeserializeObject(strValue); case enumFasdValueType.DATETIME: var DT = JsonConvert.DeserializeObject(strValue); return DT; // ToDo: VERSION deserialization //case enumFasdValueType.VERSION: // var strVal1 = JsonConvert.DeserializeObject(strValue); // if (Version.TryParse(strVal1, out var RetVersion)) // return RetVersion; // return null; case enumFasdValueType.BOOLEAN: var strVal2 = JsonConvert.DeserializeObject(strValue); return cXmlParser.GetBoolFromString(strVal2); } } catch (Exception E) { LogException(E); } return null; } public static void ComputeEventDetailColumns(cDataHistoryConfigTable TableConfig, cF4SDHealthCardRawData.cHealthCardDetailsTable TableResult) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { if (TableResult.Columns == null || TableResult.Columns.Count == 0 || TableResult.Values == null) return; var lstComputations = new List(); var index = TableResult.Columns.Count; foreach (var Entry in TableConfig.Columns.Values) if (Entry is cDataHistoryConfigColumnComputation comp) { var valueIndexes = new int[comp.Computation.Columns.Count]; for (int i = 0; i < comp.Computation.Columns.Count; i++) { var compVal = comp.Computation.Columns[i]; var idx = TableResult.Columns.IndexOf(compVal.Name); if (idx < 0) { valueIndexes = null; break; } valueIndexes[i] = idx; } if (valueIndexes == null) continue; var compInfo = new cDetailsComputationInfo() { Computation = comp.Computation, ValueIndexes = valueIndexes }; lstComputations.Add(compInfo); TableResult.Columns.Add(comp.Name); } foreach (var day in TableResult.Values.Values) foreach (var Entry in day) { var idx = index; foreach (var compInfo in lstComputations) { var vals = new object[compInfo.ValueIndexes.Length]; for (int j = 0; j < vals.Length; j++) vals[j] = Entry[compInfo.ValueIndexes[j]]; Entry[idx] = compInfo.Computation.Compute(vals); idx++; } } } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } } public async Task GetLastScanTime(string ScanName, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { if (!DataHistorySqlHelper.GetWellKnownSqlStatement("GetLastScanTime", out var Query)) return null; var Params = new Dictionary() { { "Name", ScanName } }; DateTime? retVal = null; using (var conn = new cDbConnection(mainDbConnection)) { if (!conn.IsOpen) { LogEntry($"Could not open main sql database '{mainDbConnection.Database}', aborting scan...'", LogLevels.Error); return null; } retVal = await DataHistorySqlHelper.GetScalarResultAsync(conn, Query, Params, requestInfo, CancellationToken.None); } if (retVal == null) { retVal = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); await SetLastScanTime(ScanName, (DateTime)retVal, requestInfo, LogDeep + 1, Token); } return retVal; } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public async Task SetLastScanTime(string ScanName, DateTime LastTime, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { if (!DataHistorySqlHelper.GetWellKnownSqlStatement("SetLastScanTime", out var Query)) return false; var Params = new Dictionary() { { "Name", ScanName }, { "LastTime", LastTime } }; using (var conn = new cDbConnection(mainDbConnection)) { if (!conn.IsOpen) { LogEntry($"Could not open main sql database '{mainDbConnection.Database}', aborting scan...'", LogLevels.Error); return false; } var retVal = await DataHistorySqlHelper.GetScalarResultAsync(conn, Query, Params, requestInfo, Token); return (retVal != null && retVal > 0); } } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return false; } public async Task CreateScanHistoryEntry(string ScanName, DateTime TimeFrom, DateTime TimeTo, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var RetVal = Guid.Empty; if (!DataHistorySqlHelper.GetWellKnownSqlStatement("CreateScanHistoryEntry", out var Query)) return RetVal; var RetVal2 = Guid.NewGuid(); var Params = new Dictionary() { { "ID", RetVal2 }, { "Name", ScanName }, { "From", TimeFrom }, { "To", TimeTo }, { "Execute", DateTime.UtcNow } }; using (var conn = new cDbConnection(mainDbConnection)) { if (!conn.IsOpen) { LogEntry($"Could not open main sql database '{mainDbConnection.Database}', aborting scan...'", LogLevels.Error); return RetVal; } var rv = await DataHistorySqlHelper.GetScalarResultAsync(conn, Query, Params, requestInfo, Token); if (rv == 1) return RetVal2; } } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return Guid.Empty; } public async Task ConfirmScanHistoryEntry(Guid Id, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { if (!DataHistorySqlHelper.GetWellKnownSqlStatement("ConfirmScanHistoryEntry", out var Query)) return; var Params = new Dictionary() { { "ID", Id } }; using (var conn = new cDbConnection(mainDbConnection)) { if (!conn.IsOpen) { LogEntry($"Could not open main sql database '{mainDbConnection.Database}', aborting scan...'", LogLevels.Error); return; } var ScanName = await DataHistorySqlHelper.GetScalarResultAsync(conn, Query, Params, requestInfo, Token); if (!string.IsNullOrEmpty(ScanName)) await SetLastScanTime(ScanName, DateTime.UtcNow, requestInfo, LogDeep + 1, Token); } } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } } public async Task RemoveLastScanHistoryEntry(string ScanName, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { if (!DataHistorySqlHelper.GetWellKnownSqlStatement("RemoveLastScanHistoryEntry", out var Query)) return; var Params = new Dictionary() { { "Name", ScanName } }; using (var conn = new cDbConnection(mainDbConnection)) { if (!conn.IsOpen) { LogEntry($"Could not open main sql database '{mainDbConnection.Database}', aborting scan...'", LogLevels.Error); return; } var executionTime = await DataHistorySqlHelper.GetScalarResultAsync(conn, Query, Params, requestInfo, Token); if (executionTime == null) await SetLastScanTime(ScanName, new DateTime(1970, 1, 1, 0, 0, 0), requestInfo, LogDeep + 1, Token); else await SetLastScanTime(ScanName, (DateTime)executionTime, requestInfo, LogDeep + 1, Token); } } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } } public async Task> GetTableColumnValidationAsync(cDataHistoryConfigTable TableConfig, string Instance, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token, cDbConnection MainConn = null) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; var closeDbConnection = false; if (!DataHistorySqlHelper.GetWellKnownSqlStatement("GetTableColumnValidation", out var Query)) return null; var Params = new Dictionary() { { "Table", TableConfig.SourceName }, { "Instance", Instance } }; int apiError = 0; try { if (MainConn == null) { closeDbConnection = true; MainConn = new cDbConnection(mainDbConnection); if (!MainConn.IsOpen) return null; } var RetVal = new Dictionary(); DbTransaction trans = MainConn.Connection.BeginTransaction(System.Data.IsolationLevel.Snapshot); try { using (var Reader = await DataHistorySqlHelper.GetDataReaderAsync(MainConn, Query, Params, Token)) { if (Reader != null) try { if (Reader.HasRows) { while (await Reader.ReadAsync() && !Token.IsCancellationRequested) { var strColumn = Reader.GetString(0); if (TableConfig.Columns.TryGetValue(strColumn, out var Col)) RetVal[Col.Name] = Col; } } } catch (Exception E) { LogException(E); } } if (!Token.IsCancellationRequested) { trans.Commit(); return RetVal; } } catch (Exception E) { LogException(E); trans.Rollback(); } } catch (Exception E) { apiError = E.HResult; LogException(E); } finally { if (closeDbConnection && MainConn != null) { MainConn.Dispose(); } if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(Query.Name, _startTime, Params, apiError, requestInfo?.requestName); if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public async Task SetTableColumnValidationAsync(cDataHistoryConfigTable TableConfig, string Instance, HashSet ValidColumns, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token, cDbConnection MainConn = null) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; var closeDbConnection = false; try { if (MainConn == null) { closeDbConnection = true; MainConn = new cDbConnection(mainDbConnection); if (!MainConn.IsOpen) return false; } var RetVal = new Dictionary(); using (DbTransaction trans = MainConn.Connection.BeginTransaction(System.Data.IsolationLevel.Serializable)) { bool doCommit = false; try { if (!DataHistorySqlHelper.GetWellKnownSqlStatement("GetTableColumnValidationEx", out var Query)) return false; var Params = new Dictionary() { { "Table", TableConfig.SourceName }, { "Instance", Instance } }; int apiError = 0; var _startTime2 = DateTime.UtcNow; try { using (var Reader = await DataHistorySqlHelper.GetDataReaderAsync(MainConn, Query, Params, Token, Transaction: trans)) { if (Reader != null) try { if (Reader.HasRows) { while (await Reader.ReadAsync() && !Token.IsCancellationRequested) { var strColumn = Reader.GetString(0); var bIsValid = Reader.GetInt16(1); RetVal[strColumn] = bIsValid == 1; } } } catch (Exception E) { LogException(E); } } } catch (Exception E) { apiError = E.HResult; LogException(E); } finally { if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(Query.Name, _startTime, Params, apiError, requestInfo?.requestName); } if (Token.IsCancellationRequested) return false; var toDelete = new List(); var toUpdate = new Dictionary(); var toInsert = new Dictionary(); foreach (var Column in TableConfig.Columns.Values) { var isValid = ValidColumns.Contains(Column.Name); if (RetVal.TryGetValue(Column.Name, out var ColInfo)) { if (ColInfo != isValid) toUpdate[Column.Name] = isValid; } else { toInsert[Column.Name] = isValid; } } foreach (var ColumnName in ValidColumns) { if (!RetVal.ContainsKey(ColumnName)) toDelete.Add(ColumnName); } // do the table inserts if (!DataHistorySqlHelper.GetWellKnownSqlStatement("InsertTableColumnValidation", out Query)) return false; foreach (var updEntry in toInsert) { Params = new Dictionary() { { "Table", TableConfig.SourceName }, { "Instance", Instance }, { "Column", updEntry.Key }, { "isValid", updEntry.Value ? 1 : 0 } }; await DataHistorySqlHelper.ExecuteAsync(MainConn, Query, Params, requestInfo, Token, Transaction: trans); } // do the table updates if (!DataHistorySqlHelper.GetWellKnownSqlStatement("UpdateTableColumnValidation", out Query)) return false; foreach (var updEntry in toUpdate) { Params = new Dictionary() { { "Table", TableConfig.SourceName }, { "Instance", Instance }, { "Column", updEntry.Key }, { "isValid", updEntry.Value ? 1 : 0 } }; await DataHistorySqlHelper.ExecuteAsync(MainConn, Query, Params, requestInfo, Token, Transaction: trans); } // do the table deletions if (!DataHistorySqlHelper.GetWellKnownSqlStatement("DeleteTableColumnValidation", out Query)) return false; foreach (var updEntry in toDelete) { Params = new Dictionary() { { "Table", TableConfig.SourceName }, { "Instance", Instance }, { "Column", updEntry } }; await DataHistorySqlHelper.ExecuteAsync(MainConn, Query, Params, requestInfo, Token, Transaction: trans); } doCommit = true; return true; } catch (Exception E) { LogException(E); } finally { if (doCommit) trans.Commit(); else trans.Rollback(); } } } catch (Exception E) { LogException(E); } finally { if (closeDbConnection && MainConn != null) { MainConn.Dispose(); } if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return false; } public async Task> GetQuickActionAllList() { var returnValue = new List(); foreach (var Connector in GetConnectors()) { var _quickActions = await Connector.GetQuickActionList(); if (_quickActions != null && _quickActions.Count > 0) returnValue.AddRange(_quickActions); } return returnValue; } public bool CheckCleanupTimeframes() { if (InfrastructureConfig.HistoryDB.CleanupTimeFrames == null) return true; if (InfrastructureConfig.HistoryDB.CleanupTimeFrames.Count == 0) return true; foreach (var TF in InfrastructureConfig.HistoryDB.CleanupTimeFrames) { if (TF.Check()) return true; } return false; } private async Task> getCleanupScanIds(cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; if (!DataHistorySqlHelper.GetWellKnownSqlStatement("GetScanHistoryCleanup", out var Query)) return null; var Params = new Dictionary() { { "Age1", InfrastructureConfig.HistoryDB.DaysToCache }, { "Age2", 60 } }; int apiError = 0; try { using (var Conn = new cDbConnection(mainDbConnection)) { if (!Conn.IsOpen) { LogEntry($"Could not open main database '{mainDbConnection.Database}', aborting query'", LogLevels.Error); return null; } using (var Reader = await DataHistorySqlHelper.GetDataReaderAsync(Conn, Query, Params, Token)) { if (Reader != null) try { var RetVal = new HashSet(); if (Reader.HasRows) { while (await Reader.ReadAsync() && !Token.IsCancellationRequested) try { var _id = Reader.GetGuid(0); RetVal.Add(_id); } catch (Exception E) { LogException(E); } } return RetVal; } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } } } } catch (Exception E) { apiError = E.HResult; LogException(E); } finally { if (DataHistorySqlHelper.LogSql) DataHistorySqlHelper.SaveSqlTimingEntry(Query.Name, _startTime, Params, apiError, requestInfo?.requestName); if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public async Task CheckCleanup(cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { var l = await getCleanupScanIds(requestInfo, LogDeep + 1, Token); if (l != null) return l.Count; } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return 0; } public async Task DoCleanup(bool DontUseScanTiming, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { if (!DontUseScanTiming && !CheckCleanupTimeframes()) { DoProcessUiMessage(0, "The current time is not within the defined scan time intervals."); return -2; } // get the historic scan ids to cleanup var lstIds = await getCleanupScanIds(requestInfo, LogDeep + 1, Token); if (lstIds == null) return -1; if (lstIds.Count == 0) { DoProcessUiMessage(0, "No outdated scans found. Cleanup is not nescessary."); return 0; } DoProcessUiMessage(0, $"{lstIds.Count} outdated scans found. Starting cleanup..."); if (!DataHistorySqlHelper.GetWellKnownSqlStatement("DeleteScanHistoryEntry", out var Query)) return -1; Query.TimeoutFactor = 100; using (var Conn = new cDbConnection(mainDbConnection)) { if (!Conn.IsOpen) { LogEntry($"Could not open main database '{mainDbConnection.Database}', aborting query'", LogLevels.Error); return -1; } var ValidRemoves = 0; foreach (var _id in lstIds) { try { if (!DontUseScanTiming && !CheckCleanupTimeframes()) return ValidRemoves; var Params = new Dictionary(1) { { "ID", _id } }; var n = await DataHistorySqlHelper.ExecuteAsync(Conn, Query, Params, requestInfo, Token); if (n != null && n > 0) ValidRemoves += (int)n; } catch (Exception E) { LogException(E); } } DoProcessUiMessage(0, $"{ValidRemoves} history scans removed."); return ValidRemoves; } } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return -1; } public override async Task WritePropertyAsync(cF4SDWriteParameters PropertiesToWrite, cF4sdWebRequestInfo requestInfo, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { // check if properties are writable if (!this.ClusterConfig.Tables.TryGetValue(PropertiesToWrite.TableName, out var tableConfig)) return false; if (PropertiesToWrite.Values == null) return false; var lstIllegal = new List(); foreach (var Entry in PropertiesToWrite.Values) { if (!tableConfig.Columns.TryGetValue(Entry.Key, out var colInfo) || !colInfo.IsWritable) lstIllegal.Add(Entry.Key); } foreach (var Entry in lstIllegal) PropertiesToWrite.Values.Remove(Entry); if (PropertiesToWrite.Values.Count == 0) return false; var result = lstIllegal.Count == 0; if (this.Connectors.TryGetValue(tableConfig.ParentCluster.Origin, out var _mod)) { var res = await _mod.WritePropertyAsync(PropertiesToWrite, requestInfo, Token); if (res) { } return result & res; } } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } return false; } private Guid GetUserHashGuid(Guid userId) { // check, if we have a GUID if (!Guid.TryParse(userId.ToString(), out var _guid)) return Guid.Empty; // convert the GUID into a byte arry and 'salt' it a little bit var _arr = _guid.ToByteArray(); if (_arr.Length != 16) return Guid.Empty; var _arrSalt = new byte[3 * 16]; for (byte i = 0; i < 16; i++) { byte j = Convert.ToByte(i * 3); _arrSalt[j] = _arr[i]; _arrSalt[j + 1] = _arr[i]; _arrSalt[j + 2] = j; } // get the md5 hash value (128 bit = 16 byte) var _md5 = MD5.Create(); var _arrHash = _md5.ComputeHash(_arrSalt); if (_arrHash == null) return Guid.Empty; if (_arrHash.Length != 16) return Guid.Empty; // convert the hash value into a GUID return new Guid(_arrHash); } public void AddRolesByMembership(cF4sdUserInfo userInfo, List _membershipGroups) { if (userInfo.Roles == null) userInfo.Roles = new List(); AddRolesByMembership(userInfo.Roles, _membershipGroups, userInfo.Name); } public void AddRolesByMembership(List Roles, List _membershipGroups, string userName) { if (_membershipGroups?.Count > 0) { var _roles = InfrastructureConfig?.Authorisation?.Roles; if (_roles != null) foreach (var _roleEntry in _roles.Values) { if (_roleEntry.MembershipGroups != null) foreach (var _grp in _roleEntry.MembershipGroups) { if (_membershipGroups.Contains(_grp)) { if (Roles?.Contains(_roleEntry.Name) != true) { if (Roles == null) Roles = new List(); Roles.Add(_roleEntry.Name); Debug.WriteLine($" {userName} is member of '{_roleEntry.Name}'"); } } } } } } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static int getDayIndex(DateTime EventTime, DateTime RefTime, int HistorySize) { var deltaTime = (EventTime - RefTime).TotalDays; int indexDay; if (deltaTime >= 0) indexDay = (int)Math.Floor(deltaTime); else indexDay = -(int)Math.Ceiling(-deltaTime); if (indexDay > 0) indexDay = 0; indexDay = -indexDay; if (indexDay >= HistorySize) indexDay = HistorySize - 1; return indexDay; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool CheckIfNotEmpty(object _o) { if (_o == null) return false; if (_o is string _s && string.IsNullOrEmpty(_s)) return false; return true; } public override async Task GetScanTimeInfoAsync(cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { await Task.CompletedTask; return null; } public override async Task DoScanAsync(bool Always, bool Rescan, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token, bool EnhancedDebug = false) { await Task.CompletedTask; return true; } public override async Task> GetIds(cF4sdConnectorIds IdEntry, enumFasdInformationClass InfoClass, cF4sdWebRequestInfo requestInfo, int LogDeep) { await Task.CompletedTask; return new List() { IdEntry.Id }; } public static string getStingList(List L) { if (L == null || L.Count == 0) return null; var RetVal = ""; foreach (var Entry in L) { if (string.IsNullOrEmpty(Entry)) continue; if (RetVal != "") RetVal += ','; RetVal += Entry; } return RetVal; } public cCockpitConfiguration GetCockpitConfiguration(cF4sdWebRequestInfo requestInfo) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } try { var retVal = new cCockpitConfiguration(); var AgentConfig = InfrastructureConfig?.ClientAgent; if (AgentConfig != null) { retVal.agentApiConfiguration = F4sdAgent.GetAgentApiConfiguration(false); } if (InfrastructureConfig?.M42Wpm?.Server != null) { var _lang = requestInfo.Culture?.TwoLetterISOLanguageName?.ToUpperInvariant() ?? ""; retVal.m42ServerConfiguration = new cM42ServerConfiguration() { Server = InfrastructureConfig.M42Wpm.Server, DisplayName = InfrastructureConfig.M42Wpm.DisplayNames.GetValue(_lang, null) }; } if (RefreshGlobalConfigurationParameters()) lock (GlobalParametersConfigLock) retVal.GlobalConfig = GlobalParametersConfigFile.Parameters; return retVal; } catch (Exception E) { LogException(E); } finally { if (CM != null) LogMethodEnd(CM); } return null; } public override async Task ValidateTokenAsync(cF4SDTokenRegistration TokenRegistration, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { if (TokenCache == null) return null; if (TokenRegistration.UserId != requestInfo.userInfo?.Id) return null; cF4SdUserInfoChange _userInfoChange = null; switch (TokenRegistration?.TokenType) { case cF4SDTokenRegistration.enumTokenType.M42Bearer: _userInfoChange = await this.M42WpmCollector.ValidateTokenAsync(TokenRegistration, requestInfo, LogDeep + 1, Token); break; } if (_userInfoChange == null || _userInfoChange.ValidLogonsUntil == null || _userInfoChange.ValidLogonsUntil.Count == 0) return null; var validPeriod = _userInfoChange.ValidLogonsUntil.First().Value; if (validPeriod.validUntil <= DateTime.UtcNow) return null; await TokenCache.SetAsync(TokenRegistration, validPeriod, Token, requestInfo, LogDeep + 1); return _userInfoChange; } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public override async Task GetAdditionalUserInfo(enumAdditionalAuthentication Type, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token) { MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); } if (cPerformanceLogger.IsActive && requestInfo != null) { if (CM == null) CM = MethodBase.GetCurrentMethod(); cPerformanceLogger.LogPerformanceStart(LogDeep, CM, requestInfo.id, requestInfo.created); } var _startTime = DateTime.UtcNow; try { switch (Type) { case enumAdditionalAuthentication.M42WinLogon: return await M42WpmCollector.GetAdditionalUserInfo(Type, requestInfo, LogDeep + 1, Token); } } catch (Exception E) { LogException(E); } finally { if (cPerformanceLogger.IsActive && requestInfo != null) { cPerformanceLogger.LogPerformanceEnd(LogDeep, CM, requestInfo.id, requestInfo.created, _startTime); } if (CM != null) LogMethodEnd(CM); } return null; } public HashSet GetSupportedInformationClasses() => new HashSet() { enumFasdInformationClass.User, enumFasdInformationClass.Computer }; public async Task GetRelationsAsync(IEnumerable ids, enumFasdInformationClass informationClass, int age, CancellationToken token = default) { List usageRelations = await GetUsageFromOnlyAgentData(informationClass, ids.Select(id => id.Id).ToList(), age, token, null, 1); return new cF4sdStagedSearchResultRelations() { Relations = usageRelations }; } } public class cScanTimeInfo { public readonly DateTime LastScan; public DateTime? NextScan = null; public SortedList Intervals = new SortedList(); public cScanTimeInfo(DateTime LastScan) { this.LastScan = LastScan; } private DateTime privGetScanTimeIntervals(DateTime time, DateTime LastScan, cDataHistoryScanTiming Timing) { try { var refTime = TimeZoneInfo.ConvertTimeFromUtc(time, Timing.Timezone); refTime = refTime.Date + Timing.Offset; refTime = refTime.ToUniversalTime(); while (refTime > time) refTime -= TimeSpan.FromDays(1); var diff = time - refTime; var nDiff = diff.TotalMilliseconds / Timing.Interval.TotalMilliseconds; nDiff = Math.Floor(nDiff); var retVal = refTime + TimeSpan.FromMilliseconds(nDiff * Timing.Interval.TotalMilliseconds); DateTime intv2 = retVal; DateTime intv1 = intv2 - Timing.Interval; while (LastScan < intv2) { Intervals.Add(intv1, intv2); intv2 -= Timing.Interval; intv1 = intv2 - Timing.Interval; } ; return retVal; } catch (Exception E) { LogException(E); } finally { } return DateTime.MaxValue; } public DateTime GetScanTime(DateTime time, cDataHistoryScanTiming Timing) { return privGetScanTimeIntervals(time, LastScan, Timing); } public void GetFirstScanTime(cDataHistoryScanTiming Timing) { var _now = DateTime.UtcNow; NextScan = privGetScanTimeIntervals(_now, _now - Timing.Interval, Timing); } static public int GetScanIntervalIndex(DateTime time, DateTime timeFrom, DateTime timeTo, cDataHistoryScanTiming Timing) { try { var refTime = TimeZoneInfo.ConvertTimeFromUtc(time, Timing.Timezone); refTime = refTime.Date + Timing.Offset; refTime = refTime.ToUniversalTime(); var Diff = (time - refTime).TotalMilliseconds / Timing.Interval.TotalMilliseconds; Diff = Math.Round(Diff); var nDiff = Convert.ToInt32(Diff); refTime = refTime.AddMilliseconds(nDiff * Timing.Interval.TotalMilliseconds); var timeCenter = timeFrom.AddTicks((timeTo - timeFrom).Ticks / 2); Diff = (refTime - timeCenter).TotalMilliseconds / Timing.Interval.TotalMilliseconds; Diff = Math.Ceiling(Diff); nDiff = Convert.ToInt32(Diff); return nDiff; } catch (Exception E) { LogException(E); } return -1; } } public class cDataHistoryInfoClassListEntry { public string Name { get; set; } public Guid id { get; set; } public override string ToString() { return Name; } } public class cF4sdConnectorIds { public class localIdEntry { public int agentId; public DateTime lastSeenByAgent; public string account; } public enumFasdInformationClass infoClass { get; set; } = enumFasdInformationClass.Unknown; public Guid Id { get; set; } public int? agentId { get; set; } = null; public int? agentId2 { get; set; } = null; public List localAgentIds { get; set; } = null; public byte[] sid { get; set; } = null; public string name { get; set; } = null; public DateTime? lastSeenByAgent { get; set; } = null; public enumAccountType accountType { get; set; } = enumAccountType.unknow; public Guid tenantId { get; set; } public Guid intuneId { get; set; } public Guid azureDeviceId { get; set; } public string citrixTenantId { get; set; } public int? citrixUserId { get; set; } } public class cDataHistoryUiStatusMessage { public int Indent = 0; public string Message; public static cDataHistoryUiStatusMessage Create(int Indent, string Message) { return new cDataHistoryUiStatusMessage() { Indent = Indent, Message = Message }; } } public class cDataHistorySHistoryScanInfo { public Guid ID; public string Scan; public DateTime TimeFrom; public DateTime TimeTo; } internal class cDataHistoryUsageIdInfo { internal Guid Id; internal enumAccountType AccountType = enumAccountType.unknow; internal string account = null; internal string domain = null; } public class cF4sdWebRequestInfo { public readonly string requestName; public readonly string id = null; public readonly DateTime created = DateTime.UtcNow; public readonly cF4sdUserInfo userInfo = null; public readonly CultureInfo Culture = null; public cM42WebClient M42WebClient = null; public int SqlDuration = 0; private List<(string, int)> privSqlDurations { get; set; } = null; public List<(string, int)> SqlDurations { get { if (privSqlDurations == null) privSqlDurations = new List<(string, int)>(); return privSqlDurations; } } public cF4sdWebRequestInfo(string requestName, string id, cF4sdUserInfo userInfo = null) { try { this.requestName = requestName; this.id = requestName + "-" + id; this.userInfo = userInfo; if (!string.IsNullOrEmpty(userInfo?.Language)) { try { this.Culture = CultureInfo.GetCultureInfoByIetfLanguageTag(userInfo.Language); } catch { } } if (cLogManager.DefaultLogger.IsDebug) LogEntry($"authentication user language: {userInfo?.Language}, user culture: {this.Culture?.Name}", LogLevels.Debug); } catch (Exception E) { LogException(E); } } } public class cHistoricAggregationEntry { internal cDataHistoryConfigColumn Column; internal int JsonSubValue = -1; internal int HistorySize = 0; internal object LatestValue = null; internal DateTime? LastestEvent = null; internal Int64?[] aggInt = null; internal Double?[] aggDouble = null; internal Double?[] weightDouble = null; internal String[] aggString = null; internal List[] listString = null; internal Boolean?[] aggBoolean = null; internal DateTime?[] aggEvent = null; internal DateTime?[] aggTime = null; internal Version[] aggVersion = null; internal Guid?[] aggGuid = null; private object lockAggregation = new object(); internal cHistoricAggregationEntry(cDataHistoryConfigColumn Column, int HistorySize, Dictionary JsonSettings) { this.Column = Column; this.HistorySize = HistorySize; if (Column.SourceJsonColumn >= 0) JsonSubValue = Column.SourceJsonColumn; else if (Column.SourceJsonField != null && JsonSettings != null) { if (JsonSettings.TryGetValue(Column.SourceName, out var jsonList)) { for (int i = 0; i < jsonList.Length; i++) if (jsonList[i] == Column.SourceJsonField) { JsonSubValue = i; break; } } } switch (Column.AggregationType) { case eDataHistoryAggregationType.average: aggDouble = new Double?[HistorySize]; weightDouble = new Double?[HistorySize]; return; case eDataHistoryAggregationType.latestTime: aggEvent = new DateTime?[HistorySize]; return; case eDataHistoryAggregationType.count: case eDataHistoryAggregationType.valuecount: aggInt = new Int64?[HistorySize]; return; case eDataHistoryAggregationType.Unknown: return; case eDataHistoryAggregationType.latestValue: case eDataHistoryAggregationType.first: aggEvent = new DateTime?[HistorySize]; break; } switch (Column.ValueType) { case enumFasdValueType.INT: case enumFasdValueType.BIGINT: aggInt = new Int64?[HistorySize]; return; case enumFasdValueType.FLOAT: aggDouble = new Double?[HistorySize]; return; case enumFasdValueType.DATETIME: aggTime = new DateTime?[HistorySize]; return; case enumFasdValueType.VERSION: switch (Column.AggregationType) { case eDataHistoryAggregationType.sum: listString = new List[HistorySize]; return; } aggVersion = new Version[HistorySize]; return; case enumFasdValueType.GUID: aggGuid = new Guid?[HistorySize]; return; case enumFasdValueType.BOOLEAN: aggBoolean = new bool?[HistorySize]; return; case enumFasdValueType.STRING: case enumFasdValueType.IPV4: switch (Column.AggregationType) { case eDataHistoryAggregationType.sum: listString = new List[HistorySize]; return; } aggString = new String[HistorySize]; return; } } internal void addValue(object Value, DateTime EventTime, DateTime RefTime, Int32 EventDuration) { try { var indexDay = cDataHistoryCollector.getDayIndex(EventTime, RefTime, HistorySize); if (Value is cDataHistoryCustomJsonMeasure _cm) { if (_cm.Values == null) return; if (_cm.ErrorCode != null && _cm.ErrorCode != 0) return; if (!string.IsNullOrEmpty(_cm.ErrorDescription)) return; if (_cm.ResultCode != null && _cm.ResultCode != 0) return; var _s = _cm.Values.GetType().ToString(); if (_cm.Values is JValue _jVal) Value = _jVal.Value; else if (_cm.Values is JArray _jArr) { var _res = new object[_jArr.Count]; var i = 0; foreach (var _jEntry in _jArr) { _res[i] = null; if (_jEntry is JValue _jVal2) { _res[i] = _jVal2.Value; } i++; } Value = _res; } } if ((JsonSubValue >= 0) && (Value is object[] arrVals)) Value = arrVals[JsonSubValue]; lock (lockAggregation) { if ((LastestEvent == null || EventTime >= LastestEvent) && !(Value is object[])) { LatestValue = Value; LastestEvent = EventTime; } switch (Column.AggregationType) { case eDataHistoryAggregationType.average: if (cDataHistoryCollector.CheckIfNotEmpty(Value)) { switch (Column.ValueType) { case enumFasdValueType.INT: case enumFasdValueType.BIGINT: case enumFasdValueType.FLOAT: var val01 = Convert.ToDouble(Value); if (weightDouble[indexDay] == null) weightDouble[indexDay] = 0; weightDouble[indexDay] += EventDuration; if (aggDouble[indexDay] == null) aggDouble[indexDay] = 0; aggDouble[indexDay] += val01 * EventDuration; return; } } return; case eDataHistoryAggregationType.latestTime: if (aggEvent[indexDay] == null || aggEvent[indexDay] < EventTime) aggEvent[indexDay] = EventTime; return; case eDataHistoryAggregationType.count: if (aggInt[indexDay] == null) aggInt[indexDay] = 1; else aggInt[indexDay]++; return; case eDataHistoryAggregationType.valuecount: if (cDataHistoryCollector.CheckIfNotEmpty(Value)) { if (aggInt[indexDay] == null) aggInt[indexDay] = 1; else aggInt[indexDay]++; } return; case eDataHistoryAggregationType.Unknown: return; } switch (Column.ValueType) { case enumFasdValueType.INT: case enumFasdValueType.BIGINT: if (cDataHistoryCollector.CheckIfNotEmpty(Value)) { var val02 = Convert.ToInt64(Value); switch (Column.AggregationType) { case eDataHistoryAggregationType.min: if (aggInt[indexDay] == null) aggInt[indexDay] = val02; else aggInt[indexDay] = Math.Min((Int64)aggInt[indexDay], val02); return; case eDataHistoryAggregationType.max: if (aggInt[indexDay] == null) aggInt[indexDay] = val02; else aggInt[indexDay] = Math.Max((Int64)aggInt[indexDay], val02); return; case eDataHistoryAggregationType.sum: if (aggInt[indexDay] == null) aggInt[indexDay] = val02; else aggInt[indexDay] += val02; return; case eDataHistoryAggregationType.first: if (aggEvent[indexDay] == null) { aggEvent[indexDay] = EventTime; aggInt[indexDay] = val02; } else { if (EventTime < aggEvent[indexDay]) { aggEvent[indexDay] = EventTime; aggInt[indexDay] = val02; } } return; case eDataHistoryAggregationType.latestValue: if (aggEvent[indexDay] == null) { aggEvent[indexDay] = EventTime; aggInt[indexDay] = val02; } else { if (EventTime > aggEvent[indexDay]) { aggEvent[indexDay] = EventTime; aggInt[indexDay] = val02; } } return; } } return; case enumFasdValueType.FLOAT: if (cDataHistoryCollector.CheckIfNotEmpty(Value)) { var val03 = Convert.ToDouble(Value); switch (Column.AggregationType) { case eDataHistoryAggregationType.min: if (aggDouble[indexDay] == null) aggDouble[indexDay] = val03; else aggDouble[indexDay] = Math.Min((Double)aggDouble[indexDay], val03); return; case eDataHistoryAggregationType.max: if (aggDouble[indexDay] == null) aggDouble[indexDay] = val03; else aggDouble[indexDay] = Math.Max((Double)aggDouble[indexDay], val03); return; case eDataHistoryAggregationType.sum: if (aggDouble[indexDay] == null) aggDouble[indexDay] = val03; else aggDouble[indexDay] += val03; return; case eDataHistoryAggregationType.first: if (aggEvent[indexDay] == null) { aggEvent[indexDay] = EventTime; aggDouble[indexDay] = val03; } else { if (EventTime < aggEvent[indexDay]) { aggEvent[indexDay] = EventTime; aggDouble[indexDay] = val03; } } return; case eDataHistoryAggregationType.latestValue: if (aggEvent[indexDay] == null) { aggEvent[indexDay] = EventTime; aggDouble[indexDay] = val03; } else { if (EventTime > aggEvent[indexDay]) { aggEvent[indexDay] = EventTime; aggDouble[indexDay] = val03; } } return; } } return; case enumFasdValueType.DATETIME: if (cDataHistoryCollector.CheckIfNotEmpty(Value)) { var val04 = Convert.ToDateTime(Value); switch (Column.AggregationType) { case eDataHistoryAggregationType.min: if (aggTime[indexDay] == null) aggTime[indexDay] = val04; else if (val04 < aggTime[indexDay]) aggTime[indexDay] = val04; return; case eDataHistoryAggregationType.max: if (aggTime[indexDay] == null) aggTime[indexDay] = val04; else if (val04 > aggTime[indexDay]) aggTime[indexDay] = val04; return; case eDataHistoryAggregationType.sum: return; case eDataHistoryAggregationType.first: if (aggEvent[indexDay] == null) { aggEvent[indexDay] = EventTime; aggTime[indexDay] = val04; } else { if (EventTime < aggEvent[indexDay]) { aggEvent[indexDay] = EventTime; aggTime[indexDay] = val04; } } return; case eDataHistoryAggregationType.latestValue: if (aggEvent[indexDay] == null) { aggEvent[indexDay] = EventTime; aggTime[indexDay] = val04; } else { if (EventTime > aggEvent[indexDay]) { aggEvent[indexDay] = EventTime; aggTime[indexDay] = val04; } } return; } } return; case enumFasdValueType.VERSION: if (Value != null && Version.TryParse(Value.ToString(), out var val05)) { switch (Column.AggregationType) { case eDataHistoryAggregationType.min: if (aggVersion[indexDay] == null) aggVersion[indexDay] = val05; else if (val05 < aggVersion[indexDay]) aggVersion[indexDay] = val05; return; case eDataHistoryAggregationType.max: if (aggVersion[indexDay] == null) aggVersion[indexDay] = val05; else if (val05 > aggVersion[indexDay]) aggVersion[indexDay] = val05; return; case eDataHistoryAggregationType.sum: var strVal05 = val05.ToString(); if (listString[indexDay] == null) listString[indexDay] = new List() { strVal05 }; else if (listString[indexDay].Count < 32 && !listString[indexDay].Contains(strVal05)) listString[indexDay].Add(strVal05); return; case eDataHistoryAggregationType.first: if (aggEvent[indexDay] == null) { aggEvent[indexDay] = EventTime; aggVersion[indexDay] = val05; } else { if (EventTime < aggEvent[indexDay]) { aggEvent[indexDay] = EventTime; aggVersion[indexDay] = val05; } } return; case eDataHistoryAggregationType.latestValue: if (aggEvent[indexDay] == null) { aggEvent[indexDay] = EventTime; aggVersion[indexDay] = val05; } else { if (EventTime > aggEvent[indexDay]) { aggEvent[indexDay] = EventTime; aggVersion[indexDay] = val05; } } return; } } return; case enumFasdValueType.GUID: if (Value == null) return; Guid _guid = Guid.Empty; if (Value is Guid _guid2) _guid = _guid2; else { if (Guid.TryParse(Value.ToString(), out var _guid3)) _guid = _guid3; else return; } switch (Column.AggregationType) { case eDataHistoryAggregationType.first: if (aggEvent[indexDay] == null) { aggEvent[indexDay] = EventTime; aggGuid[indexDay] = _guid; } else { if (EventTime < aggEvent[indexDay]) { aggEvent[indexDay] = EventTime; aggGuid[indexDay] = _guid; } } return; case eDataHistoryAggregationType.latestValue: if (aggEvent[indexDay] == null) { aggEvent[indexDay] = EventTime; aggGuid[indexDay] = _guid; } else { if (EventTime > aggEvent[indexDay]) { aggEvent[indexDay] = EventTime; aggGuid[indexDay] = _guid; } } return; } return; case enumFasdValueType.BOOLEAN: if (!cDataHistoryCollector.CheckIfNotEmpty(Value)) return; bool val06 = false; if (Value is bool v) val06 = v; else if (Value is string val06Str) { switch (val06Str.Trim().ToLower()) { case "1": case "true": case "yes": val06 = true; break; case "0": case "false": case "no": break; default: return; } } else if (Value is sbyte || Value is byte || Value is short || Value is ushort || Value is int || Value is uint || Value is long || Value is ulong) { var val06Int = Convert.ToInt64(Value); if (val06Int == 0) { } else if (val06Int == 1) val06 = true; return; } else if (Value is float || Value is double || Value is decimal) { var val06Double = Convert.ToDouble(Value); if (val06Double == 0) { } else if (val06Double == 1) val06 = true; else return; } else return; switch (Column.AggregationType) { case eDataHistoryAggregationType.min: if (aggBoolean[indexDay] == null) aggBoolean[indexDay] = val06; else aggBoolean[indexDay] &= val06; return; case eDataHistoryAggregationType.max: if (aggBoolean[indexDay] == null) aggBoolean[indexDay] = val06; else aggBoolean[indexDay] |= val06; return; case eDataHistoryAggregationType.sum: return; case eDataHistoryAggregationType.first: if (aggEvent[indexDay] == null) { aggEvent[indexDay] = EventTime; aggBoolean[indexDay] = val06; } else { if (EventTime < aggEvent[indexDay]) { aggEvent[indexDay] = EventTime; aggBoolean[indexDay] = val06; } } return; case eDataHistoryAggregationType.latestValue: if (aggEvent[indexDay] == null) { aggEvent[indexDay] = EventTime; aggBoolean[indexDay] = val06; } else { if (EventTime > aggEvent[indexDay]) { aggEvent[indexDay] = EventTime; aggBoolean[indexDay] = val06; } } return; } return; default: if (Value == null) return; var val07 = Value.ToString(); if (val07 == "") return; switch (Column.AggregationType) { case eDataHistoryAggregationType.sum: if (listString[indexDay] == null) listString[indexDay] = new List() { val07 }; else if (listString[indexDay].Count < 32 && !listString[indexDay].Contains(val07)) listString[indexDay].Add(val07); return; case eDataHistoryAggregationType.first: if (aggEvent[indexDay] == null) { aggEvent[indexDay] = EventTime; aggString[indexDay] = val07; } else { if (EventTime < aggEvent[indexDay]) { aggEvent[indexDay] = EventTime; aggString[indexDay] = val07; } } return; case eDataHistoryAggregationType.latestValue: if (aggEvent[indexDay] == null) { aggEvent[indexDay] = EventTime; aggString[indexDay] = val07; } else { if (EventTime > aggEvent[indexDay]) { aggEvent[indexDay] = EventTime; aggString[indexDay] = val07; } } return; } return; } } } catch (Exception E) { LogException(E); LogEntry($"error while processing historical value from {Column.ParentTable.Name}/{Column.Name}: {Value}", LogLevels.Error); } } internal List getValues() { try { var RetVal = getValuesRaw(); if (RetVal == null || !Column.FillEmptyEntries) return RetVal; object LastVal = null; for (int i = RetVal.Count - 1; i >= 0; i--) { if (RetVal[i] == null) RetVal[i] = LastVal; else LastVal = RetVal[i]; } return RetVal; } catch (Exception E) { LogException(E); } return null; } internal List getValuesRaw() { try { List retVal; switch (Column.AggregationType) { case eDataHistoryAggregationType.average: switch (Column.ValueType) { case enumFasdValueType.INT: case enumFasdValueType.BIGINT: case enumFasdValueType.FLOAT: retVal = new List(HistorySize); for (int i = 0; i < HistorySize; i++) { if (weightDouble[i] == 0 || aggDouble[i] == null) retVal.Add(null); else retVal.Add(aggDouble[i] / weightDouble[i]); } return retVal; } return null; case eDataHistoryAggregationType.latestTime: retVal = aggEvent?.Select(x => (object)x).ToList(); return retVal; case eDataHistoryAggregationType.count: case eDataHistoryAggregationType.valuecount: retVal = aggInt.Select(x => (object)x).ToList(); return retVal; case eDataHistoryAggregationType.Unknown: return null; } switch (Column.ValueType) { case enumFasdValueType.INT: case enumFasdValueType.BIGINT: switch (Column.AggregationType) { case eDataHistoryAggregationType.min: case eDataHistoryAggregationType.max: case eDataHistoryAggregationType.sum: case eDataHistoryAggregationType.first: case eDataHistoryAggregationType.latestValue: retVal = aggInt.Select(x => (object)x).ToList(); return retVal; } return null; case enumFasdValueType.FLOAT: switch (Column.AggregationType) { case eDataHistoryAggregationType.min: case eDataHistoryAggregationType.max: case eDataHistoryAggregationType.sum: case eDataHistoryAggregationType.first: case eDataHistoryAggregationType.latestValue: retVal = aggDouble.Select(x => (object)x).ToList(); return retVal; } return null; case enumFasdValueType.DATETIME: switch (Column.AggregationType) { case eDataHistoryAggregationType.min: case eDataHistoryAggregationType.max: case eDataHistoryAggregationType.first: case eDataHistoryAggregationType.latestValue: retVal = aggTime.Select(x => (object)x).ToList(); return retVal; } return null; case enumFasdValueType.VERSION: switch (Column.AggregationType) { case eDataHistoryAggregationType.min: case eDataHistoryAggregationType.max: case eDataHistoryAggregationType.first: case eDataHistoryAggregationType.latestValue: retVal = aggVersion.Select(x => (object)x).ToList(); return retVal; case eDataHistoryAggregationType.sum: retVal = listString.Select(x => (object)cDataHistoryCollector.getStingList(x)).ToList(); return retVal; } return null; case enumFasdValueType.GUID: switch (Column.AggregationType) { case eDataHistoryAggregationType.first: case eDataHistoryAggregationType.latestValue: retVal = aggGuid.Select(x => (object)x).ToList(); return retVal; } return null; case enumFasdValueType.BOOLEAN: switch (Column.AggregationType) { case eDataHistoryAggregationType.min: case eDataHistoryAggregationType.max: case eDataHistoryAggregationType.first: case eDataHistoryAggregationType.latestValue: retVal = aggBoolean.Select(x => (object)x).ToList(); return retVal; } return null; default: switch (Column.AggregationType) { case eDataHistoryAggregationType.first: case eDataHistoryAggregationType.latestValue: retVal = aggString.Select(x => (object)x).ToList(); return retVal; case eDataHistoryAggregationType.sum: retVal = listString.Select(x => (object)cDataHistoryCollector.getStingList(x)).ToList(); return retVal; } return null; } } catch (Exception E) { LogException(E); } return null; } } public class cDataHistoryCustomJsonMeasure { public int? ResultCode = null; public int? ErrorCode = null; public string ErrorDescription = null; public object Values; } }