Start interagtion of new API Class

This commit is contained in:
TheJoKlLa 2022-05-16 16:07:33 +02:00
parent 0d5ad01496
commit 4f3521eec3
27 changed files with 224 additions and 763 deletions

View File

@ -87,6 +87,10 @@
<None Include="Properties\AndroidManifest.xml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\FabAccessAPI\FabAccessAPI.csproj">
<Project>{3251FCE9-FEA3-4662-8BEB-636BE6732D48}</Project>
<Name>FabAccessAPI</Name>
</ProjectReference>
<ProjectReference Include="..\Borepin\Borepin.csproj">
<Project>{F93856BD-0C8D-4469-A8DB-6E513002BFD7}</Project>
<Name>Borepin</Name>

View File

@ -1,6 +1,7 @@
using Borepin.Droid.Services;
using Borepin.Service.Storage;
using Borepin.Service.Versioning;
using FabAccessAPI;
using Prism;
using Prism.Ioc;
@ -13,6 +14,8 @@ namespace Borepin.Droid
containerRegistry.Register<IPreferenceStorageService, PreferenceStorageService>();
containerRegistry.Register<ISecretStorageService, SecretStorage>();
containerRegistry.Register<IVersioningService, VersioningService>();
containerRegistry.RegisterSingleton<IAPI, API>();
}
}
}

View File

@ -184,6 +184,10 @@
<PackageReference Include="Xamarin.Essentials" Version="1.7.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\FabAccessAPI\FabAccessAPI.csproj">
<Project>{3251FCE9-FEA3-4662-8BEB-636BE6732D48}</Project>
<Name>FabAccessAPI</Name>
</ProjectReference>
<ProjectReference Include="..\Borepin\Borepin.csproj">
<Project>{64ED6CAA-99A0-4EC4-B976-DCBD571F05D7}</Project>
<Name>Borepin</Name>

View File

@ -3,6 +3,7 @@ using Prism;
using Prism.Ioc;
using Borepin.Service.Storage;
using Borepin.Service.Versioning;
using FabAccessAPI;
namespace Borepin.UWP
{
@ -13,6 +14,8 @@ namespace Borepin.UWP
containerRegistry.Register<IPreferenceStorageService, PreferenceStorageService>();
containerRegistry.Register<ISecretStorageService, SecretStorageService>();
containerRegistry.Register<IVersioningService, VersioningService>();
containerRegistry.RegisterSingleton<IAPI, API>();
}
}
}

View File

@ -192,6 +192,10 @@
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
<ItemGroup>
<ProjectReference Include="..\..\FabAccessAPI\FabAccessAPI.csproj">
<Project>{3251FCE9-FEA3-4662-8BEB-636BE6732D48}</Project>
<Name>FabAccessAPI</Name>
</ProjectReference>
<ProjectReference Include="..\Borepin\Borepin.csproj">
<Project>{F93856BD-0C8D-4469-A8DB-6E513002BFD7}</Project>
<Name>Borepin</Name>

View File

@ -1,6 +1,7 @@
using Borepin.iOS.Services;
using Borepin.Service.Storage;
using Borepin.Service.Versioning;
using FabAccessAPI;
using Prism;
using Prism.Ioc;
@ -13,6 +14,8 @@ namespace Borepin.iOS
containerRegistry.Register<IPreferenceStorageService, PreferenceStorageService>();
containerRegistry.Register<ISecretStorageService, SecretStorageService>();
containerRegistry.Register<IVersioningService, VersioningService>();
containerRegistry.RegisterSingleton<IAPI, API>();
}
}
}

View File

@ -4,7 +4,6 @@ using Borepin.Page;
using Xamarin.Forms;
using Borepin.Dialog;
using Borepin.DialogModel;
using Borepin.Service.BFFH;
using Prism;
using Borepin.Page.SetUpProcess;
using Borepin.PageModel.SetUpProcess;
@ -12,6 +11,7 @@ using Borepin.Page.AddServerProcess;
using Borepin.PageModel.AddServerProcess;
using System;
using Prism.Navigation;
using Borepin.Service.Storage;
namespace Borepin
{
@ -65,7 +65,13 @@ namespace Borepin
#endregion
#region Register Service
containerRegistry.RegisterSingleton<IBFFHService, BFFHService>();
containerRegistry.RegisterSingleton<ILoginStorageService, LoginStorageService>();
// NEED PLATFORM SPECIFIC SERVICE
// IPreferenceStorageService
// ISecretStorageService
// IVersioningService
// IAPI
#endregion
}
}

