Added automatic login using auth tokens IO-403

This commit is contained in:
Patrick Fic
2021-01-18 11:25:24 -08:00
parent 15028cc769
commit fa70ed65cc
11 changed files with 140 additions and 18 deletions

View File

@@ -57,6 +57,12 @@
<setting name="QuickBooksFilePath" serializeAs="String">
<value />
</setting>
<setting name="AuthToken" serializeAs="String">
<value />
</setting>
<setting name="RefreshToken" serializeAs="String">
<value />
</setting>
</BodyshopPartner.Properties.Settings>
</userSettings>
</configuration>

View File

@@ -12,7 +12,7 @@ namespace BodyshopPartner.Properties {
[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 {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
@@ -104,5 +104,29 @@ namespace BodyshopPartner.Properties {
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;
}
}
}
}

View File

@@ -23,5 +23,11 @@
<Setting Name="QuickBooksFilePath" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</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>
</SettingsFile>

View File

@@ -12,15 +12,57 @@ namespace BodyshopPartner.Utils
{
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
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 string U;
private static string P;
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)
@@ -31,8 +73,12 @@ namespace BodyshopPartner.Utils
{
authlink = await ap.SignInWithEmailAndPasswordAsync(Username, Password);
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 expires in {0} seconds.", authlink.ExpiresIn);
@@ -73,7 +119,7 @@ namespace BodyshopPartner.Utils
{
logger.Trace("Old Token {0}", authlink.RefreshToken);
await authlink.GetFreshAuthAsync();
authlink = await ap.RefreshAuthAsync(authlink);
logger.Trace("new Token {0}", authlink.FirebaseToken);
}

View File

@@ -13,7 +13,7 @@ namespace BodyshopPartner.Utils
public static class GraphQL
{
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
public static GraphQLHttpClient CreateGQLClient()
{
var graphQLClient = new GraphQLHttpClient(AppMetaData.graphQlEndpoint, new NewtonsoftJsonSerializer());
@@ -31,7 +31,7 @@ namespace BodyshopPartner.Utils
var graphQLResponse = await g.SendQueryAsync<dynamic>(r);
if (graphQLResponse.Errors == null)
{
//logger.Trace("GQL Response: {0}", graphQLResponse.Data);
return graphQLResponse.Data;
}
@@ -42,7 +42,7 @@ namespace BodyshopPartner.Utils
logger.Error("Error executing query.");
Array.ForEach(graphQLResponse.Errors, x =>
{
logger.Error(x.Message);
logger.Error("Graphql Error: " + x.Message);
if (x.Message.Contains("JWTExpired"))
{
jwtExpired = true;

View File

@@ -184,7 +184,7 @@ namespace BodyshopPartner.Utils
catch (Exception Ex)
{
logger.Error("Job insert failed. Show notification");
logger.Error("Job insert failed. Show notification " + Ex.ToString());
//Succesful upsert
App.Current.Dispatcher.Invoke(() =>
{

View File

@@ -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 object Convert(object value, Type targetType, object parameter, CultureInfo culture)

View File

@@ -6,6 +6,7 @@ using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace BodyshopPartner.ViewModels
{
public partial class LoginViewModel : BaseViewModel
@@ -15,6 +16,34 @@ namespace BodyshopPartner.ViewModels
public LoginViewModel()
{
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)
@@ -25,7 +54,7 @@ namespace BodyshopPartner.ViewModels
logger.Trace("Attempting to login as user: {0}", UserName);
(Error, ErrorMsg) = await Utils.Auth.LoginAsync(UserName, Utils.LoginHelpers.DecodePassword(UserPassword));
if(ErrorMsg ==null)
if (ErrorMsg == null)
{
Views.Main m = new Views.Main();
m.Show();

View File

@@ -148,6 +148,7 @@ namespace BodyshopPartner.ViewModels
async p =>
{
await InstallUpdates();
UpdateAvailable = false;
});
}
return _installUpdatesCommand;

View File

@@ -27,7 +27,7 @@
</Window.DataContext>
<Window.Resources>
<util:NullVisibilityConverter x:Key="NullVisibilityConverter" />
<util:InvertBoolConverter x:Key="InvertBoolConverter" />
<Style TargetType="StackPanel">
<Setter Property="Margin"
Value="8" />
@@ -74,6 +74,7 @@
<PasswordBox materialDesign:HintAssist.Hint="{x:Static p:Resources.Password}"
KeyDown="PasswordBox_KeyDown"
PasswordChanged="PasswordBox_PasswordChanged"
IsEnabled="{Binding Loading, Converter={StaticResource InvertBoolConverter}}"
Width="300" />
</StackPanel>
</StackPanel>

View File

@@ -67,10 +67,5 @@ namespace BodyshopPartner.Views
{
Application.Current.Shutdown(0);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Utils.Auth.AuthTest();
}
}
}