Created login and error handling to get auth token. Refreshing not handled.
This commit is contained in:
@@ -1,6 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<configSections>
|
||||
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
|
||||
<section name="BodyshopUploader.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
|
||||
</sectionGroup>
|
||||
</configSections>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
|
||||
</startup>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
<userSettings>
|
||||
<BodyshopUploader.Properties.Settings>
|
||||
<setting name="Username" serializeAs="String">
|
||||
<value />
|
||||
</setting>
|
||||
</BodyshopUploader.Properties.Settings>
|
||||
</userSettings>
|
||||
</configuration>
|
||||
@@ -2,8 +2,16 @@
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:BodyshopUploader"
|
||||
ShutdownMode="OnExplicitShutdown"
|
||||
StartupUri="Views\Login.xaml">
|
||||
<Application.Resources>
|
||||
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.Indigo.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Indigo.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
@@ -53,9 +55,23 @@
|
||||
<ApplicationIcon>favicon.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Firebase.Auth, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\FirebaseAuthentication.net.3.4.0\lib\netstandard1.1\Firebase.Auth.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Hardcodet.Wpf.TaskbarNotification, Version=1.0.5.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Hardcodet.NotifyIcon.Wpf.1.0.8\lib\net451\Hardcodet.Wpf.TaskbarNotification.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MaterialDesignColors, Version=1.2.2.920, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MaterialDesignColors.1.2.2\lib\net45\MaterialDesignColors.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MaterialDesignThemes.Wpf, Version=3.0.1.920, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MaterialDesignThemes.3.0.1\lib\net45\MaterialDesignThemes.Wpf.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Win32.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Win32.Primitives.4.3.0\lib\net46\Microsoft.Win32.Primitives.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
@@ -63,21 +79,145 @@
|
||||
<HintPath>..\packages\NLog.4.6.8\lib\net45\NLog.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.AppContext, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.AppContext.4.3.0\lib\net463\System.AppContext.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.ComponentModel.Composition" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Console, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Console.4.3.0\lib\net46\System.Console.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.IO.Compression" />
|
||||
<Reference Include="System.Diagnostics.DiagnosticSource, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Diagnostics.DiagnosticSource.4.3.0\lib\net46\System.Diagnostics.DiagnosticSource.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Diagnostics.Tracing, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Diagnostics.Tracing.4.3.0\lib\net462\System.Diagnostics.Tracing.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Globalization.Calendars, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Globalization.Calendars.4.3.0\lib\net46\System.Globalization.Calendars.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.IO, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.4.3.0\lib\net462\System.IO.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.Compression, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.Compression.FileSystem" />
|
||||
<Reference Include="System.IO.Compression.ZipFile, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.Compression.ZipFile.4.3.0\lib\net46\System.IO.Compression.ZipFile.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.FileSystem, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.FileSystem.Primitives, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Linq, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Linq.4.3.0\lib\net463\System.Linq.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Linq.Expressions, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Linq.Expressions.4.3.0\lib\net463\System.Linq.Expressions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Net.Http.4.3.0\lib\net46\System.Net.Http.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Sockets, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Net.Sockets.4.3.0\lib\net46\System.Net.Sockets.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Reflection, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Reflection.4.3.0\lib\net462\System.Reflection.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Runtime.4.3.0\lib\net462\System.Runtime.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.Extensions, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Runtime.Extensions.4.3.0\lib\net462\System.Runtime.Extensions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.InteropServices, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Runtime.InteropServices.4.3.0\lib\net463\System.Runtime.InteropServices.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.InteropServices.RuntimeInformation, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.Security.Cryptography.Algorithms, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net463\System.Security.Cryptography.Algorithms.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Security.Cryptography.Encoding, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Security.Cryptography.Primitives, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Security.Cryptography.X509Certificates, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.ServiceModel" />
|
||||
<Reference Include="System.Text.RegularExpressions, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Text.RegularExpressions.4.3.0\lib\net463\System.Text.RegularExpressions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Transactions" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xaml">
|
||||
<RequiredTargetFramework>4.0</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.ReaderWriter, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="WindowsBase" />
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
@@ -97,9 +237,13 @@
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
</Compile>
|
||||
<Compile Include="Utils\AppMetaData.cs" />
|
||||
<Compile Include="Utils\Auth.cs" />
|
||||
<Compile Include="Utils\BaseModel.cs" />
|
||||
<Compile Include="Utils\BaseViewModel.cs" />
|
||||
<Compile Include="Utils\LoginHelpers.cs" />
|
||||
<Compile Include="Utils\RelayCommand.cs" />
|
||||
<Compile Include="Utils\UiConverters.cs" />
|
||||
<Compile Include="ViewModels\LoginViewModel.commands.cs" />
|
||||
<Compile Include="ViewModels\LoginViewModel.cs" />
|
||||
<Compile Include="ViewModels\MainViewModel.commands.cs" />
|
||||
@@ -183,4 +327,11 @@
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="..\packages\MaterialDesignThemes.3.0.1\build\MaterialDesignThemes.targets" Condition="Exists('..\packages\MaterialDesignThemes.3.0.1\build\MaterialDesignThemes.targets')" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\MaterialDesignThemes.3.0.1\build\MaterialDesignThemes.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MaterialDesignThemes.3.0.1\build\MaterialDesignThemes.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
36
BodyshopUploader/Properties/Resources.Designer.cs
generated
36
BodyshopUploader/Properties/Resources.Designer.cs
generated
@@ -60,6 +60,42 @@ namespace BodyshopUploader.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to An issue has occured. Please check the log files..
|
||||
/// </summary>
|
||||
public static string Error_Generic {
|
||||
get {
|
||||
return ResourceManager.GetString("Error_Generic", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The username and password combination is not valid. Please try again. .
|
||||
/// </summary>
|
||||
public static string Error_Login {
|
||||
get {
|
||||
return ResourceManager.GetString("Error_Login", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Too many login attempts..
|
||||
/// </summary>
|
||||
public static string Error_Login_Attempts {
|
||||
get {
|
||||
return ResourceManager.GetString("Error_Login_Attempts", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to An unknown error occured while logging in. Please check the log files..
|
||||
/// </summary>
|
||||
public static string Error_Login_Unknown {
|
||||
get {
|
||||
return ResourceManager.GetString("Error_Login_Unknown", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Exit.
|
||||
/// </summary>
|
||||
|
||||
@@ -117,6 +117,18 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Error_Generic" xml:space="preserve">
|
||||
<value>An issue has occured. Please check the log files.</value>
|
||||
</data>
|
||||
<data name="Error_Login" xml:space="preserve">
|
||||
<value>The username and password combination is not valid. Please try again. </value>
|
||||
</data>
|
||||
<data name="Error_Login_Attempts" xml:space="preserve">
|
||||
<value>Too many login attempts.</value>
|
||||
</data>
|
||||
<data name="Error_Login_Unknown" xml:space="preserve">
|
||||
<value>An unknown error occured while logging in. Please check the log files.</value>
|
||||
</data>
|
||||
<data name="Exit" xml:space="preserve">
|
||||
<value>Exit</value>
|
||||
</data>
|
||||
|
||||
45
BodyshopUploader/Properties/Settings.Designer.cs
generated
45
BodyshopUploader/Properties/Settings.Designer.cs
generated
@@ -8,23 +8,42 @@
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace BodyshopUploader.Properties
|
||||
{
|
||||
|
||||
|
||||
namespace BodyshopUploader.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
|
||||
{
|
||||
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.4.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
public static Settings Default {
|
||||
get {
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("")]
|
||||
public string Username {
|
||||
get {
|
||||
return ((string)(this["Username"]));
|
||||
}
|
||||
set {
|
||||
this["Username"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
public global::System.Security.SecureString Password {
|
||||
get {
|
||||
return ((global::System.Security.SecureString)(this["Password"]));
|
||||
}
|
||||
set {
|
||||
this["Password"] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="BodyshopUploader.Properties" GeneratedClassName="Settings">
|
||||
<Profiles />
|
||||
<Settings>
|
||||
<Setting Name="Username" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="Password" Type="System.Security.SecureString" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
</Settings>
|
||||
</SettingsFile>
|
||||
14
BodyshopUploader/Utils/AppMetaData.cs
Normal file
14
BodyshopUploader/Utils/AppMetaData.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BodyshopUploader.Utils
|
||||
{
|
||||
public static class AppMetaData
|
||||
{
|
||||
public static string FirebaseAPIKey_DEV = "AIzaSyDV9MsSHZmpLtjoaTK_ObvjFaJ-nMSd2KA";
|
||||
|
||||
}
|
||||
}
|
||||
69
BodyshopUploader/Utils/Auth.cs
Normal file
69
BodyshopUploader/Utils/Auth.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Firebase.Auth;
|
||||
using System.Timers;
|
||||
|
||||
namespace BodyshopUploader.Utils
|
||||
{
|
||||
public static class Auth
|
||||
{
|
||||
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
||||
public static FirebaseAuthLink authlink;
|
||||
public static string authToken;
|
||||
static string refreshToken;
|
||||
static int tokenExpiration;
|
||||
static FirebaseAuthProvider ap = new FirebaseAuthProvider(new FirebaseConfig(Utils.AppMetaData.FirebaseAPIKey_DEV)); //TODO: Update this to be a dynamic key. Perhaps a function that fetches?
|
||||
private static Timer tokenTimer = new Timer();
|
||||
|
||||
public async static Task<(bool, string)> LoginAsync(string Username, string Password)
|
||||
{
|
||||
try
|
||||
{
|
||||
authlink = await ap.SignInWithEmailAndPasswordAsync(Username, Password);
|
||||
authToken = authlink.FirebaseToken;
|
||||
refreshToken = authlink.RefreshToken;
|
||||
tokenExpiration = authlink.ExpiresIn;
|
||||
logger.Trace("Firebase Auth Token {0}.", authToken);
|
||||
logger.Trace("Firebase Refresh Token {0}.", refreshToken);
|
||||
logger.Trace("Firebase Auth Token expires in {0} seconds.", tokenExpiration);
|
||||
|
||||
tokenTimer.Interval = (tokenExpiration - 600) * 1000; //Set the token to refresh 10 minutes before it has to.
|
||||
tokenTimer.Elapsed += TokenTimer_Elapsed;
|
||||
return (true, null);
|
||||
}
|
||||
catch (FirebaseAuthException Ex)
|
||||
{
|
||||
switch (Ex.Reason)
|
||||
{
|
||||
case AuthErrorReason.WrongPassword:
|
||||
logger.Error("Incorrect password provided for user.");
|
||||
return (false, Properties.Resources.Error_Login);
|
||||
|
||||
case AuthErrorReason.UnknownEmailAddress:
|
||||
logger.Error("User does not exist.");
|
||||
return (false, Properties.Resources.Error_Login);
|
||||
case AuthErrorReason.TooManyAttemptsTryLater:
|
||||
logger.Error("Too many attempts logging in.");
|
||||
return (false, Properties.Resources.Error_Login_Attempts);
|
||||
default:
|
||||
logger.Error(Ex, "Unknown error occured while logging in. {0}", Ex.Reason);
|
||||
return (false, Properties.Resources.Error_Login_Unknown);
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
logger.Error(Ex, "Unknown error encountered while obtaining auth token.");
|
||||
return (false, Properties.Resources.Error_Generic);
|
||||
}
|
||||
}
|
||||
|
||||
private static void TokenTimer_Elapsed(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
//Gotta do some stuff now that i got a new token!
|
||||
//Maybe the token auto refreshes?
|
||||
}
|
||||
}
|
||||
}
|
||||
30
BodyshopUploader/Utils/LoginHelpers.cs
Normal file
30
BodyshopUploader/Utils/LoginHelpers.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BodyshopUploader.Utils
|
||||
{
|
||||
public static class LoginHelpers
|
||||
{
|
||||
public static void SaveLoginSettings(string Username, SecureString Password)
|
||||
{
|
||||
Properties.Settings.Default.Username = Username;
|
||||
//Todo: Figure out how to save the secure string. Perhaps serialize to JSON?
|
||||
Properties.Settings.Default.Password = Password;
|
||||
Properties.Settings.Default.Save();
|
||||
}
|
||||
|
||||
public static string DecodePassword (SecureString s)
|
||||
{
|
||||
//Manage the secure string for the password.
|
||||
IntPtr stringPointer = Marshal.SecureStringToBSTR(s);
|
||||
string UP = Marshal.PtrToStringBSTR(stringPointer);
|
||||
Marshal.ZeroFreeBSTR(stringPointer);
|
||||
return UP;
|
||||
}
|
||||
}
|
||||
}
|
||||
44
BodyshopUploader/Utils/UiConverters.cs
Normal file
44
BodyshopUploader/Utils/UiConverters.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace BodyshopUploader.Utils
|
||||
{
|
||||
public class BoolVisibilityConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if ((bool)value)
|
||||
return Visibility.Visible;
|
||||
else
|
||||
return Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotSupportedException("Two-way binding not supported by BoolVisibilityConverter");
|
||||
}
|
||||
}
|
||||
|
||||
public class NullVisibilityConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value == null)
|
||||
return Visibility.Collapsed;
|
||||
else
|
||||
return Visibility.Visible;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotSupportedException("Two-way binding not supported by ZeroVisibilityConverter");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +1,24 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace BodyshopUploader.ViewModels
|
||||
{
|
||||
public partial class LoginViewModel : BaseViewModel
|
||||
{
|
||||
private ICommand _openMainCommand;
|
||||
public ICommand OpenMainCommand
|
||||
private ICommand _loginCommand;
|
||||
public ICommand LoginCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_openMainCommand == null)
|
||||
if (_loginCommand == null)
|
||||
{
|
||||
_openMainCommand = new RelayCommand(
|
||||
p => true,
|
||||
p => { Views.Main m = new Views.Main(); m.Show(); });
|
||||
_loginCommand = new RelayCommand(
|
||||
p => !string.IsNullOrEmpty(UserName) && UserPassword?.Length > 6,
|
||||
async p => { await LoginAsync(p as Window); });
|
||||
}
|
||||
return _openMainCommand;
|
||||
return _loginCommand;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,37 @@
|
||||
using System;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace BodyshopUploader.ViewModels
|
||||
{
|
||||
{
|
||||
public partial class LoginViewModel : BaseViewModel
|
||||
{
|
||||
{
|
||||
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
||||
|
||||
public LoginViewModel()
|
||||
{
|
||||
logger.Trace("We're in boys.");
|
||||
logger.Trace("Login VM Created.");
|
||||
}
|
||||
|
||||
private async Task LoginAsync(Window W)
|
||||
{
|
||||
Loading = true;
|
||||
|
||||
Utils.LoginHelpers.SaveLoginSettings(UserName, UserPassword);
|
||||
|
||||
logger.Trace("Attempting to login as user: {0}", UserName);
|
||||
(Error, ErrorMsg) = await Utils.Auth.LoginAsync(UserName, Utils.LoginHelpers.DecodePassword(UserPassword));
|
||||
if(ErrorMsg ==null)
|
||||
{
|
||||
Views.Main m = new Views.Main();
|
||||
m.Show();
|
||||
W.Hide();
|
||||
}
|
||||
Loading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,25 +2,47 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BodyshopUploader.ViewModels
|
||||
{
|
||||
public partial class LoginViewModel: BaseViewModel
|
||||
public partial class LoginViewModel : BaseViewModel
|
||||
{
|
||||
private ObservableCollection<string> _invoiceList;
|
||||
public ObservableCollection<string> InvoiceList
|
||||
private string _userName = Properties.Settings.Default.Username;
|
||||
public string UserName
|
||||
{
|
||||
get { return _invoiceList; }
|
||||
set { SetProperty(ref _invoiceList, value); }
|
||||
get { return _userName; }
|
||||
set { SetProperty(ref _userName, value); }
|
||||
}
|
||||
|
||||
private int _progress = 5;
|
||||
public int Progress
|
||||
private SecureString _userPassword = Properties.Settings.Default.Password;
|
||||
public SecureString UserPassword
|
||||
{
|
||||
get { return _progress; }
|
||||
set { SetProperty(ref _progress, value); }
|
||||
get { return _userPassword; }
|
||||
set { SetProperty(ref _userPassword, value); }
|
||||
}
|
||||
|
||||
private bool _error = false;
|
||||
public bool Error
|
||||
{
|
||||
get { return _error; }
|
||||
set { SetProperty(ref _error, value); }
|
||||
}
|
||||
|
||||
private string _errorMsg;
|
||||
public string ErrorMsg
|
||||
{
|
||||
get { return _errorMsg; }
|
||||
set { SetProperty(ref _errorMsg, value); }
|
||||
}
|
||||
|
||||
private bool _loading = false;
|
||||
public bool Loading
|
||||
{
|
||||
get { return _loading; }
|
||||
set { SetProperty(ref _loading, value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,15 +9,56 @@
|
||||
Title="{x:Static p:Resources.Title_Login}"
|
||||
Height="450"
|
||||
Width="800"
|
||||
xmlns:p="clr-namespace:BodyshopUploader.Properties">
|
||||
xmlns:p="clr-namespace:BodyshopUploader.Properties"
|
||||
xmlns:util="clr-namespace:BodyshopUploader.Utils"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
|
||||
TextElement.FontWeight="Regular"
|
||||
TextElement.FontSize="13"
|
||||
TextOptions.TextFormattingMode="Ideal"
|
||||
TextOptions.TextRenderingMode="Auto"
|
||||
Background="{DynamicResource MaterialDesignPaper}"
|
||||
FontFamily="{DynamicResource MaterialDesignFont}"
|
||||
Closing="Window_Closing">
|
||||
<Window.DataContext>
|
||||
<vm:LoginViewModel />
|
||||
</Window.DataContext>
|
||||
<Window.Resources>
|
||||
<util:NullVisibilityConverter x:Key="NullVisibilityConverter" />
|
||||
</Window.Resources>
|
||||
|
||||
<StackPanel>
|
||||
<Button Command="{Binding OpenMainCommand}"
|
||||
Content="{x:Static p:Resources.Login}" />
|
||||
<StackPanel Orientation="Vertical"
|
||||
HorizontalAlignment="Center">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="Person"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBox materialDesign:HintAssist.Hint="{x:Static p:Resources.Username}"
|
||||
Width="300"
|
||||
Style="{StaticResource MaterialDesignFloatingHintTextBox}"
|
||||
Text="{Binding UserName}" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="Key"
|
||||
VerticalAlignment="Center" />
|
||||
<PasswordBox materialDesign:HintAssist.Hint="{x:Static p:Resources.Password}"
|
||||
KeyDown="PasswordBox_KeyDown"
|
||||
PasswordChanged="PasswordBox_PasswordChanged"
|
||||
Width="300"
|
||||
Style="{StaticResource MaterialDesignFloatingHintPasswordBox}" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Text="{Binding ErrorMsg}"
|
||||
Visibility="{Binding ErrorMsg, Converter={StaticResource NullVisibilityConverter}}" />
|
||||
|
||||
<TextBlock Text="{Binding Progress, TargetNullValue=QUE, FallbackValue=QUE2}" />
|
||||
<Button Command="{Binding LoginCommand}"
|
||||
CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"
|
||||
Content="{x:Static p:Resources.Login}"
|
||||
Style="{StaticResource MaterialDesignRaisedButton}"
|
||||
IsDefault="True"
|
||||
materialDesign:ButtonProgressAssist.Value="-1"
|
||||
materialDesign:ButtonProgressAssist.IsIndicatorVisible="True"
|
||||
materialDesign:ButtonProgressAssist.IsIndeterminate="{Binding Loading}" />
|
||||
</StackPanel>
|
||||
</Window>
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
@@ -23,5 +24,43 @@ namespace BodyshopUploader.Views
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (this.DataContext != null)
|
||||
{ ((dynamic)this.DataContext).UserPassword = ((PasswordBox)sender).SecurePassword; }
|
||||
}
|
||||
|
||||
private void PasswordBox_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
|
||||
{
|
||||
var pb = sender as PasswordBox;
|
||||
|
||||
if ((Keyboard.GetKeyStates(Key.CapsLock) & KeyStates.Toggled) == KeyStates.Toggled)
|
||||
{
|
||||
if (pb.ToolTip == null)
|
||||
{
|
||||
ToolTip tt = new ToolTip();
|
||||
tt.Content = "Warning: CapsLock is on";
|
||||
tt.PlacementTarget = sender as UIElement;
|
||||
tt.Placement = PlacementMode.Right;
|
||||
pb.ToolTip = tt;
|
||||
tt.IsOpen = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var currentToolTip = pb.ToolTip as ToolTip;
|
||||
if (currentToolTip != null)
|
||||
{
|
||||
currentToolTip.IsOpen = false;
|
||||
}
|
||||
|
||||
pb.ToolTip = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
|
||||
{
|
||||
Application.Current.Shutdown(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,57 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="FirebaseAuthentication.net" version="3.4.0" targetFramework="net472" />
|
||||
<package id="Hardcodet.NotifyIcon.Wpf" version="1.0.8" targetFramework="net472" />
|
||||
<package id="MaterialDesignColors" version="1.2.2" targetFramework="net472" />
|
||||
<package id="MaterialDesignThemes" version="3.0.1" targetFramework="net472" />
|
||||
<package id="Microsoft.NETCore.Platforms" version="1.1.0" targetFramework="net472" />
|
||||
<package id="Microsoft.Win32.Primitives" version="4.3.0" targetFramework="net472" />
|
||||
<package id="NETStandard.Library" version="1.6.1" targetFramework="net472" />
|
||||
<package id="Newtonsoft.Json" version="12.0.3" targetFramework="net472" />
|
||||
<package id="NLog" version="4.6.8" targetFramework="net472" />
|
||||
<package id="NLog.Config" version="4.6.8" targetFramework="net472" />
|
||||
<package id="NLog.Schema" version="4.6.8" targetFramework="net472" />
|
||||
<package id="System.AppContext" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Collections" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Console" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Diagnostics.DiagnosticSource" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Diagnostics.Tools" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Diagnostics.Tracing" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Globalization" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Globalization.Calendars" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.IO" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.IO.Compression" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.IO.Compression.ZipFile" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.IO.FileSystem" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Linq" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Linq.Expressions" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Net.Http" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Net.Primitives" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Net.Sockets" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.ObjectModel" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Reflection" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Reflection.Extensions" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Reflection.Primitives" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Runtime" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Runtime.Extensions" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Runtime.Handles" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Runtime.InteropServices" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Runtime.Numerics" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Text.Encoding" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Text.Encoding.Extensions" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Text.RegularExpressions" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Threading" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Threading.Tasks" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Threading.Timer" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Xml.ReaderWriter" version="4.3.0" targetFramework="net472" />
|
||||
<package id="System.Xml.XDocument" version="4.3.0" targetFramework="net472" />
|
||||
</packages>
|
||||
Reference in New Issue
Block a user