From 007d56ee320536c6576ece24c197e3295d8a3cbe Mon Sep 17 00:00:00 2001 From: Astrian Zheng Date: Fri, 15 Sep 2023 17:28:39 +1000 Subject: [PATCH] Complete account creation process --- .../Controllers/HomeController.cs | 120 +++++++++++------- FIT5032-Assignment/FIT5032-Assignment.csproj | 3 +- .../FIT5032-Assignment.csproj.user | 4 +- ...eAccountForm.cs => CompleteProfileForm.cs} | 6 +- .../Views/Home/CompleteProfile.cshtml | 49 +++++++ .../Views/Home/CreateAccount.cshtml | 4 +- 6 files changed, 126 insertions(+), 60 deletions(-) rename FIT5032-Assignment/Models/{CreateAccountForm.cs => CompleteProfileForm.cs} (73%) create mode 100644 FIT5032-Assignment/Views/Home/CompleteProfile.cshtml diff --git a/FIT5032-Assignment/Controllers/HomeController.cs b/FIT5032-Assignment/Controllers/HomeController.cs index 8dc7deb..cad3f24 100644 --- a/FIT5032-Assignment/Controllers/HomeController.cs +++ b/FIT5032-Assignment/Controllers/HomeController.cs @@ -16,11 +16,34 @@ using System.IO; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.OpenSsl; using Org.BouncyCastle.Security; +using System.Net.Http; +using System.Threading.Tasks; +using Newtonsoft.Json; +using System.Net.Http.Headers; namespace FIT5032_Assignment.Controllers { + // Endpoint Response + public class PassageUserReply + { + public PassageUserReplyUser User { get; set; } + } + + public class PassageUserReplyUser + { + public string Email { get; set; } + } + + // Database + public class Database1Entities : DbContext + { + public DbSet Users { get; set; } + public DbSet Credentials { get; set; } + public DbSet Sessions { get; set; } + } public class HomeController : Controller { + private static readonly HttpClient httpClient = new HttpClient(); public static RsaSecurityKey LoadRsaSecurityKeyFromPem(string pem) { TextReader textReader = new StringReader(pem); @@ -102,6 +125,15 @@ namespace FIT5032_Assignment.Controllers return new string(bytes.Select(x => validChars[x % validChars.Length]).ToArray()); } + public HomeController() + { + // if auth token setted, ignore + if (httpClient.DefaultRequestHeaders.Authorization == null) + { + httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "vF4ch1wUf8.1cqOms9JMmUbqMGohlkJLzGDVlbF51D03fJnLfxwkn8kyAaVVjfvySufW9vXb3p3"); + } + } + public ActionResult Index() { return View(); @@ -125,41 +157,51 @@ namespace FIT5032_Assignment.Controllers } else { - Trace.WriteLine(sub); + var db = new Database1Entities(); + var credential = db.Credentials.Where(res => (res.uniqueIdCode == sub) && (res.provider == 0)); + // Register: if no credential, redirect to create account + if (credential.Count() == 0) + { + return RedirectToAction("CompleteProfile"); + } + else + { + // Successful login + return RedirectToAction("Index"); + } } - - return View(); } - // POST /CreateAccount + // POST /ComplteteProfile [HttpPost] - public ActionResult CreateAccount(Models.CreateAccountForm model) + public async Task CompleteProfile(Models.CompleteProfileForm model) { if (!ModelState.IsValid) { - ModelState.AddModelError("emailaddress", "Form not valid"); - return View(model); - } - - // Email address is not valid - // Use regular expression to verify email address - if (!System.Text.RegularExpressions.Regex.IsMatch(model.emailaddress, @"^([a-zA-Z0-9]|\-|_|\.){1,}@([a-zA-Z0-9]|\-|_|){1,}(\.([a-zA-Z0-9]|\-|_){1,}){1,}$")) - { - ModelState.AddModelError("emailaddress", "Email address is not valid"); + ModelState.AddModelError("fullname", "Form not valid"); return View(model); } - // If email address existed in database - var users = db.Credentials.Where(res => (res.uniqueIdCode == model.emailaddress) && (res.provider == 0)); - if (users.Count() > 0) + // Verify user is logged in + var psg_auth_token = Request.Cookies["psg_auth_token"]; + var user = loginVerify(psg_auth_token.Value); + if (user == null) { - ModelState.AddModelError("emailaddress", "Email address existed"); - return View(model); + return RedirectToAction("Login"); } + // Get users email from Passage API + var app_id = "ZHM5whW5xsZEczTn2loffzjN"; + var user_id = user; + var url = $"https://api.passage.id/v1/apps/{app_id}/users/{user_id}"; + Trace.WriteLine(url); + Trace.WriteLine(httpClient.DefaultRequestHeaders.Authorization); + var res = await httpClient.GetStringAsync(url); + string emailaddress = JsonConvert.DeserializeObject(res).User.Email; + // MD5 hash email to get avatar from gravatar var md5 = MD5.Create(); - byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(model.emailaddress); + byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(emailaddress); byte[] hash = md5.ComputeHash(inputBytes); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hash.Length; i++) @@ -170,7 +212,7 @@ namespace FIT5032_Assignment.Controllers // Create a new credential and a new user string userUuid = Guid.NewGuid().ToString(); - Users user = new Users + Users newDbUser = new Users { uuid = userUuid, displayName = model.fullname, @@ -181,47 +223,27 @@ namespace FIT5032_Assignment.Controllers { uuid = Guid.NewGuid().ToString(), user = userUuid, - uniqueIdCode = model.emailaddress, + uniqueIdCode = user_id, provider = 0, }; - // Assign a new session for user - // Generate 32-bit random string as session token - string token = GenerateRandomString(32); - - // Use bcrypt to hash token - string hashedToken = BCryptNet.HashPassword(token); - - string sessionUuid = Guid.NewGuid().ToString(); - - Sessions session = new Sessions - { - uuid = sessionUuid, - user = userUuid, - token = token, - alias = "Web", - validFrom = DateTime.Now, - validTo = DateTime.Now.AddDays(7) - }; - // Add them into database - db.Users.Add(user); + db.Users.Add(newDbUser); db.Credentials.Add(credential); - db.Sessions.Add(session); db.SaveChanges(); - // write cookie (`session`) - HttpCookie cookie1 = new HttpCookie("session", sessionUuid + ":" + token); - cookie1.Expires = DateTime.Now.AddDays(7); - Response.Cookies.Add(cookie1); - - return RedirectToAction("InitialPasskey"); + return RedirectToAction("Index"); } public ActionResult InitialPasskey() { return View(); } + + public ActionResult CompleteProfile() + { + return View(); + } } } \ No newline at end of file diff --git a/FIT5032-Assignment/FIT5032-Assignment.csproj b/FIT5032-Assignment/FIT5032-Assignment.csproj index 8c6e050..7bf90dc 100644 --- a/FIT5032-Assignment/FIT5032-Assignment.csproj +++ b/FIT5032-Assignment/FIT5032-Assignment.csproj @@ -188,7 +188,7 @@ FIT5032-Assignment.tt - + FIT5032-Assignment.tt @@ -308,6 +308,7 @@ + diff --git a/FIT5032-Assignment/FIT5032-Assignment.csproj.user b/FIT5032-Assignment/FIT5032-Assignment.csproj.user index 1c8e750..971363c 100644 --- a/FIT5032-Assignment/FIT5032-Assignment.csproj.user +++ b/FIT5032-Assignment/FIT5032-Assignment.csproj.user @@ -14,9 +14,9 @@ 600 - False + True False - False + True FIT5032_Assignment.Models.Database1Entities False False diff --git a/FIT5032-Assignment/Models/CreateAccountForm.cs b/FIT5032-Assignment/Models/CompleteProfileForm.cs similarity index 73% rename from FIT5032-Assignment/Models/CreateAccountForm.cs rename to FIT5032-Assignment/Models/CompleteProfileForm.cs index a6b1ba3..1e656f2 100644 --- a/FIT5032-Assignment/Models/CreateAccountForm.cs +++ b/FIT5032-Assignment/Models/CompleteProfileForm.cs @@ -6,12 +6,8 @@ using System.ComponentModel.DataAnnotations; namespace FIT5032_Assignment.Models { - public class CreateAccountForm + public class CompleteProfileForm { - [Required] - [Display(Name = "Email address")] - public string emailaddress { get; set; } - [Required] [Display(Name = "Full name")] public string fullname { get; set; } diff --git a/FIT5032-Assignment/Views/Home/CompleteProfile.cshtml b/FIT5032-Assignment/Views/Home/CompleteProfile.cshtml new file mode 100644 index 0000000..66cca49 --- /dev/null +++ b/FIT5032-Assignment/Views/Home/CompleteProfile.cshtml @@ -0,0 +1,49 @@ +@model FIT5032_Assignment.Models.CompleteProfileForm + +@{ + ViewBag.Title = "CompleteProfile"; +} + +

CompleteProfile

+ + +@using (Html.BeginForm()) +{ + @Html.AntiForgeryToken() + +
+

CompleteProfileForm

+
+ @Html.ValidationSummary(true, "", new { @class = "text-danger" }) +
+ @Html.LabelFor(model => model.fullname, htmlAttributes: new { @class = "control-label col-md-2" }) +
+ @Html.EditorFor(model => model.fullname, new { htmlAttributes = new { @class = "form-control" } }) + @Html.ValidationMessageFor(model => model.fullname, "", new { @class = "text-danger" }) +
+
+ +
+ @Html.LabelFor(model => model.role, htmlAttributes: new { @class = "control-label col-md-2" }) +
+ + @Html.DropDownListFor(model => model.role, new List + { + new SelectListItem{ Text="Patient", Value = "1"}, + new SelectListItem{ Text="Doctor", Value = "2"} + }, "Select Role", new { @class = "form-control" }) + @Html.ValidationMessageFor(model => model.role, "", new { @class = "text-danger" }) +
+
+ +
+
+ +
+
+
+} + +@section Scripts { + @Scripts.Render("~/bundles/jqueryval") +} diff --git a/FIT5032-Assignment/Views/Home/CreateAccount.cshtml b/FIT5032-Assignment/Views/Home/CreateAccount.cshtml index 951cda6..cd3fd4a 100644 --- a/FIT5032-Assignment/Views/Home/CreateAccount.cshtml +++ b/FIT5032-Assignment/Views/Home/CreateAccount.cshtml @@ -1,6 +1,4 @@ -@model FIT5032_Assignment.Models.CreateAccountForm - -@{ +@{ ViewBag.Title = "CreateAccount"; Layout = "~/Views/Shared/_Layout.cshtml"; }