using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using Logic.ProductionToProductMapper.Cordonel; using Logic.ProductionToProductMapper.Files.Fw; using Newtonsoft.Json; using Xylem.Common.CommonCore.Configuration; using Xylem.Common.CommonCore.Consts; using Xylem.Common.Cryptology.Security; using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore; using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile; using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisPwd; using Xylem.Common.Hardware.WaterMeter.Genesis.Registers; using Xylem.Common.Logic.ProductionOrderCore.FW; using Xylem.Common.Logic.ProductionOrderCore.OrderData; using Xylem.Common.Logic.SoftwareAccessHelper; using Xylem.Common.Utils.DateTimeServer; using Xylem.ServiceFwUpdate.Common.FwUpdateSafe; namespace Xylem.ServiceFwUpdate.Common.FwUpdateDb { /// /// Class for DB interfaces. /// [Serializable] public class FwUpdateDb { private const Int32 shortTimeoutDbRequest = 2000; private const Int32 moderateTimeoutDbRequest = 10000; private const Int32 hugeTimeoutDbRequest = 30000; /// /// DB connection cannot be established. /// public Boolean DbIsConnected { get; private set; } /// /// Complete information of all builder operators registered in DB. /// public List DbAllBuilderOperators { get; private set; } /// /// Complete information of all update operators registered in DB. /// public List DbAllUpdateOperators { get; private set; } /// /// Cordonel SW package. /// public List DbFwUpdateSwPackage { get; private set; } /// /// Cordonel configuration files. /// public List DbFwUpdateConfigFiles { get; private set; } /// /// Cordonel FW packages information. /// public List DbCordonelFwPackagesInfo { get; private set; } /// /// Single Cordonel FW package. /// public ClusteredFile DbCordonelFwPackage { get; private set; } /// /// Cordonel safes. /// public List DbCordonelSafes { get; private set; } /// /// Complete information of all searched Cordonel customers. /// public List DbSearchedCordonelCustomers { get; private set; } /// /// All production orders of Cordonels by a specific customer. /// public List DbCordonelCustomerOrders { get; private set; } /// /// All serial numbers for a specific Cordonel (Customer serial number, Sensus serial number and PCB ID). /// public List DbCordonelSerialNumbers { get; private set; } /// /// Complete information of fully qualified users registered in DB. /// Only these users can be used for en- and decryption as the Pwd Hash and Hw Id /// shall be used for this operation. /// public List DbFullQualifiedUpdateOperators { get; private set; } /// /// Get the FW-Update SW validation from DB. /// /// /// /// /// - Initial. /// /// /// - timeout to 1200 ms. /// /// /// - License assigned in DB access. /// public Boolean GetSwLicenseFromDb(String programName, out SoftwareLicense swLicense) { swLicense = new SoftwareLicense(); try { var url = ServiceUrls.GetSoftwareLicenseUrl(); var requestResponse = LocalWebRequest.GetRequest(url + programName, moderateTimeoutDbRequest); if (string.IsNullOrEmpty(requestResponse)) { DbIsConnected = false; return false; } DbIsConnected = true; swLicense = JsonConvert.DeserializeObject(requestResponse); return true; } catch (Exception) { DbIsConnected = false; return false; } } /// /// Get the FW-Update SW validation from DB. /// /// /// /// - Initial. /// /// /// - Modified. /// /// /// - timeout to 1200 ms. /// public Boolean CheckSwLicenseIsValidFromDb(SoftwareLicense swLicense) { if (swLicense == null) return false; try { var url = ServiceUrls.GetSoftwareStartUpAccessUrl(); url += $"?Program={swLicense.Program}" + $"&Major={swLicense.Major}" + $"&Minor={swLicense.Minor}" + $"&Build={swLicense.Build}"; var requestResponse = LocalWebRequest.GetRequest(url, moderateTimeoutDbRequest); var ret = bool.Parse(requestResponse.Trim('"')); if (string.IsNullOrEmpty(requestResponse)) { DbIsConnected = false; return false; } DbIsConnected = true; return ret; } catch (Exception) { DbIsConnected = false; return false; } } /// /// Set the FW-Update SW validation to DB /// /// /// /// - Initial. /// /// /// - Modified url string. /// /// /// - Set DB connection state. /// /// /// - timeout to 1200 ms. /// public Boolean SetSwLicenseToDb(SoftwareLicense swLicense) { if (swLicense == null) return false; try { var url = ServiceUrls.SetSoftwareLicenseUrl(); url += $"{swLicense.Program}&Major={swLicense.Major}&Minor={swLicense.Minor}" + $"&Build={swLicense.Build}&ValidTo={swLicense.ValidTo:yyyy-MM-ddTHH:mm:ss}" + $"&Description={swLicense.Description ?? "null"}&ProgramNameIsUnique={swLicense.ProgramNameIsUnique}"; var requestResponse = LocalWebRequest.PostRequestAsyncAndGetContent(url, moderateTimeoutDbRequest); if (requestResponse != null && string.IsNullOrEmpty(requestResponse) && !JsonConvert.DeserializeObject(requestResponse)) { DbIsConnected = false; return false; } DbIsConnected = true; return true; } catch (Exception) { DbIsConnected = false; return false; } } /// /// Collect programming parameters from DB. /// /// /// /// recovery registers /// /// - Initial. /// /// /// - Sort the registers from DB but keep the PrepareProgramming and FinalizeProgramming in the required sequence. /// /// /// - Removed preparation and finalization of register recovery to remove sequencing as this will be done in the /// RegisterRestorer by the FwUpdateSw worker giving the ability to log this in the report. /// /// /// - Use common interface for programming parameters for EOL (shipping) and CUST from . /// public Boolean DownloadCordonelRecoveryRegistersFromDb(String pcbId, List recoveryRegisters) { if (StatusReturn.Okay == RegisterRestorer.DownloadProgrammingParametersFromDb(pcbId, recoveryRegisters)) { DbIsConnected = true; return true; } DbIsConnected = false; return false; } /// /// Collect order number, radio address, skeleton key, password hashes and passwords from DB. /// /// /// /// password container /// /// - Initial. /// /// /// - Returns bool. /// /// /// - Check content of password container. /// /// /// - Using software access helper class. /// /// /// - Additional timeout as the password request will redirected from DB Laatzen to DB Ludwigshafen. /// /// /// - Set DB connection state. /// /// /// - Used the as common interface to request the password container, /// if the password container does not exist, it will be generated. /// /// /// - Used the as common routine for password hash file generation out of /// the raw text passwords. This routine verifies the password container. /// /// /// - Avoid generation of password file if new generated Lvl8 password is not the Lvl8 production password, /// if the password is the skeleton key the password file was never generated so go ahead. /// public Boolean DownloadCordonelPwdFromDb(String pcbId, out PasswordContainer passwordContainer) { passwordContainer = new PasswordContainer(); try { if (!MeterPwdHandlerDb.RequestPwdFileFromDb(pcbId, out var meterPwdDb)) { DbIsConnected = false; return false; } if (meterPwdDb == null ) { DbIsConnected = false; return false; } // Avoid generation of password file if new generated Lvl8 password is not the Lvl8 production password, // if the password is the skeleton key the password file was never generated so go ahead if (meterPwdDb.Password != meterPwdDb.Skeleton && meterPwdDb.Password != Encoding.UTF8.GetString(meterPwdDb.ListOfPasswords[MeterPwdDb.PwdLevel8Idx])) { throw new ApplicationException("Production password is neither the SkeletonKey nor the required level 8 " + "password from password service! Password file cannot be generated!"); } DbIsConnected = true; passwordContainer.PcbId = pcbId; passwordContainer.SkeletonKey = Encoding.UTF8.GetString(meterPwdDb.ListOfPasswords[MeterPwdDb.SkeletonKeyIdx]); passwordContainer.PasswordLvl8 = Encoding.UTF8.GetString(meterPwdDb.ListOfPasswords[MeterPwdDb.PwdLevel8Idx]); // Use the standard constructor as writing to meter is not necessary var meterPwdFile = new MeterPwdFile(); // The BuildPwdFile has an extended validation check var retBol = meterPwdFile.BuildPwdFile(meterPwdDb.ListOfPasswords, 1, passwordContainer.SkeletonKey); if (!retBol) { DbIsConnected = false; return false; } passwordContainer.EncryptedPasswordFile = new Byte[MeterPwdDb.PwdFileLength]; passwordContainer.EncryptedPasswordFile = meterPwdFile.HashedPasswordFile; var hashList = new List(); foreach (var hash in meterPwdDb.ListOfHashes) { hashList.AddRange(hash); } var pwdControllerPwdFile = hashList.ToArray(); //passwordContainer.EncryptedPasswordFile = hashList.ToArray(); // Compare password controller hashed password file with this generated new one for (var c = 0; c < MeterPwdDb.PwdFileLength; c++) { if (passwordContainer.EncryptedPasswordFile[c] != pwdControllerPwdFile[c]) return false; } // If the password file is written, the "Password" from meterPwdDb is overwritten from Skeleton-key // to the "level 8 password" form the LuDB server. The DB password column is the current login password // for production. Initially the "Password" is the Skeleton-key which can not be part of the list of // Passwords. The level 8 password is the last in the pwContainer list of passwords. if (Encoding.UTF8.GetString(meterPwdDb.ListOfPasswords.Last()) != meterPwdDb.Password) { if (!MeterPwdHandlerDb.SetPwdFromSkeletonToLvl8inDd(pcbId, meterPwdDb)) { DbIsConnected = false; return false; } } return !string.IsNullOrEmpty(passwordContainer.SkeletonKey) && !string.IsNullOrEmpty(passwordContainer.PasswordLvl8) && passwordContainer.EncryptedPasswordFile.Length == MeterPwdDb.PwdFileLength; } catch (Exception ex) { DbIsConnected = false; throw new ApplicationException(ex.Message + $" - PcbId: {pcbId}"); } } /// /// Get the update operators information from DB needed to generate the primary key for encryption. /// This is a direct DB access. The read information from DB may be incomplete as the password hash and /// hardware id are optional. /// /// true if successful /// /// - Initial. /// /// /// - Refresh all DbAllUsersInfos and DbFullQualifiedUsersInfos lists. /// /// /// - Set DB connection state. /// public Boolean GetAllUpdateOperatorsFromDb() { if (DbAllUpdateOperators == null) DbAllUpdateOperators = new List(); if (DbFullQualifiedUpdateOperators == null) DbFullQualifiedUpdateOperators = new List(); DbAllUpdateOperators.Clear(); DbFullQualifiedUpdateOperators.Clear(); try { var url = ServiceUrls.ListAllFwUpdateUsersServiceUrl(); var requestResponse = LocalWebRequest.GetRequest(url, moderateTimeoutDbRequest); if (string.IsNullOrEmpty(requestResponse)) { DbIsConnected = false; return false; } DbIsConnected = true; DbAllUpdateOperators = JsonConvert.DeserializeObject>(requestResponse); if (DbAllUpdateOperators == null || DbAllUpdateOperators.Count == 0 || DbFullQualifiedUpdateOperators == null) { return false; } // If the user is fully qualified it will be put to the DbFullQualifiedUsersInfos list. foreach (var user in DbAllUpdateOperators.Where(CheckIfUpdateOperatorIsFullyQualified)) { // Avoid doubling of names if these are already listed if (DbFullQualifiedUpdateOperators.Any(u => u.FullName == user.FullName)) continue; DbFullQualifiedUpdateOperators.Add(user); } return true; } catch (Exception) { DbIsConnected = false; return false; } } /// /// Get the Builder Operator information from DB for user validation check. /// /// true if successful /// /// - Initial. /// public Boolean GetAllBuilderOperatorsFromDb() { if (DbAllBuilderOperators == null) DbAllBuilderOperators = new List(); DbAllBuilderOperators.Clear(); try { var url = ServiceUrls.ListAllFwUpdateBuilderOperatorsServiceUrl(); var requestResponse = LocalWebRequest.GetRequest(url, moderateTimeoutDbRequest); if (string.IsNullOrEmpty(requestResponse)) { DbIsConnected = false; return false; } DbIsConnected = true; DbAllBuilderOperators = JsonConvert.DeserializeObject>(requestResponse); return DbAllBuilderOperators != null && DbAllBuilderOperators.Count != 0; } catch (Exception) { DbIsConnected = false; return false; } } /// /// Load the latest FW update SW package from DB. /// /// true if successful /// /// - Initial. /// public Boolean DownloadFwUpdateSwContainerFromDb() { try { var url = ServiceUrls.ListAllSwPackages(); var requestResponse = LocalWebRequest.GetRequest(url, hugeTimeoutDbRequest); if (string.IsNullOrEmpty(requestResponse)) { DbIsConnected = false; return false; } DbIsConnected = true; // get a list of all stored FW update SW packages var dbCordonelSwPackages = JsonConvert.DeserializeObject>(requestResponse); if (dbCordonelSwPackages == null || dbCordonelSwPackages.Count == 0) { return false; } // get latest version var fileId = dbCordonelSwPackages.Select(package => package.FileId).Prepend(0).Max(); if (fileId == 0) { return false; } if (DbFwUpdateSwPackage == null) DbFwUpdateSwPackage = new List(); DbFwUpdateSwPackage.Clear(); // download content url = ServiceUrls.DownloadFileParts(); url += $"{fileId}&readContent=true"; requestResponse = LocalWebRequest.GetRequest(url, hugeTimeoutDbRequest); if (string.IsNullOrEmpty(requestResponse)) { DbIsConnected = false; return false; } DbIsConnected = true; DbFwUpdateSwPackage = JsonConvert.DeserializeObject>(requestResponse); return DbFwUpdateSwPackage != null && DbFwUpdateSwPackage.Count > 0; } catch (Exception) { DbIsConnected = false; return false; } } /// /// Load the latest FW update configuration files from DB. /// /// true if successful /// /// - Initial. /// public Boolean DownloadFwUpdateConfigurationFilesFromDb() { try { var url = ServiceUrls.ListAllConfigurationFilePackages(); var requestResponse = LocalWebRequest.GetRequest(url, moderateTimeoutDbRequest); if (string.IsNullOrEmpty(requestResponse)) { DbIsConnected = false; return false; } DbIsConnected = true; // get a list of all stored FW update config file packages var dbConfigFilePackages = JsonConvert.DeserializeObject>(requestResponse); if (dbConfigFilePackages == null || dbConfigFilePackages.Count == 0) { return false; } // get latest version var fileId = dbConfigFilePackages.Select(package => package.FileId).Prepend(0).Max(); if (fileId == 0) { return false; } if (DbFwUpdateConfigFiles == null) DbFwUpdateConfigFiles = new List(); DbFwUpdateConfigFiles.Clear(); // download content url = ServiceUrls.DownloadFileParts(); url += $"{fileId}&readContent=true"; requestResponse = LocalWebRequest.GetRequest(url, moderateTimeoutDbRequest); if (string.IsNullOrEmpty(requestResponse)) { DbIsConnected = false; return false; } DbIsConnected = true; DbFwUpdateConfigFiles = JsonConvert.DeserializeObject>(requestResponse); return DbFwUpdateConfigFiles != null && DbFwUpdateConfigFiles.Count > 0; } catch (Exception) { DbIsConnected = false; return false; } } /// /// Get all Cordonel safe info files from DB. /// /// true if successful /// /// - Initial. /// public Boolean GetAllCordonelSafeInfoFilesFromDb() { if (DbCordonelSafes == null) DbCordonelSafes = new List(); DbCordonelSafes.Clear(); try { var url = ServiceUrls.ListAllFwUpdateSafes(); var requestResponse = LocalWebRequest.GetRequest(url, hugeTimeoutDbRequest); if (string.IsNullOrEmpty(requestResponse)) { DbIsConnected = false; return false; } DbIsConnected = true; DbCordonelSafes = JsonConvert.DeserializeObject>(requestResponse); return DbCordonelSafes != null && DbCordonelSafes.Count != 0; } catch (Exception) { DbIsConnected = false; return false; } } /// /// Get EOL production parameters for power correction from DB. /// /// /// /// true if successful /// /// - Initial. /// public Boolean DownloadDbDataAtEol(String pcbId, ref PowerCorrection pwrCorr) { try { var url = ServiceUrls.DownloadDbDataAtEolServiceUrl(); url += pcbId; var requestResponse = LocalWebRequest.GetRequest(url, hugeTimeoutDbRequest); if (string.IsNullOrEmpty(requestResponse)) { DbIsConnected = false; return false; } DbIsConnected = true; pwrCorr = JsonConvert.DeserializeObject(requestResponse); return true; } catch (Exception) { DbIsConnected = false; return false; } } /// /// Getting all FW-Update Safes information by user id. The download has to be triggered with /// the DownloadFileContentFromDB with FilePartId as reference /// /// /// /// true if containers exists /// /// - Initial. /// /// /// - timeout to 1200 ms. /// /// /// - timeout to 3000 ms. /// public Boolean ListAllFwUpdateSafesOfUserFromDb(Int32 userId, out List fwUpdSafeContainers) { fwUpdSafeContainers = new List(); try { var url = ServiceUrls.ListAllFwUpdateSafesForUserServiceUrl(); url += $"{userId}"; var requestResponse = LocalWebRequest.GetRequest(url, moderateTimeoutDbRequest); if (string.IsNullOrEmpty(requestResponse)) { DbIsConnected = false; return false; } DbIsConnected = true; fwUpdSafeContainers = JsonConvert.DeserializeObject>(requestResponse); return fwUpdSafeContainers != null && fwUpdSafeContainers.Count > 0; } catch (Exception) { DbIsConnected = false; return false; } } /// /// Get a single Cordonel safe from DB. /// /// the file id previously read with /// the safe /// reading content if true, else only the file information /// true if successful /// /// - Initial. /// /// /// - timeout to 5000 ms. /// public Boolean GetCordonelSafeFromDb(Int32 fileId, out FilePart safe, Boolean readContent = true) { safe = new FilePart(); try { var url = ServiceUrls.DownloadFileParts(); url += $"{fileId}&readContent={readContent}"; var requestResponse = LocalWebRequest.GetRequest(url, hugeTimeoutDbRequest); if (string.IsNullOrEmpty(requestResponse)) { DbIsConnected = false; return false; } DbIsConnected = true; safe = JsonConvert.DeserializeObject(requestResponse); return safe != null; } catch (Exception) { DbIsConnected = false; return false; } } /// /// Get a single Cordonel FW package from DB. /// /// the file id previously read with /// the FW as package /// reading content if true, else only the file information /// true if successful /// /// - Initial. /// /// /// - Timeout increased to 5000 ms. /// public Boolean GetCordonelFwPackageFromDb(Int32 fileId, out List fwPackage, Boolean readContent = true) { fwPackage = new List(); try { var url = ServiceUrls.DownloadFileParts(); url += $"{fileId}&readContent={readContent}"; var requestResponse = LocalWebRequest.GetRequest(url, hugeTimeoutDbRequest); if (string.IsNullOrEmpty(requestResponse)) { DbIsConnected = false; return false; } DbIsConnected = true; fwPackage = JsonConvert.DeserializeObject>(requestResponse); return fwPackage != null && fwPackage.Count > 0; } catch (Exception) { DbIsConnected = false; return false; } } /// /// Get all Cordonel customers from DB. The return can be used to select a specific customer and get /// the customer number which is the base for the order search. /// /// specific search pattern for customer name /// true if successful /// /// - Initial. /// /// /// - Moved DB access to . /// public Boolean GetAllCordonelCustomersFromDb(String searchPattern = Constants.StrWildcard) { // for the DB interface a specific search pattern will be used, so replace it from the user interface // as there is a Constants.StrWildcard the placeholder for "all". searchPattern = searchPattern.Replace(Constants.StrWildcard, "%"); if (DbSearchedCordonelCustomers == null) DbSearchedCordonelCustomers = new List(); DbSearchedCordonelCustomers.Clear(); DbIsConnected = OrderDetailsDb.GetAllCordonelCustomersFromDb(out var dbCordonelCustomers, searchPattern); foreach (var customer in dbCordonelCustomers) { DbSearchedCordonelCustomers.Add(customer); } return DbIsConnected; } /// /// Get all Cordonel customers orders from DB. The return can be used to select a specific order number /// and position which is the base for the Cordonel serial number search. /// /// /// true if successful /// /// - Initial. /// /// /// - Sort list by customer order numbers. /// /// /// - Moved DB access to . /// public Boolean GetAllCordonelCustomerOrdersFromDb(Int64 customerNumber) { if (DbCordonelCustomerOrders == null) DbCordonelCustomerOrders = new List(); DbCordonelCustomerOrders.Clear(); DbIsConnected = OrderDetailsDb.GetAllCordonelCustomerOrdersFromDb(customerNumber, out var dbCordonelCustomerOrders); foreach (var order in dbCordonelCustomerOrders) { DbCordonelCustomerOrders.Add(order); } return DbIsConnected; } /// /// Get all Cordonel serial numbers of a specific order. /// /// /// /// true if successful /// /// - Initial. /// /// /// - Moved DB access to . /// public Boolean GetAllCordonelSerialNumbersFromDb(Int64 orderNumber, Int64 orderPos) { if (DbCordonelSerialNumbers == null) DbCordonelSerialNumbers = new List(); DbCordonelSerialNumbers.Clear(); DbIsConnected = OrderDetailsDb.GetAllCordonelSerialNumbersFromDb(orderNumber, orderPos, out var dbSerialNumbers); foreach (var serialNumber in dbSerialNumbers) { DbCordonelSerialNumbers.Add(serialNumber); } return DbIsConnected; } /// /// Get all Cordonel FW packages information from DB. /// /// true if successful /// /// - Initial. /// public Boolean GetAllCordonelFwPackagesInfoFromDb() { if (DbCordonelFwPackagesInfo == null) DbCordonelFwPackagesInfo = new List(); DbCordonelFwPackagesInfo.Clear(); try { var url = ServiceUrls.ListAllCordonelFwPackagesUrl(); var requestResponse = LocalWebRequest.GetRequest(url, moderateTimeoutDbRequest); if (string.IsNullOrEmpty(requestResponse)) { DbIsConnected = false; return false; } DbIsConnected = true; DbCordonelFwPackagesInfo = JsonConvert.DeserializeObject>(requestResponse); return DbCordonelFwPackagesInfo != null && DbCordonelFwPackagesInfo.Count != 0; } catch (Exception) { DbIsConnected = false; return false; } } /// /// Simple command to access the DB and check therefore if it is available. /// /// true if successful /// /// - Initial. /// /// /// - Timeout extended to 1200 ms. /// public Boolean CheckDbConnection() { try { var url = ServiceUrls.GetFwUpdateUserByIdServiceUrl(); url += "0"; var requestResponse = LocalWebRequest.GetRequest(url, moderateTimeoutDbRequest); if (string.IsNullOrEmpty(requestResponse)) { DbIsConnected = false; return false; } DbIsConnected = true; return true; } catch (Exception) { DbIsConnected = false; return false; } } /// /// Check if user is registered to DB with all contents including Hw Id and pwd hash. /// The DbAllUsersInfos has to be loaded or updated in advance, which will be done in the Ctor or on every /// registration of a new user or update of Hw Id or User Pwd Hash . /// The first fully specified user will be returned by its user id. This routine can be used to create /// the Db /// /// /// - user to search for registration in DB with full specification, /// - the search parameter is the FullName, /// - the first found full qualified DB user will set the user id /// true if user is registered in DB /// /// - Initial. /// /// /// - Input full specified user info. /// private Boolean CheckIfUpdateOperatorIsFullyQualified(UserInformation dbCheckFullSpecUpdateOperator) { // The fully specified user has to be defined by FullName, LogInName, Domain, Hw Id and User Pwd Hash. // The user id mustn't be set as this will be returned by the DB search. if (dbCheckFullSpecUpdateOperator == null || DbAllUpdateOperators == null || DbAllUpdateOperators.Count == 0 || string.IsNullOrEmpty(dbCheckFullSpecUpdateOperator.FullName) || string.IsNullOrEmpty(dbCheckFullSpecUpdateOperator.LogInName) || string.IsNullOrEmpty(dbCheckFullSpecUpdateOperator.Domain) || string.IsNullOrEmpty(dbCheckFullSpecUpdateOperator.HardwareId) || string.IsNullOrEmpty(dbCheckFullSpecUpdateOperator.PasswordHash)) return false; foreach (var user in DbAllUpdateOperators.Where(user => user.FullName == dbCheckFullSpecUpdateOperator.FullName && user.LogInName == dbCheckFullSpecUpdateOperator.LogInName && user.Domain == dbCheckFullSpecUpdateOperator.Domain && user.HardwareId == dbCheckFullSpecUpdateOperator.HardwareId && user.PasswordHash == dbCheckFullSpecUpdateOperator.PasswordHash)) { dbCheckFullSpecUpdateOperator.Id = user.Id; return true; } return false; } /// /// Register user to DB. This is a direct DB access. The user hardware id and and password hash are optional. /// The dbNewUser will get his user id on registration. /// /// new user to register to DB /// true if successful and all fields set except pwd hash and hw id /// /// - Initial. /// /// /// - Extended to full registration, optional hw id and pwd hash, /// - Refresh all DbAllUsersInfos and DbFullQualifiedUsersInfos lists. /// /// /// - Set initial validation date. /// /// /// - Set DB connection state. /// /// /// - Added initial valid date. /// /// /// - timeout to 1200 ms. /// private Boolean RegisterUpdateOperatorToDbAndRefreshLists(UserInformation dbNewUser) { // The new user has to be defined by FullName, LogInName and Domain if (dbNewUser == null || string.IsNullOrEmpty(dbNewUser.FullName) || string.IsNullOrEmpty(dbNewUser.LogInName) || string.IsNullOrEmpty(dbNewUser.Domain)) return false; // Hw Id and Pwd Hash are optional on initial registration if (dbNewUser.HardwareId == null) dbNewUser.HardwareId = ""; if (dbNewUser.PasswordHash == null) dbNewUser.PasswordHash = ""; var validDateTime = DateTimeServer.SetValidationDate(FwUpdateConfig.Consts.FwUpdateConfig.ValidDays); try { var url = ServiceUrls.CreateNewFwUpdateUserServiceUrl(); url += $"FullName={dbNewUser.FullName}" + $"&LoginName={dbNewUser.LogInName}" + $"&Domain={dbNewUser.Domain}" + $"&HardwareId={dbNewUser.HardwareId}" + $"&PasswordHash={dbNewUser.PasswordHash} +" + $"&ValidDate={validDateTime:yyyy-MM-ddTHH:mm:ss}&AccountActive=true"; var requestResponse = LocalWebRequest.GetRequest(url, 5000); if (string.IsNullOrEmpty(requestResponse)) { DbIsConnected = false; return false; } DbIsConnected = true; // During registration the user id will be set. This is needed to access later the hw id and pwd hash. dbNewUser.Id = JsonConvert.DeserializeObject(requestResponse); // Set validation date and refresh all DbAllUsersInfos and DbFullQualifiedUsersInfos lists return RefreshValidDateToDbAndRefreshUserLists(dbNewUser.Id); } catch (Exception) { DbIsConnected = false; return false; } } /// /// Set user pwd hash to DB. This is a direct DB access. The user has to be referenced by id. /// On every refresh the DbAllUsersInfos and DbFullQualifiedUsersInfos lists will be generated /// . /// /// user id as reference /// the password hash as string /// /// - Initial. /// /// /// - Input is user Id and pwd hash as string. /// - Refresh all DbAllUsersInfos and DbFullQualifiedUsersInfos lists. /// /// /// - Refresh validation date. /// /// /// - Set DB connection state. /// /// /// - timeout to 1200 ms. /// private void RefreshPwdHashToDbAndRefreshUserLists(Int32 dbUserId, String dbUserPwdHash) { if (dbUserId < 0 || string.IsNullOrEmpty(dbUserPwdHash)) return; try { var url = ServiceUrls.RefreshFwUpdateUsersPasswordHashServiceUrl(); url += $"{dbUserId}&PasswordHash={dbUserPwdHash}"; var requestResponse = LocalWebRequest.GetRequest(url, moderateTimeoutDbRequest); if (string.IsNullOrEmpty(requestResponse)) { DbIsConnected = false; return; } DbIsConnected = true; if (!JsonConvert.DeserializeObject(requestResponse)) return; // Set validation date and refresh all DbAllUsersInfos and DbFullQualifiedUsersInfos lists RefreshValidDateToDbAndRefreshUserLists(dbUserId); } catch (Exception) { DbIsConnected = false; } } /// /// Set user validation to DB. This is a direct DB access. The user has to be referenced by id. /// On every refresh the DbAllUsersInfos and DbFullQualifiedUsersInfos lists will be generated. /// . /// /// user id as reference /// /// - Initial. /// /// /// - Valid date as string. /// /// /// - Set DB connection state. /// /// /// - timeout to 1200 ms. /// private Boolean RefreshValidDateToDbAndRefreshUserLists(Int32 dbUserId) { if (dbUserId < 0) return false; try { var validDateTime = DateTimeServer.SetValidationDate(FwUpdateConfig.Consts.FwUpdateConfig.ValidDays); var url = ServiceUrls.EditFwUpdateUserValidityServiceUrl(); url += $"{dbUserId}&ValidDate={validDateTime:yyyy-MM-ddTHH:mm:ss}&AccountActive=true"; var requestResponse = LocalWebRequest.GetRequest(url, moderateTimeoutDbRequest); if (string.IsNullOrEmpty(requestResponse)) { DbIsConnected = false; return false; } DbIsConnected = true; // Refresh all DbAllUsersInfos and DbFullQualifiedUsersInfos lists return JsonConvert.DeserializeObject(requestResponse) && GetAllUpdateOperatorsFromDb(); } catch (Exception) { DbIsConnected = false; return false; } } /// /// Set user hw id to DB. This is a direct DB access. The user has to be referenced by the user Id. /// On every refresh the DbAllUsersInfos and DbFullQualifiedUsersInfos lists will be generated /// . /// /// user id as reference /// the hardware identifier as string /// /// - Initial. /// /// /// - Input is user Id and Hw Id as string. Refresh /// - Refresh all DbAllUsersInfos and DbFullQualifiedUsersInfos lists. /// /// /// - Refresh validation date. /// /// /// - Set DB connection state. /// /// /// - timeout to 1200 ms. /// private void RefreshHwIdToDbAndRefreshUserLists(Int32 dbUserId, String dbHwId) { if (dbUserId < 0 || string.IsNullOrEmpty(dbHwId)) return; try { var url = ServiceUrls.RefreshFwUpdateUsersHardwareIdServiceUrl(); url += $"{dbUserId}&HardwareId={dbHwId}"; var requestResponse = LocalWebRequest.GetRequest(url, moderateTimeoutDbRequest); if (string.IsNullOrEmpty(requestResponse)) { DbIsConnected = false; return; } DbIsConnected = true; if (!JsonConvert.DeserializeObject(requestResponse)) return; // Set validation date and refresh all DbAllUsersInfos and DbFullQualifiedUsersInfos lists RefreshValidDateToDbAndRefreshUserLists(dbUserId); } catch (Exception) { DbIsConnected = false; } } /// /// Get all user infos by full name. The user information needed to be fully registered. /// All user infos will be returned. The first user will be taken where the FullName, Domain, LogInName /// HW Id and pwd hash matches and the Id is set. The DbFullQualifiedUsersInfos will be set in advance in /// the and has been verified to be fully qualified. /// /// user name to search for /// user to search for registration in DB with full name only, all contents /// will be filled with the information out of DbFullQualifiedUsersInfos /// /// - true if user is registered in DB and sets all other informational fields, /// - false if the essential fields are missed. /// /// /// - Initial. /// /// /// - Input user name to get at all infos of fully qualified user. /// /// /// - Input user name to search for, /// - UserInformation object will be build here to avoid preset requirements of name. /// public Boolean GetFullQualifiedUserByFullName(String userName, out UserInformation dbFullQualifiedUser) { // The user has to be defined by FullName only. It will be searched in DbFullQualifiedUsersInfos as this // list is already checked for fully qualification. dbFullQualifiedUser = new UserInformation(); if (dbFullQualifiedUser == null || DbFullQualifiedUpdateOperators == null || DbFullQualifiedUpdateOperators.Count == 0 || string.IsNullOrEmpty(userName)) return false; foreach (var user in DbFullQualifiedUpdateOperators.Where(user => user.FullName == userName)) { return CloneUser(dbFullQualifiedUser, user); } return false; } /// /// Get all user infos by full name. User needn't to be be fully registered, but domain, logInName /// and FullName are essential. All user infos will be returned. The first user will be taken where /// the FullName, Domain and LogInName matches and the Id is set. /// /// user to search for registration in DB with full name only /// /// - true if user is registered in DB and sets all other informational fields, /// - false if the essential fields are missed. /// /// /// - Initial. /// /// /// - Input user name to get at least the user id, but all other infos will be returned as well. /// public Boolean GetUserFromAllRegUsersByFullName(UserInformation dbAllRegUserByFullName) { // The user has to be defined by FullName only. It will be searched in DbAllUsersInfos if (dbAllRegUserByFullName == null || DbAllUpdateOperators == null || DbAllUpdateOperators.Count == 0 || string.IsNullOrEmpty(dbAllRegUserByFullName.FullName)) return false; foreach (var user in DbAllUpdateOperators.Where(user => user.FullName == dbAllRegUserByFullName.FullName)) { // Skip all users which do not have set the essential needed elements: Domain, LogInName and FullName. if (string.IsNullOrEmpty(user.Domain) || string.IsNullOrEmpty(user.LogInName)) continue; return CloneUser(dbAllRegUserByFullName, user); } return false; } /// /// Clone user with all contents /// /// /// /// true if users are identical /// /// - Initial. /// public static Boolean CloneUser(UserInformation destinationUser, UserInformation sourceUser) { if (destinationUser == null || sourceUser == null) return false; destinationUser.Id = sourceUser.Id; destinationUser.FullName = sourceUser.FullName; destinationUser.Domain = sourceUser.Domain; destinationUser.LogInName = sourceUser.LogInName; destinationUser.PasswordHash = sourceUser.PasswordHash; destinationUser.HardwareId = sourceUser.HardwareId; destinationUser.RegisterDate = sourceUser.RegisterDate; destinationUser.ValidDate = sourceUser.ValidDate; destinationUser.AccountActive = sourceUser.AccountActive; return true; } /// /// Compare two users with all contents. /// /// /// /// true if users are identical /// /// - Initial. /// public static Boolean UsersAreIdentical(UserInformation user1, UserInformation user2) { return user1.Id == user2.Id && user1.FullName == user2.FullName && user1.Domain == user2.Domain && user1.LogInName == user2.LogInName && user1.PasswordHash == user2.PasswordHash && user1.HardwareId == user2.HardwareId && user1.RegisterDate == user2.RegisterDate && user1.ValidDate == user2.ValidDate && user1.AccountActive == user2.AccountActive; } /// /// Register new user or refresh password hash and Hw Id. /// /// user to search for registration in DB /// true if user is registered in DB /// /// - Initial. /// /// /// - Backup newUserInfo before trying to GetPartialRegisteredUser.. as this overwrites all elements /// and therefor the NEW pwd hash and/or NEW hw id will be lost and couldn't be changed. /// public Boolean UserRegisterOrRefresh(UserInformation newUser) { if (newUser == null) return false; // Use a new dbUser for the search to avoid overwriting of newUserInfo. Copy the minimal elements which are // needed for a registered users: Domain, LogInName and FullName. var dbUser = new UserInformation { FullName = newUser.FullName, Domain = newUser.Domain, LogInName = newUser.LogInName }; // This routine returns at least the needed user id for refresh of pwd hash and hw id. // This user can be in both lists, fully qualified or partial in all users list. if (GetUserFromAllRegUsersByFullName(dbUser)) { // The dbUser has feedback the user id and the newUserInfo contains the info to change. newUser.Id = dbUser.Id; if (!string.IsNullOrEmpty(newUser.PasswordHash) && dbUser.PasswordHash != newUser.PasswordHash) { // The DbAllUsersInfos and DbFullQualifiedUsersInfos will be refreshed. RefreshPwdHashToDbAndRefreshUserLists(newUser.Id, newUser.PasswordHash); } if (!string.IsNullOrEmpty(newUser.HardwareId) && dbUser.HardwareId != newUser.HardwareId) { // The DbAllUsersInfos and DbFullQualifiedUsersInfos will be refreshed. RefreshHwIdToDbAndRefreshUserLists(newUser.Id, newUser.HardwareId); } } // Check if the user is fully qualified! if (CheckIfUpdateOperatorIsFullyQualified(newUser)) { // Set validation date and refresh all DbAllUsersInfos and DbFullQualifiedUsersInfos lists RefreshValidDateToDbAndRefreshUserLists(newUser.Id); return true; } // Or if the user is at least initially set without Hw Id and/ or Pwd Hash if (GetUserFromAllRegUsersByFullName(newUser)) return true; // If the user is unknown, it shall be initially registered. The fields pwd hash and hw id are optional, // but only fully registered users can be used for en- and decryption. This will also refresh the // DbAllUsersInfos and DbFullQualifiedUsersInfos lists. return RegisterUpdateOperatorToDbAndRefreshLists(newUser); } /// /// Refresh actual validation date if FW-Update Safes are existing or create new password hash if not /// to invalidate the old FW-Update Safes. /// /// /// /// true if refresh succeeded /// /// - Initial. /// public Boolean RefreshUserValidation(UserInformation regUser, Boolean keepActualPwdHash) { if (regUser == null || string.IsNullOrEmpty(regUser.FullName)) return false; // All user information shall be set as the user needs to be fully // qualified. This form adds exclusively the FullName of the user, // so that the "FW-Update Builder" operator can select a real user name! var newUser = new UserInformation { FullName = regUser.FullName }; // Keep the password hash as an encrypted container exists if (keepActualPwdHash) { return UserRegisterOrRefresh(regUser); } // create a new password hash to invalidate all previously created password safes CryptInformation.GetSysUser(newUser); return UserRegisterOrRefresh(newUser); } /// /// Download FW update safe referenced by container id /// /// /// true if file content exists /// /// - Initial. /// public List DownloadFwUpdateSafeFromDb(Int32 containerId) { var fwUpdateSafes = new List(); try { var url = ServiceUrls.DownloadFwUpdateSafeServiceUrl(); url += $"{containerId}"; var requestResponse = LocalWebRequest.GetRequest(url, hugeTimeoutDbRequest); if (string.IsNullOrEmpty(requestResponse)) { DbIsConnected = false; return fwUpdateSafes; } DbIsConnected = true; fwUpdateSafes = JsonConvert.DeserializeObject>(requestResponse); return fwUpdateSafes; } catch (Exception) { DbIsConnected = false; return fwUpdateSafes; } } /// /// Download all pcbIds contained in a special FW update safe for information referenced by container id /// /// /// true if file content exists /// /// - Initial. /// public List GetFwUpdateSafePcbIdsFromDb(Int32 containerId) { var fwUpdateSafesPcbIds = new List(); try { var url = ServiceUrls.ListAllPcbIdsFromSafe(); url += $"{containerId}"; var requestResponse = LocalWebRequest.GetRequest(url, hugeTimeoutDbRequest); if (string.IsNullOrEmpty(requestResponse)) { DbIsConnected = false; return fwUpdateSafesPcbIds; } DbIsConnected = true; fwUpdateSafesPcbIds = JsonConvert.DeserializeObject>(requestResponse); return fwUpdateSafesPcbIds; } catch (Exception) { DbIsConnected = false; return fwUpdateSafesPcbIds; } } /// /// Getting file contents referenced by file part id. /// -http://localhost:56011/GetFileContent?FileId=3831 /// /// /// /// true if file content exists /// /// - Initial. /// public Boolean DownloadFileContentFromDb(Int32 filePartId, out Byte[] fileContent) { fileContent = new Byte[] { }; try { var url = ServiceUrls.DownloadFileContentServiceUrl(); url += "{filePartId}"; var requestResponse = LocalWebRequest.GetRequest(url, hugeTimeoutDbRequest); if (string.IsNullOrEmpty(requestResponse)) { DbIsConnected = false; return false; } DbIsConnected = true; fileContent = JsonConvert.DeserializeObject(requestResponse); return fileContent != null && fileContent.Length > 0; } catch (Exception) { DbIsConnected = false; return false; } } /// /// Get reports from DB. /// It can be searched for: /// PCB ID, /// User ID, /// Order Number, /// Read content ( if false, a preview is available only). /// Leaving all empty will search all reports. /// /// list of reports /// optional pcbId /// optional userId /// optional order number /// if false a preview of the reports will be loaded /// true reports could be loaded /// /// - Initial. /// /// /// - Read content. /// public Boolean DownloadFwUpdateReportsFromDb(out List fwUpdRpt, Int64 pcbId = 0, Int32 userId = 0, Int64 orderNr = 0, Boolean readContent = false) { fwUpdRpt = new List(); try { var url = ServiceUrls.DownloadFwUpdateReportServiceUrl(); if (pcbId > 0) { url += $"PcbId={pcbId}"; if (userId > 0) url += $"&UserId={userId}"; if (orderNr > 0) url += $"&OrderNr={orderNr}"; } else if (userId > 0) { url += $"UserId={userId}"; if (orderNr > 0) url += $"&OrderNr={orderNr}"; } else if (orderNr > 0) { url += $"OrderNr={orderNr}"; } url += $"&readContent={readContent}"; var requestResponse = LocalWebRequest.GetRequest(url, hugeTimeoutDbRequest); if (string.IsNullOrEmpty(requestResponse)) { DbIsConnected = false; return false; } DbIsConnected = true; fwUpdRpt = JsonConvert.DeserializeObject>(requestResponse); return fwUpdRpt != null && fwUpdRpt.Count != 0; } catch (Exception) { DbIsConnected = false; return false; } } /// /// Upload the report file to DB. /// /// /// true if file could be uploaded /// /// - Initial. /// /// /// - Changed to FwUpdateReportDb. /// /// /// - DB interface restructured. /// public Boolean UploadFwUpdateReportToDb(FwUpdateReportDb fwUpdRpt) { try { var url = ServiceUrls.UploadFwUpdateReportServiceUrl(); if (LocalWebRequest.PostRequestAsync(url, hugeTimeoutDbRequest, fwUpdRpt)) { DbIsConnected = true; return true; } DbIsConnected = false; return false; } catch (Exception) { DbIsConnected = false; return false; } } /// /// Upload the FW-Update Safe as container to DB. /// /// /// /// true if file could be uploaded /// /// - Initial. /// /// /// - Set container Id, needed to assign PCB IDs. /// public Boolean UploadFwUpdateSafeToDb(FwUpdateSafeDb fwUpdateSafeDb, List pcbIds) { if (fwUpdateSafeDb == null) return false; fwUpdateSafeDb.ContainerId = 0; try { var url = ServiceUrls.UploadFwUpdateSafeContainerServiceUrl(); url += $"?PUserId={fwUpdateSafeDb.UserId}"; url += $"&PFileName={fwUpdateSafeDb.Name}"; url += $"&PValidDate={fwUpdateSafeDb.ValidDate:yyyy-MM-ddTHH:mm:ss}"; url += $"&PBuilderOperatorName={fwUpdateSafeDb.BuilderOperatorName}"; var success = LocalWebRequest.PostBinaryFileRequestAsync(url, fwUpdateSafeDb.Name, fwUpdateSafeDb.Content, out var requestResponse); var containerId = JsonConvert.DeserializeObject(requestResponse); if (success && !string.IsNullOrEmpty(requestResponse) && containerId > 0) { fwUpdateSafeDb.ContainerId = containerId; url = ServiceUrls.AddPcbIdsToSafeServiceUrl(); url += containerId; if (LocalWebRequest.PostRequestAsync(url, hugeTimeoutDbRequest, pcbIds)) { DbIsConnected = true; return true; } } DbIsConnected = false; return false; } catch (Exception) { DbIsConnected = false; return false; } } /// /// Upload installed FW versions and core revision to DB. /// /// /// /// true if apps could be uploaded /// /// - Initial /// /// /// - Changed version from Uint32 to String /// /// /// - timeout to 1200 ms. /// /// /// - changed service url. /// public Boolean UploadCordonelAppVersionsToDb(Int64 pcbId, List apps) { try { var url = ServiceUrls.UploadCordonelAppVersionServiceUrl(); url += $"{pcbId}&ProgressName={Assembly.GetExecutingAssembly().GetName().Name}"; url += $"&version={Assembly.GetExecutingAssembly().GetName().Version}"; if (LocalWebRequest.PostRequestAsync(url, moderateTimeoutDbRequest, apps)) { DbIsConnected = true; return true; } DbIsConnected = false; return false; } catch (Exception) { DbIsConnected = false; return false; } } /// /// Get all installed application versions from DB. /// /// /// /// true if app list could be loaded /// /// - Initial. /// /// /// - Add request for radio version. /// public Boolean DownloadCordonelAppVersionsFromDb(String pcbId, out List apps) { apps = new List(); try { var url = ServiceUrls.DownloadCordonelAppVersionServiceUrl(); url += $"{pcbId}&returnRadioFRQ=true"; var requestResponse = LocalWebRequest.GetRequest(url, hugeTimeoutDbRequest); if (string.IsNullOrEmpty(requestResponse)) { DbIsConnected = false; return false; } DbIsConnected = true; apps = JsonConvert.DeserializeObject>(requestResponse); return apps != null && apps.Count != 0; } catch (Exception) { DbIsConnected = false; return false; } } } }