diff --git a/Neo.Gui.Base/BaseRegistrationModule.cs b/Neo.Gui.Base/BaseRegistrationModule.cs new file mode 100644 index 00000000..4f6fc079 --- /dev/null +++ b/Neo.Gui.Base/BaseRegistrationModule.cs @@ -0,0 +1,18 @@ +using Autofac; +using Neo.Gui.Base.Certificates; + +namespace Neo.Gui.Base +{ + public class BaseRegistrationModule : Module + { + protected override void Load(ContainerBuilder builder) + { + builder + .RegisterType() + .As() + .SingleInstance(); + + base.Load(builder); + } + } +} diff --git a/Neo.Gui.Wpf/Certificates/CertificateQueryResult.cs b/Neo.Gui.Base/Certificates/CertificateQueryResult.cs similarity index 90% rename from Neo.Gui.Wpf/Certificates/CertificateQueryResult.cs rename to Neo.Gui.Base/Certificates/CertificateQueryResult.cs index d1536346..ef2c61a8 100644 --- a/Neo.Gui.Wpf/Certificates/CertificateQueryResult.cs +++ b/Neo.Gui.Base/Certificates/CertificateQueryResult.cs @@ -1,7 +1,7 @@ using System; using System.Security.Cryptography.X509Certificates; -namespace Neo.Gui.Wpf.Certificates +namespace Neo.Gui.Base.Certificates { public class CertificateQueryResult : IDisposable { diff --git a/Neo.Gui.Wpf/Certificates/CertificateQueryResultType.cs b/Neo.Gui.Base/Certificates/CertificateQueryResultType.cs similarity index 82% rename from Neo.Gui.Wpf/Certificates/CertificateQueryResultType.cs rename to Neo.Gui.Base/Certificates/CertificateQueryResultType.cs index c68b985b..8944cf05 100644 --- a/Neo.Gui.Wpf/Certificates/CertificateQueryResultType.cs +++ b/Neo.Gui.Base/Certificates/CertificateQueryResultType.cs @@ -1,4 +1,4 @@ -namespace Neo.Gui.Wpf.Certificates +namespace Neo.Gui.Base.Certificates { public enum CertificateQueryResultType { diff --git a/Neo.Gui.Wpf/Certificates/CertificateQueryService.cs b/Neo.Gui.Base/Certificates/CertificateQueryService.cs similarity index 51% rename from Neo.Gui.Wpf/Certificates/CertificateQueryService.cs rename to Neo.Gui.Base/Certificates/CertificateQueryService.cs index a606a95a..b8b92add 100644 --- a/Neo.Gui.Wpf/Certificates/CertificateQueryService.cs +++ b/Neo.Gui.Base/Certificates/CertificateQueryService.cs @@ -5,65 +5,51 @@ using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using Neo.Core; -using Neo.Gui.Wpf.Properties; using Neo.SmartContract; using Neo.Wallets; using ECCurve = Neo.Cryptography.ECC.ECCurve; using ECPoint = Neo.Cryptography.ECC.ECPoint; -namespace Neo.Gui.Wpf.Certificates +namespace Neo.Gui.Base.Certificates { - public static class CertificateQueryService + internal class CertificateQueryService : ICertificateQueryService { - private static readonly Dictionary Results = new Dictionary(); + private readonly Dictionary results = new Dictionary(); - static CertificateQueryService() - { - Directory.CreateDirectory(Settings.Default.CertCachePath); - } + private string certCachePath; + private bool initialized; - private static void Web_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e) + public void Initialize(string certificateCachePath) { - using ((WebClient) sender) - { - var hash = (UInt160) e.UserState; - if (e.Cancelled || e.Error != null) - { - lock (Results) - { - Results[hash].Type = CertificateQueryResultType.Missing; - } - } - else - { - var address = Wallet.ToAddress(hash); - var path = Path.Combine(Settings.Default.CertCachePath, $"{address}.cer"); - File.WriteAllBytes(path, e.Result); - lock (Results) - { - UpdateResultFromFile(hash); - } - } - } + this.certCachePath = certificateCachePath; + + Directory.CreateDirectory(this.certCachePath); + + this.initialized = true; } - public static CertificateQueryResult Query(ECPoint pubkey) + public CertificateQueryResult Query(ECPoint pubkey) { return Query(Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash()); } - public static CertificateQueryResult Query(UInt160 hash) + public CertificateQueryResult Query(UInt160 hash) { - lock (Results) + if (!this.initialized) + { + throw new Exception("Service has not been initialized!"); + } + + lock (results) { - if (Results.ContainsKey(hash)) return Results[hash]; - Results[hash] = new CertificateQueryResult { Type = CertificateQueryResultType.Querying }; + if (results.ContainsKey(hash)) return results[hash]; + results[hash] = new CertificateQueryResult { Type = CertificateQueryResultType.Querying }; } var address = Wallet.ToAddress(hash); - var path = Path.Combine(Settings.Default.CertCachePath, $"{address}.cer"); + var path = Path.Combine(this.certCachePath, $"{address}.cer"); if (File.Exists(path)) { - lock (Results) + lock (results) { UpdateResultFromFile(hash); } @@ -72,51 +58,82 @@ public static CertificateQueryResult Query(UInt160 hash) { var url = $"http://cert.onchain.com/antshares/{address}.cer"; var web = new WebClient(); - web.DownloadDataCompleted += Web_DownloadDataCompleted; + web.DownloadDataCompleted += this.Web_DownloadDataCompleted; web.DownloadDataAsync(new Uri(url), hash); } - return Results[hash]; + return results[hash]; } - private static void UpdateResultFromFile(UInt160 hash) + #region Private methods + + private void UpdateResultFromFile(UInt160 hash) { var address = Wallet.ToAddress(hash); X509Certificate2 cert; try { - cert = new X509Certificate2(Path.Combine(Settings.Default.CertCachePath, $"{address}.cer")); + cert = new X509Certificate2(Path.Combine(this.certCachePath, $"{address}.cer")); } catch (CryptographicException) { - Results[hash].Type = CertificateQueryResultType.Missing; + results[hash].Type = CertificateQueryResultType.Missing; return; } if (cert.PublicKey.Oid.Value != "1.2.840.10045.2.1") { - Results[hash].Type = CertificateQueryResultType.Missing; + results[hash].Type = CertificateQueryResultType.Missing; return; } if (!hash.Equals(Contract.CreateSignatureRedeemScript(ECPoint.DecodePoint(cert.PublicKey.EncodedKeyValue.RawData, ECCurve.Secp256r1)).ToScriptHash())) { - Results[hash].Type = CertificateQueryResultType.Missing; + results[hash].Type = CertificateQueryResultType.Missing; return; } using (var chain = new X509Chain()) { - Results[hash].Certificate = cert; + results[hash].Certificate = cert; if (chain.Build(cert)) { - Results[hash].Type = CertificateQueryResultType.Good; + results[hash].Type = CertificateQueryResultType.Good; } else if (chain.ChainStatus.Length == 1 && chain.ChainStatus[0].Status == X509ChainStatusFlags.NotTimeValid) { - Results[hash].Type = CertificateQueryResultType.Expired; + results[hash].Type = CertificateQueryResultType.Expired; + } + else + { + results[hash].Type = CertificateQueryResultType.Invalid; + } + } + } + + private void Web_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e) + { + if (!this.initialized) return; + + using ((WebClient)sender) + { + var hash = (UInt160)e.UserState; + if (e.Cancelled || e.Error != null) + { + lock (results) + { + results[hash].Type = CertificateQueryResultType.Missing; + } } else { - Results[hash].Type = CertificateQueryResultType.Invalid; + var address = Wallet.ToAddress(hash); + var path = Path.Combine(this.certCachePath, $"{address}.cer"); + File.WriteAllBytes(path, e.Result); + lock (results) + { + this.UpdateResultFromFile(hash); + } } } } + + #endregion } } diff --git a/Neo.Gui.Base/Certificates/ICertificateQueryService.cs b/Neo.Gui.Base/Certificates/ICertificateQueryService.cs new file mode 100644 index 00000000..33be6403 --- /dev/null +++ b/Neo.Gui.Base/Certificates/ICertificateQueryService.cs @@ -0,0 +1,13 @@ +using ECPoint = Neo.Cryptography.ECC.ECPoint; + +namespace Neo.Gui.Base.Certificates +{ + public interface ICertificateQueryService + { + void Initialize(string certificateCachePath); + + CertificateQueryResult Query(ECPoint pubkey); + + CertificateQueryResult Query(UInt160 hash); + } +} diff --git a/Neo.Gui.Base/Neo.Gui.Base.csproj b/Neo.Gui.Base/Neo.Gui.Base.csproj index 07248afb..e5b52463 100644 --- a/Neo.Gui.Base/Neo.Gui.Base.csproj +++ b/Neo.Gui.Base/Neo.Gui.Base.csproj @@ -5,6 +5,7 @@ + @@ -25,4 +26,8 @@ + + + + diff --git a/Neo.Gui.Base/Theming/Theme.cs b/Neo.Gui.Base/Theming/Theme.cs index 1b466228..6ca81da6 100644 --- a/Neo.Gui.Base/Theming/Theme.cs +++ b/Neo.Gui.Base/Theming/Theme.cs @@ -6,12 +6,17 @@ namespace Neo.Gui.Base.Theming { public class Theme { + // TODO Add default theme colors to a config file so the default values can be changed by the user + private const string DefaultHighlightColorHex = "#76B466"; + private const string DefaultAccentBaseColorHex = "#3DA43C"; + private const string DefaultWindowBorderColorHex = "#9EAF99"; + public static readonly Theme Default = new Theme { Style = Style.Light, - HighlightColor = "#76B466".HexToColor(), - AccentBaseColor = "#3DA43C".HexToColor(), - WindowBorderColor = "#9EAF99".HexToColor() + HighlightColor = DefaultHighlightColorHex.HexToColor(), + AccentBaseColor = DefaultAccentBaseColorHex.HexToColor(), + WindowBorderColor = DefaultWindowBorderColorHex.HexToColor() }; public Style Style { get; set; } diff --git a/Neo.Gui.Wpf/App.xaml.cs b/Neo.Gui.Wpf/App.xaml.cs index 2907e8f4..f26c0454 100644 --- a/Neo.Gui.Wpf/App.xaml.cs +++ b/Neo.Gui.Wpf/App.xaml.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using System.Windows; using Autofac; +using Neo.Gui.Base; using Neo.Gui.Base.Controllers.Interfaces; using Neo.Gui.Base.Helpers.Interfaces; using Neo.Gui.Base.Messages; @@ -124,6 +125,7 @@ private static ILifetimeScope BuildContainer() { var autoFacContainerBuilder = new ContainerBuilder(); + autoFacContainerBuilder.RegisterModule(); autoFacContainerBuilder.RegisterModule(); autoFacContainerBuilder.RegisterModule(); autoFacContainerBuilder.RegisterModule(); diff --git a/Neo.Gui.Wpf/Controllers/WalletController.cs b/Neo.Gui.Wpf/Controllers/WalletController.cs index 352ca305..fde92f2e 100644 --- a/Neo.Gui.Wpf/Controllers/WalletController.cs +++ b/Neo.Gui.Wpf/Controllers/WalletController.cs @@ -6,6 +6,7 @@ using System.Security.Cryptography; using System.Timers; using Neo.Core; +using Neo.Gui.Base.Certificates; using Neo.Gui.Base.Controllers; using Neo.Gui.Base.Controllers.Interfaces; using Neo.Gui.Base.Data; @@ -38,6 +39,7 @@ public class WalletController : #region Private Fields private readonly IBlockChainController blockChainController; + private readonly ICertificateQueryService certificateQueryService; private readonly INotificationHelper notificationHelper; private readonly IMessagePublisher messagePublisher; @@ -64,11 +66,13 @@ public class WalletController : public WalletController( IBlockChainController blockChainController, + ICertificateQueryService certificateQueryService, INotificationHelper notificationHelper, IMessagePublisher messagePublisher, IMessageSubscriber messageSubscriber) { this.blockChainController = blockChainController; + this.certificateQueryService = certificateQueryService; this.notificationHelper = notificationHelper; this.messagePublisher = messagePublisher; @@ -87,6 +91,8 @@ public class WalletController : public void Initialize() { + this.certificateQueryService.Initialize(Settings.Default.CertCachePath); + // Setup automatic refresh timer this.refreshTimer = new Timer { @@ -1015,7 +1021,7 @@ private CertificateQueryResult GetCertificateQueryResult(AssetState asset) { if (!this.certificateQueryResultCache.ContainsKey(asset.Owner)) { - result = CertificateQueryService.Query(asset.Owner); + result = this.certificateQueryService.Query(asset.Owner); if (result == null) return null; diff --git a/Neo.Gui.Wpf/Neo.Gui.Wpf.csproj b/Neo.Gui.Wpf/Neo.Gui.Wpf.csproj index c43dda79..df779ca9 100644 --- a/Neo.Gui.Wpf/Neo.Gui.Wpf.csproj +++ b/Neo.Gui.Wpf/Neo.Gui.Wpf.csproj @@ -279,9 +279,6 @@ - - - True True