View File

@ -1,7 +0,0 @@
namespace Borepin.Model
{
public enum AuthenticationTyp
{
PLAIN,
}
}

View File

@ -1,12 +0,0 @@
using System;
namespace Borepin.Model
{
public class BFFHInstance
{
public Uri Address { get; set; }
public string Name { get; set; } = "";
public string Description { get; set; } = "";
}
}

View File

@ -1,78 +0,0 @@
using System;
using System.Collections.Generic;
namespace Borepin.Model
{
/// <summary>
/// Class to contain all Information about a Connection
/// </summary>
public class Connection
{
#region Constructors
public Connection()
{
Address = new Uri("http://127.0.0.1:59661");
}
public Connection(Connection connection)
{
ConnectionTyp = connection.ConnectionTyp;
AuthenticationTyp = connection.AuthenticationTyp;
Address = connection.Address;
Username = connection.Username;
LastTime = connection.LastTime;
}
#endregion
#region Members
/// <summary>
/// Type of Connection
/// </summary>
public ConnectionTyp ConnectionTyp { get; set; } = ConnectionTyp.SINGLE;
/// <summary>
/// Type of Authentication
/// </summary>
public AuthenticationTyp AuthenticationTyp { get; set; } = AuthenticationTyp.PLAIN;
/// <summary>
/// Address to Host
/// </summary>
public Uri Address { get; set; }
/// <summary>
/// Username for Connection
/// </summary>
public string Username { get; set; } = "";
/// <summary>
/// Last Timestamp connection was successfully established
/// </summary>
public DateTime LastTime { get; set; }
#endregion
#region Methods
#region Equals and HashCode
public override bool Equals(object obj)
{
return obj is Connection connection &&
EqualityComparer<Uri>.Default.Equals(Address, connection.Address) &&
string.Equals(Username, connection.Username, StringComparison.Ordinal) &&
ConnectionTyp == connection.ConnectionTyp &&
AuthenticationTyp == connection.AuthenticationTyp;
}
public override int GetHashCode()
{
int hashCode = -904541792;
hashCode = hashCode * -1521134295 + EqualityComparer<Uri>.Default.GetHashCode(Address);
hashCode = hashCode * -1521134295 + LastTime.GetHashCode();
hashCode = hashCode * -1521134295 + StringComparer.Ordinal.GetHashCode(Username);
hashCode = hashCode * -1521134295 + ConnectionTyp.GetHashCode();
hashCode = hashCode * -1521134295 + AuthenticationTyp.GetHashCode();
return hashCode;
}
#endregion
#endregion
}
}

View File

@ -1,8 +0,0 @@
namespace Borepin.Model
{
public enum ConnectionTyp
{
SINGLE,
FEDERATED,
}
}

View File

@ -1,19 +0,0 @@
namespace Borepin.Model
{
public class Connection_Plain : Connection
{
#region Constructors
public Connection_Plain(Connection connection) : base(connection)
{
}
#endregion
#region Members
/// <summary>
/// Password for Connection
/// </summary>
public string Password { get; set; } = "";
#endregion
}
}

View File

@ -1,7 +0,0 @@
namespace Borepin.Model
{
public class ListItem
{
public string Value1 { get; set; }
}
}

View File

