Created login and error handling to get auth token. Refreshing not handled.

This commit is contained in:
Patrick Fic
2020-01-16 18:43:50 -08:00
parent 0daf17a3f0
commit cfec5327dd
17 changed files with 625 additions and 47 deletions

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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;
}
}
}
}

View File

@@ -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>

View 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";
}
}

View 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?
}
}
}

View 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;
}
}
}

View 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");
}
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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); }
}
}
}

View File

@@ -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>

View File

@@ -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);
}
}
}

View File

@@ -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>