From de742220637b544a34537de058ce3afc442d644d Mon Sep 17 00:00:00 2001 From: Tlaster Date: Sat, 9 May 2020 17:00:22 +0800 Subject: [PATCH 01/15] Create NtgeApp --- NtgeApp/.gitignore | 337 +++++++++++++++++++++++ NtgeApp/App.xaml | 16 ++ NtgeApp/App.xaml.cs | 26 ++ NtgeApp/Common/Consts.cs | 14 + NtgeApp/DataSource/KeySource.cs | 57 ++++ NtgeApp/Dialogs/CreateKeyDialog.xaml | 34 +++ NtgeApp/Dialogs/CreateKeyDialog.xaml.cs | 46 ++++ NtgeApp/Dialogs/KeyPickerDialog.xaml | 58 ++++ NtgeApp/Dialogs/KeyPickerDialog.xaml.cs | 53 ++++ NtgeApp/FodyWeavers.xml | 4 + NtgeApp/FodyWeavers.xsd | 64 +++++ NtgeApp/MainWindow.xaml | 65 +++++ NtgeApp/MainWindow.xaml.cs | 21 ++ NtgeApp/Models/KeyModel.cs | 29 ++ NtgeApp/NtgeApp.csproj | 27 ++ NtgeApp/Program.cs | 23 ++ NtgeApp/ViewModels/EncryptViewModel.cs | 25 ++ NtgeApp/ViewModels/KeyPickerViewModel.cs | 10 + NtgeApp/ViewModels/KeysViewModel.cs | 17 ++ NtgeApp/ViewModels/MainViewModel.cs | 14 + NtgeApp/ViewModels/ViewModelBase.cs | 16 ++ NtgeApp/Views/EncryptView.xaml | 40 +++ NtgeApp/Views/EncryptView.xaml.cs | 46 ++++ NtgeApp/Views/KeysView.xaml | 39 +++ NtgeApp/Views/KeysView.xaml.cs | 32 +++ NtgeApp/nuget.config | 6 + 26 files changed, 1119 insertions(+) create mode 100644 NtgeApp/.gitignore create mode 100644 NtgeApp/App.xaml create mode 100644 NtgeApp/App.xaml.cs create mode 100644 NtgeApp/Common/Consts.cs create mode 100644 NtgeApp/DataSource/KeySource.cs create mode 100644 NtgeApp/Dialogs/CreateKeyDialog.xaml create mode 100644 NtgeApp/Dialogs/CreateKeyDialog.xaml.cs create mode 100644 NtgeApp/Dialogs/KeyPickerDialog.xaml create mode 100644 NtgeApp/Dialogs/KeyPickerDialog.xaml.cs create mode 100644 NtgeApp/FodyWeavers.xml create mode 100644 NtgeApp/FodyWeavers.xsd create mode 100644 NtgeApp/MainWindow.xaml create mode 100644 NtgeApp/MainWindow.xaml.cs create mode 100644 NtgeApp/Models/KeyModel.cs create mode 100644 NtgeApp/NtgeApp.csproj create mode 100644 NtgeApp/Program.cs create mode 100644 NtgeApp/ViewModels/EncryptViewModel.cs create mode 100644 NtgeApp/ViewModels/KeyPickerViewModel.cs create mode 100644 NtgeApp/ViewModels/KeysViewModel.cs create mode 100644 NtgeApp/ViewModels/MainViewModel.cs create mode 100644 NtgeApp/ViewModels/ViewModelBase.cs create mode 100644 NtgeApp/Views/EncryptView.xaml create mode 100644 NtgeApp/Views/EncryptView.xaml.cs create mode 100644 NtgeApp/Views/KeysView.xaml create mode 100644 NtgeApp/Views/KeysView.xaml.cs create mode 100644 NtgeApp/nuget.config diff --git a/NtgeApp/.gitignore b/NtgeApp/.gitignore new file mode 100644 index 0000000..dbe7c8f --- /dev/null +++ b/NtgeApp/.gitignore @@ -0,0 +1,337 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +## Visual Studio Code specific files and folder +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.jsons + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ diff --git a/NtgeApp/App.xaml b/NtgeApp/App.xaml new file mode 100644 index 0000000..89a458b --- /dev/null +++ b/NtgeApp/App.xaml @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/NtgeApp/App.xaml.cs b/NtgeApp/App.xaml.cs new file mode 100644 index 0000000..ecbeb10 --- /dev/null +++ b/NtgeApp/App.xaml.cs @@ -0,0 +1,26 @@ +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Markup.Xaml; +using PropertyChanged; + +namespace NtgeApp +{ + [DoNotNotify] + public class App : Application + { + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); + } + + public override void OnFrameworkInitializationCompleted() + { + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + desktop.MainWindow = new MainWindow(); + } + + base.OnFrameworkInitializationCompleted(); + } + } +} \ No newline at end of file diff --git a/NtgeApp/Common/Consts.cs b/NtgeApp/Common/Consts.cs new file mode 100644 index 0000000..aedae0e --- /dev/null +++ b/NtgeApp/Common/Consts.cs @@ -0,0 +1,14 @@ +using System; + +namespace NtgeApp.Common +{ + public class Consts + { + public static string HomeDir => (Environment.OSVersion.Platform == PlatformID.Unix || + Environment.OSVersion.Platform == PlatformID.MacOSX) + ? Environment.GetEnvironmentVariable("HOME") + : Environment.ExpandEnvironmentVariables("%HOMEDRIVE%%HOMEPATH%"); + + public const string NtgeFolder = ".ntge"; + } +} \ No newline at end of file diff --git a/NtgeApp/DataSource/KeySource.cs b/NtgeApp/DataSource/KeySource.cs new file mode 100644 index 0000000..e7cd94e --- /dev/null +++ b/NtgeApp/DataSource/KeySource.cs @@ -0,0 +1,57 @@ +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using Avalonia.Threading; +using NtgeApp.Common; +using NtgeApp.Models; + +namespace NtgeApp.DataSource +{ + public class KeySource + { + public static KeySource Instance { get; } = new KeySource(); + private readonly FileSystemWatcher _watcher; + public ObservableCollection Items { get; } = new ObservableCollection(); + + private KeySource() + { + var path = Path.Combine(Consts.HomeDir, Consts.NtgeFolder); + var files = Directory.GetFiles(path); + foreach (var file in files) + { + Items.Add(new KeyModel(file)); + } + + _watcher = new FileSystemWatcher(); + _watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.CreationTime | NotifyFilters.LastWrite; + _watcher.Path = path; + _watcher.Renamed += WatcherOnRenamed; + _watcher.Created += WatcherOnCreated; + _watcher.Deleted += WatcherOnDeleted; + _watcher.EnableRaisingEvents = true; + } + + private void WatcherOnDeleted(object sender, FileSystemEventArgs e) + { + var item = Items.FirstOrDefault(it => it.Path == e.FullPath); + if (item != null) + { + Dispatcher.UIThread.Post(() => Items.Remove(item)); + } + } + + private void WatcherOnCreated(object sender, FileSystemEventArgs e) + { + Dispatcher.UIThread.Post(() => Items.Add(new KeyModel(e.FullPath))); + } + + private void WatcherOnRenamed(object sender, RenamedEventArgs e) + { + var item = Items.FirstOrDefault(it => it.Path == e.OldFullPath); + if (item != null) + { + Dispatcher.UIThread.Post(() => item.Path = e.FullPath); + } + } + } +} \ No newline at end of file diff --git a/NtgeApp/Dialogs/CreateKeyDialog.xaml b/NtgeApp/Dialogs/CreateKeyDialog.xaml new file mode 100644 index 0000000..37cafdf --- /dev/null +++ b/NtgeApp/Dialogs/CreateKeyDialog.xaml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/NtgeApp/Dialogs/CreateKeyDialog.xaml.cs b/NtgeApp/Dialogs/CreateKeyDialog.xaml.cs new file mode 100644 index 0000000..9b42752 --- /dev/null +++ b/NtgeApp/Dialogs/CreateKeyDialog.xaml.cs @@ -0,0 +1,46 @@ +using System.IO; +using Avalonia.Controls; +using Avalonia.Interactivity; +using Avalonia.Markup.Xaml; +using NtgeApp.Common; +using NtgeCore.Net.Ed25519; +using PropertyChanged; + +namespace NtgeApp.Dialogs +{ + [DoNotNotify] + public class CreateKeyDialog : Window + { + public CreateKeyDialog() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + + private void OnCancelClicked(object? sender, RoutedEventArgs e) + { + Close(); + } + + private async void OnOkClicked(object? sender, RoutedEventArgs e) + { + var textBlock = this.Find("CreateKeyTextBox"); + var text = textBlock.Text; + if (string.IsNullOrEmpty(text)) + { + return; + } + + using var keypair = Ed25519Keypair.New(); + using var publicKey = keypair.PublicKey; + using var privateKey = keypair.PrivateKey; + await File.WriteAllTextAsync(Path.Combine(Consts.HomeDir, Consts.NtgeFolder, text), privateKey.Serialize()); + await File.WriteAllTextAsync(Path.Combine(Consts.HomeDir, Consts.NtgeFolder, $"{text}.pub"), publicKey.Serialize()); + this.Close(); + } + } +} \ No newline at end of file diff --git a/NtgeApp/Dialogs/KeyPickerDialog.xaml b/NtgeApp/Dialogs/KeyPickerDialog.xaml new file mode 100644 index 0000000..d78b37c --- /dev/null +++ b/NtgeApp/Dialogs/KeyPickerDialog.xaml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NtgeApp/Dialogs/KeyPickerDialog.xaml.cs b/NtgeApp/Dialogs/KeyPickerDialog.xaml.cs new file mode 100644 index 0000000..a7c4639 --- /dev/null +++ b/NtgeApp/Dialogs/KeyPickerDialog.xaml.cs @@ -0,0 +1,53 @@ +using System.IO; +using Avalonia.Controls; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Interactivity; +using Avalonia.Markup.Xaml; +using NtgeApp.ViewModels; +using PropertyChanged; + +namespace NtgeApp.Dialogs +{ + [DoNotNotify] + public class KeyPickerDialog : Window + { + public KeyPickerDialog() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + + private void OnCancelClicked(object? sender, RoutedEventArgs e) + { + Close(); + } + + private async void OnOkClicked(object? sender, RoutedEventArgs e) + { + if (!(DataContext is KeyPickerViewModel viewModel)) + { + return; + } + var tabControl = this.Find("PickerTabControl"); + if (tabControl.SelectedIndex == 0) + { + if (viewModel.SelectedModel != null) + { + if (viewModel.SelectedModel.Content == null) + { + viewModel.SelectedModel.Content = await File.ReadAllTextAsync(viewModel.SelectedModel.Path); + } + this.Close(viewModel.SelectedModel.Content); + } + } + else + { + this.Close(viewModel.CustomKeyContent); + } + } + } +} \ No newline at end of file diff --git a/NtgeApp/FodyWeavers.xml b/NtgeApp/FodyWeavers.xml new file mode 100644 index 0000000..4e68ed1 --- /dev/null +++ b/NtgeApp/FodyWeavers.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/NtgeApp/FodyWeavers.xsd b/NtgeApp/FodyWeavers.xsd new file mode 100644 index 0000000..221aeb8 --- /dev/null +++ b/NtgeApp/FodyWeavers.xsd @@ -0,0 +1,64 @@ + + + + + + + + + + + Used to control if the On_PropertyName_Changed feature is enabled. + + + + + Used to change the name of the method that fires the notify event. This is a string that accepts multiple values in a comma separated form. + + + + + Used to control if equality checks should be inserted. If false, equality checking will be disabled for the project. + + + + + Used to control if equality checks should use the Equals method resolved from the base class. + + + + + Used to control if equality checks should use the static Equals method resolved from the base class. + + + + + Used to turn off build warnings from this weaver. + + + + + Used to turn off build warnings about mismatched On_PropertyName_Changed methods. + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/NtgeApp/MainWindow.xaml b/NtgeApp/MainWindow.xaml new file mode 100644 index 0000000..81111c3 --- /dev/null +++ b/NtgeApp/MainWindow.xaml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NtgeApp/MainWindow.xaml.cs b/NtgeApp/MainWindow.xaml.cs new file mode 100644 index 0000000..9533b14 --- /dev/null +++ b/NtgeApp/MainWindow.xaml.cs @@ -0,0 +1,21 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using PropertyChanged; + +namespace NtgeApp +{ + [DoNotNotify] + public class MainWindow : Window + { + public MainWindow() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + } +} \ No newline at end of file diff --git a/NtgeApp/Models/KeyModel.cs b/NtgeApp/Models/KeyModel.cs new file mode 100644 index 0000000..40791f7 --- /dev/null +++ b/NtgeApp/Models/KeyModel.cs @@ -0,0 +1,29 @@ +using System.ComponentModel; +using System.Runtime.CompilerServices; +using JetBrains.Annotations; +using PropertyChanged; + +namespace NtgeApp.Models +{ + public class KeyModel : INotifyPropertyChanged + { + public KeyModel(string path) + { + Path = path; + } + + public string Path { get; set; } + + [DependsOn(nameof(Path))] + public string Name => System.IO.Path.GetFileName(Path); + + public string Content { get; set; } + + public event PropertyChangedEventHandler PropertyChanged; + + protected void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } +} \ No newline at end of file diff --git a/NtgeApp/NtgeApp.csproj b/NtgeApp/NtgeApp.csproj new file mode 100644 index 0000000..b47b9b0 --- /dev/null +++ b/NtgeApp/NtgeApp.csproj @@ -0,0 +1,27 @@ + + + WinExe + netcoreapp3.1 + + + + %(Filename) + + + Designer + + + + + + + + + + + + + + + + diff --git a/NtgeApp/Program.cs b/NtgeApp/Program.cs new file mode 100644 index 0000000..ea95ad8 --- /dev/null +++ b/NtgeApp/Program.cs @@ -0,0 +1,23 @@ +using System; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Logging.Serilog; + +namespace NtgeApp +{ + class Program + { + // Initialization code. Don't use any Avalonia, third-party APIs or any + // SynchronizationContext-reliant code before AppMain is called: things aren't initialized + // yet and stuff might break. + public static void Main(string[] args) => BuildAvaloniaApp() + .StartWithClassicDesktopLifetime(args); + + // Avalonia configuration, don't remove; also used by visual designer. + public static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure() + .UsePlatformDetect() + .LogToDebug(); + } +} diff --git a/NtgeApp/ViewModels/EncryptViewModel.cs b/NtgeApp/ViewModels/EncryptViewModel.cs new file mode 100644 index 0000000..94b6c14 --- /dev/null +++ b/NtgeApp/ViewModels/EncryptViewModel.cs @@ -0,0 +1,25 @@ +using System.Collections.ObjectModel; +using System.Linq; +using NtgeCore.Net.Ed25519; +using NtgeCore.Net.Message; +using PropertyChanged; + +namespace NtgeApp.ViewModels +{ + public class EncryptViewModel : ViewModelBase + { + public ObservableCollection Keys { get; } = new ObservableCollection(); + + public string Input { get; set; } + + [DependsOn(nameof(Input))] + public string Output + { + get + { + return Encryptor.New(Keys.Select(it => Ed25519PublicKey.Deserialize(it).ToX25519()).ToArray()) + .EncryptPlaintext(Input).Serialize(); + } + } + } +} \ No newline at end of file diff --git a/NtgeApp/ViewModels/KeyPickerViewModel.cs b/NtgeApp/ViewModels/KeyPickerViewModel.cs new file mode 100644 index 0000000..e3b4c3e --- /dev/null +++ b/NtgeApp/ViewModels/KeyPickerViewModel.cs @@ -0,0 +1,10 @@ +using NtgeApp.Models; + +namespace NtgeApp.ViewModels +{ + public class KeyPickerViewModel : KeysViewModel + { + public KeyModel SelectedModel { get; set; } + public string CustomKeyContent { get; set; } + } +} \ No newline at end of file diff --git a/NtgeApp/ViewModels/KeysViewModel.cs b/NtgeApp/ViewModels/KeysViewModel.cs new file mode 100644 index 0000000..f42a3b0 --- /dev/null +++ b/NtgeApp/ViewModels/KeysViewModel.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using Avalonia.Threading; +using NtgeApp.Common; +using NtgeApp.DataSource; +using NtgeApp.Models; + +namespace NtgeApp.ViewModels +{ + public class KeysViewModel : ViewModelBase + { + public IEnumerable Items => KeySource.Instance.Items; + } +} \ No newline at end of file diff --git a/NtgeApp/ViewModels/MainViewModel.cs b/NtgeApp/ViewModels/MainViewModel.cs new file mode 100644 index 0000000..102f436 --- /dev/null +++ b/NtgeApp/ViewModels/MainViewModel.cs @@ -0,0 +1,14 @@ +namespace NtgeApp.ViewModels +{ + class MainViewModel : ViewModelBase + { + public string[] Menus { get; } = new[] + { + "Keys", + "Encrypt", + "Decrypt", + "Sign", + "Verify" + }; + } +} \ No newline at end of file diff --git a/NtgeApp/ViewModels/ViewModelBase.cs b/NtgeApp/ViewModels/ViewModelBase.cs new file mode 100644 index 0000000..7a6fea0 --- /dev/null +++ b/NtgeApp/ViewModels/ViewModelBase.cs @@ -0,0 +1,16 @@ +using System.ComponentModel; +using System.Runtime.CompilerServices; +using JetBrains.Annotations; + +namespace NtgeApp.ViewModels +{ + public abstract class ViewModelBase : INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged; + + protected void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } +} \ No newline at end of file diff --git a/NtgeApp/Views/EncryptView.xaml b/NtgeApp/Views/EncryptView.xaml new file mode 100644 index 0000000..fa5c8a6 --- /dev/null +++ b/NtgeApp/Views/EncryptView.xaml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NtgeApp/Views/EncryptView.xaml.cs b/NtgeApp/Views/EncryptView.xaml.cs new file mode 100644 index 0000000..2e30e54 --- /dev/null +++ b/NtgeApp/Views/EncryptView.xaml.cs @@ -0,0 +1,46 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Interactivity; +using Avalonia.Markup.Xaml; +using NtgeApp.Dialogs; +using NtgeApp.ViewModels; +using PropertyChanged; + +namespace NtgeApp.Views +{ + [DoNotNotify] + public class EncryptView : UserControl + { + public EncryptView() + { + InitializeComponent(); + } + + private async void OnAddClick(object? sender, RoutedEventArgs e) + { + if (!(DataContext is EncryptViewModel viewModel)) + { + return; + } + var dialog = new KeyPickerDialog(); + if (App.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + var result = await dialog.ShowDialog(desktop.MainWindow); + if (!string.IsNullOrEmpty(result)) + { + result = result.Trim(); + if (!viewModel.Keys.Contains(result)) + { + viewModel.Keys.Add(result); + } + } + } + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + } +} \ No newline at end of file diff --git a/NtgeApp/Views/KeysView.xaml b/NtgeApp/Views/KeysView.xaml new file mode 100644 index 0000000..d83ed7f --- /dev/null +++ b/NtgeApp/Views/KeysView.xaml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NtgeApp/Views/KeysView.xaml.cs b/NtgeApp/Views/KeysView.xaml.cs new file mode 100644 index 0000000..e846ec6 --- /dev/null +++ b/NtgeApp/Views/KeysView.xaml.cs @@ -0,0 +1,32 @@ +using Avalonia.Controls; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Interactivity; +using Avalonia.Markup.Xaml; +using NtgeApp.Dialogs; +using PropertyChanged; + +namespace NtgeApp.Views +{ + [DoNotNotify] + public class KeysView : UserControl + { + public KeysView() + { + InitializeComponent(); + } + + private async void OnCreateClicked(object? sender, RoutedEventArgs e) + { + if (App.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + var dialog = new CreateKeyDialog(); + await dialog.ShowDialog(desktop.MainWindow); + } + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + } +} \ No newline at end of file diff --git a/NtgeApp/nuget.config b/NtgeApp/nuget.config new file mode 100644 index 0000000..7c07e22 --- /dev/null +++ b/NtgeApp/nuget.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file From 8b11b894a2f3eb8eba99e00c15748fb9556b1087 Mon Sep 17 00:00:00 2001 From: Tlaster Date: Sat, 9 May 2020 17:31:43 +0800 Subject: [PATCH 02/15] Ensure folder exisits when fetching keys --- NtgeApp/DataSource/KeySource.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NtgeApp/DataSource/KeySource.cs b/NtgeApp/DataSource/KeySource.cs index e7cd94e..541c1a5 100644 --- a/NtgeApp/DataSource/KeySource.cs +++ b/NtgeApp/DataSource/KeySource.cs @@ -16,6 +16,10 @@ public class KeySource private KeySource() { var path = Path.Combine(Consts.HomeDir, Consts.NtgeFolder); + if (!Directory.Exists(path)) + { + Directory.CreateDirectory(path); + } var files = Directory.GetFiles(path); foreach (var file in files) { From fa4372bca463eef1eaa089e71a73a62e90a334d9 Mon Sep 17 00:00:00 2001 From: Tlaster Date: Sun, 10 May 2020 01:41:02 +0800 Subject: [PATCH 03/15] Refactor and cleanup NtgeApp --- NtgeApp/App.xaml | 23 ++++++--- NtgeApp/App.xaml.cs | 4 +- NtgeApp/Common/Consts.cs | 7 +-- NtgeApp/DataSource/KeySource.cs | 53 ++++++++++--------- NtgeApp/Dialogs/CreateKeyDialog.xaml | 45 ++++++++-------- NtgeApp/Dialogs/CreateKeyDialog.xaml.cs | 40 ++++++++++++-- NtgeApp/Dialogs/Dialog.cs | 27 ++++++++++ NtgeApp/Dialogs/KeyPickerDialog.xaml | 37 ++++++------- NtgeApp/Dialogs/KeyPickerDialog.xaml.cs | 29 ++++++----- NtgeApp/MainWindow.xaml | 66 +++++++++++++----------- NtgeApp/MainWindow.xaml.cs | 1 - NtgeApp/Models/KeyModel.cs | 37 ++++++++++--- NtgeApp/Models/TabItemModel.cs | 18 +++++++ NtgeApp/NtgeApp.csproj | 6 ++- NtgeApp/Program.cs | 20 +++---- NtgeApp/Resources/Icons.xaml | 15 ++++++ NtgeApp/ViewModels/EncryptViewModel.cs | 18 ++++++- NtgeApp/ViewModels/KeyPickerViewModel.cs | 4 +- NtgeApp/ViewModels/KeysViewModel.cs | 7 +-- NtgeApp/ViewModels/MainViewModel.cs | 22 +++++--- NtgeApp/ViewModels/ViewModelBase.cs | 5 +- NtgeApp/Views/EncryptView.xaml | 47 +++++++++++------ NtgeApp/Views/EncryptView.xaml.cs | 28 +++++++--- NtgeApp/Views/KeysView.xaml | 23 +++++---- NtgeApp/Views/KeysView.xaml.cs | 5 +- 25 files changed, 391 insertions(+), 196 deletions(-) create mode 100644 NtgeApp/Dialogs/Dialog.cs create mode 100644 NtgeApp/Models/TabItemModel.cs create mode 100644 NtgeApp/Resources/Icons.xaml diff --git a/NtgeApp/App.xaml b/NtgeApp/App.xaml index 89a458b..3a60820 100644 --- a/NtgeApp/App.xaml +++ b/NtgeApp/App.xaml @@ -2,15 +2,24 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="NtgeApp.App"> - - + + + + - + + + #2B579A + + \ No newline at end of file diff --git a/NtgeApp/App.xaml.cs b/NtgeApp/App.xaml.cs index ecbeb10..96905e7 100644 --- a/NtgeApp/App.xaml.cs +++ b/NtgeApp/App.xaml.cs @@ -12,7 +12,7 @@ public override void Initialize() { AvaloniaXamlLoader.Load(this); } - + public override void OnFrameworkInitializationCompleted() { if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) @@ -22,5 +22,5 @@ public override void OnFrameworkInitializationCompleted() base.OnFrameworkInitializationCompleted(); } - } + } } \ No newline at end of file diff --git a/NtgeApp/Common/Consts.cs b/NtgeApp/Common/Consts.cs index aedae0e..0999fb9 100644 --- a/NtgeApp/Common/Consts.cs +++ b/NtgeApp/Common/Consts.cs @@ -4,11 +4,8 @@ namespace NtgeApp.Common { public class Consts { - public static string HomeDir => (Environment.OSVersion.Platform == PlatformID.Unix || - Environment.OSVersion.Platform == PlatformID.MacOSX) - ? Environment.GetEnvironmentVariable("HOME") - : Environment.ExpandEnvironmentVariables("%HOMEDRIVE%%HOMEPATH%"); - public const string NtgeFolder = ".ntge"; + + public static string HomeDir => Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); } } \ No newline at end of file diff --git a/NtgeApp/DataSource/KeySource.cs b/NtgeApp/DataSource/KeySource.cs index 541c1a5..1f0ef10 100644 --- a/NtgeApp/DataSource/KeySource.cs +++ b/NtgeApp/DataSource/KeySource.cs @@ -9,53 +9,60 @@ namespace NtgeApp.DataSource { public class KeySource { - public static KeySource Instance { get; } = new KeySource(); private readonly FileSystemWatcher _watcher; - public ObservableCollection Items { get; } = new ObservableCollection(); private KeySource() { + LoadKeys(); + + _watcher = new FileSystemWatcher(); + _watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.CreationTime | NotifyFilters.LastWrite; + _watcher.Path = Path.Combine(Consts.HomeDir, Consts.NtgeFolder); + _watcher.Renamed += WatcherOnRenamed; + _watcher.Created += WatcherOnCreated; + _watcher.Deleted += WatcherOnDeleted; + _watcher.EnableRaisingEvents = true; + } + + public static KeySource Instance { get; } = new KeySource(); + public ObservableCollection Items { get; } = new ObservableCollection(); + + private void LoadKeys() + { + Items.Clear(); var path = Path.Combine(Consts.HomeDir, Consts.NtgeFolder); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } - var files = Directory.GetFiles(path); + + var files = Directory.GetFiles(path) + .Select(it => (path: it, name: Path.GetFileNameWithoutExtension(it))) + .Where(it => !string.IsNullOrEmpty(it.name)) + .GroupBy(it => it.name) + .Where(it => it.Count() == 2 && File.Exists(it.FirstOrDefault().path + ".pub")) + .SelectMany(it => it.Where(tuple => !tuple.path.EndsWith(".pub"))) + .Select(it => it.path); + foreach (var file in files) { Items.Add(new KeyModel(file)); } - - _watcher = new FileSystemWatcher(); - _watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.CreationTime | NotifyFilters.LastWrite; - _watcher.Path = path; - _watcher.Renamed += WatcherOnRenamed; - _watcher.Created += WatcherOnCreated; - _watcher.Deleted += WatcherOnDeleted; - _watcher.EnableRaisingEvents = true; } - + private void WatcherOnDeleted(object sender, FileSystemEventArgs e) { - var item = Items.FirstOrDefault(it => it.Path == e.FullPath); - if (item != null) - { - Dispatcher.UIThread.Post(() => Items.Remove(item)); - } + Dispatcher.UIThread.Post(LoadKeys); } private void WatcherOnCreated(object sender, FileSystemEventArgs e) { - Dispatcher.UIThread.Post(() => Items.Add(new KeyModel(e.FullPath))); + Dispatcher.UIThread.Post(LoadKeys); } private void WatcherOnRenamed(object sender, RenamedEventArgs e) { - var item = Items.FirstOrDefault(it => it.Path == e.OldFullPath); - if (item != null) - { - Dispatcher.UIThread.Post(() => item.Path = e.FullPath); - } + Dispatcher.UIThread.Post(LoadKeys); } } } \ No newline at end of file diff --git a/NtgeApp/Dialogs/CreateKeyDialog.xaml b/NtgeApp/Dialogs/CreateKeyDialog.xaml index 37cafdf..f8b35cc 100644 --- a/NtgeApp/Dialogs/CreateKeyDialog.xaml +++ b/NtgeApp/Dialogs/CreateKeyDialog.xaml @@ -1,34 +1,35 @@ - - + + - - - - + + + + - - + + - - + + - + \ No newline at end of file diff --git a/NtgeApp/Dialogs/CreateKeyDialog.xaml.cs b/NtgeApp/Dialogs/CreateKeyDialog.xaml.cs index 9b42752..0a5dc90 100644 --- a/NtgeApp/Dialogs/CreateKeyDialog.xaml.cs +++ b/NtgeApp/Dialogs/CreateKeyDialog.xaml.cs @@ -1,7 +1,10 @@ using System.IO; +using System.Threading.Tasks; using Avalonia.Controls; +using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Markup.Xaml; +using Avalonia.Threading; using NtgeApp.Common; using NtgeCore.Net.Ed25519; using PropertyChanged; @@ -9,24 +12,50 @@ namespace NtgeApp.Dialogs { [DoNotNotify] - public class CreateKeyDialog : Window + public class CreateKeyDialog : Dialog { public CreateKeyDialog() { InitializeComponent(); + var textBox = this.Find("CreateKeyTextBox"); + textBox.KeyDown += TextBoxOnKeyDown; + Dispatcher.UIThread.Post(() => textBox.Focus()); + } + + private async void TextBoxOnKeyDown(object? sender, KeyEventArgs e) + { + if (!(sender is TextBox textBox)) + { + return; + } + + if (e.Key == Key.Return) + { + e.Handled = true; + if (!string.IsNullOrEmpty(textBox.Text)) + { + textBox.IsEnabled = false; + await CreateKey(); + } + } } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); } - + private void OnCancelClicked(object? sender, RoutedEventArgs e) { Close(); } - + private async void OnOkClicked(object? sender, RoutedEventArgs e) + { + await CreateKey(); + } + + private async Task CreateKey() { var textBlock = this.Find("CreateKeyTextBox"); var text = textBlock.Text; @@ -39,8 +68,9 @@ private async void OnOkClicked(object? sender, RoutedEventArgs e) using var publicKey = keypair.PublicKey; using var privateKey = keypair.PrivateKey; await File.WriteAllTextAsync(Path.Combine(Consts.HomeDir, Consts.NtgeFolder, text), privateKey.Serialize()); - await File.WriteAllTextAsync(Path.Combine(Consts.HomeDir, Consts.NtgeFolder, $"{text}.pub"), publicKey.Serialize()); - this.Close(); + await File.WriteAllTextAsync(Path.Combine(Consts.HomeDir, Consts.NtgeFolder, $"{text}.pub"), + publicKey.Serialize()); + Close(); } } } \ No newline at end of file diff --git a/NtgeApp/Dialogs/Dialog.cs b/NtgeApp/Dialogs/Dialog.cs new file mode 100644 index 0000000..b58a1c0 --- /dev/null +++ b/NtgeApp/Dialogs/Dialog.cs @@ -0,0 +1,27 @@ +using Avalonia.Controls; +using Avalonia.Input; +using PropertyChanged; + +namespace NtgeApp.Dialogs +{ + [DoNotNotify] + public class Dialog : Window + { + public Dialog() + { + SystemDecorations = SystemDecorations.BorderOnly; + WindowStartupLocation = WindowStartupLocation.CenterOwner; + ShowInTaskbar = false; + } + + protected override void OnKeyDown(KeyEventArgs e) + { + base.OnKeyDown(e); + if (e.Key == Key.Escape) + { + e.Handled = true; + Close(); + } + } + } +} \ No newline at end of file diff --git a/NtgeApp/Dialogs/KeyPickerDialog.xaml b/NtgeApp/Dialogs/KeyPickerDialog.xaml index d78b37c..2a75509 100644 --- a/NtgeApp/Dialogs/KeyPickerDialog.xaml +++ b/NtgeApp/Dialogs/KeyPickerDialog.xaml @@ -1,37 +1,38 @@ - - - - + + + - - + + - - + + - + - - + + @@ -39,20 +40,20 @@ - + - - + + - \ No newline at end of file + \ No newline at end of file diff --git a/NtgeApp/Dialogs/KeyPickerDialog.xaml.cs b/NtgeApp/Dialogs/KeyPickerDialog.xaml.cs index a7c4639..3e7cdc0 100644 --- a/NtgeApp/Dialogs/KeyPickerDialog.xaml.cs +++ b/NtgeApp/Dialogs/KeyPickerDialog.xaml.cs @@ -1,52 +1,57 @@ -using System.IO; using Avalonia.Controls; -using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Interactivity; using Avalonia.Markup.Xaml; +using NtgeApp.Models; using NtgeApp.ViewModels; using PropertyChanged; namespace NtgeApp.Dialogs { [DoNotNotify] - public class KeyPickerDialog : Window + public class KeyPickerDialog : Dialog { public KeyPickerDialog() { InitializeComponent(); } + private void OnItemDoubleTapped(object? sender, RoutedEventArgs e) + { + if (sender is Grid view && view.DataContext is KeyModel model) + { + e.Handled = true; + Close(model); + } + } + private void InitializeComponent() { AvaloniaXamlLoader.Load(this); } - + private void OnCancelClicked(object? sender, RoutedEventArgs e) { Close(); } - - private async void OnOkClicked(object? sender, RoutedEventArgs e) + + private void OnOkClicked(object? sender, RoutedEventArgs e) { if (!(DataContext is KeyPickerViewModel viewModel)) { return; } + var tabControl = this.Find("PickerTabControl"); if (tabControl.SelectedIndex == 0) { if (viewModel.SelectedModel != null) { - if (viewModel.SelectedModel.Content == null) - { - viewModel.SelectedModel.Content = await File.ReadAllTextAsync(viewModel.SelectedModel.Path); - } - this.Close(viewModel.SelectedModel.Content); + Close(viewModel.SelectedModel); } } else { - this.Close(viewModel.CustomKeyContent); + Close(viewModel.CustomKeyContent); } } } diff --git a/NtgeApp/MainWindow.xaml b/NtgeApp/MainWindow.xaml index 81111c3..434a7ab 100644 --- a/NtgeApp/MainWindow.xaml +++ b/NtgeApp/MainWindow.xaml @@ -5,61 +5,69 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:viewModels="clr-namespace:NtgeApp.ViewModels" xmlns:views="clr-namespace:NtgeApp.Views" + xmlns:models="clr-namespace:NtgeApp.Models" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="NtgeApp.MainWindow" Title="NtgeApp"> - - - - + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NtgeApp/MainWindow.xaml.cs b/NtgeApp/MainWindow.xaml.cs index 9533b14..89fde8b 100644 --- a/NtgeApp/MainWindow.xaml.cs +++ b/NtgeApp/MainWindow.xaml.cs @@ -1,4 +1,3 @@ -using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; using PropertyChanged; diff --git a/NtgeApp/Models/KeyModel.cs b/NtgeApp/Models/KeyModel.cs index 40791f7..a3e98ad 100644 --- a/NtgeApp/Models/KeyModel.cs +++ b/NtgeApp/Models/KeyModel.cs @@ -1,6 +1,7 @@ using System.ComponentModel; +using System.IO; using System.Runtime.CompilerServices; -using JetBrains.Annotations; +using System.Threading.Tasks; using PropertyChanged; namespace NtgeApp.Models @@ -13,15 +14,35 @@ public KeyModel(string path) } public string Path { get; set; } - - [DependsOn(nameof(Path))] - public string Name => System.IO.Path.GetFileName(Path); - public string Content { get; set; } - - public event PropertyChangedEventHandler PropertyChanged; + [DependsOn(nameof(Path))] public string Name => System.IO.Path.GetFileName(Path); - protected void OnPropertyChanged([CallerMemberName] string propertyName = null) + // public string Content { get; set; } + + public string? PublicKeyContent { get; set; } + public string? PrivateKeyContent { get; set; } + + public event PropertyChangedEventHandler? PropertyChanged; + + public async Task EnsurePublicKeyContent() + { + if (string.IsNullOrEmpty(PublicKeyContent)) + { + var result = await File.ReadAllTextAsync(Path + ".pub"); + PublicKeyContent = result.Trim(); + } + } + + public async Task EnsurePrivateKeyContent() + { + if (string.IsNullOrEmpty(PrivateKeyContent)) + { + var result = await File.ReadAllTextAsync(Path); + PublicKeyContent = result.Trim(); + } + } + + protected void OnPropertyChanged([CallerMemberName] string? propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } diff --git a/NtgeApp/Models/TabItemModel.cs b/NtgeApp/Models/TabItemModel.cs new file mode 100644 index 0000000..9451c9d --- /dev/null +++ b/NtgeApp/Models/TabItemModel.cs @@ -0,0 +1,18 @@ +using Avalonia.Media; + +namespace NtgeApp.Models +{ + internal class TabItemModel + { + public TabItemModel(string title, GeometryDrawing? icon, object content) + { + Title = title; + Icon = icon; + Content = content; + } + + public string Title { get; } + public GeometryDrawing? Icon { get; } + public object Content { get; } + } +} \ No newline at end of file diff --git a/NtgeApp/NtgeApp.csproj b/NtgeApp/NtgeApp.csproj index b47b9b0..ebdc785 100644 --- a/NtgeApp/NtgeApp.csproj +++ b/NtgeApp/NtgeApp.csproj @@ -2,6 +2,8 @@ WinExe netcoreapp3.1 + preview + enable @@ -10,6 +12,9 @@ Designer + + Designer + @@ -22,6 +27,5 @@ - diff --git a/NtgeApp/Program.cs b/NtgeApp/Program.cs index ea95ad8..a500282 100644 --- a/NtgeApp/Program.cs +++ b/NtgeApp/Program.cs @@ -1,23 +1,25 @@ -using System; -using Avalonia; -using Avalonia.Controls; -using Avalonia.Controls.ApplicationLifetimes; +using Avalonia; using Avalonia.Logging.Serilog; namespace NtgeApp { - class Program + internal class Program { // Initialization code. Don't use any Avalonia, third-party APIs or any // SynchronizationContext-reliant code before AppMain is called: things aren't initialized // yet and stuff might break. - public static void Main(string[] args) => BuildAvaloniaApp() - .StartWithClassicDesktopLifetime(args); + public static void Main(string[] args) + { + BuildAvaloniaApp() + .StartWithClassicDesktopLifetime(args); + } // Avalonia configuration, don't remove; also used by visual designer. public static AppBuilder BuildAvaloniaApp() - => AppBuilder.Configure() + { + return AppBuilder.Configure() .UsePlatformDetect() .LogToDebug(); + } } -} +} \ No newline at end of file diff --git a/NtgeApp/Resources/Icons.xaml b/NtgeApp/Resources/Icons.xaml new file mode 100644 index 0000000..e264f23 --- /dev/null +++ b/NtgeApp/Resources/Icons.xaml @@ -0,0 +1,15 @@ + + + \ No newline at end of file diff --git a/NtgeApp/ViewModels/EncryptViewModel.cs b/NtgeApp/ViewModels/EncryptViewModel.cs index 94b6c14..294d090 100644 --- a/NtgeApp/ViewModels/EncryptViewModel.cs +++ b/NtgeApp/ViewModels/EncryptViewModel.cs @@ -1,4 +1,5 @@ using System.Collections.ObjectModel; +using System.Collections.Specialized; using System.Linq; using NtgeCore.Net.Ed25519; using NtgeCore.Net.Message; @@ -8,18 +9,33 @@ namespace NtgeApp.ViewModels { public class EncryptViewModel : ViewModelBase { + public EncryptViewModel() + { + Keys.CollectionChanged += KeysOnCollectionChanged; + } + public ObservableCollection Keys { get; } = new ObservableCollection(); - public string Input { get; set; } + public string? Input { get; set; } [DependsOn(nameof(Input))] public string Output { get { + if (string.IsNullOrEmpty(Input)) + { + return string.Empty; + } + return Encryptor.New(Keys.Select(it => Ed25519PublicKey.Deserialize(it).ToX25519()).ToArray()) .EncryptPlaintext(Input).Serialize(); } } + + private void KeysOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + OnPropertyChanged(Output); + } } } \ No newline at end of file diff --git a/NtgeApp/ViewModels/KeyPickerViewModel.cs b/NtgeApp/ViewModels/KeyPickerViewModel.cs index e3b4c3e..f120433 100644 --- a/NtgeApp/ViewModels/KeyPickerViewModel.cs +++ b/NtgeApp/ViewModels/KeyPickerViewModel.cs @@ -4,7 +4,7 @@ namespace NtgeApp.ViewModels { public class KeyPickerViewModel : KeysViewModel { - public KeyModel SelectedModel { get; set; } - public string CustomKeyContent { get; set; } + public KeyModel? SelectedModel { get; set; } + public string? CustomKeyContent { get; set; } } } \ No newline at end of file diff --git a/NtgeApp/ViewModels/KeysViewModel.cs b/NtgeApp/ViewModels/KeysViewModel.cs index f42a3b0..ec7ecc9 100644 --- a/NtgeApp/ViewModels/KeysViewModel.cs +++ b/NtgeApp/ViewModels/KeysViewModel.cs @@ -1,9 +1,6 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; -using System.Linq; -using Avalonia.Threading; using NtgeApp.Common; using NtgeApp.DataSource; using NtgeApp.Models; @@ -12,6 +9,6 @@ namespace NtgeApp.ViewModels { public class KeysViewModel : ViewModelBase { - public IEnumerable Items => KeySource.Instance.Items; + public ObservableCollection Items => KeySource.Instance.Items; } } \ No newline at end of file diff --git a/NtgeApp/ViewModels/MainViewModel.cs b/NtgeApp/ViewModels/MainViewModel.cs index 102f436..1ab6323 100644 --- a/NtgeApp/ViewModels/MainViewModel.cs +++ b/NtgeApp/ViewModels/MainViewModel.cs @@ -1,14 +1,20 @@ -namespace NtgeApp.ViewModels +using Avalonia; +using Avalonia.Controls; +using Avalonia.Media; +using NtgeApp.Models; +using NtgeApp.Views; + +namespace NtgeApp.ViewModels { - class MainViewModel : ViewModelBase + internal class MainViewModel : ViewModelBase { - public string[] Menus { get; } = new[] + public TabItemModel[] Tabs { get; } = { - "Keys", - "Encrypt", - "Decrypt", - "Sign", - "Verify" + new TabItemModel("Keys", Application.Current.FindResource("BoxIcons.RegularKey") as GeometryDrawing, + new KeysView()), + new TabItemModel("Encrypt", + Application.Current.FindResource("MaterialDesign.EnhancedEncryption") as GeometryDrawing, + new EncryptView()) }; } } \ No newline at end of file diff --git a/NtgeApp/ViewModels/ViewModelBase.cs b/NtgeApp/ViewModels/ViewModelBase.cs index 7a6fea0..ab3d85c 100644 --- a/NtgeApp/ViewModels/ViewModelBase.cs +++ b/NtgeApp/ViewModels/ViewModelBase.cs @@ -1,14 +1,13 @@ using System.ComponentModel; using System.Runtime.CompilerServices; -using JetBrains.Annotations; namespace NtgeApp.ViewModels { public abstract class ViewModelBase : INotifyPropertyChanged { - public event PropertyChangedEventHandler PropertyChanged; + public event PropertyChangedEventHandler? PropertyChanged; - protected void OnPropertyChanged([CallerMemberName] string propertyName = null) + protected void OnPropertyChanged([CallerMemberName] string? propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } diff --git a/NtgeApp/Views/EncryptView.xaml b/NtgeApp/Views/EncryptView.xaml index fa5c8a6..fa9a0a1 100644 --- a/NtgeApp/Views/EncryptView.xaml +++ b/NtgeApp/Views/EncryptView.xaml @@ -6,35 +6,50 @@ xmlns:viewModels="clr-namespace:NtgeApp.ViewModels" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="NtgeApp.Views.EncryptView"> - + - + - + - - - - - + + + + + - + - + + + + + + - + + + + - - - + + + - + \ No newline at end of file diff --git a/NtgeApp/Views/EncryptView.xaml.cs b/NtgeApp/Views/EncryptView.xaml.cs index 2e30e54..7ca431f 100644 --- a/NtgeApp/Views/EncryptView.xaml.cs +++ b/NtgeApp/Views/EncryptView.xaml.cs @@ -4,6 +4,7 @@ using Avalonia.Interactivity; using Avalonia.Markup.Xaml; using NtgeApp.Dialogs; +using NtgeApp.Models; using NtgeApp.ViewModels; using PropertyChanged; @@ -17,22 +18,37 @@ public EncryptView() InitializeComponent(); } + private void OnRemoveClick(object? sender, RoutedEventArgs e) + { + if (!(DataContext is EncryptViewModel viewModel)) + { + return; + } + + if (sender is Button button && button.DataContext is string value) + { + viewModel.Keys.Remove(value); + } + } + private async void OnAddClick(object? sender, RoutedEventArgs e) { if (!(DataContext is EncryptViewModel viewModel)) { return; } + var dialog = new KeyPickerDialog(); - if (App.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { - var result = await dialog.ShowDialog(desktop.MainWindow); - if (!string.IsNullOrEmpty(result)) + var result = await dialog.ShowDialog(desktop.MainWindow); + if (result != null) { - result = result.Trim(); - if (!viewModel.Keys.Contains(result)) + await result.EnsurePublicKeyContent(); + if (!string.IsNullOrEmpty(result.PublicKeyContent) && + !viewModel.Keys.Contains(result.PublicKeyContent)) { - viewModel.Keys.Add(result); + viewModel.Keys.Add(result.PublicKeyContent); } } } diff --git a/NtgeApp/Views/KeysView.xaml b/NtgeApp/Views/KeysView.xaml index d83ed7f..ad08fd6 100644 --- a/NtgeApp/Views/KeysView.xaml +++ b/NtgeApp/Views/KeysView.xaml @@ -7,33 +7,34 @@ xmlns:models="clr-namespace:NtgeApp.Models" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="NtgeApp.Views.KeysView"> - + - + - - - + + + - - - + - + - + \ No newline at end of file diff --git a/NtgeApp/Views/KeysView.xaml.cs b/NtgeApp/Views/KeysView.xaml.cs index e846ec6..e90f173 100644 --- a/NtgeApp/Views/KeysView.xaml.cs +++ b/NtgeApp/Views/KeysView.xaml.cs @@ -1,3 +1,4 @@ +using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Interactivity; @@ -17,13 +18,13 @@ public KeysView() private async void OnCreateClicked(object? sender, RoutedEventArgs e) { - if (App.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { var dialog = new CreateKeyDialog(); await dialog.ShowDialog(desktop.MainWindow); } } - + private void InitializeComponent() { AvaloniaXamlLoader.Load(this); From b9cb7c90930b0dd613a457114baf951b97b65d97 Mon Sep 17 00:00:00 2001 From: Tlaster Date: Sun, 10 May 2020 01:52:25 +0800 Subject: [PATCH 04/15] Add CI configure --- .github/workflows/NtgeApp.yaml | 79 ++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 .github/workflows/NtgeApp.yaml diff --git a/.github/workflows/NtgeApp.yaml b/.github/workflows/NtgeApp.yaml new file mode 100644 index 0000000..96cbcfc --- /dev/null +++ b/.github/workflows/NtgeApp.yaml @@ -0,0 +1,79 @@ +name: .NET Core + +on: + push: + paths: + - "ntge-core/**" + - "NtgeCore.Net/**" + - "NtgeApp/**" + pull_request: + paths: + - "ntge-core/**" + - "NtgeCore.Net/**" + - "NtgeApp/**" + +jobs: + + linux: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - name: Setup .NET Core + uses: actions/setup-dotnet@v1 + with: + dotnet-version: 3.1.201 + - name: Install dependencies + working-directory: ./NtgeApp + run: dotnet restore + - name: Publish + working-directory: ./NtgeApp + run: dotnet publish -c Release -r linux-x64 --self-contained true + - name: Archive publish artifacts + uses: actions/upload-artifact@v1 + with: + name: NtgeApp_linux-x64 + path: NtgeApp/bin/Release/netcoreapp3.1/linux-x64/publish + + win: + runs-on: windows-latest + + steps: + - uses: actions/checkout@v1 + - name: Setup .NET Core + uses: actions/setup-dotnet@v1 + with: + dotnet-version: 3.1.201 + - name: Install dependencies + working-directory: ./NtgeApp + run: dotnet restore + - name: Publish + working-directory: ./NtgeApp + run: dotnet publish -c Release -r win-x64 --self-contained true + - name: Archive publish artifacts + uses: actions/upload-artifact@v1 + with: + name: NtgeApp_win-x64 + path: NtgeApp/bin/Release/netcoreapp3.1/win-x64/publish + + osx: + runs-on: macos-latest + + steps: + - uses: actions/checkout@v1 + - name: Setup .NET Core + uses: actions/setup-dotnet@v1 + with: + dotnet-version: 3.1.201 + - name: Install dependencies + working-directory: ./NtgeApp + run: dotnet restore + - name: Publish + working-directory: ./NtgeApp + run: dotnet publish -c Release -r osx-x64 --self-contained true + - name: Archive publish artifacts + uses: actions/upload-artifact@v1 + with: + name: NtgeApp_osx-64 + path: NtgeApp/bin/Release/netcoreapp3.1/osx-x64/publish \ No newline at end of file From e4a467545b542d13025c279033e336597e90c3f8 Mon Sep 17 00:00:00 2001 From: Tlaster Date: Sun, 10 May 2020 02:04:34 +0800 Subject: [PATCH 05/15] Update NtgeApp CI name --- .github/workflows/NtgeApp.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/NtgeApp.yaml b/.github/workflows/NtgeApp.yaml index 96cbcfc..ad87602 100644 --- a/.github/workflows/NtgeApp.yaml +++ b/.github/workflows/NtgeApp.yaml @@ -1,4 +1,4 @@ -name: .NET Core +name: NtgeApp on: push: From b1add94b86c43b7d9347f6202f4ac926c5fb14d3 Mon Sep 17 00:00:00 2001 From: Tlaster Date: Sun, 10 May 2020 11:45:43 +0800 Subject: [PATCH 06/15] Keep FileSystemWatcher avoid being trimmed --- NtgeApp/NtgeApp.csproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NtgeApp/NtgeApp.csproj b/NtgeApp/NtgeApp.csproj index ebdc785..fb69e55 100644 --- a/NtgeApp/NtgeApp.csproj +++ b/NtgeApp/NtgeApp.csproj @@ -5,6 +5,9 @@ preview enable + + + %(Filename) From 6a21e873a07427549d04a0e59dad4e31aeace2c1 Mon Sep 17 00:00:00 2001 From: Tlaster Date: Sun, 10 May 2020 11:48:15 +0800 Subject: [PATCH 07/15] Publish trimmed file --- .github/workflows/NtgeApp.yaml | 6 +++--- NtgeApp/NtgeApp.csproj | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/NtgeApp.yaml b/.github/workflows/NtgeApp.yaml index ad87602..42bd781 100644 --- a/.github/workflows/NtgeApp.yaml +++ b/.github/workflows/NtgeApp.yaml @@ -29,7 +29,7 @@ jobs: run: dotnet restore - name: Publish working-directory: ./NtgeApp - run: dotnet publish -c Release -r linux-x64 --self-contained true + run: dotnet publish -c Release -r linux-x64 --self-contained true /p:PublishSingleFile=true - name: Archive publish artifacts uses: actions/upload-artifact@v1 with: @@ -50,7 +50,7 @@ jobs: run: dotnet restore - name: Publish working-directory: ./NtgeApp - run: dotnet publish -c Release -r win-x64 --self-contained true + run: dotnet publish -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true - name: Archive publish artifacts uses: actions/upload-artifact@v1 with: @@ -71,7 +71,7 @@ jobs: run: dotnet restore - name: Publish working-directory: ./NtgeApp - run: dotnet publish -c Release -r osx-x64 --self-contained true + run: dotnet publish -c Release -r osx-x64 --self-contained true /p:PublishSingleFile=true - name: Archive publish artifacts uses: actions/upload-artifact@v1 with: diff --git a/NtgeApp/NtgeApp.csproj b/NtgeApp/NtgeApp.csproj index fb69e55..cdd7752 100644 --- a/NtgeApp/NtgeApp.csproj +++ b/NtgeApp/NtgeApp.csproj @@ -4,6 +4,7 @@ netcoreapp3.1 preview enable + True From c89b8d92d00714d1ee737810faf8300d217e8465 Mon Sep 17 00:00:00 2001 From: Tlaster Date: Sun, 10 May 2020 13:55:47 +0800 Subject: [PATCH 08/15] Add DecryptView --- NtgeApp/Models/DecryptKeyModel.cs | 22 +++++++++ NtgeApp/ViewModels/DecryptViewModel.cs | 65 ++++++++++++++++++++++++++ NtgeApp/ViewModels/MainViewModel.cs | 5 +- NtgeApp/Views/DecryptView.xaml | 44 +++++++++++++++++ NtgeApp/Views/DecryptView.xaml.cs | 56 ++++++++++++++++++++++ 5 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 NtgeApp/Models/DecryptKeyModel.cs create mode 100644 NtgeApp/ViewModels/DecryptViewModel.cs create mode 100644 NtgeApp/Views/DecryptView.xaml create mode 100644 NtgeApp/Views/DecryptView.xaml.cs diff --git a/NtgeApp/Models/DecryptKeyModel.cs b/NtgeApp/Models/DecryptKeyModel.cs new file mode 100644 index 0000000..10e9d95 --- /dev/null +++ b/NtgeApp/Models/DecryptKeyModel.cs @@ -0,0 +1,22 @@ +using System; +using NtgeCore.Net.X25519; + +namespace NtgeApp.Models +{ + public class DecryptKeyModel : IDisposable + { + public DecryptKeyModel(string content, X25519PrivateKey x25519PrivateKey) + { + Content = content; + X25519PrivateKey = x25519PrivateKey; + } + + public string Content { get; } + public X25519PrivateKey X25519PrivateKey { get; } + + public void Dispose() + { + X25519PrivateKey.Dispose(); + } + } +} \ No newline at end of file diff --git a/NtgeApp/ViewModels/DecryptViewModel.cs b/NtgeApp/ViewModels/DecryptViewModel.cs new file mode 100644 index 0000000..3597b5b --- /dev/null +++ b/NtgeApp/ViewModels/DecryptViewModel.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using NtgeApp.Models; +using NtgeCore.Net; +using NtgeCore.Net.Ed25519; +using NtgeCore.Net.Message; +using PropertyChanged; + +namespace NtgeApp.ViewModels +{ + public class DecryptViewModel : ViewModelBase + { + public DecryptKeyModel? DecryptKeyModel { get; private set; } + + public string? Input { get; set; } + + public string? Output { get; set; } + + public void OnInputChanged() + { + Decrypt(); + } + + public void OnDecryptKeyModelChanged() + { + Decrypt(); + } + + void Decrypt() + { + if (string.IsNullOrEmpty(Input) || DecryptKeyModel == null) + { + Output = string.Empty; + return; + } + try + { + using var message = NtgeMessage.Deserialize(Input); + using var decryptor = Decryptor.New(message); + using var fileKey = decryptor.GetFileKey(DecryptKeyModel.X25519PrivateKey); + Output = decryptor.DecryptPayload(fileKey); + } + catch (NtgeException e) + { + Output = e.Message; + } + } + + public void SetKey(string privateKeyContent) + { + DecryptKeyModel?.Dispose(); + try + { + using var privateKey = Ed25519PrivateKey.Deserialize(privateKeyContent); + DecryptKeyModel = new DecryptKeyModel(privateKeyContent, privateKey.ToX25519()); + } + catch (NtgeException e) + { + DecryptKeyModel = null; + } + + } + } +} \ No newline at end of file diff --git a/NtgeApp/ViewModels/MainViewModel.cs b/NtgeApp/ViewModels/MainViewModel.cs index 1ab6323..b0ed807 100644 --- a/NtgeApp/ViewModels/MainViewModel.cs +++ b/NtgeApp/ViewModels/MainViewModel.cs @@ -14,7 +14,10 @@ internal class MainViewModel : ViewModelBase new KeysView()), new TabItemModel("Encrypt", Application.Current.FindResource("MaterialDesign.EnhancedEncryption") as GeometryDrawing, - new EncryptView()) + new EncryptView()), + new TabItemModel("Decrypt", + Application.Current.FindResource("Ionicons.UnlockiOS") as GeometryDrawing, + new DecryptView()) }; } } \ No newline at end of file diff --git a/NtgeApp/Views/DecryptView.xaml b/NtgeApp/Views/DecryptView.xaml new file mode 100644 index 0000000..3fb55ef --- /dev/null +++ b/NtgeApp/Views/DecryptView.xaml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NtgeApp/Views/DecryptView.xaml.cs b/NtgeApp/Views/DecryptView.xaml.cs new file mode 100644 index 0000000..6fe43f8 --- /dev/null +++ b/NtgeApp/Views/DecryptView.xaml.cs @@ -0,0 +1,56 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Interactivity; +using Avalonia.Markup.Xaml; +using NtgeApp.Dialogs; +using NtgeApp.Models; +using NtgeApp.ViewModels; +using PropertyChanged; + +namespace NtgeApp.Views +{ + [DoNotNotify] + public class DecryptView : UserControl + { + public DecryptView() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + + + + private async void OnSelectKeyClick(object? sender, RoutedEventArgs e) + { + if (!(DataContext is DecryptViewModel viewModel)) + { + return; + } + + var dialog = new KeyPickerDialog(); + if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + var result = await dialog.ShowDialog(desktop.MainWindow); + switch (result) + { + case KeyModel keyModel: + await keyModel.EnsurePrivateKeyContent(); + if (!string.IsNullOrEmpty(keyModel.PrivateKeyContent)) + { + viewModel.SetKey(keyModel.PrivateKeyContent); + } + break; + case string key: + viewModel.SetKey(key); + break; + } + } + } + + } +} \ No newline at end of file From 91d261b4abaada51a9e8a204d9eff2a1ac6b9caf Mon Sep 17 00:00:00 2001 From: Tlaster Date: Sun, 10 May 2020 13:56:18 +0800 Subject: [PATCH 09/15] Update KeysView design --- NtgeApp/App.xaml | 1 + NtgeApp/Models/KeyModel.cs | 11 ++++++++--- NtgeApp/NtgeApp.csproj | 1 + NtgeApp/Views/KeysView.xaml | 30 ++++++++++++++++++------------ 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/NtgeApp/App.xaml b/NtgeApp/App.xaml index 3a60820..f957a6f 100644 --- a/NtgeApp/App.xaml +++ b/NtgeApp/App.xaml @@ -4,6 +4,7 @@ + - - From 06b0264260510ce51d3283ae952bf354e3d330bf Mon Sep 17 00:00:00 2001 From: Tlaster Date: Sun, 10 May 2020 14:23:16 +0800 Subject: [PATCH 12/15] Impove error handling for Decryptor --- NtgeCore.Net/src/Message/Decryptor.cs | 16 +++++++++++++--- NtgeCore.Net/src/Native.cs | 2 +- NtgeCore.Net/src/StringHandle.cs | 5 +++++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/NtgeCore.Net/src/Message/Decryptor.cs b/NtgeCore.Net/src/Message/Decryptor.cs index dd133a9..7107ba0 100644 --- a/NtgeCore.Net/src/Message/Decryptor.cs +++ b/NtgeCore.Net/src/Message/Decryptor.cs @@ -21,13 +21,23 @@ public bool VerifyMessageMac(X25519FileKey fileKey) public X25519FileKey GetFileKey(X25519PrivateKey privateKey) { - return new X25519FileKey(Native.messageDecryptorDecryptFileKey(Ptr, privateKey.Ptr)); + var ptr = Native.messageDecryptorDecryptFileKey(Ptr, privateKey.Ptr); + if (ptr == IntPtr.Zero) + { + throw new NtgeException("Can not get file key"); + } + return new X25519FileKey(ptr); } public string DecryptPayload(X25519FileKey fileKey) { - using var result = Native.messageDecryptorDecryptPayload(Ptr, fileKey.Ptr); - return result.AsString(); + var ptr = Native.messageDecryptorDecryptPayload(Ptr, fileKey.Ptr); + if (ptr == IntPtr.Zero) + { + throw new NtgeException("Can not decrypt payload"); + } + using var stringHandle = new StringHandle(ptr); + return stringHandle.AsString(); } public override void Dispose() diff --git a/NtgeCore.Net/src/Native.cs b/NtgeCore.Net/src/Native.cs index 168ac0c..5e58333 100644 --- a/NtgeCore.Net/src/Native.cs +++ b/NtgeCore.Net/src/Native.cs @@ -81,7 +81,7 @@ internal class Native public static extern IntPtr messageDecryptorDecryptFileKey(IntPtr decryptor_ptr, IntPtr private_key_ptr); [DllImport(LIB_NAME)] - public static extern StringHandle messageDecryptorDecryptPayload(IntPtr decryptor_ptr, IntPtr file_key_ptr); + public static extern IntPtr messageDecryptorDecryptPayload(IntPtr decryptor_ptr, IntPtr file_key_ptr); [DllImport(LIB_NAME)] [return: MarshalAs(UnmanagedType.I1)] diff --git a/NtgeCore.Net/src/StringHandle.cs b/NtgeCore.Net/src/StringHandle.cs index 64b0751..688e8ea 100644 --- a/NtgeCore.Net/src/StringHandle.cs +++ b/NtgeCore.Net/src/StringHandle.cs @@ -6,6 +6,11 @@ namespace NtgeCore.Net { internal class StringHandle : SafeHandle { + public StringHandle(IntPtr ptr) : this() + { + SetHandle(ptr); + } + public StringHandle() : base(IntPtr.Zero, true) { From 998a42aa7fd65a0ce0e9849c713675d2d8d4600f Mon Sep 17 00:00:00 2001 From: Tlaster Date: Sun, 10 May 2020 14:23:54 +0800 Subject: [PATCH 13/15] Fix artifact name for osx --- .github/workflows/NtgeApp.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/NtgeApp.yaml b/.github/workflows/NtgeApp.yaml index 42bd781..f395fc0 100644 --- a/.github/workflows/NtgeApp.yaml +++ b/.github/workflows/NtgeApp.yaml @@ -75,5 +75,5 @@ jobs: - name: Archive publish artifacts uses: actions/upload-artifact@v1 with: - name: NtgeApp_osx-64 + name: NtgeApp_osx-x64 path: NtgeApp/bin/Release/netcoreapp3.1/osx-x64/publish \ No newline at end of file From 3ba9724659fbf639a7138058948f2ba5023bda5c Mon Sep 17 00:00:00 2001 From: Tlaster Date: Sat, 27 Jun 2020 01:18:21 +0800 Subject: [PATCH 14/15] Update avalonia --- NtgeApp/App.xaml | 7 +++---- NtgeApp/MainWindow.xaml | 6 +++--- NtgeApp/Program.cs | 1 - 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/NtgeApp/App.xaml b/NtgeApp/App.xaml index f957a6f..de07eb8 100644 --- a/NtgeApp/App.xaml +++ b/NtgeApp/App.xaml @@ -2,11 +2,10 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="NtgeApp.App"> - - + - @@ -17,7 +16,7 @@ + --> diff --git a/NtgeApp/MainWindow.xaml b/NtgeApp/MainWindow.xaml index 74cb8c4..a98d4f4 100644 --- a/NtgeApp/MainWindow.xaml +++ b/NtgeApp/MainWindow.xaml @@ -9,7 +9,7 @@ x:Class="NtgeApp.MainWindow" Title="NtgeApp"> - + + --> diff --git a/NtgeApp/Program.cs b/NtgeApp/Program.cs index a500282..d22c091 100644 --- a/NtgeApp/Program.cs +++ b/NtgeApp/Program.cs @@ -1,5 +1,4 @@ using Avalonia; -using Avalonia.Logging.Serilog; namespace NtgeApp { From 77dc9ab69f6dbc070a92efee36a3526dede57426 Mon Sep 17 00:00:00 2001 From: Tlaster Date: Thu, 16 Jul 2020 18:42:24 +0800 Subject: [PATCH 15/15] update app --- NtgeApp/App.xaml | 17 +++---- NtgeApp/Dialogs/CreateKeyDialog.xaml | 4 +- NtgeApp/Dialogs/KeyPickerDialog.xaml | 4 +- NtgeApp/FluentWindow.cs | 49 ++++++++++++++++++ NtgeApp/MainWindow.xaml | 71 +++++++++----------------- NtgeApp/MainWindow.xaml.cs | 2 +- NtgeApp/NtgeApp.csproj | 6 +-- NtgeApp/Resources/SideBar.xaml | 75 ++++++++++++++++++++++++++++ NtgeApp/Views/DecryptView.xaml | 2 +- NtgeApp/Views/EncryptView.xaml | 2 +- 10 files changed, 166 insertions(+), 66 deletions(-) create mode 100644 NtgeApp/FluentWindow.cs create mode 100644 NtgeApp/Resources/SideBar.xaml diff --git a/NtgeApp/App.xaml b/NtgeApp/App.xaml index de07eb8..2483457 100644 --- a/NtgeApp/App.xaml +++ b/NtgeApp/App.xaml @@ -2,21 +2,20 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="NtgeApp.App"> - + + - diff --git a/NtgeApp/Dialogs/CreateKeyDialog.xaml b/NtgeApp/Dialogs/CreateKeyDialog.xaml index f8b35cc..d5f060e 100644 --- a/NtgeApp/Dialogs/CreateKeyDialog.xaml +++ b/NtgeApp/Dialogs/CreateKeyDialog.xaml @@ -24,10 +24,10 @@ - - diff --git a/NtgeApp/Dialogs/KeyPickerDialog.xaml b/NtgeApp/Dialogs/KeyPickerDialog.xaml index 2a75509..d040146 100644 --- a/NtgeApp/Dialogs/KeyPickerDialog.xaml +++ b/NtgeApp/Dialogs/KeyPickerDialog.xaml @@ -48,10 +48,10 @@ - - diff --git a/NtgeApp/FluentWindow.cs b/NtgeApp/FluentWindow.cs new file mode 100644 index 0000000..cce34fb --- /dev/null +++ b/NtgeApp/FluentWindow.cs @@ -0,0 +1,49 @@ +using Avalonia.Styling; +using System; +using System.Collections.Generic; +using System.Text; +using Avalonia.Platform; +using Avalonia.Controls.Primitives; +using PropertyChanged; + +namespace Avalonia.Controls +{ + [DoNotNotify] + public class FluentWindow : Window, IStyleable + { + Type IStyleable.StyleKey => typeof(Window); + + public FluentWindow() + { + ExtendClientAreaToDecorationsHint = true; + ExtendClientAreaTitleBarHeightHint = -1; + + TransparencyLevelHint = WindowTransparencyLevel.AcrylicBlur; + + this.GetObservable(WindowStateProperty) + .Subscribe(x => + { + PseudoClasses.Set(":maximized", x == WindowState.Maximized); + PseudoClasses.Set(":fullscreen", x == WindowState.FullScreen); + }); + + this.GetObservable(IsExtendedIntoWindowDecorationsProperty) + .Subscribe(x => + { + if (!x) + { + SystemDecorations = SystemDecorations.Full; + TransparencyLevelHint = WindowTransparencyLevel.Blur; + } + }); + } + + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) + { + base.OnApplyTemplate(e); + ExtendClientAreaChromeHints = + ExtendClientAreaChromeHints.PreferSystemChrome | + ExtendClientAreaChromeHints.OSXThickTitleBar; + } + } +} diff --git a/NtgeApp/MainWindow.xaml b/NtgeApp/MainWindow.xaml index a98d4f4..70b642a 100644 --- a/NtgeApp/MainWindow.xaml +++ b/NtgeApp/MainWindow.xaml @@ -1,4 +1,4 @@ - - - - - - - + - - - + + + + + + + + + + + + + + + + @@ -71,5 +48,5 @@ - - \ No newline at end of file + + \ No newline at end of file diff --git a/NtgeApp/MainWindow.xaml.cs b/NtgeApp/MainWindow.xaml.cs index 89fde8b..7e1fe16 100644 --- a/NtgeApp/MainWindow.xaml.cs +++ b/NtgeApp/MainWindow.xaml.cs @@ -5,7 +5,7 @@ namespace NtgeApp { [DoNotNotify] - public class MainWindow : Window + public class MainWindow : FluentWindow { public MainWindow() { diff --git a/NtgeApp/NtgeApp.csproj b/NtgeApp/NtgeApp.csproj index a718485..2919db5 100644 --- a/NtgeApp/NtgeApp.csproj +++ b/NtgeApp/NtgeApp.csproj @@ -21,9 +21,9 @@ - - - + + + diff --git a/NtgeApp/Resources/SideBar.xaml b/NtgeApp/Resources/SideBar.xaml new file mode 100644 index 0000000..4155b7b --- /dev/null +++ b/NtgeApp/Resources/SideBar.xaml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + diff --git a/NtgeApp/Views/DecryptView.xaml b/NtgeApp/Views/DecryptView.xaml index 3fb55ef..b06e225 100644 --- a/NtgeApp/Views/DecryptView.xaml +++ b/NtgeApp/Views/DecryptView.xaml @@ -24,7 +24,7 @@ - diff --git a/NtgeApp/Views/EncryptView.xaml b/NtgeApp/Views/EncryptView.xaml index 384a70c..12842ad 100644 --- a/NtgeApp/Views/EncryptView.xaml +++ b/NtgeApp/Views/EncryptView.xaml @@ -22,7 +22,7 @@ -