@ -1,76 +0,0 @@
using System;
using System.Globalization;
using System.Threading.Tasks;
using Borepin.Service.Storage;
using Borepin.Service.Storage.Exceptions;
namespace Borepin.Model.Storage
{
/// <summary>
/// Store Credentials for Connection in SecureStorageService
/// </summary>
public class ConnectionCredentialStorage
{
#region Private Fields
private readonly ISecretStorageService _SecretStorageService;
#endregion
#region Constructors
public ConnectionCredentialStorage(ISecretStorageService secretService)
{
_SecretStorageService = secretService;
}
#endregion
#region Methods
/// <summary>
/// Get Password for Connection from SecureStorageService
/// </summary>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="MissingConnectionException"></exception>
public async Task<string> GetPassword(Connection connection)
{
if (connection.AuthenticationTyp != AuthenticationTyp.PLAIN)
{
throw new ArgumentException("AuthenticationTyp is not PLAIN", nameof(connection));
}
string password = await _SecretStorageService.GetAsync(string.Format(CultureInfo.InvariantCulture, "bffh_password_{0}_{1}", connection.Address.ToString(), connection.Username)).ConfigureAwait(false);
if (password == null)
{
throw new MissingConnectionException();
}
return password;
}
/// <summary>
/// Add Password for Connection to SecureStorageService
/// </summary>
public async Task AddCredentials(Connection connection, string password)
{
await _SecretStorageService.SetAsync(string.Format(CultureInfo.InvariantCulture, "bffh_password_{0}_{1}", connection.Address.ToString(), connection.Username), password).ConfigureAwait(false);
}
/// <summary>
/// Remove Password for Connection from SecureStorageService
/// </summary>
public Task RemoveCredentials(Connection connection)
{
_SecretStorageService.Remove(string.Format(CultureInfo.InvariantCulture, "bffh_password_{0}_{1}", connection.Address.ToString(), connection.Username));
return Task.CompletedTask;
}
/// <summary>
/// Remove all Connections from SecureStorage
/// </summary>
public Task RemoveAllCredentials()
{
_SecretStorageService.RemoveAll();
return Task.CompletedTask;
}
#endregion
}
}

View File

@ -1,135 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Borepin.Service.Storage;
using Borepin.Service.Storage.Exceptions;
using Newtonsoft.Json;
namespace Borepin.Model.Storage
{
/// <summary>
/// Store Connection in PreferenceStorageService
/// </summary>
public class ConnectionStorage
{
#region Private Fields
private readonly IPreferenceStorageService _PreferenceService;
#endregion
#region Constructors
public ConnectionStorage(IPreferenceStorageService preferenceService)
{
_PreferenceService = preferenceService;
}
#endregion
#region Methods
/// <summary>
/// Get Connection List from Storage
/// </summary>
/// <returns></returns>
public Task<IList<Connection>> GetConnectionList()
{
return Task.FromResult(_LoadConnectionFormStorage());
}
/// <summary>
/// Add Connection to Storage
/// </summary>
/// <exception cref="DuplicateConnectionException"></exception>
public Task<bool> AddConnection(Connection connection)
{
IList<Connection> connection_list = _LoadConnectionFormStorage();
if (connection_list.Contains(connection))
{
throw new DuplicateConnectionException();
}
connection_list.Add(connection);
_SaveConnectionToStorage(connection_list);
return Task.FromResult(true);
}
/// <summary>
/// Remove Connection from Storage
/// </summary>
public Task<bool> RemoveConnection(Connection connection)
{
IList<Connection> connection_list = _LoadConnectionFormStorage();
if (!connection_list.Contains(connection))
{
throw new MissingConnectionException();
}
while(connection_list.Contains(connection))
{
connection_list.Remove(connection);
}
_SaveConnectionToStorage(connection_list);
return Task.FromResult(true);
}
/// <summary>
/// Remove All Connection from Storage
/// </summary>
public Task<bool> RemoveAllConnections()
{
_SaveConnectionToStorage(new List<Connection>());
return Task.FromResult(true);
}
/// <summary>
/// Update Connections Timestamp in Storage
/// </summary>
/// <exception cref="MissingConnectionException"></exception>
public Task<bool> UpdateConnectionTimestamp(Connection connection)
{
IList<Connection> connection_list = _LoadConnectionFormStorage();
if (!connection_list.Contains(connection))
{
throw new MissingConnectionException();
}
int index = connection_list.IndexOf(connection);
Connection connection_update = connection_list[index];
connection_update.LastTime = DateTime.UtcNow;
connection_list[index] = connection_update;
_SaveConnectionToStorage(connection_list);
return Task.FromResult(true);
}
#endregion
#region Private Methodss
private IList<Connection> _LoadConnectionFormStorage()
{
List<Connection> connection_list;
try
{
connection_list = JsonConvert.DeserializeObject<List<Connection>>(_PreferenceService.Get("connection_list", "[]"));
}
catch (JsonSerializationException)
{
connection_list = new List<Connection>();
_PreferenceService.Set("connection_list", JsonConvert.SerializeObject(connection_list));
}
return connection_list;
}
private void _SaveConnectionToStorage(IList<Connection> connection_list)
{
_PreferenceService.Set("connection_list", JsonConvert.SerializeObject(connection_list));
}
#endregion
}
}

