Compare commits

...

9 Commits

Author SHA1 Message Date
derek 059c755d14 Update client to use forms 2025-06-19 16:49:43 -07:00
derek 34d3d047d2 fix namespacing issues 2025-06-19 16:49:34 -07:00
derek a3de3d573a Make api 'FormBody' -> cleaner & smaller dto's 2025-06-19 16:48:52 -07:00
derek bbab4972c3 Update usings for new shared folder 2025-06-19 16:48:16 -07:00
derek 07a1014889 Fix warnings by cleaning CSS 2025-06-19 16:47:23 -07:00
derek 2ce398a8d4 Organize imports file 2025-06-19 16:46:53 -07:00
derek fcf64f335d Remove non-essential website pages 2025-06-19 16:46:39 -07:00
derek c873f473c8 Delete Launch Settings 2025-06-19 16:46:18 -07:00
derek f110ad8d27 Modify GitIgnore 2025-06-19 16:46:06 -07:00
23 changed files with 425 additions and 1151 deletions
+2 -1
View File
@@ -2,4 +2,5 @@
**/obj
.git
.env
data
data
Properties
@@ -34,10 +34,21 @@
}
public async Task TrySendCode() {
Result = "Waiting on response from server";
HttpResponseMessage TestLogin = await Http.PostAsJsonAsync("api/account/sendresetpassword", new Account(){ Email = Email });
Result = await TestLogin.Content.ReadAsStringAsync();
MailAddress addr = new MailAddress(Email);
if ( addr.Address != Email ){
Result = "Enter a valid email address";
}else{
Result = "";
}
if (string.IsNullOrEmpty(Result)){
Dictionary<string, string> formData = new Dictionary<string, string>{
{ "Email", Email }
};
Result = "Waiting on response from server";
HttpResponseMessage TestLogin = await Http.PostAsync("api/account/sendresetpassword", new FormUrlEncodedContent(formData) );
Result = await TestLogin.Content.ReadAsStringAsync();
}
base.StateHasChanged();
}
}
}
@@ -54,34 +54,36 @@
Loading = "Waiting for login response from server";
ReturnURL = string.IsNullOrEmpty(ReturnURL) ? "/" : ReturnURL;
ErrorMsgs = new List<string>();
if( !string.IsNullOrEmpty(UserName) ) {
if( !string.IsNullOrEmpty(Password) ) {
if (Password.Length >= 6 ) {
HttpResponseMessage TestLogin = await Http.PostAsJsonAsync("api/account/login", new MistoxWebsite.Shared.Account(){ UserName = UserName, PasswordHash = Password, EmailVerified = StayLoggedIn });
string result = await TestLogin.Content.ReadAsStringAsync();
Account? user = JsonConvert.DeserializeObject<Account>(result);
if (user == null ) {
ErrorMsgs.Add("No response from the server");
base.StateHasChanged();
return;
}
if ( string.IsNullOrEmpty(user.Error) ) {
ErrorMsgs.Add("Login Success");
Nav.NavigateTo("/", true);
} else {
ErrorMsgs.Add(user.Error);
}
Loading = "";
} else {
ErrorMsgs.Add("Password must be at least 6 Characters long");
}
} else {
ErrorMsgs.Add("The 'password' field is required");
}
} else{
if( string.IsNullOrEmpty(UserName) ) {
ErrorMsgs.Add("The 'username' field is required");
}
if( string.IsNullOrEmpty(Password) ) {
ErrorMsgs.Add("The 'password' field is required");
}
if (Password.Length < 6 ) {
ErrorMsgs.Add("Password must be at least 6 Characters long");
}
if (ErrorMsgs.Count == 0){
Dictionary<string, string> formData = new Dictionary<string, string>{
{ "UserName", UserName },
{ "PasswordHash", Password },
{ "StayLoggedIn", StayLoggedIn.ToString() }
};
HttpResponseMessage TestLogin = await Http.PostAsync("api/account/login", new FormUrlEncodedContent(formData) );
string result = await TestLogin.Content.ReadAsStringAsync();
Account? user = JsonConvert.DeserializeObject<Account>(result);
if (user == null ) {
ErrorMsgs.Add("No response from the server");
base.StateHasChanged();
return;
}
if ( string.IsNullOrEmpty(user.Error) ) {
ErrorMsgs.Add("Login Success");
Nav.NavigateTo(ReturnURL, true);
} else {
ErrorMsgs.Add(user.Error);
}
}
Loading = "";
base.StateHasChanged();
}
@@ -52,63 +52,41 @@
}
}
public bool CheckEmail(string email ) {
int ATcount = 0;
int DOTcount = 0;
char[] cmail = email.ToArray();
foreach(char cur in cmail ) {
if(cur == '@' ) {
ATcount += 1;
}else if(cur == '.' ) {
DOTcount += 1;
}
}
if (ATcount == 1 && DOTcount >= 1 ) {
return true;
}
return false;
}
public async Task TryRegister() {
Loading = "Waiting for a response from the server";
ReturnURL = string.IsNullOrEmpty(ReturnURL) ? "/" : ReturnURL;
ErrorMsgs = new List<string>();
if ( !string.IsNullOrEmpty(Email) ){
if( CheckEmail( Email ) ) {
if( !string.IsNullOrEmpty(UserName) ) {
if( !string.IsNullOrEmpty(Password) ) {
if (Password.Length >= 6 ) {
HttpResponseMessage TestRegister = await Http.PostAsJsonAsync("api/account/register", new Account(){
UserName = UserName,
Email = Email,
PasswordHash = Password,
EmailVerified = false,
});
Account? user = await TestRegister.Content.ReadFromJsonAsync<Account>();
if ( string.IsNullOrEmpty(user?.Error) ) {
ErrorMsgs.Add("Register Success");
Nav.NavigateTo("/", true);
} else {
ErrorMsgs.Add( user.Error );
}
Loading = "";
}else{
ErrorMsgs.Add("Password must be at least 6 Characters long");
}
}else{
ErrorMsgs.Add("The 'password' field is required");
}
}else{
ErrorMsgs.Add("The 'username' field is required");
}
}else{
ErrorMsgs.Add("Please check your email address");
}
}else{
MailAddress addr = new MailAddress(Email);
if ( addr.Address != Email ){
ErrorMsgs.Add("Please check your email address");
}
if (Password.Length < 6 ) {
ErrorMsgs.Add("Password must be at least 6 Characters long");
}
if( string.IsNullOrEmpty(UserName) ) {
ErrorMsgs.Add("The 'username' field is required");
}
if( string.IsNullOrEmpty(Password) ) {
ErrorMsgs.Add("The 'password' field is required");
}
if ( string.IsNullOrEmpty(Email) ){
ErrorMsgs.Add("The 'email' field is required");
}
if (ErrorMsgs.Count == 0){
Dictionary<string, string> formData = new Dictionary<string, string>{
{ "Email", Email },
{ "UserName", UserName },
{ "PasswordHash", Password },
};
HttpResponseMessage TestRegister = await Http.PostAsync("api/account/register", new FormUrlEncodedContent(formData) );
Account? user = await TestRegister.Content.ReadFromJsonAsync<Account>();
if ( string.IsNullOrEmpty(user?.Error) ) {
ErrorMsgs.Add("Register Success");
Nav.NavigateTo(ReturnURL, true);
} else {
ErrorMsgs.Add( user.Error );
}
}
Loading = "";
base.StateHasChanged();
}
@@ -38,7 +38,6 @@
[Parameter]
[SupplyParameterFromQuery]
public string ResetPwd { get; set; } = "";
public string NewPassword{ get; set; } = "";
public string RepeatPassword{ get; set; } = "";
@@ -52,24 +51,29 @@
protected async Task TryChange() {
Result = "Waiting on response from server";
if (NewPassword.Length >= 6){
if (NewPassword == RepeatPassword){
HttpResponseMessage TestLogin = await Http.PostAsJsonAsync("api/account/resetpassword", new Account(){ UserName = UserName, PasswordHash = NewPassword, Error = ResetPwd });
string result = await TestLogin.Content.ReadAsStringAsync();
bool success = result == "true" ? true : false;
if (success){
Result = "Password changed successfully";
Thread.Sleep(2000);
Nav.NavigateTo("/", true);
}else{
Result = "Something is wrong";
}
}else{
Result = "Passwords must match";
}
}else{
if (NewPassword != RepeatPassword){
Result = "Passwords must match";
}
if (NewPassword.Length < 6){
Result = "Password must be at least 6 Characters long";
}
if (string.IsNullOrEmpty(Result)){
Dictionary<string, string> formData = new Dictionary<string, string>{
{ "UserName", UserName },
{ "NewPassword", NewPassword },
{ "ResetToken", ResetPwd },
};
HttpResponseMessage TestLogin = await Http.PostAsync("api/account/resetpassword", new FormUrlEncodedContent(formData) );
string result = await TestLogin.Content.ReadAsStringAsync();
bool success = result == "true" ? true : false;
if (success){
Result = "Password changed successfully";
Thread.Sleep(2000);
Nav.NavigateTo("/", true);
}else{
Result = "Something is wrong";
}
}
}
}
@@ -26,7 +26,11 @@
public string Result{ get; set; } = "";
protected override async Task OnInitializedAsync() {
HttpResponseMessage Query = await Http.PostAsJsonAsync("api/account/verifyemail", new Account(){ UserName = UserName, PasswordHash = Guid });
Dictionary<string, string> formData = new Dictionary<string, string>{
{ "UserName", UserName },
{ "EmailToken", Guid },
};
HttpResponseMessage Query = await Http.PostAsync("api/account/verifyemail", new FormUrlEncodedContent(formData) );
bool Answer = await Query.Content.ReadFromJsonAsync<bool>();
if (Answer == true ) {
Result = "Verified Email Successfully";
@@ -41,7 +41,7 @@
@code {
public MistoxWebsite.Shared.Account? _account = null;
public MistoxWebsite.Shared.Database.Account? _account = null;
public int MaxFailedLogin = 0;
public bool FailedLoginToggle = false;
@@ -49,18 +49,19 @@
public async Task SubmitLoginLock() {
if (_account != null ) {
_account.SiteData.FailedPasswordLock = FailedLoginToggle;
_account.SiteData.PasswordAttempts = MaxFailedLogin;
_account.PasswordHash = "";
HttpResponseMessage SendVerifyEmail = await Http.PostAsJsonAsync("api/account/toggleAccountLock", _account);
LoginCounterResult = await SendVerifyEmail.Content.ReadAsStringAsync();
Dictionary<string, string> formData = new Dictionary<string, string>{
{ "UserName", _account.UserName },
{ "AccountLock", FailedLoginToggle.ToString() },
};
HttpResponseMessage Query = await Http.PostAsync("api/account/toggleAccountLock", new FormUrlEncodedContent(formData) );
LoginCounterResult = await Query.Content.ReadAsStringAsync();
}
}
protected override async Task OnInitializedAsync() {
HttpResponseMessage x = await Http.PostAsync("api/account/get", new StringContent(""));
string body = await x.Content.ReadAsStringAsync();
_account = JsonConvert.DeserializeObject<MistoxWebsite.Shared.Account>(body);
_account = JsonConvert.DeserializeObject<MistoxWebsite.Shared.Database.Account>(body);
if (_account != null){
FailedLoginToggle = _account.SiteData.FailedPasswordLock;
MaxFailedLogin = _account.SiteData.PasswordAttempts;
@@ -73,8 +74,11 @@
public async Task SendVerifyEmail() {
if (_account != null){
HttpResponseMessage SendVerifyEmail = await Http.PostAsJsonAsync("api/account/sendverifyemail", new MistoxWebsite.Shared.Account(){ UserName = _account.UserName });
bool result = await SendVerifyEmail.Content.ReadFromJsonAsync<bool>();
Dictionary<string, string> formData = new Dictionary<string, string>{
{ "UserName", _account.UserName },
};
HttpResponseMessage Query = await Http.PostAsync("api/account/sendverifyemail", new FormUrlEncodedContent(formData) );
bool result = await Query.Content.ReadFromJsonAsync<bool>();
if (result == true ) {
EmailSentResult = "Email Sent";
} else {
@@ -108,8 +112,13 @@
return;
}
if (_account != null){
HttpResponseMessage TryChangePassword = await Http.PostAsJsonAsync("api/account/changepassword", new MistoxWebsite.Shared.Account(){ UserName = _account.UserName, PasswordHash = CurPass, Error = NewPass1 });
bool resultText = await TryChangePassword.Content.ReadFromJsonAsync<bool>();
Dictionary<string, string> formData = new Dictionary<string, string>{
{ "UserName", _account.UserName },
{ "OldPassword", CurPass },
{ "NewPassword", NewPass1 }
};
HttpResponseMessage Query = await Http.PostAsync("api/account/changepassword", new FormUrlEncodedContent(formData) );
bool resultText = await Query.Content.ReadFromJsonAsync<bool>();
if (resultText == true ) {
PasswordErrorText = "Password changed successfully";
} else {
@@ -5,10 +5,6 @@
margin-bottom: 1.4rem;
}
.title-frame{
}
.title-frame h1 input{
padding-left: 1.4rem;
padding-top: 0.4rem;
@@ -1,6 +1,3 @@
body {
}
.lower-frame{
.lower-frame{
padding: 1.4rem;
}
@@ -119,12 +119,12 @@
}
async Task confirmDeleteAccount() {
HttpResponseMessage Delete = await Http.PostAsJsonAsync( "api/account/delete", new MistoxWebsite.Shared.Account(){
ID = Statics.User.ID,
UserName = Statics.User.Email,
PasswordHash = Password
});
string result = await Delete.Content.ReadAsStringAsync();
Dictionary<string, string> formData = new Dictionary<string, string>{
{ "UserName", Statics.User.UserName },
{ "Password", Password },
};
HttpResponseMessage Query = await Http.PostAsync("api/account/delete", new FormUrlEncodedContent(formData) );
string result = await Query.Content.ReadAsStringAsync();
bool status = result == "true" ? true : false;
if (status){
await Http.PostAsync("api/account/logout", new StringContent(""));
@@ -6,28 +6,11 @@
<div class="Big-Div">
<div id="DirTree">
@if (output != null ) {
<ExplorerChild Title=@output.Path Children=output.Children PartialPath="\"></ExplorerChild>
}
</div>
<span>@ErrorTxt</span>
</div>
@code{
public string ErrorTxt = "";
public DirObj? output = null;
protected override async void OnInitialized() {
try {
byte[] resultBody = await (await Http.PostAsync( "api/product/showdownloads", new StringContent("") )).Content.ReadAsByteArrayAsync();
string JsonData = Encoding.UTF8.GetString(resultBody);
output = JsonConvert.DeserializeObject<DirObj>( JsonData );
base.StateHasChanged();
} catch( Exception e ) {
ErrorTxt = "Error : " + e.ToString();
}
}
}
@@ -1,283 +0,0 @@
@page "/resume/derek"
<div class="PopOutFrame">
<div class="Content" style="height: 170px !important;">
<div class="ImgFrame">
<img class="Picture" src="/img/ResumeFace.jpg" />
</div>
<div class="NameFrame">
<h1>Derek Holloway</h1>
<h1>Owner and sole developer</h1>
</div>
<div class="ContactFrame">
<h1>derek@mistox.net</h1>
</div>
</div>
<div class="PopOutHr"></div>
</div>
<div class="PopOutFrame">
<div class="Content">
<h1 style="margin: 0; margin-bottom: 5px;">Work Experience</h1>
<!-- NAVWAR Assistant Contract Tech. Rep. -->
<div class="capsule" @onmouseenter="()=>{ MouseEnter(1); }" @onmouseleave="()=>{ MouseLeave(1); }">
<div class="Skills" style="height: calc(100% - 40px);">
<div class="paddedcell">
<h2 class="jobTitle">NAVWAR Assistant Contract Tech. Rep.</h2>
<h3 class="jobSub">Redhorse corp. - San Diego, CA</h3>
<h3 class="jobSub">888-445-8010</h3>
<h3 class="jobSub">February 2022 - Today</h3>
<span></span>
</div>
</div>
<div class="SkillsContent colored" style="height: calc(100% - 40px); @ContentStyle1">
<div class="paddedcell">
<ul>
<li><span>The first line of support for end users</span></li>
<li><span>Fix or escalate issues as required to the correct authority for resolution</span></li>
<li><span>The ACTR performs routine office IT functions managing mechanical and printer supplies</span></li>
<li><span>Assisting with connectivity to and troubleshooting networked systems and Video Teleconferences</span></li>
<li><span>This includes setting up new accounts</span></li>
<li><span>Managing users accesses</span></li>
<li><span>Uses the building badging system to grant access to appropriate personnel Assist with transition to Office 365 and Navy Flank Speed as required.</span></li>
<li><span>Leading role on Junior level tasks/projects</span></li>
<li><span>Supports the customer performing moderately complex tasks on a routine basis.</span></li>
<br />
<li><span>Project manager for NAVWAR tech refresh</span></li>
<li><span>Replacing 4010+ computers within a 1 year time-frame</span></li>
<li><span>Manage warranties with HP Federal</span></li>
<li><span>Coordinating orders and returns for old leased hardware</span></li>
</ul>
</div>
</div>
</div>
<!-- NMCI Field Service -->
<div class="capsule" @onmouseenter="()=>{ MouseEnter(2); }" @onmouseleave="()=>{ MouseLeave(2); }">
<div class="Skills" style="height: calc(100% - 40px);">
<div class="paddedcell">
<h2 class="jobTitle">NMCI Field Service Technitian</h2>
<h3 class="jobSub">Super Systems Inc - San Diego, CA</h3>
<h3 class="jobSub">757-399-3000 - info@supersystemsinc.com</h3>
<h3 class="jobSub">June 2021 - Feburary 2022</h3>
<br />
<h3 class="jobSub">Ohm Systems, Inc - San Diego, CA</h3>
<h3 class="jobSub">215-675-2766 - info@ohmsysinc.com</h3>
<h3 class="jobSub">February 2021 - June 2021</h3>
<span></span>
</div>
</div>
<div class="SkillsContent colored" style="height: calc(100% - 40px); @ContentStyle2">
<div class="paddedcell">
<ul>
<li><span>Performed layer 1 network troubleshooting; windows netsh firewalls, 802.1x Authentication issues, and cable and port issues.</span></li>
<li><span>Performed hardware troubleshooting and replacements; replacing laptop motherboards, displays, cpus, ram, and peripherals.</span></li>
<li><span>Performed software troubleshooting using event viewer, task manager, and command prompt. By uninstalling and reinstalling or reconfiguring.</span></li>
<li><span>Worked with network printers, voip's, and video telecommunication devices.</span></li>
<li><span>Worked face to face with customers, managing my time between calls and work orders.</span></li>
</ul>
</div>
</div>
</div>
<!-- NMCI Help Desk -->
<div class="capsule" @onmouseenter="()=>{ MouseEnter(3); }" @onmouseleave="()=>{ MouseLeave(3); }">
<div class="Skills" style="height: calc(100% - 40px);">
<div class="paddedcell">
<h2 class="jobTitle">NMCI Help Desk Technitian</h2>
<h3 class="jobSub">Apex Systems - Coronado, CA</h3>
<h3 class="jobSub">619-757-1646</h3>
<h3 class="jobSub">September 2019 - September 2020</h3>
<span></span>
</div>
</div>
<div class="SkillsContent colored" style="height: calc(100% - 40px); @ContentStyle3">
<div class="paddedcell">
<ul>
<li><span>Performed remote troubleshooting: windows cmd, winrs, rdc, winrs. Fixing software issues</span></li>
<li><span>Performed administrative Tasks: create active directory accounts and verifying identity to unlock accounts.</span></li>
<li><span>Walked users through diagnosing network issues over the phone or escalated issue to field services</span></li>
<li><span>Fixed users email issues; server mappings, proxy email addresses, shared emails, and outlook related issues.</span></li>
<li><span>Moved users profiles from one domain to another and moved users files along with it.</span></li>
<li><span>Fixed account related issues; id to user mismatch and wrong display name.</span></li>
</ul>
</div>
</div>
</div>
<!-- Warehouse Reciever -->
<div class="capsule" @onmouseenter="()=>{ MouseEnter(4); }" @onmouseleave="()=>{ MouseLeave(4); }">
<div class="Skills" style="height: calc(100% - 40px);">
<div class="paddedcell">
<h2 class="jobTitle">Warehouse receiver</h2>
<h3 class="jobSub">Ababa Bolt - El Cajon, CA</h3>
<h3 class="jobSub">619-440-1781</h3>
<h3 class="jobSub">May 2019 - August 2019</h3>
<span></span>
</div>
</div>
<div class="SkillsContent colored" style="height: calc(100% - 40px); @ContentStyle4">
<div class="paddedcell">
<ul>
<li><span>Verified that all parts came in off the packing slip</span></li>
<li><span>Rejected parts that were damaged and sent back to manufacturer</span></li>
<li><span>Sort and add parts into the tracking system</span></li>
<li><span>Put parts away in appropriate areas</span></li>
</ul>
</div>
</div>
</div>
<!-- Warehouse packer -->
<div class="capsule" @onmouseenter="()=>{ MouseEnter(5); }" @onmouseleave="()=>{ MouseLeave(5); }">
<div class="Skills" style="height: calc(100% - 40px);">
<div class="paddedcell">
<h2 class="jobTitle">Warehouse packer</h2>
<h3 class="jobSub">Ababa Bolt - El Cajon, CA</h3>
<h3 class="jobSub">619-440-1781</h3>
<h3 class="jobSub">October 2017 - September 2018</h3>
<span></span>
</div>
</div>
<div class="SkillsContent colored" style="height: calc(100% - 40px); @ContentStyle5">
<div class="paddedcell">
<ul>
<li><span>Find which parts need more stock on shelves</span></li>
<li><span>Split out parts by count or weight</span></li>
<li><span>Verified and marked appropriate compliance such as RoHS</span></li>
<li><span>Operated forklifts and scissor lifts</span></li>
</ul>
</div>
</div>
</div>
<!-- California Army National Guard -->
<div class="capsule" @onmouseenter="()=>{ MouseEnter(6); }" @onmouseleave="()=>{ MouseLeave(6); }">
<div class="Skills" style="height: calc(100% - 40px);">
<div class="paddedcell">
<h2 class="jobTitle">Motor Vehicle Trasport Operator</h2>
<h3 class="jobSub">California Army National Guard</h3>
<h3 class="jobSub">760-607-8574</h3>
<h3 class="jobSub">September 2018 - Today</h3>
<h3 class="jobSub">Rank/Grade - Specialist / E-4</h3>
<span></span>
</div>
</div>
<div class="SkillsContent colored" style="height: calc(100% - 40px); @ContentStyle6">
<div class="paddedcell">
<ul>
<li><span>88M - Motor Transport Operator</span></li>
<li><span>Neccesarry to hold secret clearence and keep all cyber security certifications up to date.</span></li>
<li><span>June 2020 - Protected and defended the Los Alamitos police department and Six Flags Magic Mountain during the rios cause by BLM movement that caused rioting in the streets.</span></li>
<li><span>September 2020 - Worked with Cal-Fire in Chico, CA and Alderpoint, CA to cut fire lines to prevent the spread of fires during the <a href="https://en.wikipedia.org/wiki/August_Complex_fire">August Fire Complex</a> fires.</span></li>
</ul>
</div>
</div>
</div>
</div>
<div class="PopOutHr"></div>
</div>
<div class="PopOutFrame" @onmouseenter="()=>{ MouseEnter(7); }" @onmouseleave="()=>{ MouseLeave(7); }">
<div class="Content">
<div class="Skills">
<h1>Development</h1>
<ul>
<li class="LIPrime">C#</li>
<li>Mono</li>
<li>ASP.NET</li>
<li>ASP Core</li>
<li>Blazor Web Assembly</li>
<li>Windows Forms Apps</li>
<li class="LIPrime">C++</li>
<li>Arm Embedded</li>
<li>Raspberry Pi</li>
<li class="LIPrime">Database</li>
<li>MySql</li>
<li>MsSql</li>
<li>LINQ</li>
<li class="LIPrime">Game Engines</li>
<li>Godot</li>
<li>Unity 3D</li>
<li>Solar 2D</li>
<li class="LIPrime">Web Development</li>
<li>Front End</li>
<li>Back End</li>
<li>Interfaces</li>
<li>Square Payment API</li>
<li>Rest Clients</li>
</ul>
</div>
<div class="SkillsContent" style="@ContentStyle7">
<div class="paddedcell textSection">
<a href="https://github.com/reverseslayer/LUADNS-DDNS">LUADNS-DDNS : https://github.com/reverseslayer/LUADNS-DDNS</a><br />
<span>This is a service that I made for </span><a href="http://luadns.com">luadns.com</a><span>. This allows free ddns by simply changing the dns name servers to luadns nameservers and running this program as a service. This was made for linux but shoud easily run on windows.</span><br /><br />
</div>
<div class="paddedcell textSection">
<a href="https://github.com/reverseslayer/MistoxServer">Mistox-Server : https://github.com/reverseslayer/MistoxServer</a><br />
<span>This is a </span><a href="https://en.wikipedia.org/wiki/UDP_hole_punching">UDP Hole Punched</a><span> server; that allows clients to direct connect over the wan without opening ports. It works by having a dedicated TCP server that routes the UDP connections directly to each client. Based on this </span><a href="img/IdeaMap.jpg">Idea map.</a>
</div>
<div class="paddedcell textSection">
<a href="https://www.mistox.net">Mistox.net : https://mistox.net</a><br />
<span>Mistox.net is all done by me. The DNS is hosted by <a href="https://domains.google.com">domains.google.com</a> and pushed through <a href="http://luadns.com">luadns.com</a> name server so that I can run LUA-DDNS a service I made to reach other places that behind ddns. The webservers are hosted by <a href="https://www.vultr.com/">vultr.com</a> and the entire stack is built on <a href="https://dotnet.microsoft.com/en-us/apps/aspnet">asp.net</a>. The payment services are run through <a href="https://stripe.com/">stripe-payments</a>. I built this as a side project but its slowly becoming more and more something that I would like to be able to share things that I make; paid or free.</span>
</div>
</div>
</div>
<div class="PopOutHr" style="margin-bottom: 30px;"></div>
</div>
@code {
string ContentStyle1 = "";
string ContentStyle2 = "";
string ContentStyle3 = "";
string ContentStyle4 = "";
string ContentStyle5 = "";
string ContentStyle6 = "";
string ContentStyle7 = "";
void MouseEnter( int frameNumber ) {
if (frameNumber == 1){
ContentStyle1 = "right: 0px;";
base.StateHasChanged();
}else if (frameNumber == 2){
ContentStyle2 = "right: 0px;";
base.StateHasChanged();
}else if (frameNumber == 3){
ContentStyle3 = "right: 0px;";
base.StateHasChanged();
}else if (frameNumber == 4){
ContentStyle4 = "right: 0px;";
base.StateHasChanged();
}else if (frameNumber == 5){
ContentStyle5 = "right: 0px;";
base.StateHasChanged();
}else if (frameNumber == 6){
ContentStyle6 = "right: 0px;";
base.StateHasChanged();
}else if (frameNumber == 7){
ContentStyle7 = "right: 0px;";
base.StateHasChanged();
}
}
void MouseLeave( int frameNumber ){
if (frameNumber == 1){
ContentStyle1 = "right: -700px;";
base.StateHasChanged();
}else if (frameNumber == 2){
ContentStyle2 = "right: -700px;";
base.StateHasChanged();
}else if (frameNumber == 3){
ContentStyle3 = "right: -700px;";
base.StateHasChanged();
}else if (frameNumber == 4){
ContentStyle4 = "right: -700px;";
base.StateHasChanged();
}else if (frameNumber == 5){
ContentStyle5 = "right: -700px;";
base.StateHasChanged();
}else if (frameNumber == 6){
ContentStyle6 = "right: -700px;";
base.StateHasChanged();
}else if (frameNumber == 7){
ContentStyle7 = "right: -700px;";
base.StateHasChanged();
}
}
}
@@ -1,191 +0,0 @@
* {
--popout-shadow-color-left: #8c8c8c;
--popout-shadow-color-bottom: #595959;
--popout-background-color: #004262;
--frame-background-color: #005662;
--frame-title-color: #ffffff;
--job-title-color: #f35100;
--job-sub-color: #c85c00;
--text-color: #dddddd;
--link-color: #4cff00;
--link-visited-color: #73ac5b;
--skills-bg-color: #c85c00;
--skills-text-color: #000;
--skills-text-shadow-color: #f35100;
--skills-prime-background-color: #972500;
--skills-prime-text-color: #fff;
}
body {
position: relative;
}
h1 {
color: var(--frame-title-color);
}
span {
color: var(--text-color);
}
.PopOutFrame {
position: relative;
background-color: white;
width: 100%;
max-width: 1080px;
margin: 15px auto 0 auto;
content: "";
}
.PopOutFrame::before {
position: absolute;
width: 6px;
left: -6px;
margin-top: 6px;
background: var(--popout-shadow-color-left);
content: "";
display: block;
transform: skew(0deg, -61deg);
height: 100%;
}
.PopOutHr {
width: 100%;
float: left;
}
.PopOutHr::after {
position: absolute;
width: 100%;
margin-top: 0px;
bottom: -11px;
left: -3px;
background: var(--popout-shadow-color-bottom);
content: "";
display: block;
transform: skew(-31deg, 0deg);
height: 11px;
}
.Content{
position: relative;
padding: 15px;
overflow: hidden;
background-color: var(--popout-background-color);
}
.ImgFrame {
float: left;
}
.Picture{
width: 140px;
height: 140px;
}
.NameFrame {
float: left;
width: calc(100% - 510px);
margin-left: 20px;
}
.ContactFrame {
float: left;
width: 300px;
height: 140px;
}
.ContactFrame h1{
font-size: 30px;
}
.SkillsContent {
position: relative;
float: left;
height: 100%;
width: 60%;
transition-duration: 2s;
right: -700px;
}
.SkillsContent :link {
color: var(--link-color);
}
.SkillsContent :visited{
color: var(--link-visited-color) !important;
}
.paddedcell {
padding: 10px 5px;
padding-bottom: 0;
margin-bottom: 5px;
}
.colored {
background-color: var(--frame-background-color);
}
.paddedcell br{
display: block;
margin: 10px 0;
content: "";
}
.Skills {
float: left;
height: 100%;
width: 40%;
transition-duration: 2s;
}
.Skills h1{
margin: 5px;
}
.Skills ul{
font-size: 14px;
list-style: none;
margin: 0;
padding: 0 5px;
}
.Skills li {
float: left;
padding: 4px 6px;
margin: 0 4px 4px 0;
background-color: var(--skills-bg-color);
text-shadow: 0 1px 1px var(--skills-text-shadow-color);
color: var(--skills-text-color);
}
.LIPrime{
text-shadow: none;
background-color: var(--skills-prime-background-color) !important;
color: var(--skills-prime-text-color) !important;
clear: left;
}
.capsule {
margin-top: 15px;
overflow: hidden;
border: solid var(--frame-background-color);
border-radius: 5px;
}
.jobTitle {
margin: 0;
color: var(--job-title-color);
}
.jobSub {
margin: 0;
color: var(--job-sub-color);
font-size: 15px;
}
.textSection {
margin-top: 15px;
background-color: var(--frame-background-color);
border-radius: 5px;
}
@@ -1,38 +0,0 @@
<button type="button" class="collapsible" @onclick=OpenCollapseable>@Title</button>
<ul class="dropdown-content" style="display : @collapseStyle;">
@if (Children != null){
@foreach(var Cur in Children){
<li>
@if(Cur.Type == FileType.Directory) {
<ExplorerChild Title=@Cur.Path Children=Cur.Children PartialPath=@(PartialPath+Cur.Path) ></ExplorerChild>
} else {
<button type="button" @onclick=@((e)=>{ Download(Cur.Path); })>@Cur.Path</button>
}
</li>
}
}
</ul>
@code{
[Parameter]
public string Title{ get; set; } = "";
[Parameter]
public DirObj[]? Children{ get; set; }
[Parameter]
public string PartialPath{ get; set; } = "";
public string collapseStyle = "none";
void OpenCollapseable() {
if (collapseStyle == "block") {
collapseStyle = "none";
} else {
collapseStyle = "block";
}
}
void Download(string Path) {
Nav.NavigateTo( "api/product/download?Product=" + PartialPath + Path, true );
}
}
@@ -7,7 +7,7 @@
@code {
protected override void OnInitialized() {
if (Statics.User.ID == -1 ) {
Nav.NavigateTo( "/account/login?ReturnURL=Null" );
Nav.NavigateTo( "/account/login" );
}
}
}
-164
View File
@@ -1,164 +0,0 @@
@page "/snake"
<div @onkeydown="OnKeyDown" tabindex="0" style="background-color: #333;" >
<h1 id="Score" style="width: 100%; text-align: center; color:#fff;">Score : 0</h1>
<div id="BODY" style="position: relative; margin-bottom: 5px; margin-left: 50%; right: 300px; background-color: #666; width: 600px; height: 600px;">
<!-- Game -->
@foreach(SnakePart part in SnakeParts ) {
<div style="position: absolute; left: @part.getX(); top: @part.getY(); width: 10px; height: 10px; background-color: #111; border: 0; padding: 0; margin: 0;"></div>
}
<div style="position: absolute; left: @Collectable.getX(); top: @Collectable.getY(); width: 10px; height: 10px; background-color: #f00; border: 0; padding: 0; margin: 0;"></div>
<!-- End Game -->
</div>
<div id="PauseScreen"style="position: relative; display: none; width: 500px; margin-left: 50%; right: 250px;">
<h2 style="text-align: center; color: #f00; ">Game Paused</h2>
</div>
<div style="margin: 0 40px; width: calc(100% - 80px); background-color: #777;">
<h3 style="text-align: center; font-size: 25px; color: #0f0; padding: 0; margin: 0; border: 0;">LEADERBOARD</h3>
</div>
<hr style="margin: 0px; width:calc(100% - 82px);" />
<div id="Scoreboard" style="margin: 0 40px; width: calc(100% - 80px); background-color: #777;"></div>
<h3 style="position: absolute; right: 10px; bottom: 3px; color: #fff;">Designed by Derek in California</h3>
</div>
@code {
struct SnakePart {
public int X{ get; set; }
public int Y{ get; set; }
public int Hue{ get; set; }
public string getX() {
return X * 10 + "px";
}
public string getY() {
return Y * 10 + "px";
}
}
enum Direction {
Up,
Down,
Left,
Right
}
List<SnakePart> SnakeParts = new List<SnakePart>(){
new SnakePart{ X = 5, Y = 10 }, // Tail
new SnakePart{ X = 6, Y = 10 },
new SnakePart{ X = 7, Y = 10 },
new SnakePart{ X = 8, Y = 10 } // Head
};
int Score = 0;
bool Paused = false;
Direction SnakeDirection = Direction.Right;
int FrameRate = 1000 / 10;
int HueRate = 5;
SnakePart Collectable = new SnakePart{ X = 15, Y = 15 };
void OnKeyDown(KeyboardEventArgs e) {
Console.WriteLine(e.Key);
if (e.Key.ToLower() == "w" ) {
SnakeDirection = Direction.Up;
}else if (e.Key.ToLower() == "a" ) {
SnakeDirection = Direction.Left;
}else if (e.Key.ToLower() == "s" ) {
SnakeDirection = Direction.Down;
}else if (e.Key.ToLower() == "d" ) {
SnakeDirection = Direction.Right;
}
}
bool CheckSelfHit() {
foreach(SnakePart cur in SnakeParts ) {
if (SnakeParts[SnakeParts.Count-1].X == cur.X ) {
if (SnakeParts[SnakeParts.Count-1].Y == cur.Y ) {
return false;
}
}
}
return true;
}
bool CheckBounds() {
if (SnakeParts[SnakeParts.Count-1].X > 0 && SnakeParts[SnakeParts.Count-1].X < 50 ) {
if (SnakeParts[SnakeParts.Count-1].Y > 0 && SnakeParts[SnakeParts.Count-1].Y < 50 ) {
return true;
}
}
return false;
}
bool CheckCollectibleHit() { // return true if hit
if (SnakeParts[SnakeParts.Count-1].X == Collectable.X ) {
if (SnakeParts[SnakeParts.Count-1].Y == Collectable.Y ) {
return true;
}
}
return false;
}
void ResetCollectable() {
Collectable.X = new Random().Next(1, 40);
Collectable.Y = new Random().Next(1, 40);
}
void Die() {
}
void Update() {
// Get Next Position
if( SnakeDirection == Direction.Up ) {
SnakeParts.Add( new SnakePart {
X = SnakeParts[SnakeParts.Count-1].X,
Y = SnakeParts[SnakeParts.Count-1].Y - 1,
Hue = SnakeParts[SnakeParts.Count-1].Hue + HueRate
});
}else if (SnakeDirection == Direction.Right ) {
SnakeParts.Add( new SnakePart {
X = SnakeParts[SnakeParts.Count-1].X + 1,
Y = SnakeParts[SnakeParts.Count-1].Y,
Hue = SnakeParts[SnakeParts.Count-1].Hue + HueRate
});
}else if (SnakeDirection == Direction.Down ) {
SnakeParts.Add( new SnakePart {
X = SnakeParts[SnakeParts.Count-1].X,
Y = SnakeParts[SnakeParts.Count-1].Y + 1,
Hue = SnakeParts[SnakeParts.Count-1].Hue + HueRate
});
}else if (SnakeDirection == Direction.Left ) {
SnakeParts.Add( new SnakePart {
X = SnakeParts[SnakeParts.Count-1].X - 1,
Y = SnakeParts[SnakeParts.Count-1].Y,
Hue = SnakeParts[SnakeParts.Count-1].Hue + HueRate
});
}
if (CheckSelfHit() && CheckBounds() ) {
if( CheckCollectibleHit() ) {
Score += 1;
ResetCollectable();
} else {
SnakeParts.RemoveAt( 0 );
}
} else {
Die();
}
StateHasChanged();
}
protected override void OnInitialized() {
ResetCollectable();
var timer = new System.Threading.Timer((e) => {
if (!Paused){
Update();
}
}, null, 0, FrameRate );
}
}
@@ -4,7 +4,7 @@
<h3 class="cart-title">Cart</h3>
<div class="Spacer">
@foreach( MistoxWebsite.Shared.Cart obj in Statics.Carts ) {
@foreach( MistoxWebsite.Shared.Database.Cart obj in Statics.Carts ) {
<div class="cart-item">
<h1>@getItem(obj.ProductID)?.Name</h1>
@foreach( string cur in getItem( obj.ProductID )?.Images ) {
@@ -43,7 +43,7 @@
protected override void OnInitialized() {
total = 0;
foreach( MistoxWebsite.Shared.Cart obj in Statics.Carts ) {
foreach( MistoxWebsite.Shared.Database.Cart obj in Statics.Carts ) {
foreach( Product item in Statics.Products ) {
if( obj.ProductID == item.ID ) {
total = total + (item.Cost / 100f);
@@ -99,7 +99,7 @@
public bool isOwned(int ID ) {
if(Statics.Owned.Count > 0 ) {
foreach( MistoxWebsite.Shared.Receipt cur in Statics.Owned ) {
foreach( MistoxWebsite.Shared.Database.Receipt cur in Statics.Owned ) {
if( cur.ProductID == ID ) {
return true;
}
@@ -109,7 +109,7 @@
}
public bool isInCart(int id) {
foreach( MistoxWebsite.Shared.Cart cur in Statics.Carts ) {
foreach( MistoxWebsite.Shared.Database.Cart cur in Statics.Carts ) {
if (cur.ProductID == id ) {
return true;
}
@@ -118,7 +118,7 @@
}
public async void onAddToCart( int ID ) {
MistoxWebsite.Shared.Cart item = new MistoxWebsite.Shared.Cart {
MistoxWebsite.Shared.Database.Cart item = new MistoxWebsite.Shared.Database.Cart {
ProductID = ID,
AccountID = Statics.User.ID
};
@@ -1,6 +1,6 @@
using System.Security.Claims;
using Microsoft.AspNetCore.Components.Authorization;
using MistoxWebsite.Shared;
using MistoxWebsite.Shared.DTO.Session;
using Newtonsoft.Json;
namespace MistoxWebsite.Client.AuthState {
+1 -1
View File
@@ -1,4 +1,4 @@
using MistoxWebsite.Shared;
using MistoxWebsite.Shared.Database;
namespace MistoxWebsite.Client.Statics {
public class Statics {
+13 -9
View File
@@ -1,24 +1,28 @@
@using System.Net.Http
@using System.Net.Http.Json
@using System.Net.Mail
@using System.Security.Claims
@using System.Security.Cryptography
@using System.Text
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.AspNetCore.Components.WebAssembly.Http
@using Microsoft.JSInterop
@using MistoxWebsite.Client
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
@using System.Security.Claims
@using MistoxWebsite.Client
@using MistoxWebsite.Client.AuthState
@using MistoxWebsite.Client.Statics
@using System.Security.Cryptography
@using System.Text
@using MistoxWebsite.Shared
@using Newtonsoft.Json
@using MistoxWebsite.Client.Pages.Shared
@using MistoxWebsite.Shared.Database
@using MistoxWebsite.Shared.DTO.Account
@using MistoxWebsite.Shared.DTO.Session
@using Newtonsoft.Json
@inject IJSRuntime JS
@inject NavigationManager Nav
@@ -13,29 +13,27 @@ namespace MistoxWebsite.Server.Controllers {
DatabaseService _accountContext;
EmailService _emailContext;
public AuthenticationController( DatabaseService DatabaseContext, EmailService emailContext ) {
public AuthenticationController(DatabaseService DatabaseContext, EmailService emailContext) {
_accountContext = DatabaseContext;
_emailContext = emailContext;
}
// In Account -> References UserName / PasswordHash
// Out Account
[Route( "api/account/login" )]
[Route("api/account/login")]
[HttpPost]
public async Task<ActionResult<Account>> Login( [FromBody] Account request ) {
public async Task<ActionResult<Account>> Login([FromForm] string UserName, [FromForm] string PasswordHash, [FromForm] bool StayLoggedIn) {
try {
Account? test = await _accountContext.GetAccount(request.UserName.ToLower());
if( test != null ) {
if( test.EmailVerified == true ) {
if( test.SiteData.FailedPasswordLock ) {
if( test.SiteData.CurrentPasswordAttempts >= test.SiteData.PasswordAttempts ) {
Account? test = await _accountContext.GetAccount(UserName.ToLower());
if (test != null) {
if (test.EmailVerified == true) {
if (test.SiteData.FailedPasswordLock) {
if (test.SiteData.CurrentPasswordAttempts >= test.SiteData.PasswordAttempts) {
return new Account() { Error = "Too many failed password attempts. Please reset your password" };
}
}
if( BCrypt.Net.BCrypt.Verify( request.PasswordHash, test.PasswordHash ) ) {
if (BCrypt.Net.BCrypt.Verify(PasswordHash, test.PasswordHash)) {
test.SiteData.CurrentPasswordAttempts = 0;
await _accountContext.SetAccount( test );
await _accountContext.SetAccount(test);
AccountClaims aClaims = await getClaims(test.ID);
List<Claim> claims = new List<Claim>() {
@@ -49,64 +47,306 @@ namespace MistoxWebsite.Server.Controllers {
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal( new ClaimsIdentity( claims, "Auth" ) ),
new ClaimsPrincipal(new ClaimsIdentity(claims, "Auth")),
new AuthenticationProperties {
ExpiresUtc = DateTime.UtcNow.AddYears(30), // Add 30 years with sliding on
IsPersistent = request.EmailVerified, // Is set from the StayLoggedIn
IsPersistent = StayLoggedIn, // Is set from the StayLoggedIn
}
);
return test;
} else {
}
else {
test.SiteData.CurrentPasswordAttempts += 1;
await _accountContext.SetAccount( test );
await _accountContext.SetAccount(test);
return new Account() { Error = "Wrong password" };
}
}else{
await SendVerify(test);
}
else {
await SendVerify(test.UserName);
return new Account() { Error = "A new verify email has been sent. \n Note only 1 email send every 5 mintes" };
}
}
return new Account() { Error = "User doesn't exist" };
} catch( Exception ex ) {
} catch (Exception ex) {
return new Account() { Error = ex.Message };
}
}
// In Account -> References UserName / PasswordHash
// Out Account
[Route( "api/account/session" )]
[Route("api/account/session")]
[HttpPost]
public async Task<ActionResult<Account>> LoginSession( [FromBody] Account request ) {
public async Task<ActionResult<Account>> LoginSession([FromBody] Account request) {
try {
Account? test = await _accountContext.GetAccount(request.UserName.ToLower());
if( test != null ) {
if( request.PasswordHash == test.PasswordHash ) {
if (test != null) {
if (request.PasswordHash == test.PasswordHash) {
return test;
} else {
}
else {
test.SiteData.CurrentPasswordAttempts += 1;
await _accountContext.SetAccount( test );
await _accountContext.SetAccount(test);
return new Account() { Error = "Wrong password" };
}
}
return new Account() { Error = "User doesn't exist" };
} catch( Exception ex ) {
} catch (Exception ex) {
return new Account() { Error = ex.Message };
}
}
// In Account
// Out List<String>
[Route( "api/account/claims" )]
[Route("api/account/claims")]
[HttpPost]
public async Task<ActionResult<AccountClaims>> Claims( [FromBody] Account Account ) {
public async Task<ActionResult<AccountClaims>> Claims([FromBody] Account Account) {
AccountClaims claims = await getClaims(Account.ID);
return claims;
}
async Task<AccountClaims> getClaims( int AccountID ) {
[Route("api/account/register")]
[HttpPost]
public async Task<ActionResult<Account>> Register([FromForm] string Email, [FromForm] string UserName, [FromForm] string PasswordHash) {
try {
if (await _accountContext.GetAccount(UserName.ToLower()) == null) {
if (await _accountContext.GetAccount(Email.ToLower()) == null) {
Account? created = new Account() {
UserName = UserName.ToLower(),
Email = Email.ToLower(),
EmailVerified = false,
PasswordHash = BCrypt.Net.BCrypt.HashPassword(PasswordHash),
};
await _accountContext.NewAccount(created);
created = await _accountContext.GetAccount(Email.ToLower());
if (created != null) {
AccountClaims aClaims = await getClaims(created.ID);
List<Claim> claims = new List<Claim>() {
new Claim(ClaimTypes.Name, aClaims.UserName),
new Claim(ClaimTypes.Email, aClaims.Email),
new Claim("emailverified", aClaims.EmailVerified),
new Claim(ClaimTypes.Role, aClaims.Role),
new Claim("LockAccount", aClaims.FailedPasswordLock)
};
await SendVerify(created.UserName);
return created;
}
return new Account() { Error = "Unknown Error" };
}
else {
return new Account() { Error = "Email is already in use" };
}
}
else {
return new Account() { Error = "UserName is taken" };
}
} catch (Exception ex) {
Console.WriteLine("Error: " + ex.Message);
return new Account() { Error = ex.Message };
}
}
[Route("api/account/changepassword")]
[HttpPost]
public async Task<ActionResult<bool>> ChangePassword([FromForm]string UserName, [FromForm]string OldPassword, [FromForm]string NewPassword) {
try {
Account? test = await _accountContext.GetAccount(UserName.ToLower());
if (test != null) {
if (BCrypt.Net.BCrypt.Verify(OldPassword, test.PasswordHash)) {
test.PasswordHash = BCrypt.Net.BCrypt.HashPassword(NewPassword);
test.SiteData.CurrentPasswordAttempts = 0;
await _accountContext.SetAccount(test);
return true;
}
}
return false;
} catch {
return false;
}
}
[Route("api/account/toggleAccountLock")]
[HttpPost]
public async Task<ActionResult<string>> ToggleAccountLock([FromForm]string UserName, [FromForm]bool AccountLock) {
try {
Account? test = await _accountContext.GetAccount(UserName);
if (test != null) {
test.SiteData.FailedPasswordLock = AccountLock;
test.SiteData.CurrentPasswordAttempts = 0;
await _accountContext.SetAccount(test);
return "Account Lock Status Updated";
}
return "Unknown Error Occurred";
} catch (Exception ex) {
return ex.Message;
}
}
[Route("api/account/get")]
[HttpPost]
public async Task<ActionResult<Account?>> Get() {
try {
if (User.Identity != null && User.Identity.IsAuthenticated) {
string? email = User.FindFirstValue(ClaimTypes.Email);
if (!string.IsNullOrEmpty(email)) {
Account? test = await _accountContext.GetAccount(email);
if (test != null) {
return test;
}
}
}
return Ok();
} catch {
return Ok();
}
}
[Route("api/account/logout")]
[HttpPost]
public async Task Logout() {
await HttpContext.SignOutAsync();
}
[Route("api/account/sendverifyemail")]
[HttpPost]
public async Task<ActionResult<string>> SendVerify([FromForm]string UserName) {
try {
string key = "v" + UserName;
// Stop from sending multiple emails quickly
if (_emailContext._SentEmails.ContainsKey(key)) {
DateTime PreviousSentTime = _emailContext._SentEmails.GetValueOrDefault(key);
if (PreviousSentTime.AddMinutes(5) > DateTime.Now) {
return "Cannot sent another verify email until 5 minutes has elapsed ";
}
else {
_emailContext._SentEmails.Remove(key);
}
}
Account? test = await _accountContext.GetAccount(UserName.ToLower());
if (test != null) {
test.SiteData.EmailToken = Guid.NewGuid().ToString();
await _accountContext.SetAccount(test);
string EmailContents = EmailService.VerifyEmailEmail;
EmailContents = Substitue(EmailContents, "@UserName", UserName);
EmailContents = Substitue(EmailContents, "@UserName", UserName);
EmailContents = Substitue(EmailContents, "@VerifyPassword", test.SiteData.EmailToken);
string result = _emailContext.Send(test.Email, EmailService.VerifyEmailSubject, EmailContents);
_emailContext._SentEmails.Add(key, DateTime.Now);
return result;
}
return "Account not found";
} catch (Exception) {
return "The connection couldn't be established to the email server";
}
}
[Route("api/account/verifyemail")]
[HttpPost]
public async Task<ActionResult<bool>> VerifyEmail([FromForm]string UserName, [FromForm]string EmailToken) {
try {
Account? test = await _accountContext.GetAccount(UserName.ToLower());
if (test != null) {
if (test.SiteData.EmailToken == EmailToken) {
test.SiteData.EmailToken = "";
test.EmailVerified = true;
await _accountContext.SetAccount(test);
return true;
}
}
return false;
} catch {
return false;
}
}
[Route("api/account/sendresetpassword")]
[HttpPost]
public async Task<ActionResult<string>> ResetPassword([FromForm] string Email) {
try {
string key = "p" + Email.ToLower();
// Stop from sending multiple emails quickly
if (_emailContext._SentEmails.ContainsKey(key)) {
DateTime PreviousSentTime = _emailContext._SentEmails.GetValueOrDefault(key);
if (PreviousSentTime.AddMinutes(5) > DateTime.Now) {
return "Cannot sent another reset requests until 5 minutes has elapsed";
}
else {
_emailContext._SentEmails.Remove(key);
}
}
Account? test = await _accountContext.GetAccount(Email.ToLower());
if (test != null) {
test.SiteData.EmailToken = Guid.NewGuid().ToString();
await _accountContext.SetAccount(test);
string EmailContents = EmailService.ResetPasswordEmail;
EmailContents = Substitue(EmailContents, "@UserName", test.UserName);
EmailContents = Substitue(EmailContents, "@UserName", test.UserName);
EmailContents = Substitue(EmailContents, "@ResetPassWord", test.SiteData.EmailToken);
string result = _emailContext.Send(test.Email, EmailService.VerifyEmailSubject, EmailContents);
_emailContext._SentEmails.Add(key, DateTime.Now);
return result;
}
return "Account Not Found";
} catch (Exception) {
return "The connection couldn't be established to the email server";
}
}
[Route("api/account/resetpassword")]
[HttpPost]
public async Task<ActionResult<bool>> ResetPwdVerify([FromForm] string UserName, [FromForm] string NewPassword, [FromForm] string ResetToken) {
try {
Account? test = await _accountContext.GetAccount(UserName.ToLower());
if (test != null && !string.IsNullOrEmpty(test.SiteData.EmailToken)) {
if (test.SiteData.EmailToken == ResetToken) {
test.SiteData.CurrentPasswordAttempts = 0;
test.PasswordHash = BCrypt.Net.BCrypt.HashPassword(NewPassword);
await _accountContext.SetAccount(test);
return true;
}
}
return false;
} catch {
return false;
}
}
[Route("api/account/delete")]
[HttpPost]
public async Task<ActionResult<bool>> delete([FromForm]string UserName, [FromForm]string Password) {
try {
Account? test = await _accountContext.GetAccount(UserName.ToLower());
if (test != null) {
if (BCrypt.Net.BCrypt.Verify(Password, test.PasswordHash)) {
await _accountContext.DeleteAccount(test);
return true;
}
}
return false;
} catch {
return false;
}
}
// Helper Functions
string Substitue(string message, string subString, string Replacement) {
for (int i = 0; i < (message.Length - subString.Length); i++) {
if (message.Substring(i, subString.Length) == subString) {
string before = message.Substring(0, i);
string after = message.Substring(i + subString.Length);
return before + Replacement + after;
}
}
return message;
}
async Task<AccountClaims> getClaims(int AccountID) {
try {
Account? test = await _accountContext.GetAccountByID(AccountID);
if( test != null ) {
if (test != null) {
AccountClaims aClaims = new AccountClaims() {
UserName = test.UserName,
Email = test.Email,
@@ -122,265 +362,5 @@ namespace MistoxWebsite.Server.Controllers {
}
}
// In Account -> Full account
// Out Account
[Route( "api/account/register" )]
[HttpPost]
public async Task<ActionResult<Account>> Register( [FromBody] Account request ) {
try {
if( await _accountContext.GetAccount( request.UserName.ToLower() ) == null ) {
if( await _accountContext.GetAccount( request.Email.ToLower() ) == null ) {
Account? created = new Account(){
UserName = request.UserName.ToLower(),
Email = request.Email.ToLower(),
EmailVerified = false,
PasswordHash = BCrypt.Net.BCrypt.HashPassword(request.PasswordHash),
};
await _accountContext.NewAccount( created );
created = await _accountContext.GetAccount( request.Email.ToLower() );
if( created != null ) {
AccountClaims aClaims = await getClaims(created.ID);
List<Claim> claims = new List<Claim>() {
new Claim(ClaimTypes.Name, aClaims.UserName),
new Claim(ClaimTypes.Email, aClaims.Email),
new Claim("emailverified", aClaims.EmailVerified),
new Claim(ClaimTypes.Role, aClaims.Role),
new Claim("LockAccount", aClaims.FailedPasswordLock)
};
await SendVerify(created);
return created;
}
return new Account() { Error = "Unknown Error" };
} else {
return new Account() { Error = "Email is already in use" };
}
} else {
return new Account() { Error = "UserName is taken" };
}
} catch( Exception ex ) {
Console.WriteLine("Error: " + ex.Message);
return new Account() { Error = ex.Message };
}
}
// In Account -> References UserName / PasswordHash( Current Password ) / Error( New Password )
// Out Bool
[Route( "api/account/changepassword" )]
[HttpPost]
public async Task<ActionResult<bool>> ChangePassword( [FromBody] Account request ) {
try {
Account? test = await _accountContext.GetAccount(request.UserName.ToLower());
if( test != null ) {
if( BCrypt.Net.BCrypt.Verify( request.PasswordHash, test.PasswordHash ) ) {
test.PasswordHash = BCrypt.Net.BCrypt.HashPassword( request.Error );
test.SiteData.CurrentPasswordAttempts = 0;
await _accountContext.SetAccount( test );
return true;
}
}
return false;
} catch {
return false;
}
}
// In Account -> References UserName / SiteData FailedPasswordLock / SiteData.PasswordAttempts
// Out Error String
[Route( "api/account/toggleAccountLock" )]
[HttpPost]
public async Task<ActionResult<string>> ToggleAccountLock( [FromBody] Account request ) {
try {
Account? test = await _accountContext.GetAccount(request.UserName);
if( test != null ) {
test.SiteData.FailedPasswordLock = request.SiteData.FailedPasswordLock;
test.SiteData.CurrentPasswordAttempts = 0;
test.SiteData.PasswordAttempts = request.SiteData.PasswordAttempts;
await _accountContext.SetAccount( test );
return "Account Lock Status Updated";
}
return "Unknown Error Occurred";
} catch( Exception ex ) {
return ex.Message;
}
}
// Out Account -> only if logged in
[Route( "api/account/get" )]
[HttpPost]
public async Task<ActionResult<Account?>> Get() {
try {
if( User.Identity != null && User.Identity.IsAuthenticated ) {
string? email = User.FindFirstValue(ClaimTypes.Email);
if( !string.IsNullOrEmpty( email ) ) {
Account? test = await _accountContext.GetAccount(email);
if( test != null ) {
return test;
}
}
}
return Ok();
} catch {
return Ok();
}
}
// In Null
// Out Null
[Route( "api/account/logout" )]
[HttpPost]
public async Task Logout() {
await HttpContext.SignOutAsync();
}
string Substitue( string message, string subString, string Replacement ) {
for( int i = 0; i < (message.Length - subString.Length); i++ ) {
if( message.Substring( i, subString.Length ) == subString ) {
string before = message.Substring( 0, i );
string after = message.Substring(i + subString.Length );
return before + Replacement + after;
}
}
return message;
}
// In Account -> References UserName
// Out Success bool
[Route( "api/account/sendverifyemail" )]
[HttpPost]
public async Task<ActionResult<string>> SendVerify( [FromBody] Account request ) {
try {
string key = "v" + request.UserName;
// Stop from sending multiple emails quickly
if ( _emailContext._SentEmails.ContainsKey(key) ){
DateTime PreviousSentTime = _emailContext._SentEmails.GetValueOrDefault(key);
if (PreviousSentTime.AddMinutes(5) > DateTime.Now){
return "Cannot sent another verify email until 5 minutes has elapsed ";
}else{
_emailContext._SentEmails.Remove(key);
}
}
Account? test = await _accountContext.GetAccount(request.UserName.ToLower());
if( test != null ) {
test.SiteData.EmailToken = Guid.NewGuid().ToString();
await _accountContext.SetAccount( test );
string EmailContents = EmailService.VerifyEmailEmail;
EmailContents = Substitue( EmailContents, "@UserName", request.UserName );
EmailContents = Substitue( EmailContents, "@UserName", request.UserName );
EmailContents = Substitue( EmailContents, "@VerifyPassword", test.SiteData.EmailToken );
string result = _emailContext.Send( test.Email, EmailService.VerifyEmailSubject, EmailContents );
_emailContext._SentEmails.Add(key, DateTime.Now);
return result;
}
return "Account not found";
} catch (Exception) {
return "The connection couldn't be established to the email server";
}
}
// In Account -> References UserName / Password( EmailToken )
// Out Success bool
[Route( "api/account/verifyemail" )]
[HttpPost]
public async Task<ActionResult<bool>> VerifyEmail( [FromBody] Account request ) {
try {
Account? test = await _accountContext.GetAccount(request.UserName.ToLower());
if( test != null ) {
if( test.SiteData.EmailToken == request.PasswordHash ) {
test.SiteData.EmailToken = "";
test.EmailVerified = true;
await _accountContext.SetAccount( test );
return true;
}
}
return false;
} catch {
return false;
}
}
// In Account -> References Email
// Out Success bool
[Route( "api/account/sendresetpassword" )]
[HttpPost]
public async Task<ActionResult<string>> ResetPassword( [FromBody] Account request ) {
try {
string key = "p" + request.Email.ToLower();
// Stop from sending multiple emails quickly
if ( _emailContext._SentEmails.ContainsKey(key) ){
DateTime PreviousSentTime = _emailContext._SentEmails.GetValueOrDefault(key);
if (PreviousSentTime.AddMinutes(5) > DateTime.Now){
return "Cannot sent another reset requests until 5 minutes has elapsed";
}else{
_emailContext._SentEmails.Remove(key);
}
}
Account? test = await _accountContext.GetAccount(request.Email.ToLower());
if( test != null ) {
test.SiteData.EmailToken = Guid.NewGuid().ToString();
await _accountContext.SetAccount( test );
string EmailContents = EmailService.ResetPasswordEmail;
EmailContents = Substitue( EmailContents, "@UserName", test.UserName );
EmailContents = Substitue( EmailContents, "@UserName", test.UserName );
EmailContents = Substitue( EmailContents, "@ResetPassWord", test.SiteData.EmailToken );
string result = _emailContext.Send( test.Email, EmailService.VerifyEmailSubject, EmailContents );
_emailContext._SentEmails.Add(key, DateTime.Now);
return result;
}
return "Account Not Found";
} catch (Exception) {
return "The connection couldn't be established to the email server";
}
}
// In Account -> References UserName / Password( NewPassword ) / Error( EmailToken )
// Out Success bool
[Route( "api/account/resetpassword" )]
[HttpPost]
public async Task<ActionResult<bool>> ResetPwdVerify( [FromBody] Account request ) {
try {
Account? test = await _accountContext.GetAccount(request.UserName.ToLower());
if( test != null && !string.IsNullOrEmpty(test.SiteData.EmailToken) ) {
if( test.SiteData.EmailToken == request.Error ) {
test.SiteData.CurrentPasswordAttempts = 0;
test.PasswordHash = BCrypt.Net.BCrypt.HashPassword( request.PasswordHash );
await _accountContext.SetAccount( test );
return true;
}
}
return false;
} catch {
return false;
}
}
// In Account -> References UserName / Password( Password ) )
// Out Success bool
[Route( "api/account/delete" )]
[HttpPost]
public async Task<ActionResult<bool>> delete( [FromBody] Account request ) {
try {
Account? test = await _accountContext.GetAccount(request.UserName.ToLower());
if( test != null ) {
if( BCrypt.Net.BCrypt.Verify( request.PasswordHash, test.PasswordHash ) ) {
await _accountContext.DeleteAccount( test );
return true;
}
}
return false;
} catch {
return false;
}
}
}
}
@@ -1,19 +0,0 @@
{
"profiles": {
"IIS Express": {
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:6003",
"sslPort": 6003
},
"ProjectName": {
"commandName": "Project",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:6003",
"sslPort": 6003
}
}
}