@page "/credentials" @using System.Linq @using CredentialManager.Models @using CredentialManager.Services @using DataConnection.CredentialManagement.Interfaces @using DataConnection.CredentialManagement.Models @using Microsoft.AspNetCore.Components.Forms @using Microsoft.JSInterop @inject IDataConnectionCredentialService CredentialService @inject IOdbcDsnDiscoveryService OdbcDsnDiscoveryService @inject IJSRuntime JSRuntime @inject NavigationManager Navigation Gestione Credenziali

Gestione Credenziali

@* Controllo per credenziali problematiche *@ @if (hasProblematicCredentials && !loading) { }
@if (loading) {
Caricamento...
} else if (!string.IsNullOrEmpty(errorMessage)) { } else {

Credenziali Database (@databaseCredentials.Count)

@if (databaseCredentials.Any()) {
@foreach (var credential in databaseCredentials) { }
Nome Tipo Database Host:Porta Database Username Azioni
@credential.Name @credential.DatabaseType @credential.Host:@credential.Port @if (string.IsNullOrEmpty(credential.DatabaseName)) { Connessione server } else { @credential.DatabaseName } @credential.Username
} else {
Nessuna credenziale database configurata.
}

Credenziali REST API / Servizi (@restApiCredentials.Count)

@if (restApiCredentials.Any()) {
@foreach (var credential in restApiCredentials) { }
Nome Tipo Servizio Base URL Autenticazione Timeout (s) Azioni
@credential.Name @if (credential.ServiceType == RestServiceType.SapB1ServiceLayer) { SAP B1 } else if (credential.ServiceType == RestServiceType.Salesforce) { Salesforce @if (credential.IsSandbox) { Sandbox } } else { Generic REST } @credential.BaseUrl @GetAuthenticationType(credential) @credential.TimeoutSeconds
} else {
Nessuna credenziale REST API configurata.
}
} @if (showDatabaseModal) { } @if (showRestApiModal) { } @* Modale di Conferma Eliminazione *@ @if (showDeleteConfirmModal) { } @code { private List databaseCredentials = new(); private List restApiCredentials = new(); private bool loading = true; private string? errorMessage = null; private bool testingConnection = false; private bool hasProblematicCredentials = false; // Modal state private bool showDatabaseModal = false; private bool showRestApiModal = false; private bool showDeleteConfirmModal = false; private string? credentialToDeleteName = null; private bool credentialToDeleteIsDatabase = false; private DatabaseCredential? editingDatabaseCredential = null; private RestApiCredential? editingRestApiCredential = null; private DatabaseCredential currentDatabaseCredential = new(); private RestApiCredential currentRestApiCredential = new(); // ODBC specific state private List availableOdbcDsn = new(); private List availableOdbcDrivers = new(); private string selectedOdbcDriver = string.Empty; private bool loadingOdbcData = false; protected override async Task OnInitializedAsync() { await RefreshCredentials(); CheckForProblematicCredentials(); } private async Task RefreshCredentials() { loading = true; errorMessage = null; try { databaseCredentials = await CredentialService.GetAllDatabaseCredentialsAsync(); restApiCredentials = await CredentialService.GetAllRestApiCredentialsAsync(); CheckForProblematicCredentials(); } catch (Exception ex) { errorMessage = $"Errore nel caricamento delle credenziali: {ex.Message}"; // Se l'errore è relativo alla tabella mancante, mostriamo un messaggio più specifico if (ex.Message.Contains("no such table: Credentials")) { errorMessage = "Database non inizializzato correttamente. Riavviare l'applicazione."; } } finally { loading = false; } } #region Database Credential Methods private async Task ShowAddDatabaseModal() { editingDatabaseCredential = null; currentDatabaseCredential = new DatabaseCredential { DatabaseType = CredentialManager.Models.DatabaseType.SqlServer, Port = 1433, CommandTimeout = 30, AdditionalParameters = new Dictionary() }; showDatabaseModal = true; // Se è ODBC, carica i dati automaticamente if (currentDatabaseCredential.DatabaseType == DatabaseType.Odbc) { await LoadOdbcData(); } } private async Task EditDatabaseCredential(DatabaseCredential credential) { editingDatabaseCredential = credential; currentDatabaseCredential = new DatabaseCredential { Name = credential.Name, DatabaseType = credential.DatabaseType, Host = credential.Host, Port = credential.Port, DatabaseName = credential.DatabaseName, Username = credential.Username, Password = credential.Password, CommandTimeout = credential.CommandTimeout, IgnoreSslErrors = credential.IgnoreSslErrors, OdbcDsnName = credential.OdbcDsnName, OdbcMode = credential.OdbcMode, AdditionalParameters = credential.AdditionalParameters != null ? new Dictionary(credential.AdditionalParameters) : new Dictionary() }; // Se è ODBC, carica i dati e ripristina il driver selezionato if (currentDatabaseCredential.DatabaseType == DatabaseType.Odbc) { await LoadOdbcData(); if (currentDatabaseCredential.AdditionalParameters?.ContainsKey("Driver") == true) { selectedOdbcDriver = currentDatabaseCredential.AdditionalParameters["Driver"]; } } showDatabaseModal = true; } private async Task SaveDatabaseCredential() { try { await CredentialService.SaveDatabaseCredentialAsync(currentDatabaseCredential); await JSRuntime.InvokeVoidAsync("alert", "Credenziale database salvata con successo!"); CloseDatabaseModal(); await RefreshCredentials(); } catch (Exception ex) { await JSRuntime.InvokeVoidAsync("alert", $"Errore nel salvare la credenziale: {ex.Message}"); } } private void CloseDatabaseModal() { showDatabaseModal = false; editingDatabaseCredential = null; } private async Task TestDatabaseConnection(DatabaseCredential credential) { try { var (success, message) = await CredentialService.TestDatabaseConnectionAsync(credential.Name); var title = success ? "Test Connessione - Successo" : "Test Connessione - Errore"; await JSRuntime.InvokeVoidAsync("alert", $"{title}\n\n{message}"); } catch (Exception ex) { await JSRuntime.InvokeVoidAsync("alert", $"Errore nel test della connessione: {ex.Message}"); } } private async Task TestCurrentDatabaseConnection() { if (testingConnection) return; testingConnection = true; try { // Validazione base: Nome sempre obbligatorio if (string.IsNullOrEmpty(currentDatabaseCredential.Name)) { await JSRuntime.InvokeVoidAsync("alert", "Il nome della credenziale è obbligatorio."); return; } // Validazione specifica per tipo database if (currentDatabaseCredential.DatabaseType == DatabaseType.Odbc) { // ODBC: Validazione in base alla modalità if (currentDatabaseCredential.OdbcMode == OdbcConnectionMode.Dsn) { // Modalità DSN: richiede DSN selezionato if (string.IsNullOrEmpty(currentDatabaseCredential.OdbcDsnName)) { await JSRuntime.InvokeVoidAsync("alert", "Seleziona un DSN ODBC."); return; } } else { // Modalità Custom: richiede driver e host if (!currentDatabaseCredential.AdditionalParameters?.ContainsKey("Driver") ?? true) { await JSRuntime.InvokeVoidAsync("alert", "Seleziona un driver ODBC."); return; } if (string.IsNullOrEmpty(currentDatabaseCredential.Host)) { await JSRuntime.InvokeVoidAsync("alert", "Inserisci il server/host."); return; } } } else { // Altri database: validazione standard (Host, Username, Password) // Per SQL Server, permetti Windows Authentication (username vuoto o "Integrated") bool isSqlServerWithWindowsAuth = currentDatabaseCredential.DatabaseType == DatabaseType.SqlServer && (string.IsNullOrWhiteSpace(currentDatabaseCredential.Username) || currentDatabaseCredential.Username.Equals("Integrated", StringComparison.OrdinalIgnoreCase) || currentDatabaseCredential.Username.Equals("Windows", StringComparison.OrdinalIgnoreCase)); if (string.IsNullOrEmpty(currentDatabaseCredential.Host)) { await JSRuntime.InvokeVoidAsync("alert", "Il campo Host è obbligatorio."); return; } if (!isSqlServerWithWindowsAuth) { // Per database che non usano Windows Authentication, richiedi username e password if (string.IsNullOrEmpty(currentDatabaseCredential.Username) || string.IsNullOrEmpty(currentDatabaseCredential.Password)) { await JSRuntime.InvokeVoidAsync("alert", "Username e Password sono obbligatori. Per SQL Server con Windows Authentication, inserisci 'Integrated' come username."); return; } } } var (success, message) = await CredentialService.TestDatabaseConnectionAsync(currentDatabaseCredential); var title = success ? "Test Connessione - Successo" : "Test Connessione - Errore"; await JSRuntime.InvokeVoidAsync("alert", $"{title}\n\n{message}"); } catch (Exception ex) { await JSRuntime.InvokeVoidAsync("alert", $"Errore nel test della connessione: {ex.Message}"); } finally { testingConnection = false; } } #region ODBC Methods /// /// Gestisce il cambio di tipo database per caricare le liste ODBC quando necessario /// private async Task OnDatabaseTypeChangedAsync() { // Se è ODBC, carica le liste DSN e driver if (currentDatabaseCredential.DatabaseType == DatabaseType.Odbc) { await LoadOdbcData(); } StateHasChanged(); } /// /// Carica i dati ODBC (DSN e driver disponibili) /// private async Task LoadOdbcData() { if (loadingOdbcData) return; loadingOdbcData = true; try { await Task.Run(() => { try { availableOdbcDsn = OdbcDsnDiscoveryService.GetAllDsn(); availableOdbcDrivers = OdbcDsnDiscoveryService.GetInstalledDrivers(); } catch (Exception ex) { Console.WriteLine($"Errore nel caricamento dati ODBC: {ex.Message}"); availableOdbcDsn = new List(); availableOdbcDrivers = new List(); } }); } finally { loadingOdbcData = false; StateHasChanged(); } } /// /// Ricarica manualmente la lista dei DSN ODBC /// private async Task RefreshOdbcDsnList() { await LoadOdbcData(); await JSRuntime.InvokeVoidAsync("alert", $"Lista DSN aggiornata: {availableOdbcDsn.Count} DSN trovati"); } /// /// Ricarica manualmente la lista dei driver ODBC /// private async Task RefreshOdbcDriverList() { await LoadOdbcData(); await JSRuntime.InvokeVoidAsync("alert", $"Lista driver aggiornata: {availableOdbcDrivers.Count} driver trovati"); } /// /// Genera l'anteprima della stringa di connessione ODBC /// private string GetOdbcConnectionStringPreview() { if (currentDatabaseCredential.DatabaseType != DatabaseType.Odbc) return string.Empty; try { // Salva il driver selezionato nei parametri aggiuntivi temporaneamente if (!string.IsNullOrEmpty(selectedOdbcDriver)) { currentDatabaseCredential.AdditionalParameters ??= new Dictionary(); currentDatabaseCredential.AdditionalParameters["Driver"] = selectedOdbcDriver; } // Usa il metodo di ConnectionStringBuilder per generare la stringa return ConnectionStringBuilder.BuildConnectionString(currentDatabaseCredential); } catch (Exception ex) { return $"Errore nella generazione: {ex.Message}"; } } /// /// Gestisce la selezione di un DSN dalla lista /// private void OnOdbcDsnSelected(ChangeEventArgs e) { var dsnName = e.Value?.ToString(); if (!string.IsNullOrEmpty(dsnName)) { currentDatabaseCredential.OdbcDsnName = dsnName; StateHasChanged(); } } /// /// Gestisce il cambio di modalità ODBC (DSN vs Custom) /// private void OnOdbcModeChanged(ChangeEventArgs e) { if (Enum.TryParse(e.Value?.ToString(), out var mode)) { currentDatabaseCredential.OdbcMode = mode; StateHasChanged(); } } /// /// Ottiene i dettagli di un DSN selezionato /// private OdbcDsnInfo? GetSelectedDsnDetails() { if (string.IsNullOrEmpty(currentDatabaseCredential.OdbcDsnName)) return null; return availableOdbcDsn.FirstOrDefault(dsn => dsn.Name.Equals(currentDatabaseCredential.OdbcDsnName, StringComparison.OrdinalIgnoreCase)); } /// /// Aggiunge un nuovo parametro personalizzato ODBC /// private void AddOdbcCustomParameter() { currentDatabaseCredential.AdditionalParameters ??= new Dictionary(); // Genera un nome univoco per il nuovo parametro var index = 1; var paramName = $"Param{index}"; while (currentDatabaseCredential.AdditionalParameters.ContainsKey(paramName)) { index++; paramName = $"Param{index}"; } currentDatabaseCredential.AdditionalParameters[paramName] = string.Empty; StateHasChanged(); } /// /// Aggiorna la chiave di un parametro personalizzato /// private void UpdateOdbcParameterKey(string oldKey, string newKey) { if (string.IsNullOrWhiteSpace(newKey) || oldKey == newKey) return; if (currentDatabaseCredential.AdditionalParameters == null) return; // Se la nuova chiave esiste già, non fare nulla if (currentDatabaseCredential.AdditionalParameters.ContainsKey(newKey)) { StateHasChanged(); return; } var value = currentDatabaseCredential.AdditionalParameters[oldKey]; currentDatabaseCredential.AdditionalParameters.Remove(oldKey); currentDatabaseCredential.AdditionalParameters[newKey] = value; StateHasChanged(); } /// /// Aggiorna il valore di un parametro personalizzato /// private void UpdateOdbcParameterValue(string key, string value) { if (currentDatabaseCredential.AdditionalParameters == null) return; if (currentDatabaseCredential.AdditionalParameters.ContainsKey(key)) { currentDatabaseCredential.AdditionalParameters[key] = value; StateHasChanged(); } } /// /// Rimuove un parametro personalizzato /// private void RemoveOdbcParameter(string key) { if (currentDatabaseCredential.AdditionalParameters == null) return; // Non permettere la rimozione del parametro Driver if (key == "Driver") return; currentDatabaseCredential.AdditionalParameters.Remove(key); StateHasChanged(); } #endregion #endregion #region REST API Credential Methods private void ShowAddRestApiModal() { editingRestApiCredential = null; currentRestApiCredential = new RestApiCredential { ServiceType = RestServiceType.Generic, TimeoutSeconds = 100 }; SetDefaultsForServiceType(currentRestApiCredential.ServiceType); showRestApiModal = true; } private void EditRestApiCredential(RestApiCredential credential) { editingRestApiCredential = credential; currentRestApiCredential = new RestApiCredential { Name = credential.Name, ServiceType = credential.ServiceType, BaseUrl = credential.BaseUrl, ApiKey = credential.ApiKey, Username = credential.Username, Password = credential.Password, AuthToken = credential.AuthToken, BearerToken = credential.BearerToken, TimeoutSeconds = credential.TimeoutSeconds, IgnoreSslErrors = credential.IgnoreSslErrors, Headers = credential.Headers, AdditionalParameters = credential.AdditionalParameters, // Campi SAP B1 CompanyDatabase = credential.CompanyDatabase, Language = credential.Language, Version = credential.Version, UseTrustedConnection = credential.UseTrustedConnection, // Campi Salesforce SecurityToken = credential.SecurityToken, ClientId = credential.ClientId, ClientSecret = credential.ClientSecret, ApiVersion = credential.ApiVersion, IsSandbox = credential.IsSandbox, UseSoapApi = credential.UseSoapApi, GrantType = credential.GrantType, RefreshToken = credential.RefreshToken, AccessToken = credential.AccessToken, TokenExpiry = credential.TokenExpiry }; showRestApiModal = true; } private async Task SaveRestApiCredential() { try { await CredentialService.SaveRestApiCredentialAsync(currentRestApiCredential); await JSRuntime.InvokeVoidAsync("alert", $"Credenziale {GetServiceTypeDisplayName(currentRestApiCredential.ServiceType)} salvata con successo!"); CloseRestApiModal(); await RefreshCredentials(); } catch (Exception ex) { await JSRuntime.InvokeVoidAsync("alert", $"Errore nel salvare la credenziale: {ex.Message}"); } } private void CloseRestApiModal() { showRestApiModal = false; editingRestApiCredential = null; } private async Task TestRestApiConnection(RestApiCredential credential) { try { var (success, message) = credential.ServiceType switch { RestServiceType.SapB1ServiceLayer => await CredentialService.TestSapB1ConnectionAsync(credential.Name), RestServiceType.Salesforce => await CredentialService.TestSalesforceConnectionAsync(credential.Name), _ => await CredentialService.TestRestApiConnectionAsync(credential.Name) }; var title = success ? $"Test {GetServiceTypeDisplayName(credential.ServiceType)} - Successo" : $"Test {GetServiceTypeDisplayName(credential.ServiceType)} - Errore"; await JSRuntime.InvokeVoidAsync("alert", $"{title}\n\n{message}"); } catch (Exception ex) { await JSRuntime.InvokeVoidAsync("alert", $"Errore nel test della connessione: {ex.Message}"); } } private void OnServiceTypeChanged(ChangeEventArgs e) { if (Enum.TryParse(e.Value?.ToString(), out var serviceType)) { currentRestApiCredential.ServiceType = serviceType; SetDefaultsForServiceType(serviceType); } } private void SetDefaultsForServiceType(RestServiceType serviceType) { switch (serviceType) { case RestServiceType.SapB1ServiceLayer: currentRestApiCredential.Language = "en-US"; currentRestApiCredential.Version = "v1"; currentRestApiCredential.TimeoutSeconds = 300; if (string.IsNullOrEmpty(currentRestApiCredential.BaseUrl)) currentRestApiCredential.BaseUrl = "https://server:50000/b1s/v1/"; break; case RestServiceType.Salesforce: currentRestApiCredential.ApiVersion = "59.0"; currentRestApiCredential.TimeoutSeconds = 120; currentRestApiCredential.IsSandbox = false; currentRestApiCredential.UseSoapApi = false; if (string.IsNullOrEmpty(currentRestApiCredential.BaseUrl)) currentRestApiCredential.BaseUrl = "https://login.salesforce.com"; break; case RestServiceType.Generic: default: currentRestApiCredential.TimeoutSeconds = 100; break; } } private string GetServiceTypeDisplayName(RestServiceType serviceType) { return serviceType switch { RestServiceType.SapB1ServiceLayer => "SAP B1 Service Layer", RestServiceType.Salesforce => "Salesforce", RestServiceType.Generic => "REST API", _ => "REST API" }; } private string GetUrlFieldLabel(RestServiceType serviceType) { return serviceType switch { RestServiceType.SapB1ServiceLayer => "Server URL", RestServiceType.Salesforce => "Login URL", _ => "Base URL" }; } private string GetUrlPlaceholder(RestServiceType serviceType) { return serviceType switch { RestServiceType.SapB1ServiceLayer => "https://server:50000/b1s/v1/", RestServiceType.Salesforce => "https://login.salesforce.com", _ => "https://api.example.com" }; } private string GetUrlHelpText(RestServiceType serviceType) { return serviceType switch { RestServiceType.SapB1ServiceLayer => "URL del SAP B1 Service Layer (esempio: https://server:50000/b1s/v1/)", RestServiceType.Salesforce => "Production: https://login.salesforce.com | Sandbox: https://test.salesforce.com", _ => "URL base del servizio REST API" }; } private void OnSandboxChanged(ChangeEventArgs e) { if (bool.TryParse(e.Value?.ToString(), out bool isSandbox)) { currentRestApiCredential.IsSandbox = isSandbox; currentRestApiCredential.BaseUrl = isSandbox ? "https://test.salesforce.com" : "https://login.salesforce.com"; } } #endregion #region Common Methods private void DeleteCredential(string name, bool isDatabase) { credentialToDeleteName = name; credentialToDeleteIsDatabase = isDatabase; showDeleteConfirmModal = true; } private void CloseDeleteConfirmModal() { showDeleteConfirmModal = false; credentialToDeleteName = null; credentialToDeleteIsDatabase = false; } private async Task ConfirmDeleteCredential() { if (string.IsNullOrEmpty(credentialToDeleteName)) { CloseDeleteConfirmModal(); return; } try { bool success = await CredentialService.DeleteCredentialCascadeAsync(credentialToDeleteName); if (success) { await JSRuntime.InvokeVoidAsync("alert", "Credenziale e tutti i dati associati eliminati con successo!"); CloseDeleteConfirmModal(); await RefreshCredentials(); } else { await JSRuntime.InvokeVoidAsync("alert", "Errore nell'eliminazione della credenziale."); CloseDeleteConfirmModal(); } } catch (Exception ex) { await JSRuntime.InvokeVoidAsync("alert", $"Errore nell'eliminazione: {ex.Message}"); CloseDeleteConfirmModal(); } } private string GetAuthenticationType(RestApiCredential credential) { if (!string.IsNullOrEmpty(credential.ApiKey)) return "API Key"; if (!string.IsNullOrEmpty(credential.AuthToken)) return "Auth Token"; if (!string.IsNullOrEmpty(credential.Username)) return "Basic Auth"; return "Nessuna"; } private async Task TestRestApiConnectionFromModal() { try { testingConnection = true; // Creiamo una credenziale temporanea per il test var tempCredential = new RestApiCredential { Name = $"temp_test_{Guid.NewGuid():N}", ServiceType = currentRestApiCredential.ServiceType, BaseUrl = currentRestApiCredential.BaseUrl, Username = currentRestApiCredential.Username, Password = currentRestApiCredential.Password, ApiKey = currentRestApiCredential.ApiKey, AuthToken = currentRestApiCredential.AuthToken, TimeoutSeconds = currentRestApiCredential.TimeoutSeconds, IgnoreSslErrors = currentRestApiCredential.IgnoreSslErrors, // Campi SAP B1 CompanyDatabase = currentRestApiCredential.CompanyDatabase, Version = currentRestApiCredential.Version, Language = currentRestApiCredential.Language, UseTrustedConnection = currentRestApiCredential.UseTrustedConnection, // Campi Salesforce SecurityToken = currentRestApiCredential.SecurityToken, ClientId = currentRestApiCredential.ClientId, ClientSecret = currentRestApiCredential.ClientSecret, ApiVersion = currentRestApiCredential.ApiVersion, IsSandbox = currentRestApiCredential.IsSandbox, UseSoapApi = currentRestApiCredential.UseSoapApi, GrantType = currentRestApiCredential.GrantType }; // Salviamo temporaneamente la credenziale per il test await CredentialService.SaveRestApiCredentialAsync(tempCredential); // Testiamo la connessione var (success, message) = await CredentialService.TestRestApiConnectionAsync(tempCredential.Name); // Rimuoviamo la credenziale temporanea await CredentialService.DeleteRestApiCredentialAsync(tempCredential.Name); var title = success ? "Test Connessione - Successo" : "Test Connessione - Errore"; await JSRuntime.InvokeVoidAsync("alert", $"{title}\n\n{message}"); } catch (Exception ex) { await JSRuntime.InvokeVoidAsync("alert", $"Errore nel test della connessione: {ex.Message}"); } finally { testingConnection = false; } } private bool IsFieldRequired(string fieldName, RestServiceType serviceType) { return (fieldName, serviceType) switch { ("Username", RestServiceType.Generic) => string.IsNullOrEmpty(currentRestApiCredential.ApiKey) && string.IsNullOrEmpty(currentRestApiCredential.AuthToken), ("Password", RestServiceType.Generic) => string.IsNullOrEmpty(currentRestApiCredential.ApiKey) && string.IsNullOrEmpty(currentRestApiCredential.AuthToken), ("Username", RestServiceType.SapB1ServiceLayer) => !currentRestApiCredential.UseTrustedConnection, ("Password", RestServiceType.SapB1ServiceLayer) => !currentRestApiCredential.UseTrustedConnection, ("CompanyDatabase", RestServiceType.SapB1ServiceLayer) => true, ("Username", RestServiceType.Salesforce) => true, ("Password", RestServiceType.Salesforce) => true, ("SecurityToken", RestServiceType.Salesforce) => string.IsNullOrEmpty(currentRestApiCredential.ClientId) && string.IsNullOrEmpty(currentRestApiCredential.ClientSecret), _ => false }; } private string GetFieldLabel(string fieldName, RestServiceType serviceType) { var label = (fieldName, serviceType) switch { ("Username", RestServiceType.SapB1ServiceLayer) => "Username", ("Password", RestServiceType.SapB1ServiceLayer) => "Password", ("CompanyDatabase", RestServiceType.SapB1ServiceLayer) => "Company Database", ("Username", RestServiceType.Salesforce) => "Username", ("Password", RestServiceType.Salesforce) => "Password", ("SecurityToken", RestServiceType.Salesforce) => "Security Token", _ => fieldName }; return IsFieldRequired(fieldName, serviceType) ? $"{label} *" : label; } /// /// Verifica se ci sono credenziali che non possono essere decrittografate /// private void CheckForProblematicCredentials() { try { hasProblematicCredentials = false; // Verifica credenziali database foreach (var dbCred in databaseCredentials) { if (HasProblematicPassword(dbCred.Password)) { hasProblematicCredentials = true; break; } } // Verifica credenziali REST API se non trovate problematiche if (!hasProblematicCredentials) { foreach (var restCred in restApiCredentials) { if (HasProblematicPassword(restCred.Password) || HasProblematicPassword(restCred.ApiKey) || HasProblematicPassword(restCred.AuthToken) || HasProblematicPassword(restCred.ClientSecret)) { hasProblematicCredentials = true; break; } } } StateHasChanged(); } catch (Exception ex) { // Log dell'errore, ma non bloccare l'interfaccia Console.WriteLine($"Errore nella verifica delle credenziali problematiche: {ex.Message}"); } } /// /// Verifica se una password indica un problema di decrittografia /// private bool HasProblematicPassword(string? password) { return !string.IsNullOrEmpty(password) && (password.Contains("*** CREDENZIALI NON DISPONIBILI") || password.Contains("*** ERRORE DECRITTOGRAFIA ***")); } #endregion }