View File

@ -1,22 +0,0 @@
using System;
namespace Borepin.Model.Storage.Exceptions
{
public class MissingCredentialsException : Exception
{
public MissingCredentialsException()
{
}
public MissingCredentialsException(string message) : base(message)
{
}
public MissingCredentialsException(string message, Exception inner) : base(message, inner)
{
}
}
}

View File

@ -1,287 +0,0 @@
using System;
using Borepin.Model;
using System.Threading.Tasks;
using System.Collections.Generic;
using FabAccessAPI.Schema;
using Borepin.Service.Storage;
using Borepin.Model.Storage;
using Borepin.Service.BFFH.Exceptions;
using Borepin.Service.Storage.Exceptions;
using Capnp.Rpc;
using FabAccessAPI.Exceptions;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
using System.Security.Authentication;
using FabAccessAPI;
namespace Borepin.Service.BFFH
{
public class BFFHService : IBFFHService
{
#region Private Fields
private readonly ConnectionStorage _ConnectionStorage;
private readonly ConnectionCredentialStorage _ConnectionCredentialStorage;
private Connection_Plain _CurrentConnection;
#endregion
#region Constructors
public BFFHService(IPreferenceStorageService preferenceStorageService, ISecretStorageService secretStorageService)
{
_ConnectionStorage = new ConnectionStorage(preferenceStorageService);
_ConnectionCredentialStorage = new ConnectionCredentialStorage(secretStorageService);
}
#endregion
#region Fields
/// <summary>
/// API Connection
/// </summary>
public API API { get; private set; }
#endregion
#region Method
/// <summary>
/// Get all known Connections from Storage
/// </summary>
public async Task<IList<Connection>> GetConnections()
{
return await _ConnectionStorage.GetConnectionList().ConfigureAwait(false);
}
/// <summary>
/// Remove Connection from Storage
/// </summary>
public async Task RemoveConnection(Connection connection)
{
if (API != null && API.IsConnected && connection.Equals(_CurrentConnection))
{
await Disconnect().ConfigureAwait(false);
}
try
{
await _ConnectionCredentialStorage.RemoveCredentials(connection).ConfigureAwait(false);
}
catch (KeyNotFoundException)
{
}
try
{
await _ConnectionStorage.RemoveConnection(connection).ConfigureAwait(false);
}
catch (KeyNotFoundException)
{
}
}
/// <summary>
/// Test a if a Server is reachable
/// </summary>
public async Task<bool> TestConnection(Connection connection)
{
try
{
TcpRpcClient rpcClient = await _ConnectAsync(connection.Address.Host, connection.Address.Port).ConfigureAwait(false);
rpcClient.Dispose();
return true;
}
catch
{
return false;
}
}
/// <summary>
/// Connects to Server with Credential from ConnectionCredentialStorage
/// </summary>
/// <exception cref="AllreadyConnectedException"></exception>
/// <exception cref="MissingCredentialsException"></exception>
/// <exception cref="ConnectingFailedException"></exception>
/// <exception cref="AuthenticatingFailedException"></exception>
public async Task Connect(Connection connection)
{
string password;
try
{
password = await _ConnectionCredentialStorage.GetPassword(connection).ConfigureAwait(false);
}
catch (KeyNotFoundException)
{
await _ConnectionCredentialStorage.RemoveAllCredentials().ConfigureAwait(false);
await _ConnectionStorage.RemoveAllConnections().ConfigureAwait(false);
throw new MissingCredentialsException();
}
try
{
TcpRpcClient rpcClient = await _ConnectAsync(connection.Address.Host, connection.Address.Port).ConfigureAwait(false);
_APIConnection = new FabAccessAPI.Connection(rpcClient);
}
catch (RpcException exception) when (string.Equals(exception.Message, "TcpRpcClient is unable to connect", StringComparison.Ordinal))
{
throw new ConnectingFailedException("Connecting failed", exception);
}
if (! await _AuthenticatePlainAsync(connection.Username, password).ConfigureAwait(false))
{
await Disconnect().ConfigureAwait(false);
}
_CurrentConnection = new Connection_Plain(connection)
{
Password = password,
};
await _ConnectionStorage.UpdateConnectionTimestamp(_CurrentConnection).ConfigureAwait(false);
}
/// <summary>
/// Connects to Server with Password
/// Connection is saved to Storage if connecting was successfuss
/// </summary>
/// <exception cref="AllreadyConnectedException"></exception>
/// <exception cref="MissingCredentialsException"></exception>
/// <exception cref="ConnectingFailedException"></exception>
/// <exception cref="AuthenticatingFailedException"></exception>
public async Task Connect(Connection connection, string password)
{
try
{
TcpRpcClient rpcClient = await _ConnectAsync(connection.Address.Host, connection.Address.Port).ConfigureAwait(false);
_APIConnection = new FabAccessAPI.Connection(rpcClient);
}
catch (RpcException exception) when (string.Equals(exception.Message, "TcpRpcClient is unable to connect", StringComparison.Ordinal))
{
throw new ConnectingFailedException("Connecting failed", exception);
}
if (!await _AuthenticatePlainAsync(connection.Username, password).ConfigureAwait(false))
{
await Disconnect().ConfigureAwait(false);
}
_CurrentConnection = new Connection_Plain(connection)
{
Password = password,
};
try
{
await _ConnectionStorage.AddConnection(_CurrentConnection).ConfigureAwait(false);
}
catch(DuplicateConnectionException)
{
}
await _ConnectionCredentialStorage.AddCredentials(_CurrentConnection, password).ConfigureAwait(false);
await _ConnectionStorage.UpdateConnectionTimestamp(_CurrentConnection).ConfigureAwait(false);
}
/// <summary>
/// Reconnects to server if connection has lost
/// </summary>
/// <exception cref="InvalidOperationException"></exception>
/// <exception cref="ReconnectingFailedException"></exception>
public async Task Reconnect()
{
if (IsConnected || _CurrentConnection == null)
{
throw new InvalidOperationException();
}
try
{
TcpRpcClient rpcClient = await _ConnectAsync(_CurrentConnection.Address.Host, _CurrentConnection.Address.Port).ConfigureAwait(false);
_APIConnection = new FabAccessAPI.Connection(rpcClient);
}
catch
{
}
}
/// <summary>
/// Disconnects from Server
/// </summary>
/// <returns></returns>
public Task Disconnect()
{
if (IsConnected)
{
_APIConnection.RpcClient?.Dispose();
}
_APIConnection = null;
_CurrentConnection = null;
return Task.CompletedTask;
}
#region FabAccess API Systems
public async Task<Session> GetSession()
{
if (!IsConnected)
{
await Reconnect().ConfigureAwait(false);
}
return _APIConnection.Session;
}
#endregion
#endregion
#region Private Methods
private static bool RemoteCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
return true;
}
private async Task<TcpRpcClient> _ConnectAsync(string host, int port)
{
TcpRpcClient rpcClient = new TcpRpcClient();
rpcClient.InjectMidlayer((tcpstream) =>
{
var sslStream = new SslStream(tcpstream, false, new RemoteCertificateValidationCallback(RemoteCertificateValidationCallback));
try
{
sslStream.AuthenticateAsClient("bffhd");
return sslStream;
}
catch (AuthenticationException)
{
sslStream.Close();
throw;
}
});
rpcClient.Connect(host, port);
await rpcClient.WhenConnected.ConfigureAwait(false);
return rpcClient;
}
private async Task<bool> _AuthenticatePlainAsync(string username, string password)
{
try
{
await _APIConnection.Auth("PLAIN", new Dictionary<string, object>(StringComparer.Ordinal) { { "Username", username }, { "Password", password } }).ConfigureAwait(false);
return await Task.FromResult(true).ConfigureAwait(false);
}
catch(UnsupportedMechanismException)
{
return await Task.FromResult(true).ConfigureAwait(false);
}
}
#endregion
}
}

