Added automatic login using auth tokens IO-403
This commit is contained in:
@@ -57,6 +57,12 @@
|
|||||||
<setting name="QuickBooksFilePath" serializeAs="String">
|
<setting name="QuickBooksFilePath" serializeAs="String">
|
||||||
<value />
|
<value />
|
||||||
</setting>
|
</setting>
|
||||||
|
<setting name="AuthToken" serializeAs="String">
|
||||||
|
<value />
|
||||||
|
</setting>
|
||||||
|
<setting name="RefreshToken" serializeAs="String">
|
||||||
|
<value />
|
||||||
|
</setting>
|
||||||
</BodyshopPartner.Properties.Settings>
|
</BodyshopPartner.Properties.Settings>
|
||||||
</userSettings>
|
</userSettings>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|||||||
26
BodyshopUploader/Properties/Settings.Designer.cs
generated
26
BodyshopUploader/Properties/Settings.Designer.cs
generated
@@ -12,7 +12,7 @@ namespace BodyshopPartner.Properties {
|
|||||||
|
|
||||||
|
|
||||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.7.0.0")]
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.8.1.0")]
|
||||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||||
|
|
||||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||||
@@ -104,5 +104,29 @@ namespace BodyshopPartner.Properties {
|
|||||||
this["QuickBooksFilePath"] = value;
|
this["QuickBooksFilePath"] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Configuration.DefaultSettingValueAttribute("")]
|
||||||
|
public string AuthToken {
|
||||||
|
get {
|
||||||
|
return ((string)(this["AuthToken"]));
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
this["AuthToken"] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Configuration.DefaultSettingValueAttribute("")]
|
||||||
|
public string RefreshToken {
|
||||||
|
get {
|
||||||
|
return ((string)(this["RefreshToken"]));
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
this["RefreshToken"] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,5 +23,11 @@
|
|||||||
<Setting Name="QuickBooksFilePath" Type="System.String" Scope="User">
|
<Setting Name="QuickBooksFilePath" Type="System.String" Scope="User">
|
||||||
<Value Profile="(Default)" />
|
<Value Profile="(Default)" />
|
||||||
</Setting>
|
</Setting>
|
||||||
|
<Setting Name="AuthToken" Type="System.String" Scope="User">
|
||||||
|
<Value Profile="(Default)" />
|
||||||
|
</Setting>
|
||||||
|
<Setting Name="RefreshToken" Type="System.String" Scope="User">
|
||||||
|
<Value Profile="(Default)" />
|
||||||
|
</Setting>
|
||||||
</Settings>
|
</Settings>
|
||||||
</SettingsFile>
|
</SettingsFile>
|
||||||
@@ -12,15 +12,57 @@ namespace BodyshopPartner.Utils
|
|||||||
{
|
{
|
||||||
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
||||||
public static FirebaseAuthLink authlink;
|
public static FirebaseAuthLink authlink;
|
||||||
static FirebaseAuthProvider ap = new FirebaseAuthProvider(new FirebaseConfig(Utils.AppMetaData.FirebaseAPIKey));
|
static FirebaseAuthProvider ap = new FirebaseAuthProvider(new FirebaseConfig(Utils.AppMetaData.FirebaseAPIKey));
|
||||||
private static Timer tokenTimer = new Timer();
|
private static Timer tokenTimer = new Timer();
|
||||||
private static string U;
|
private static string U;
|
||||||
private static string P;
|
private static string P;
|
||||||
|
|
||||||
|
|
||||||
public async static Task AuthTest()
|
public async static Task AuthTest()
|
||||||
{
|
{
|
||||||
await ap.RefreshAuthAsync( new FirebaseAuth() { });
|
await ap.RefreshAuthAsync(new FirebaseAuth() { });
|
||||||
|
}
|
||||||
|
|
||||||
|
public async static Task<(bool, string)> AutoLogin(string AuthToken, string RefreshToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
authlink = await new FirebaseAuthLink(ap, new FirebaseAuth() { FirebaseToken = AuthToken, RefreshToken = RefreshToken, }).GetFreshAuthAsync();
|
||||||
|
await authlink.RefreshUserDetails();
|
||||||
|
authlink.FirebaseAuthRefreshed += Authlink_FirebaseAuthRefreshed;
|
||||||
|
|
||||||
|
logger.Trace("Firebase Auth Token {0}.", authlink.FirebaseToken);
|
||||||
|
logger.Trace("Firebase Auth Token expires in {0} seconds.", authlink.ExpiresIn);
|
||||||
|
tokenTimer.Interval = (authlink.ExpiresIn - 600) * 1000; //Set the token to refresh 10 minutes before it has to.
|
||||||
|
logger.Trace("Refresh timer interval set to {0}ms", (authlink.ExpiresIn - 600) * 1000);
|
||||||
|
tokenTimer.Elapsed += TokenTimer_Tick;
|
||||||
|
tokenTimer.Start();
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async static Task<(bool, string)> LoginAsync(string Username, string Password)
|
public async static Task<(bool, string)> LoginAsync(string Username, string Password)
|
||||||
@@ -31,8 +73,12 @@ namespace BodyshopPartner.Utils
|
|||||||
{
|
{
|
||||||
authlink = await ap.SignInWithEmailAndPasswordAsync(Username, Password);
|
authlink = await ap.SignInWithEmailAndPasswordAsync(Username, Password);
|
||||||
authlink.FirebaseAuthRefreshed += Authlink_FirebaseAuthRefreshed;
|
authlink.FirebaseAuthRefreshed += Authlink_FirebaseAuthRefreshed;
|
||||||
|
|
||||||
|
Properties.Settings.Default.AuthToken = authlink.FirebaseToken;
|
||||||
|
Properties.Settings.Default.RefreshToken = authlink.RefreshToken;
|
||||||
|
Properties.Settings.Default.Save();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
logger.Trace("Firebase Auth Token {0}.", authlink.FirebaseToken);
|
logger.Trace("Firebase Auth Token {0}.", authlink.FirebaseToken);
|
||||||
logger.Trace("Firebase Auth Token expires in {0} seconds.", authlink.ExpiresIn);
|
logger.Trace("Firebase Auth Token expires in {0} seconds.", authlink.ExpiresIn);
|
||||||
@@ -73,7 +119,7 @@ namespace BodyshopPartner.Utils
|
|||||||
{
|
{
|
||||||
logger.Trace("Old Token {0}", authlink.RefreshToken);
|
logger.Trace("Old Token {0}", authlink.RefreshToken);
|
||||||
await authlink.GetFreshAuthAsync();
|
await authlink.GetFreshAuthAsync();
|
||||||
|
|
||||||
authlink = await ap.RefreshAuthAsync(authlink);
|
authlink = await ap.RefreshAuthAsync(authlink);
|
||||||
logger.Trace("new Token {0}", authlink.FirebaseToken);
|
logger.Trace("new Token {0}", authlink.FirebaseToken);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ namespace BodyshopPartner.Utils
|
|||||||
public static class GraphQL
|
public static class GraphQL
|
||||||
{
|
{
|
||||||
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
public static GraphQLHttpClient CreateGQLClient()
|
public static GraphQLHttpClient CreateGQLClient()
|
||||||
{
|
{
|
||||||
var graphQLClient = new GraphQLHttpClient(AppMetaData.graphQlEndpoint, new NewtonsoftJsonSerializer());
|
var graphQLClient = new GraphQLHttpClient(AppMetaData.graphQlEndpoint, new NewtonsoftJsonSerializer());
|
||||||
@@ -31,7 +31,7 @@ namespace BodyshopPartner.Utils
|
|||||||
var graphQLResponse = await g.SendQueryAsync<dynamic>(r);
|
var graphQLResponse = await g.SendQueryAsync<dynamic>(r);
|
||||||
if (graphQLResponse.Errors == null)
|
if (graphQLResponse.Errors == null)
|
||||||
{
|
{
|
||||||
|
|
||||||
//logger.Trace("GQL Response: {0}", graphQLResponse.Data);
|
//logger.Trace("GQL Response: {0}", graphQLResponse.Data);
|
||||||
return graphQLResponse.Data;
|
return graphQLResponse.Data;
|
||||||
}
|
}
|
||||||
@@ -42,7 +42,7 @@ namespace BodyshopPartner.Utils
|
|||||||
logger.Error("Error executing query.");
|
logger.Error("Error executing query.");
|
||||||
Array.ForEach(graphQLResponse.Errors, x =>
|
Array.ForEach(graphQLResponse.Errors, x =>
|
||||||
{
|
{
|
||||||
logger.Error(x.Message);
|
logger.Error("Graphql Error: " + x.Message);
|
||||||
if (x.Message.Contains("JWTExpired"))
|
if (x.Message.Contains("JWTExpired"))
|
||||||
{
|
{
|
||||||
jwtExpired = true;
|
jwtExpired = true;
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ namespace BodyshopPartner.Utils
|
|||||||
|
|
||||||
catch (Exception Ex)
|
catch (Exception Ex)
|
||||||
{
|
{
|
||||||
logger.Error("Job insert failed. Show notification");
|
logger.Error("Job insert failed. Show notification " + Ex.ToString());
|
||||||
//Succesful upsert
|
//Succesful upsert
|
||||||
App.Current.Dispatcher.Invoke(() =>
|
App.Current.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -25,6 +25,20 @@ namespace BodyshopPartner.Utils
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class InvertBoolConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
return !((bool)value);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
return ((bool)value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class NullVisibilityConverter : IValueConverter
|
public class NullVisibilityConverter : IValueConverter
|
||||||
{
|
{
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using System.Text;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
||||||
|
|
||||||
namespace BodyshopPartner.ViewModels
|
namespace BodyshopPartner.ViewModels
|
||||||
{
|
{
|
||||||
public partial class LoginViewModel : BaseViewModel
|
public partial class LoginViewModel : BaseViewModel
|
||||||
@@ -15,6 +16,34 @@ namespace BodyshopPartner.ViewModels
|
|||||||
public LoginViewModel()
|
public LoginViewModel()
|
||||||
{
|
{
|
||||||
logger.Trace("Login VM Created.");
|
logger.Trace("Login VM Created.");
|
||||||
|
|
||||||
|
AutoLogin();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task AutoLogin()
|
||||||
|
{
|
||||||
|
Loading = true;
|
||||||
|
string AuthToken = Properties.Settings.Default.AuthToken;
|
||||||
|
string RefreshToken = Properties.Settings.Default.RefreshToken;
|
||||||
|
|
||||||
|
|
||||||
|
if (!String.IsNullOrEmpty(AuthToken) && !String.IsNullOrEmpty(RefreshToken))
|
||||||
|
{
|
||||||
|
//Attempt auto login.
|
||||||
|
logger.Debug("Good to attempt auto login.");
|
||||||
|
(Error, ErrorMsg) = await Utils.Auth.AutoLogin(AuthToken, RefreshToken);
|
||||||
|
if (ErrorMsg == null)
|
||||||
|
{
|
||||||
|
App.Current.MainWindow.Hide();
|
||||||
|
Views.Main m = new Views.Main();
|
||||||
|
m.Show();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
Loading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task LoginAsync(Window W)
|
private async Task LoginAsync(Window W)
|
||||||
@@ -25,7 +54,7 @@ namespace BodyshopPartner.ViewModels
|
|||||||
|
|
||||||
logger.Trace("Attempting to login as user: {0}", UserName);
|
logger.Trace("Attempting to login as user: {0}", UserName);
|
||||||
(Error, ErrorMsg) = await Utils.Auth.LoginAsync(UserName, Utils.LoginHelpers.DecodePassword(UserPassword));
|
(Error, ErrorMsg) = await Utils.Auth.LoginAsync(UserName, Utils.LoginHelpers.DecodePassword(UserPassword));
|
||||||
if(ErrorMsg ==null)
|
if (ErrorMsg == null)
|
||||||
{
|
{
|
||||||
Views.Main m = new Views.Main();
|
Views.Main m = new Views.Main();
|
||||||
m.Show();
|
m.Show();
|
||||||
|
|||||||
@@ -148,6 +148,7 @@ namespace BodyshopPartner.ViewModels
|
|||||||
async p =>
|
async p =>
|
||||||
{
|
{
|
||||||
await InstallUpdates();
|
await InstallUpdates();
|
||||||
|
UpdateAvailable = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return _installUpdatesCommand;
|
return _installUpdatesCommand;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
</Window.DataContext>
|
</Window.DataContext>
|
||||||
<Window.Resources>
|
<Window.Resources>
|
||||||
<util:NullVisibilityConverter x:Key="NullVisibilityConverter" />
|
<util:NullVisibilityConverter x:Key="NullVisibilityConverter" />
|
||||||
|
<util:InvertBoolConverter x:Key="InvertBoolConverter" />
|
||||||
<Style TargetType="StackPanel">
|
<Style TargetType="StackPanel">
|
||||||
<Setter Property="Margin"
|
<Setter Property="Margin"
|
||||||
Value="8" />
|
Value="8" />
|
||||||
@@ -74,6 +74,7 @@
|
|||||||
<PasswordBox materialDesign:HintAssist.Hint="{x:Static p:Resources.Password}"
|
<PasswordBox materialDesign:HintAssist.Hint="{x:Static p:Resources.Password}"
|
||||||
KeyDown="PasswordBox_KeyDown"
|
KeyDown="PasswordBox_KeyDown"
|
||||||
PasswordChanged="PasswordBox_PasswordChanged"
|
PasswordChanged="PasswordBox_PasswordChanged"
|
||||||
|
IsEnabled="{Binding Loading, Converter={StaticResource InvertBoolConverter}}"
|
||||||
Width="300" />
|
Width="300" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|||||||
@@ -67,10 +67,5 @@ namespace BodyshopPartner.Views
|
|||||||
{
|
{
|
||||||
Application.Current.Shutdown(0);
|
Application.Current.Shutdown(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Button_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
Utils.Auth.AuthTest();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user