diff --git a/gaseous-server/.DS_Store b/gaseous-server/.DS_Store
index af3f72a..e33e0ab 100644
Binary files a/gaseous-server/.DS_Store and b/gaseous-server/.DS_Store differ
diff --git a/gaseous-server/Assets/.DS_Store b/gaseous-server/Assets/.DS_Store
index 95b3a7b..dd4ab63 100644
Binary files a/gaseous-server/Assets/.DS_Store and b/gaseous-server/Assets/.DS_Store differ
diff --git a/gaseous-server/Assets/Ratings/.DS_Store b/gaseous-server/Assets/Ratings/.DS_Store
index 47d5f24..50a7adc 100644
Binary files a/gaseous-server/Assets/Ratings/.DS_Store and b/gaseous-server/Assets/Ratings/.DS_Store differ
diff --git a/gaseous-server/Classes/Auth/Classes/IdentityRole.cs b/gaseous-server/Classes/Auth/Classes/IdentityRole.cs
new file mode 100644
index 0000000..64a2548
--- /dev/null
+++ b/gaseous-server/Classes/Auth/Classes/IdentityRole.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using gaseous_server.Classes;
+using Microsoft.AspNetCore.Identity;
+
+namespace Authentication
+{
+ ///
+ /// Class that implements the ASP.NET Identity
+ /// IRole interface
+ ///
+ public class ApplicationRole : IdentityRole
+ {
+ }
+}
diff --git a/gaseous-server/Classes/Auth/Classes/IdentityUser.cs b/gaseous-server/Classes/Auth/Classes/IdentityUser.cs
new file mode 100644
index 0000000..e263b70
--- /dev/null
+++ b/gaseous-server/Classes/Auth/Classes/IdentityUser.cs
@@ -0,0 +1,15 @@
+using gaseous_server.Classes;
+using Microsoft.AspNetCore.Identity;
+using System;
+
+namespace Authentication
+{
+ ///
+ /// Class that implements the ASP.NET Identity
+ /// IUser interface
+ ///
+ public class ApplicationUser : IdentityUser
+ {
+ public SecurityProfileViewModel SecurityProfile { get; set; }
+ }
+}
diff --git a/gaseous-server/Classes/Auth/Classes/RoleStore.cs b/gaseous-server/Classes/Auth/Classes/RoleStore.cs
new file mode 100644
index 0000000..3a80cb2
--- /dev/null
+++ b/gaseous-server/Classes/Auth/Classes/RoleStore.cs
@@ -0,0 +1,171 @@
+using System;
+using System.Security.Claims;
+using System.Threading.Tasks;
+using gaseous_server.Classes;
+using Microsoft.AspNetCore.Identity;
+using MySqlConnector;
+
+namespace Authentication
+{
+ ///
+ /// Class that implements the key ASP.NET Identity role store iterfaces
+ ///
+ public class RoleStore : IQueryableRoleStore
+ {
+ private RoleTable roleTable;
+ public Database Database { get; private set; }
+
+ public IQueryable Roles
+ {
+ get
+ {
+ List roles = roleTable.GetRoles();
+ return roles.AsQueryable();
+ }
+ }
+
+ public RoleStore()
+ {
+ Database = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
+ roleTable = new RoleTable(Database);
+ }
+
+ ///
+ /// Constructor that takes a MySQLDatabase as argument
+ ///
+ ///
+ public RoleStore(Database database)
+ {
+ Database = database;
+ roleTable = new RoleTable(database);
+ }
+
+ public Task CreateAsync(ApplicationRole role, CancellationToken cancellationToken)
+ {
+ if (role == null)
+ {
+ throw new ArgumentNullException("role");
+ }
+
+ roleTable.Insert(role);
+
+ return Task.FromResult(IdentityResult.Success);
+ }
+
+ public Task DeleteAsync(ApplicationRole role, CancellationToken cancellationToken)
+ {
+ if (role == null)
+ {
+ throw new ArgumentNullException("user");
+ }
+
+ roleTable.Delete(role.Id);
+
+ return Task.FromResult(IdentityResult.Success);
+ }
+
+ public Task FindByIdAsync(string roleId, CancellationToken cancellationToken)
+ {
+ ApplicationRole result = roleTable.GetRoleById(roleId) as ApplicationRole;
+
+ return Task.FromResult(result);
+ }
+
+ public Task RoleExistsAsync(string roleId, CancellationToken cancellationToken)
+ {
+ ApplicationRole? result = roleTable.GetRoleById(roleId) as ApplicationRole;
+
+ if (result == null)
+ {
+ return Task.FromResult(false);
+ }
+ else
+ {
+ return Task.FromResult(true);
+ }
+ }
+
+ public Task FindByNameAsync(string roleName, CancellationToken cancellationToken)
+ {
+ ApplicationRole? result = roleTable.GetRoleByName(roleName) as ApplicationRole;
+
+ return Task.FromResult(result);
+ }
+
+ public Task UpdateAsync(ApplicationRole role, CancellationToken cancellationToken)
+ {
+ if (role == null)
+ {
+ throw new ArgumentNullException("user");
+ }
+
+ roleTable.Update(role);
+
+ return Task.FromResult(IdentityResult.Success);
+ }
+
+ public void Dispose()
+ {
+ if (Database != null)
+ {
+ Database = null;
+ }
+ }
+
+ public Task GetRoleIdAsync(ApplicationRole role, CancellationToken cancellationToken)
+ {
+ if (role != null)
+ {
+ return Task.FromResult(roleTable.GetRoleId(role.Name));
+ }
+
+ return Task.FromResult(null);
+ }
+
+ public Task GetRoleNameAsync(ApplicationRole role, CancellationToken cancellationToken)
+ {
+ if (role != null)
+ {
+ return Task.FromResult(roleTable.GetRoleName(role.Id));
+ }
+
+ return Task.FromResult(null);
+ }
+
+ public Task SetRoleNameAsync(ApplicationRole role, string? roleName, CancellationToken cancellationToken)
+ {
+ if (role == null)
+ {
+ throw new ArgumentNullException("role");
+ }
+
+ role.Name = roleName;
+ roleTable.Update(role);
+
+ return Task.FromResult(IdentityResult.Success);
+ }
+
+ public Task GetNormalizedRoleNameAsync(ApplicationRole role, CancellationToken cancellationToken)
+ {
+ if (role != null)
+ {
+ return Task.FromResult(roleTable.GetRoleName(role.Id));
+ }
+
+ return Task.FromResult(null);
+ }
+
+ public Task SetNormalizedRoleNameAsync(ApplicationRole role, string? normalizedName, CancellationToken cancellationToken)
+ {
+ if (role == null)
+ {
+ throw new ArgumentNullException("role");
+ }
+
+ role.Name = normalizedName;
+ roleTable.Update(role);
+
+ return Task.FromResult(IdentityResult.Success);
+ }
+ }
+}
diff --git a/gaseous-server/Classes/Auth/Classes/RoleTable.cs b/gaseous-server/Classes/Auth/Classes/RoleTable.cs
new file mode 100644
index 0000000..b9f7d89
--- /dev/null
+++ b/gaseous-server/Classes/Auth/Classes/RoleTable.cs
@@ -0,0 +1,168 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using gaseous_server.Classes;
+using Microsoft.AspNetCore.Identity;
+
+namespace Authentication
+{
+ ///
+ /// Class that represents the Role table in the MySQL Database
+ ///
+ public class RoleTable
+ {
+ private Database _database;
+
+ ///
+ /// Constructor that takes a MySQLDatabase instance
+ ///
+ ///
+ public RoleTable(Database database)
+ {
+ _database = database;
+ }
+
+ ///
+ /// Deltes a role from the Roles table
+ ///
+ /// The role Id
+ ///
+ public int Delete(string roleId)
+ {
+ string commandText = "Delete from Roles where Id = @id";
+ Dictionary parameters = new Dictionary();
+ parameters.Add("@id", roleId);
+
+ return (int)_database.ExecuteNonQuery(commandText, parameters);
+ }
+
+ ///
+ /// Inserts a new Role in the Roles table
+ ///
+ /// The role's name
+ ///
+ public int Insert(ApplicationRole role)
+ {
+ string commandText = "Insert into Roles (Id, Name) values (@id, @name)";
+ Dictionary parameters = new Dictionary();
+ parameters.Add("@name", role.Name);
+ parameters.Add("@id", role.Id);
+
+ return (int)_database.ExecuteNonQuery(commandText, parameters);
+ }
+
+ ///
+ /// Returns a role name given the roleId
+ ///
+ /// The role Id
+ /// Role name
+ public string? GetRoleName(string roleId)
+ {
+ string commandText = "Select Name from Roles where Id = @id";
+ Dictionary parameters = new Dictionary();
+ parameters.Add("@id", roleId);
+
+ DataTable table = _database.ExecuteCMD(commandText, parameters);
+
+ if (table.Rows.Count == 0)
+ {
+ return null;
+ }
+ else
+ {
+ return (string)table.Rows[0][0];
+ }
+ }
+
+ ///
+ /// Returns the role Id given a role name
+ ///
+ /// Role's name
+ /// Role's Id
+ public string? GetRoleId(string roleName)
+ {
+ string? roleId = null;
+ string commandText = "Select Id from Roles where Name = @name";
+ Dictionary parameters = new Dictionary() { { "@name", roleName } };
+
+ DataTable result = _database.ExecuteCMD(commandText, parameters);
+ if (result.Rows.Count > 0)
+ {
+ return Convert.ToString(result.Rows[0][0]);
+ }
+
+ return roleId;
+ }
+
+ ///
+ /// Gets the ApplicationRole given the role Id
+ ///
+ ///
+ ///
+ public ApplicationRole? GetRoleById(string roleId)
+ {
+ var roleName = GetRoleName(roleId);
+ ApplicationRole? role = null;
+
+ if(roleName != null)
+ {
+ role = new ApplicationRole();
+ role.Id = roleId;
+ role.Name = roleName;
+ role.NormalizedName = roleName.ToUpper();
+ }
+
+ return role;
+
+ }
+
+ ///
+ /// Gets the ApplicationRole given the role name
+ ///
+ ///
+ ///
+ public ApplicationRole? GetRoleByName(string roleName)
+ {
+ var roleId = GetRoleId(roleName);
+ ApplicationRole role = null;
+
+ if (roleId != null)
+ {
+ role = new ApplicationRole();
+ role.Id = roleId;
+ role.Name = roleName;
+ role.NormalizedName = roleName.ToUpper();
+ }
+
+ return role;
+ }
+
+ public int Update(ApplicationRole role)
+ {
+ string commandText = "Update Roles set Name = @name where Id = @id";
+ Dictionary parameters = new Dictionary();
+ parameters.Add("@id", role.Id);
+
+ return (int)_database.ExecuteNonQuery(commandText, parameters);
+ }
+
+ public List GetRoles()
+ {
+ List roles = new List();
+
+ string commandText = "Select Name from Roles";
+
+ var rows = _database.ExecuteCMDDict(commandText);
+ foreach(Dictionary row in rows)
+ {
+ ApplicationRole role = (ApplicationRole)Activator.CreateInstance(typeof(ApplicationRole));
+ role.Id = (string)row["Id"];
+ role.Name = (string)row["Name"];
+ role.NormalizedName = ((string)row["Name"]).ToUpper();
+ roles.Add(role);
+ }
+
+ return roles;
+ }
+ }
+}
diff --git a/gaseous-server/Classes/Auth/Classes/UserClaimsTable.cs b/gaseous-server/Classes/Auth/Classes/UserClaimsTable.cs
new file mode 100644
index 0000000..5940e10
--- /dev/null
+++ b/gaseous-server/Classes/Auth/Classes/UserClaimsTable.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Security.Claims;
+using gaseous_server.Classes;
+using Microsoft.AspNetCore.Identity;
+
+namespace Authentication
+{
+ ///
+ /// Class that represents the UserClaims table in the MySQL Database
+ ///
+ public class UserClaimsTable
+ {
+ private Database _database;
+
+ ///
+ /// Constructor that takes a MySQLDatabase instance
+ ///
+ ///
+ public UserClaimsTable(Database database)
+ {
+ _database = database;
+ }
+
+ ///
+ /// Returns a ClaimsIdentity instance given a userId
+ ///
+ /// The user's id
+ ///
+ public ClaimsIdentity FindByUserId(string userId)
+ {
+ ClaimsIdentity claims = new ClaimsIdentity();
+ string commandText = "Select * from UserClaims where UserId = @userId";
+ Dictionary parameters = new Dictionary() { { "@UserId", userId } };
+
+ var rows = _database.ExecuteCMD(commandText, parameters).Rows;
+ foreach (DataRow row in rows)
+ {
+ Claim claim = new Claim((string)row["ClaimType"], (string)row["ClaimValue"]);
+ claims.AddClaim(claim);
+ }
+
+ return claims;
+ }
+
+ ///
+ /// Deletes all claims from a user given a userId
+ ///
+ /// The user's id
+ ///
+ public int Delete(string userId)
+ {
+ string commandText = "Delete from UserClaims where UserId = @userId";
+ Dictionary parameters = new Dictionary();
+ parameters.Add("userId", userId);
+
+ return (int)_database.ExecuteNonQuery(commandText, parameters);
+ }
+
+ ///
+ /// Inserts a new claim in UserClaims table
+ ///
+ /// User's claim to be added
+ /// User's id
+ ///
+ public int Insert(Claim userClaim, string userId)
+ {
+ string commandText = "Insert into UserClaims (ClaimValue, ClaimType, UserId) values (@value, @type, @userId)";
+ Dictionary parameters = new Dictionary();
+ parameters.Add("value", userClaim.Value);
+ parameters.Add("type", userClaim.Type);
+ parameters.Add("userId", userId);
+
+ return (int)_database.ExecuteNonQuery(commandText, parameters);
+ }
+
+ ///
+ /// Deletes a claim from a user
+ ///
+ /// The user to have a claim deleted
+ /// A claim to be deleted from user
+ ///
+ public int Delete(IdentityUser user, Claim claim)
+ {
+ string commandText = "Delete from UserClaims where UserId = @userId and @ClaimValue = @value and ClaimType = @type";
+ Dictionary parameters = new Dictionary();
+ parameters.Add("userId", user.Id);
+ parameters.Add("value", claim.Value);
+ parameters.Add("type", claim.Type);
+
+ return (int)_database.ExecuteNonQuery(commandText, parameters);
+ }
+ }
+}
diff --git a/gaseous-server/Classes/Auth/Classes/UserLoginsTable.cs b/gaseous-server/Classes/Auth/Classes/UserLoginsTable.cs
new file mode 100644
index 0000000..2837b36
--- /dev/null
+++ b/gaseous-server/Classes/Auth/Classes/UserLoginsTable.cs
@@ -0,0 +1,117 @@
+using gaseous_server.Classes;
+using Microsoft.AspNetCore.Identity;
+using System.Collections.Generic;
+using System.Data;
+
+namespace Authentication
+{
+ ///
+ /// Class that represents the UserLogins table in the MySQL Database
+ ///
+ public class UserLoginsTable
+ {
+ private Database _database;
+
+ ///
+ /// Constructor that takes a MySQLDatabase instance
+ ///
+ ///
+ public UserLoginsTable(Database database)
+ {
+ _database = database;
+ }
+
+ ///
+ /// Deletes a login from a user in the UserLogins table
+ ///
+ /// User to have login deleted
+ /// Login to be deleted from user
+ ///
+ public int Delete(IdentityUser user, UserLoginInfo login)
+ {
+ string commandText = "Delete from UserLogins where UserId = @userId and LoginProvider = @loginProvider and ProviderKey = @providerKey";
+ Dictionary parameters = new Dictionary();
+ parameters.Add("UserId", user.Id);
+ parameters.Add("loginProvider", login.LoginProvider);
+ parameters.Add("providerKey", login.ProviderKey);
+
+ return (int)_database.ExecuteNonQuery(commandText, parameters);
+ }
+
+ ///
+ /// Deletes all Logins from a user in the UserLogins table
+ ///
+ /// The user's id
+ ///
+ public int Delete(string userId)
+ {
+ string commandText = "Delete from UserLogins where UserId = @userId";
+ Dictionary parameters = new Dictionary();
+ parameters.Add("UserId", userId);
+
+ return (int)_database.ExecuteNonQuery(commandText, parameters);
+ }
+
+ ///
+ /// Inserts a new login in the UserLogins table
+ ///
+ /// User to have new login added
+ /// Login to be added
+ ///
+ public int Insert(IdentityUser user, UserLoginInfo login)
+ {
+ string commandText = "Insert into UserLogins (LoginProvider, ProviderKey, UserId) values (@loginProvider, @providerKey, @userId)";
+ Dictionary parameters = new Dictionary();
+ parameters.Add("loginProvider", login.LoginProvider);
+ parameters.Add("providerKey", login.ProviderKey);
+ parameters.Add("userId", user.Id);
+
+ return (int)_database.ExecuteNonQuery(commandText, parameters);
+ }
+
+ ///
+ /// Return a userId given a user's login
+ ///
+ /// The user's login info
+ ///
+ public string? FindUserIdByLogin(UserLoginInfo userLogin)
+ {
+ string commandText = "Select UserId from UserLogins where LoginProvider = @loginProvider and ProviderKey = @providerKey";
+ Dictionary parameters = new Dictionary();
+ parameters.Add("loginProvider", userLogin.LoginProvider);
+ parameters.Add("providerKey", userLogin.ProviderKey);
+
+ DataTable table = _database.ExecuteCMD(commandText, parameters);
+
+ if (table.Rows.Count == 0)
+ {
+ return null;
+ }
+ else
+ {
+ return (string)table.Rows[0][0];
+ }
+ }
+
+ ///
+ /// Returns a list of user's logins
+ ///
+ /// The user's id
+ ///
+ public List FindByUserId(string userId)
+ {
+ List logins = new List();
+ string commandText = "Select * from UserLogins where UserId = @userId";
+ Dictionary parameters = new Dictionary() { { "@userId", userId } };
+
+ var rows = _database.ExecuteCMD(commandText, parameters).Rows;
+ foreach (DataRow row in rows)
+ {
+ var login = new UserLoginInfo((string)row["LoginProvider"], (string)row["ProviderKey"], (string)row["LoginProvider"]);
+ logins.Add(login);
+ }
+
+ return logins;
+ }
+ }
+}
diff --git a/gaseous-server/Classes/Auth/Classes/UserRoleTable.cs b/gaseous-server/Classes/Auth/Classes/UserRoleTable.cs
new file mode 100644
index 0000000..14f8e2a
--- /dev/null
+++ b/gaseous-server/Classes/Auth/Classes/UserRoleTable.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using gaseous_server.Classes;
+using Microsoft.AspNetCore.Identity;
+
+namespace Authentication
+{
+ ///
+ /// Class that represents the UserRoles table in the MySQL Database
+ ///
+ public class UserRolesTable
+ {
+ private Database _database;
+
+ ///
+ /// Constructor that takes a MySQLDatabase instance
+ ///
+ ///
+ public UserRolesTable(Database database)
+ {
+ _database = database;
+ }
+
+ ///
+ /// Returns a list of user's roles
+ ///
+ /// The user's id
+ ///
+ public List FindByUserId(string userId)
+ {
+ List roles = new List();
+ string commandText = "Select Roles.Name from UserRoles, Roles where UserRoles.UserId = @userId and UserRoles.RoleId = Roles.Id";
+ Dictionary parameters = new Dictionary();
+ parameters.Add("@userId", userId);
+
+ var rows = _database.ExecuteCMD(commandText, parameters).Rows;
+ foreach(DataRow row in rows)
+ {
+ roles.Add((string)row["Name"]);
+ }
+
+ return roles;
+ }
+
+ ///
+ /// Deletes all roles from a user in the UserRoles table
+ ///
+ /// The user's id
+ ///
+ public int Delete(string userId)
+ {
+ string commandText = "Delete from UserRoles where UserId = @userId";
+ Dictionary parameters = new Dictionary();
+ parameters.Add("UserId", userId);
+
+ return (int)_database.ExecuteNonQuery(commandText, parameters);
+ }
+
+ public int DeleteUserFromRole(string userId, string roleId)
+ {
+ string commandText = "Delete from UserRoles where UserId = @userId and RoleId = @roleId";
+ Dictionary parameters = new Dictionary();
+ parameters.Add("userId", userId);
+ parameters.Add("roleId", roleId);
+
+ return (int)_database.ExecuteNonQuery(commandText, parameters);
+ }
+
+ ///
+ /// Inserts a new role for a user in the UserRoles table
+ ///
+ /// The User
+ /// The Role's id
+ ///
+ public int Insert(IdentityUser user, string roleId)
+ {
+ string commandText = "Insert into UserRoles (UserId, RoleId) values (@userId, @roleId)";
+ Dictionary parameters = new Dictionary();
+ parameters.Add("userId", user.Id);
+ parameters.Add("roleId", roleId);
+
+ return (int)_database.ExecuteNonQuery(commandText, parameters);
+ }
+ }
+}
diff --git a/gaseous-server/Classes/Auth/Classes/UserStore.cs b/gaseous-server/Classes/Auth/Classes/UserStore.cs
new file mode 100644
index 0000000..348ebe5
--- /dev/null
+++ b/gaseous-server/Classes/Auth/Classes/UserStore.cs
@@ -0,0 +1,616 @@
+using System;
+using System.Security.Claims;
+using System.Threading.Tasks;
+using gaseous_server.Classes;
+using Microsoft.AspNetCore.Identity;
+using MySqlConnector;
+
+namespace Authentication
+{
+ public class UserStore :
+ IUserStore,
+ IUserRoleStore,
+ IUserLoginStore,
+ IUserClaimStore,
+ IUserPasswordStore,
+ IUserSecurityStampStore,
+ IQueryableUserStore,
+ IUserEmailStore,
+ IUserPhoneNumberStore,
+ IUserTwoFactorStore,
+ IUserLockoutStore
+ {
+ private Database database;
+
+ private UserTable userTable;
+ private RoleTable roleTable;
+ private UserRolesTable userRolesTable;
+ private UserLoginsTable userLoginsTable;
+ private UserClaimsTable userClaimsTable;
+
+ public UserStore()
+ {
+ database = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
+ userTable = new UserTable(database);
+ roleTable = new RoleTable(database);
+ userRolesTable = new UserRolesTable(database);
+ userLoginsTable = new UserLoginsTable(database);
+ userClaimsTable = new UserClaimsTable(database);
+ }
+
+ public UserStore(Database database)
+ {
+ this.database = database;
+ userTable = new UserTable(database);
+ roleTable = new RoleTable(database);
+ userRolesTable = new UserRolesTable(database);
+ userLoginsTable = new UserLoginsTable(database);
+ userClaimsTable = new UserClaimsTable(database);
+ }
+
+ public IQueryable Users
+ {
+ get
+ {
+ List users = userTable.GetUsers();
+ return users.AsQueryable();
+ }
+ }
+
+ public Task AddClaimsAsync(ApplicationUser user, IEnumerable claims, CancellationToken cancellationToken)
+ {
+ if (user == null)
+ {
+ throw new ArgumentNullException("user");
+ }
+
+ if (claims == null)
+ {
+ throw new ArgumentNullException("user");
+ }
+
+ foreach (Claim claim in claims)
+ {
+ userClaimsTable.Insert(claim, user.Id);
+ }
+
+ return Task.FromResult