View File

@ -1,22 +0,0 @@
using System;
namespace Borepin.Service.BFFH.Exceptions
{
public class MissingCredentialsException : Exception
{
public MissingCredentialsException()
{
}
public MissingCredentialsException(string message) : base(message)
{
}
public MissingCredentialsException(string message, Exception inner) : base(message, inner)
{
}
}
}

View File

@ -1,22 +0,0 @@
using System;
namespace Borepin.Service.BFFH.Exceptions
{
public class ReconnectingFailedException : Exception
{
public ReconnectingFailedException()
{
}
public ReconnectingFailedException(string message) : base(message)
{
}
public ReconnectingFailedException(string message, Exception inner) : base(message, inner)
{
}
}
}

View File

@ -1,27 +0,0 @@
using Borepin.Model;
using FabAccessAPI.Schema;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Borepin.Service.BFFH
{
public interface IBFFHService
{
Connection CurrentConnection { get; }
bool IsConnected { get; }
Task<IList<Connection>> GetConnections();
Task RemoveConnection(Connection connection);
Task<bool> TestConnection(Connection connection);
Task Connect(Connection connection);
Task Connect(Connection connection, string password);
Task Reconnect();
Task Disconnect();
Task<Session> GetSession();
}
}

View File

@ -1,22 +1,24 @@
using System;
using FabAccessAPI;
using System;
namespace Borepin.Service.Storage.Exceptions
{
public class DuplicateConnectionException : Exception
{
public DuplicateConnectionException()
public readonly ConnectionData ConnectionData;
public DuplicateConnectionException(ConnectionData connectionData)
{
ConnectionData = connectionData;
}
public DuplicateConnectionException(string message) : base(message)
public DuplicateConnectionException(ConnectionData connectionData, string message) : base(message)
{
ConnectionData = connectionData;
}
public DuplicateConnectionException(string message, Exception inner) : base(message, inner)
public DuplicateConnectionException(ConnectionData connectionData, string message, Exception inner) : base(message, inner)
{
ConnectionData = connectionData;
}
}
}

