diff --git a/AyaNovaQBI/AuthorizationRoles.cs b/AyaNovaQBI/AuthorizationRoles.cs
new file mode 100644
index 0000000..9a86239
--- /dev/null
+++ b/AyaNovaQBI/AuthorizationRoles.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AyaNovaQBI
+{
+ ///
+ /// Authorization roles
+ ///
+ [Flags]
+ public enum AuthorizationRoles : int
+ {
+ //https://stackoverflow.com/questions/8447/what-does-the-flags-enum-attribute-mean-in-c
+ //MAX 31 (2147483647)!!! or will overflow int and needs to be turned into a long
+ //Must be a power of two: https://en.wikipedia.org/wiki/Power_of_two
+
+ ///No role set
+ NoRole = 0,
+ ///BizAdminRestricted
+ BizAdminRestricted = 1,
+ ///BizAdmin
+ BizAdmin = 2,
+ ///ServiceRestricted
+ ServiceRestricted = 4,
+ ///Service
+ Service = 8,
+ ///InventoryRestricted
+ InventoryRestricted = 16,
+ ///Inventory
+ Inventory = 32,
+ ///Accounting
+ Accounting = 64,//No limited role, not sure if there is a need
+ ///TechRestricted
+ TechRestricted = 128,
+ ///Tech
+ Tech = 256,
+ ///SubContractorRestricted
+ SubContractorRestricted = 512, //same as tech but restricted by further business rules (more fine grained)
+ ///SubContractor
+ SubContractor = 1024,//same as tech limited but restricted by further business rules (more fine grained)
+ ///ClientRestricted
+ CustomerRestricted = 2048,
+ ///Client
+ Customer = 4096,
+ ///OpsAdminRestricted
+ OpsAdminRestricted = 8192,
+ ///OpsAdmin
+ OpsAdmin = 16384,
+ ///Sales
+ Sales = 32768,
+ ///SalesRestricted
+ SalesRestricted = 65536,
+
+
+ ///Anyone of any role
+ All = BizAdminRestricted | BizAdmin | ServiceRestricted | Service | InventoryRestricted |
+ Inventory | Accounting | TechRestricted | Tech | SubContractorRestricted |
+ SubContractor | CustomerRestricted | Customer | OpsAdminRestricted | OpsAdmin | Sales | SalesRestricted
+
+ // ,AllInsideUserRoles = BizAdminRestricted | BizAdmin | ServiceRestricted | Service | InventoryRestricted |
+ // Inventory | Accounting | TechRestricted | Tech | SubContractorRestricted |
+ // SubContractor | Sales | SalesRestricted | OpsAdminRestricted | OpsAdmin
+
+
+
+ }//end AuthorizationRoles
+}
diff --git a/AyaNovaQBI/AyaNovaQBI.csproj b/AyaNovaQBI/AyaNovaQBI.csproj
index f0766c2..d3e9e2b 100644
--- a/AyaNovaQBI/AyaNovaQBI.csproj
+++ b/AyaNovaQBI/AyaNovaQBI.csproj
@@ -75,6 +75,7 @@
auth.cs
+
Form
@@ -91,6 +92,7 @@
tfa.cs
+
auth.cs
diff --git a/AyaNovaQBI/UserType.cs b/AyaNovaQBI/UserType.cs
new file mode 100644
index 0000000..21f06e5
--- /dev/null
+++ b/AyaNovaQBI/UserType.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AyaNovaQBI
+{
+ ///
+ /// AyaNova User types
+ ///
+ public enum UserType : int
+ {
+ Service = 1,
+ NotService = 2,
+ Customer = 3,
+ HeadOffice = 4,
+ ServiceContractor = 5
+ }
+}
diff --git a/AyaNovaQBI/auth.cs b/AyaNovaQBI/auth.cs
index e6594a6..22a2a79 100644
--- a/AyaNovaQBI/auth.cs
+++ b/AyaNovaQBI/auth.cs
@@ -42,8 +42,7 @@ namespace AyaNovaQBI
{
if (!ValidateAndCleanServerAddress()) return;
btnLogin.Enabled = btnTest.Enabled = false;
- // if (!util.Initialized)
- //{
+
var result = await util.InitAndConfirmAddressAsync(edServerUrl.Text);
if (result != "OK")
{
@@ -51,15 +50,50 @@ namespace AyaNovaQBI
btnLogin.Enabled = btnTest.Enabled = true;
return;
}
- // }
- var res = await util.AuthenticateAsync(edUserName.Text, edPassword.Text);
- if (!res)
+ try
{
- MessageBox.Show("Login failed");
- btnLogin.Enabled = btnTest.Enabled = true;
+ var res = await util.AuthenticateAsync(edUserName.Text, edPassword.Text);
+ if (!res)
+ {
+ MessageBox.Show("Login failed");
+ btnLogin.Enabled = btnTest.Enabled = true;
+ this.DialogResult = DialogResult.Cancel;
+ return;
+ }
+ }catch(Exception ex)
+ {
+// ---------------------------
+
+//---------------------------
+//Error attempting to login:
+
+// POST error, code: 401, route: auth / tfa - authenticate
+
+//{ "error":{ "code":"2003","message":"ErrorAPI2003"} }
+
+// Unauthorized
+
+// POSTED OBJECT:
+
+// { "pin":"123456","tempToken":"YvIS2IovMIWUYc4NaovwhNcFXviWwEOx4qvpzt8vfQQ"}
+// ---------------------------
+// OK
+// -------------------------- -
+
+
+ MessageBox.Show("Error attempting to login:\r\n" + ex.Message);
this.DialogResult = DialogResult.Cancel;
return;
+
}
+
+ MessageBox.Show($@"TEST - LOGIN SUCCEEDED: \r\
+AyaNovaUserName: {util.AyaNovaUserName}\r\n
+JWT: {util.JWT}\r\n
+AyaNovaUserId: {util.AyaNovaUserId}\r\n
+AyaNovaUserTranslationId: {util.AyaNovaUserTranslationId}\r\n
+AyaNovaUserRoles: {util.AyaNovaUserRoles}\r\n
+AyaNovaUserType: {util.AyaNovaUserType}");
btnLogin.Enabled = btnTest.Enabled = true;
diff --git a/AyaNovaQBI/util.cs b/AyaNovaQBI/util.cs
index 67a8a31..617e56e 100644
--- a/AyaNovaQBI/util.cs
+++ b/AyaNovaQBI/util.cs
@@ -25,7 +25,13 @@ namespace AyaNovaQBI
internal static string GuessClientUrl { get; set; }
internal static string JWT { get; set; }
-
+ internal static long AyaNovaUserId { get; set; }
+ internal static long AyaNovaUserTranslationId { get; set; }
+ internal static string AyaNovaUserName { get; set; }
+ internal static AuthorizationRoles AyaNovaUserRoles { get; set; }
+ internal static UserType AyaNovaUserType { get; set; }
+
+
public static void InitClient()
@@ -92,8 +98,8 @@ namespace AyaNovaQBI
var InnerErr = "";
if (ex.InnerException != null)
InnerErr = ex.InnerException.Message;
- return false;
- // throw new Exception("POST error, route: " + route + "\r\nError:" + Err + "\r\nInner error:" + InnerErr + "\r\nStack:" + ex.StackTrace + "\r\nPOSTED OBJECT:\r\n" + postJson);
+
+ throw new Exception("Authentication error, route: AUTH\r\nError:" + Err + "\r\nInner error:" + InnerErr);
}
//ApiResponse a = await PostAsync("auth", creds.ToString());
@@ -107,30 +113,65 @@ namespace AyaNovaQBI
//Get temp token from response
var tempToken = a.ObjectResponse["data"]["tt"].Value();
- string tfaPin = null;
- bool keepTrying = true;
+
//get 2fa code and send it in
do
{
tfa t = new tfa();
if (t.ShowDialog() == System.Windows.Forms.DialogResult.Cancel) return false;
- tfaPin = t.TFAPin;
+ string tfaPin = t.TFAPin;
+ dynamic tfaCreds = new JObject();
+ tfaCreds.pin = tfaPin;
+ tfaCreds.tempToken = tempToken;
+ try
+ {
+ var tfaResponse = await TryPostAsync("auth/tfa-authenticate", tfaCreds.ToString(Newtonsoft.Json.Formatting.None));//trypost is no delay
+ if (ProcessLoginResponse(tfaResponse)) return true;
+ }
+ catch(Exception ex)
+ {
+ if (!ex.Message.Contains("2003"))//if not an authentication error (bad pin) then throw it back up for display
+ throw ex;
+ //otherwise eat it and let them re-enter the pin again to mirror how ayanova web client works
+ }
+
- } while (keepTrying);
+ } while (true);
}
else
{
- JWT = a.ObjectResponse["data"]["token"].Value();
- return true;
+ return ProcessLoginResponse(a);
}
}
return false;
}
+ private static bool ProcessLoginResponse(ApiResponse a)
+ {
+ if (a.ObjectResponse == null) return false;
+ if (!a.HttpResponse.IsSuccessStatusCode)
+ {
+ return false;
+ }
+ if(a.ObjectResponse["data"]["l"].Value())//license lockout
+ {
+ throw new Exception("Server login from QBI is disabled due to AyaNova license issue");
+ }
+
+ JWT = a.ObjectResponse["data"]["token"].Value();
+ // AyaNovaUserId= a.ObjectResponse["data"]["id"].Value();//nbot here maybe in jwt
+ //AyaNovaUserTranslationId = a.ObjectResponse["data"]["tid"].Value();
+ AyaNovaUserName = a.ObjectResponse["data"]["name"].Value();
+ AyaNovaUserRoles = (AuthorizationRoles)(int.Parse(a.ObjectResponse["data"]["roles"].Value()));
+ AyaNovaUserType = (UserType)(int.Parse(a.ObjectResponse["data"]["usertype"].Value()));
+
+ return true;
+ }
+
public async static Task GetAsync(string route)