View File

@ -0,0 +1,26 @@
using FabAccessAPI;
using System;
namespace Borepin.Service.Storage.Exceptions
{
[Serializable]
internal class InvalidConnectionExceptoin : Exception
{
public readonly ConnectionData ConnectionData;
public InvalidConnectionExceptoin(ConnectionData connectionData)
{
ConnectionData = connectionData;
}
public InvalidConnectionExceptoin(ConnectionData connectionData, string message) : base(message)
{
ConnectionData = connectionData;
}
public InvalidConnectionExceptoin(ConnectionData connectionData, string message, Exception innerException) : base(message, innerException)
{
ConnectionData = connectionData;
}
}
}

View File

@ -1,22 +1,24 @@
using System;
using FabAccessAPI;
using System;
namespace Borepin.Service.Storage.Exceptions
{
public class MissingConnectionException : Exception
{
public MissingConnectionException()
public readonly ConnectionData ConnectionData;
public MissingConnectionException(ConnectionData connectionData)
{
ConnectionData = connectionData;
}
public MissingConnectionException(string message) : base(message)
public MissingConnectionException(ConnectionData connectionData, string message) : base(message)
{
ConnectionData = connectionData;
}
public MissingConnectionException(string message, Exception inner) : base(message, inner)
public MissingConnectionException(ConnectionData connectionData, string message, Exception inner) : base(message, inner)
{
ConnectionData = connectionData;
}
}
}

View File

@ -0,0 +1,14 @@
using FabAccessAPI;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Borepin.Service.Storage
{
public interface ILoginStorageService
{
Task<IList<ConnectionData>> GetList();
Task Add(ConnectionData connectionData);
Task Remove(ConnectionData connectionData);
Task UpdateTimestamp(ConnectionData connectionData);
}
}

View File

@ -0,0 +1,112 @@
using Borepin.Service.Storage.Exceptions;
using FabAccessAPI;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Borepin.Service.Storage
{
public class LoginStorageService : ILoginStorageService
{
#region Static Members
const string StorageKey = "ConnectionData";
#endregion
#region Private Members
private readonly ISecretStorageService _SecretStorageService;
#endregion
#region Constructors
public LoginStorageService(ISecretStorageService secretStorageService)
{
_SecretStorageService = secretStorageService;
}
#endregion
#region Methods
public async Task<IList<ConnectionData>> GetList()
{
return await _LoadConnectionData().ConfigureAwait(false);
}
public async Task Add(ConnectionData connectionData)
{
if (connectionData.Host.Host == string.Empty || connectionData.Username == string.Empty)
{
throw new InvalidConnectionExceptoin(connectionData);
}
IList<ConnectionData> connectionData_List = await _LoadConnectionData().ConfigureAwait(false);
if(connectionData_List.Contains(connectionData))
{
throw new DuplicateConnectionException(connectionData);
}
connectionData_List.Add(connectionData);
await _SaveConnectionData(connectionData_List).ConfigureAwait(false);
}
public async Task Remove(ConnectionData connectionData)
{
if (connectionData.Host.Host == string.Empty || connectionData.Username == string.Empty)
{
throw new InvalidConnectionExceptoin(connectionData);
}
IList<ConnectionData> connectionData_List = await _LoadConnectionData().ConfigureAwait(false);
if (connectionData_List.Contains(connectionData))
{
throw new MissingConnectionException(connectionData);
}
connectionData_List.Remove(connectionData);
await _SaveConnectionData(connectionData_List).ConfigureAwait(false);
}
public async Task UpdateTimestamp(ConnectionData connectionData)
{
if (connectionData.Host.Host == string.Empty || connectionData.Username == string.Empty)
{
throw new InvalidConnectionExceptoin(connectionData);
}
IList<ConnectionData> connectionData_List = await _LoadConnectionData().ConfigureAwait(false);
if (connectionData_List.Contains(connectionData))
{
throw new MissingConnectionException(connectionData);
}
connectionData.LastTime = DateTime.UtcNow;
connectionData_List.Remove(connectionData);
connectionData_List.Add(connectionData);
await _SaveConnectionData(connectionData_List).ConfigureAwait(false);
}
#endregion
#region Private Methods
private async Task<IList<ConnectionData>> _LoadConnectionData()
{
List<ConnectionData> connectionData_List;
try
{
string data = await _SecretStorageService.GetAsync(StorageKey).ConfigureAwait(false);
connectionData_List = JsonConvert.DeserializeObject<List<ConnectionData>>(data);
}
catch (JsonSerializationException)
{
connectionData_List = new List<ConnectionData>();
await _SecretStorageService.SetAsync(StorageKey, JsonConvert.SerializeObject(connectionData_List)).ConfigureAwait(false);
}
return connectionData_List;
}
private async Task _SaveConnectionData(IList<ConnectionData> connectionData_List)
{
string data = JsonConvert.SerializeObject(connectionData_List);
await _SecretStorageService.SetAsync(StorageKey, data).ConfigureAwait(false);
}
#endregion
}
}

View File

@ -119,11 +119,7 @@ namespace FabAccessAPI
ConnectionData = null;
ConnectionInfo = null;
EventHandler<ConnectionStatusChange> eventHandler = ConnectionStatusChanged;
if (eventHandler != null)
{
eventHandler(this, ConnectionStatusChange.Disconnected);
}
ConnectionStatusChanged?.Invoke(this, ConnectionStatusChange.Disconnected);
return Task.CompletedTask;
}
@ -135,11 +131,7 @@ namespace FabAccessAPI
await Connect(ConnectionData);
}
EventHandler<ConnectionStatusChange> eventHandler = ConnectionStatusChanged;
if (eventHandler != null)
{
eventHandler(this, ConnectionStatusChange.Reconnected);
}
ConnectionStatusChanged?.Invoke(this, ConnectionStatusChange.Reconnected);
}
public async Task<ConnectionInfo> TestConnection(ConnectionData connectionData, TcpRpcClient tcpRpcClient = null)
@ -172,7 +164,7 @@ namespace FabAccessAPI
/// Validate Certificate
/// TODO: Do some validation
/// </summary>
private static bool RemoteCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
private static bool _RemoteCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
// TODO Cert Check
return true;
@ -188,7 +180,7 @@ namespace FabAccessAPI
{
rpcClient.InjectMidlayer((tcpstream) =>
{
var sslStream = new SslStream(tcpstream, false, new RemoteCertificateValidationCallback(RemoteCertificateValidationCallback));
var sslStream = new SslStream(tcpstream, false, new RemoteCertificateValidationCallback(_RemoteCertificateValidationCallback));
try
{
sslStream.AuthenticateAsClient("bffhd");
@ -236,19 +228,9 @@ namespace FabAccessAPI
/// <exception cref="AuthenticationFailedException"></exception>
private async Task<Session> _Authenticate(ConnectionData connectionData)
{
Dictionary<string, object> joinedProperties = new Dictionary<string, object>();
foreach(KeyValuePair<string, object> keyValuePair in connectionData.Properties)
{
joinedProperties.Add(keyValuePair.Key, keyValuePair.Value);
}
foreach (KeyValuePair<string, object> keyValuePair in connectionData.SecretProperties)
{
joinedProperties.Add(keyValuePair.Key, keyValuePair.Value);
}
IAuthentication? authentication = await _Bootstrap.CreateSession(MechanismString.ToString(connectionData.Mechanism)).ConfigureAwait(false);
return await _SASLAuthenticate(authentication, MechanismString.ToString(connectionData.Mechanism), joinedProperties).ConfigureAwait(false);
return await _SASLAuthenticate(authentication, MechanismString.ToString(connectionData.Mechanism), connectionData.Properties).ConfigureAwait(false);
}
/// <summary>
@ -257,7 +239,7 @@ namespace FabAccessAPI
/// <exception cref="BadMechanismException"></exception>
/// <exception cref="InvalidCredentialsException"></exception>
/// <exception cref="AuthenticationFailedException"></exception>
public async Task<Session> _SASLAuthenticate(IAuthentication authentication, string mech, Dictionary<string, object> properties)
private async Task<Session> _SASLAuthenticate(IAuthentication authentication, string mech, Dictionary<string, object> properties)
{
SaslMechanism? saslMechanism = SaslFactory.Create(mech);
foreach (KeyValuePair<string, object> entry in properties)

View File

@ -9,7 +9,25 @@ namespace FabAccessAPI
public Mechanism Mechanism;
public string Username;
public Dictionary<string, object> Properties;
public Dictionary<string, object> SecretProperties;
public DateTime LastTime;
public override bool Equals(object? obj)
{
return obj is ConnectionData data &&
EqualityComparer<Uri>.Default.Equals(Host, data.Host) &&
Mechanism == data.Mechanism &&
Username == data.Username &&
EqualityComparer<Dictionary<string, object>>.Default.Equals(Properties, data.Properties);
}
public override int GetHashCode()
{
int hashCode = -1151110446;
hashCode = hashCode * -1521134295 + EqualityComparer<Uri>.Default.GetHashCode(Host);
hashCode = hashCode * -1521134295 + Mechanism.GetHashCode();
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(Username);
hashCode = hashCode * -1521134295 + EqualityComparer<Dictionary<string, object>>.Default.GetHashCode(Properties);
return hashCode;
}
}
}