From bd5a909bcdf89a1919475ba95af3d6f912ec464a Mon Sep 17 00:00:00 2001 From: "derek.holloway" Date: Mon, 21 Jul 2025 10:07:26 -0700 Subject: [PATCH 01/17] Change to JWT inside Secure Cookie Auth --- .../Controllers/AuthenticationController.cs | 18 ++----- src/Server/Program.cs | 48 +++++++++++++---- src/Server/Server.csproj | 1 + src/Server/Services/jwt.cs | 54 +++++++++++++++++++ 4 files changed, 98 insertions(+), 23 deletions(-) create mode 100644 src/Server/Services/jwt.cs diff --git a/src/Server/Controllers/AuthenticationController.cs b/src/Server/Controllers/AuthenticationController.cs index 994ddc1..0c2bc5c 100755 --- a/src/Server/Controllers/AuthenticationController.cs +++ b/src/Server/Controllers/AuthenticationController.cs @@ -34,19 +34,9 @@ namespace BoredCareers.Controllers { test.CurrentPasswordAttempts = 0; await _databaseService.SetAccount(test); - List claims = new List() { - new Claim("ID", test.ID.ToString()), - new Claim(ClaimTypes.NameIdentifier, test.ID.ToString()) - }; + string jwt = BoredCareersJWT.GenereateJWTToken(test.ID, StayLoggedIn); + BoredCareersJWT.SignIn(Response, StayLoggedIn, jwt); - await HttpContext.SignInAsync( - CookieAuthenticationDefaults.AuthenticationScheme, - new ClaimsPrincipal(new ClaimsIdentity(claims, "Auth")), - new AuthenticationProperties { - ExpiresUtc = DateTime.UtcNow.AddYears(30), // Add 30 years with sliding on - IsPersistent = StayLoggedIn, // Is set from the StayLoggedIn - } - ); return Ok(test); } else { test.CurrentPasswordAttempts += 1; @@ -151,9 +141,9 @@ namespace BoredCareers.Controllers { [Route("logout")] [HttpPost] - public async Task Logout() { + public ActionResult Logout() { if (isLoggedIn()) { - await HttpContext.SignOutAsync(); + BoredCareersJWT.SignOut(Response); return Ok(); } return NotFound(); diff --git a/src/Server/Program.cs b/src/Server/Program.cs index d4396af..fdc9bc3 100755 --- a/src/Server/Program.cs +++ b/src/Server/Program.cs @@ -5,6 +5,11 @@ using BoredCareers.Services.DatabaseService; using System.Threading.RateLimiting; using Stripe; using System.Security.Claims; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.IdentityModel.Tokens; +using Org.BouncyCastle.Bcpg.Sig; +using System.Text; +using System.IdentityModel.Tokens.Jwt; var builder = WebApplication.CreateBuilder(args); @@ -81,15 +86,40 @@ if (IPayment._PaymentType == PaymentType.StripeIntent) { } // Authentication Service -builder.Services.AddAuthentication( options => { - options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; -} ).AddCookie(options => { - options.Cookie.HttpOnly = true; - options.Cookie.SecurePolicy = CookieSecurePolicy.Always; - options.Cookie.SameSite = SameSiteMode.Strict; - options.LoginPath = "/account/login"; - options.LogoutPath = "/account/logout"; - options.SlidingExpiration = true; +builder.Services.AddAuthentication(options => { + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; +}).AddJwtBearer(options => { + options.TokenValidationParameters = new TokenValidationParameters { + ValidateIssuer = true, + ValidateAudience = true, + ValidateLifetime = true, + ValidateIssuerSigningKey = true, + ValidIssuer = "your-app", + ValidAudience = "your-app", + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("secret-key")), + ClockSkew = TimeSpan.FromMinutes(1) + }; + options.Events = new JwtBearerEvents { + OnMessageReceived = context => { + context.Token = context.Request.Cookies["access_token"]; + return Task.CompletedTask; + }, + OnTokenValidated = context => { + var jwtToken = context.SecurityToken as JwtSecurityToken; + if (jwtToken != null) { + var exp = jwtToken.ValidTo; + var now = DateTime.UtcNow; + if ((exp - now) < TimeSpan.FromMinutes(5)) { + int accountID = Convert.ToInt32(context.Principal?.FindFirst(ClaimTypes.NameIdentifier)?.Value); + bool isPersistent = bool.Parse(context.Principal?.FindFirst(ClaimTypes.IsPersistent)?.Value); + var newJWT = BoredCareersJWT.GenereateJWTToken(accountID, isPersistent); + BoredCareersJWT.SignIn(context.HttpContext.Response, isPersistent, newJWT); + } + } + return Task.CompletedTask; + } + }; }); builder.Services.AddCors(o => o.AddDefaultPolicy(builder => { diff --git a/src/Server/Server.csproj b/src/Server/Server.csproj index 621ce3d..c14307e 100755 --- a/src/Server/Server.csproj +++ b/src/Server/Server.csproj @@ -11,6 +11,7 @@ + diff --git a/src/Server/Services/jwt.cs b/src/Server/Services/jwt.cs new file mode 100644 index 0000000..4d1a03c --- /dev/null +++ b/src/Server/Services/jwt.cs @@ -0,0 +1,54 @@ + + +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Text; +using Microsoft.IdentityModel.Tokens; + +namespace BoredCareers.Services { + public class BoredCareersJWT { + public static string GenereateJWTToken(int accountID, bool StayLoggedIn) { + var tokenHandler = new JwtSecurityTokenHandler(); + var key = Encoding.UTF8.GetBytes("your-super-secret-key"); + + var tokenDiscriptor = new SecurityTokenDescriptor { + Subject = new ClaimsIdentity(new[] { + new Claim(ClaimTypes.NameIdentifier, accountID.ToString()), + new Claim(ClaimTypes.IsPersistent, StayLoggedIn.ToString()) + }), + Expires = DateTime.UtcNow.AddMinutes(15), + IssuedAt = DateTime.UtcNow, + SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.RsaSha512), + Audience = "your-app", + Issuer = "your-app" + }; + + var token = tokenHandler.CreateToken(tokenDiscriptor); + return tokenHandler.WriteToken(token); + } + + public static void SignIn(HttpResponse Response, bool StayLoggedIn, string jwt) { + if (StayLoggedIn) { + // Stay logged in cookie + Response.Cookies.Append("access_token", jwt, new CookieOptions { + Secure = true, + HttpOnly = true, + SameSite = SameSiteMode.Strict, + Expires = DateTime.UtcNow.AddMinutes(15) + }); + } + else { + // Session cookie + Response.Cookies.Append("access_token", jwt, new CookieOptions { + Secure = true, + HttpOnly = true, + SameSite = SameSiteMode.Strict, + }); + } + } + + public static void SignOut(HttpResponse Response) { + Response.Cookies.Delete("access_token"); + } + } +} \ No newline at end of file -- 2.52.0 From dbc4d973f9d70fe25f6a755896888701e7fab73a Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Mon, 21 Jul 2025 16:41:06 -0700 Subject: [PATCH 02/17] consolidate jwt settings and setup docker compose --- .env_Template | 27 +++++++++++++--- docker-compose.yml | 5 +-- .../Controllers/AuthenticationController.cs | 5 +-- src/Server/Program.cs | 21 ++++++++---- src/Server/Services/jwt.cs | 32 +++++++++++-------- 5 files changed, 60 insertions(+), 30 deletions(-) diff --git a/.env_Template b/.env_Template index 98f082d..dee9450 100755 --- a/.env_Template +++ b/.env_Template @@ -1,13 +1,32 @@ -Payment_Service=StripeIntent # Options are [ StripeIntent ] +############# +## Payment ## +############# +# Options are [ StripeIntent ] +Payment_Service=StripeIntent + +# StripeIntent Options Stripe_PublicKey= Stripe_PublicKey= Stripe_Endpoint_Secret= -MySQL_Server=mistox-database +#################### +## Authentication ## +#################### + +# Random secret token for encrypting JWT contents +JWT_Secret= + +############## +## Database ## +############## + MySQL_User=root -MySQL_Database=mistox -MySQL_Pass=oasv34$8gpv023dd # Random value for the server and MySQL to communicate with +MySQL_Pass=oasv34$8gpv023dd + +############## +## Email ## +############## Email_Server= # Hostname of email server Email_Port= # SMTP port used diff --git a/docker-compose.yml b/docker-compose.yml index 3ec7754..4098a89 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,18 +5,19 @@ services: image: docker.mistox.net/boredcareers-website:latest restart: always environment: + - MySQLServer=boredcareers-database + - MySQLDatabase=boredcareers - PaymentService=${Payment_Service} - StripePublicKey=${Stripe_PublicKey} - StripeApiKey=${Stripe_ApiKey} - StripeEndpointSecret=&{Stripe_Endpoint_Secret} - - MySQLServer=${MySQL_Server} - MySQLUser=${MySQL_User} - MySQLPass=${MySQL_Pass} - - MySQLDatabase=${MySQL_Database} - EmailServer=${Email_Server} - EmailPort=${Email_Port} - EmailAddress=${Email_Address} - EmailPassword=${Email_Password} + - JWTsecret=${JWT_Secret} ports: - 5000:5000 depends_on: diff --git a/src/Server/Controllers/AuthenticationController.cs b/src/Server/Controllers/AuthenticationController.cs index 0c2bc5c..81fcf06 100755 --- a/src/Server/Controllers/AuthenticationController.cs +++ b/src/Server/Controllers/AuthenticationController.cs @@ -1,7 +1,4 @@ -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Authentication.Cookies; -using Microsoft.AspNetCore.Mvc; -using System.Security.Claims; +using Microsoft.AspNetCore.Mvc; using BoredCareers.Services; using BoredCareers.Services.DatabaseService; using BoredCareers.Entities; diff --git a/src/Server/Program.cs b/src/Server/Program.cs index fdc9bc3..3109476 100755 --- a/src/Server/Program.cs +++ b/src/Server/Program.cs @@ -1,4 +1,3 @@ -using Microsoft.AspNetCore.Authentication.Cookies; using BoredCareers.Controllers.Payment; using BoredCareers.Services; using BoredCareers.Services.DatabaseService; @@ -7,7 +6,6 @@ using Stripe; using System.Security.Claims; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; -using Org.BouncyCastle.Bcpg.Sig; using System.Text; using System.IdentityModel.Tokens.Jwt; @@ -41,6 +39,15 @@ string dbPass = !string.IsNullOrEmpty(_dbpass) ? _dbpass : "oasv34$8gpv023dd"; DatabaseService databaseService = new DatabaseService(connectionString: "server=" + dbserver + ";user=" + dbUser + ";database=" + dbdatabase + ";password=" + dbPass + ";port=3306;"); builder.Services.Add( new ServiceDescriptor( typeof( DatabaseService ), databaseService ) ); +//////////////////////////////// +////////// Auth Service //////// +//////////////////////////////// + +// Address +string? _jwtSecret = Environment.GetEnvironmentVariable("JWTsecret"); +string JWTsecret = !string.IsNullOrEmpty(_jwtSecret) ? _jwtSecret : "v0Ftluhdh7Nht8^2b5eaiC^IS^VS1ku0VBs3j*B2"; +BoredCareersJWT.TokenSecretKey = JWTsecret; + //////////////////////////////// ///////// Email Service //////// //////////////////////////////// @@ -95,14 +102,14 @@ builder.Services.AddAuthentication(options => { ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, - ValidIssuer = "your-app", - ValidAudience = "your-app", - IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("secret-key")), + ValidIssuer = BoredCareersJWT.TokenIssuer, + ValidAudience = BoredCareersJWT.TokenAudience, + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(BoredCareersJWT.TokenSecretKey)), ClockSkew = TimeSpan.FromMinutes(1) }; options.Events = new JwtBearerEvents { OnMessageReceived = context => { - context.Token = context.Request.Cookies["access_token"]; + context.Token = context.Request.Cookies[BoredCareersJWT.TokenName]; return Task.CompletedTask; }, OnTokenValidated = context => { @@ -110,7 +117,7 @@ builder.Services.AddAuthentication(options => { if (jwtToken != null) { var exp = jwtToken.ValidTo; var now = DateTime.UtcNow; - if ((exp - now) < TimeSpan.FromMinutes(5)) { + if ((exp - now) < TimeSpan.FromDays(3)) { int accountID = Convert.ToInt32(context.Principal?.FindFirst(ClaimTypes.NameIdentifier)?.Value); bool isPersistent = bool.Parse(context.Principal?.FindFirst(ClaimTypes.IsPersistent)?.Value); var newJWT = BoredCareersJWT.GenereateJWTToken(accountID, isPersistent); diff --git a/src/Server/Services/jwt.cs b/src/Server/Services/jwt.cs index 4d1a03c..5fe00de 100644 --- a/src/Server/Services/jwt.cs +++ b/src/Server/Services/jwt.cs @@ -1,26 +1,33 @@ using System.IdentityModel.Tokens.Jwt; +using System.Runtime.CompilerServices; using System.Security.Claims; using System.Text; using Microsoft.IdentityModel.Tokens; namespace BoredCareers.Services { public class BoredCareersJWT { + + public static string TokenAudience = "https://boredcareers.com/api"; + public static string TokenIssuer = "https://boredcareers.com"; + public static string TokenSecretKey = ""; + public static string TokenName = "mistox_session"; + public static string GenereateJWTToken(int accountID, bool StayLoggedIn) { var tokenHandler = new JwtSecurityTokenHandler(); - var key = Encoding.UTF8.GetBytes("your-super-secret-key"); + var key = Encoding.UTF8.GetBytes(TokenSecretKey); var tokenDiscriptor = new SecurityTokenDescriptor { - Subject = new ClaimsIdentity(new[] { + Subject = new ClaimsIdentity([ new Claim(ClaimTypes.NameIdentifier, accountID.ToString()), new Claim(ClaimTypes.IsPersistent, StayLoggedIn.ToString()) - }), - Expires = DateTime.UtcNow.AddMinutes(15), + ]), + Expires = DateTime.UtcNow.AddDays(7), IssuedAt = DateTime.UtcNow, - SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.RsaSha512), - Audience = "your-app", - Issuer = "your-app" + SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256), + Audience = TokenAudience, + Issuer = TokenIssuer }; var token = tokenHandler.CreateToken(tokenDiscriptor); @@ -30,16 +37,15 @@ namespace BoredCareers.Services { public static void SignIn(HttpResponse Response, bool StayLoggedIn, string jwt) { if (StayLoggedIn) { // Stay logged in cookie - Response.Cookies.Append("access_token", jwt, new CookieOptions { + Response.Cookies.Append(TokenName, jwt, new CookieOptions { Secure = true, HttpOnly = true, SameSite = SameSiteMode.Strict, - Expires = DateTime.UtcNow.AddMinutes(15) + Expires = DateTime.UtcNow.AddDays(7) }); - } - else { + } else { // Session cookie - Response.Cookies.Append("access_token", jwt, new CookieOptions { + Response.Cookies.Append(TokenName, jwt, new CookieOptions { Secure = true, HttpOnly = true, SameSite = SameSiteMode.Strict, @@ -48,7 +54,7 @@ namespace BoredCareers.Services { } public static void SignOut(HttpResponse Response) { - Response.Cookies.Delete("access_token"); + Response.Cookies.Delete(TokenName); } } } \ No newline at end of file -- 2.52.0 From c87ef1cfc29af96ab0412e34fb4b71f4b7582cad Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Mon, 21 Jul 2025 16:41:17 -0700 Subject: [PATCH 03/17] Fix some login stuff --- src/Client/src/app/pages/account/logout/logout.component.ts | 2 +- src/Client/src/app/services/Authentication.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Client/src/app/pages/account/logout/logout.component.ts b/src/Client/src/app/pages/account/logout/logout.component.ts index 4357ff9..130ee39 100644 --- a/src/Client/src/app/pages/account/logout/logout.component.ts +++ b/src/Client/src/app/pages/account/logout/logout.component.ts @@ -23,7 +23,7 @@ export class LogoutComponent { ngAfterViewInit(){ this.auth.Logout().subscribe({ next: data => { - this.router.navigate(["/"]); + window.location.href = ""; } }); } diff --git a/src/Client/src/app/services/Authentication.ts b/src/Client/src/app/services/Authentication.ts index 138ccf7..60803ba 100644 --- a/src/Client/src/app/services/Authentication.ts +++ b/src/Client/src/app/services/Authentication.ts @@ -24,6 +24,7 @@ export class Authentication{ let sub = this.http.post( "api/account/login", body, { headers } ); sub.subscribe({ next: data => { + data.passwordHash = ""; this._user.next(data); this.setUserToStorage(data, StayLoggedIn == true ? SessionType.Forever : SessionType.Session); }, -- 2.52.0 From c16f8004d7df853625458c11bb3c4135f5924e14 Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Mon, 21 Jul 2025 16:45:16 -0700 Subject: [PATCH 04/17] Fix logged in state claim id --- src/Server/Controllers/MistoxControllerBase.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Server/Controllers/MistoxControllerBase.cs b/src/Server/Controllers/MistoxControllerBase.cs index 1253b5c..eb502ca 100644 --- a/src/Server/Controllers/MistoxControllerBase.cs +++ b/src/Server/Controllers/MistoxControllerBase.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.Mvc; using BoredCareers.Entities; using BoredCareers.Services.DatabaseService; +using System.Security.Claims; namespace BoredCareers.Controllers { @@ -20,7 +21,7 @@ namespace BoredCareers.Controllers { } public int getLoggedInUserID() { - return Convert.ToInt32(User.FindFirst("ID")?.Value); + return Convert.ToInt32(User.FindFirstValue(ClaimTypes.NameIdentifier)); } public async Task getLoggedInUser() { -- 2.52.0 From 3591edda89aaaff363300ea3f0479342c6c7592d Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Mon, 21 Jul 2025 22:15:33 -0700 Subject: [PATCH 05/17] Header cleanup --- src/Server/Controllers/PaymentMethods/IPayment.cs | 4 +--- src/Server/Controllers/PaymentMethods/StripeIntents.cs | 2 +- src/Server/Services/EmailService/ResetPasswordEmail.cs | 2 -- src/Server/Services/EmailService/VerifyEmail.cs | 2 -- src/Server/Services/jwt.cs | 3 --- 5 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/Server/Controllers/PaymentMethods/IPayment.cs b/src/Server/Controllers/PaymentMethods/IPayment.cs index 73196d3..ae9c4be 100644 --- a/src/Server/Controllers/PaymentMethods/IPayment.cs +++ b/src/Server/Controllers/PaymentMethods/IPayment.cs @@ -1,5 +1,3 @@ -using BoredCareers.Entities; - namespace BoredCareers.Controllers.Payment { public interface IPayment { @@ -8,7 +6,7 @@ namespace BoredCareers.Controllers.Payment { public static string _EndpointSecret = ""; public static string _PublicKey = ""; - public Task ValidatePurchase(string WebHookData, string Headers); + public void ValidatePurchase(string WebHookData, string Headers); } diff --git a/src/Server/Controllers/PaymentMethods/StripeIntents.cs b/src/Server/Controllers/PaymentMethods/StripeIntents.cs index fca5a5e..ddb6294 100644 --- a/src/Server/Controllers/PaymentMethods/StripeIntents.cs +++ b/src/Server/Controllers/PaymentMethods/StripeIntents.cs @@ -11,7 +11,7 @@ namespace BoredCareers.Controllers { _databaseService = databaseService; } - public async Task ValidatePurchase(string WebHookData, string Headers) { + public void ValidatePurchase(string WebHookData, string Headers) { Stripe.Event e = Stripe.EventUtility.ConstructEvent( WebHookData, Headers, IPayment._EndpointSecret ); if (e.Type == "payment_intent.succeeded") { // Extract Data from payment confirm diff --git a/src/Server/Services/EmailService/ResetPasswordEmail.cs b/src/Server/Services/EmailService/ResetPasswordEmail.cs index 9481aeb..7eff79c 100755 --- a/src/Server/Services/EmailService/ResetPasswordEmail.cs +++ b/src/Server/Services/EmailService/ResetPasswordEmail.cs @@ -1,5 +1,3 @@ -using System.Net.Mail; - namespace BoredCareers.Services { public partial class EmailService { diff --git a/src/Server/Services/EmailService/VerifyEmail.cs b/src/Server/Services/EmailService/VerifyEmail.cs index 575bf08..9207038 100755 --- a/src/Server/Services/EmailService/VerifyEmail.cs +++ b/src/Server/Services/EmailService/VerifyEmail.cs @@ -1,5 +1,3 @@ -using System.Net.Mail; - namespace BoredCareers.Services { public partial class EmailService { diff --git a/src/Server/Services/jwt.cs b/src/Server/Services/jwt.cs index 5fe00de..876adb2 100644 --- a/src/Server/Services/jwt.cs +++ b/src/Server/Services/jwt.cs @@ -1,7 +1,4 @@ - - using System.IdentityModel.Tokens.Jwt; -using System.Runtime.CompilerServices; using System.Security.Claims; using System.Text; using Microsoft.IdentityModel.Tokens; -- 2.52.0 From a7f515bc335b82e7378b72a305b745f4b6104bcd Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Mon, 21 Jul 2025 22:16:23 -0700 Subject: [PATCH 06/17] fix bad await --- src/Server/Controllers/PaymentController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Server/Controllers/PaymentController.cs b/src/Server/Controllers/PaymentController.cs index 31e0537..f4c24c1 100755 --- a/src/Server/Controllers/PaymentController.cs +++ b/src/Server/Controllers/PaymentController.cs @@ -28,7 +28,7 @@ namespace BoredCareers.Controllers { public async Task paymentWebhook() { try { string body = await new StreamReader(Request.Body).ReadToEndAsync(); - await _paymentService.ValidatePurchase(body, Request.Headers["Stripe-Signature"].ToString()); + _paymentService.ValidatePurchase(body, Request.Headers["Stripe-Signature"].ToString()); return Ok(); } catch (Exception ex) { return NotFound(ex.ToString()); -- 2.52.0 From 6c2d5a18103a49537fa2e850dcfda69dd5f6549f Mon Sep 17 00:00:00 2001 From: "derek.holloway" Date: Tue, 22 Jul 2025 14:38:41 -0700 Subject: [PATCH 07/17] Remove location on Remote --- src/Client/src/app/pages/main/jobs/new/jobnew.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Client/src/app/pages/main/jobs/new/jobnew.component.html b/src/Client/src/app/pages/main/jobs/new/jobnew.component.html index d6e9e90..ff11a6f 100644 --- a/src/Client/src/app/pages/main/jobs/new/jobnew.component.html +++ b/src/Client/src/app/pages/main/jobs/new/jobnew.component.html @@ -55,7 +55,7 @@ -
+

Job Location

-- 2.52.0 From 7025da237ba11b4b289af1205e98272d26b63e6b Mon Sep 17 00:00:00 2001 From: "derek.holloway" Date: Wed, 23 Jul 2025 08:41:16 -0700 Subject: [PATCH 08/17] Update todo --- ToDo.yaml | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/ToDo.yaml b/ToDo.yaml index ca253bb..f1200a5 100755 --- a/ToDo.yaml +++ b/ToDo.yaml @@ -15,4 +15,21 @@ Client: Want to add completed job listing preview at end of carosel database: - Add Applied Jobs Table \ No newline at end of file + Add Applied Jobs Table + + + +Task: + Block API Access as much as possible [ Rate limit | Auth Req | CORS | Disallow AI keyword filters ] + Resume builder minimal user input [ Dont allow AI input ] + Auto unlist jobs after a month of no activity [ Multiple offenders marked ] + Dont allow external applications for users on company sites from the start + Allow company to look up users if their resume is public [ Maybe auto with notify ] + Allow users to look up jobs and apply [ Boost visibility | Completely manual ] + Allow multiple resume's for job specific work + Mark ghost listings to allow users to be informed and put companies on blast + Create advanced filtering tools for company lookup and resume lookup + + Create and Auth Database based on the docker compose + Create a server table inside the auth database + Point all requests after auth to the correct regional server. -> Currently only Mistox-West exists \ No newline at end of file -- 2.52.0 From 93948ffbd2bd91bce0a0094f7540eb121915dd6d Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Wed, 23 Jul 2025 17:37:54 -0700 Subject: [PATCH 09/17] Correct direction of inputs on the POST JOB --- .../pages/main/jobs/new/jobnew.component.html | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/Client/src/app/pages/main/jobs/new/jobnew.component.html b/src/Client/src/app/pages/main/jobs/new/jobnew.component.html index ff11a6f..93e290c 100644 --- a/src/Client/src/app/pages/main/jobs/new/jobnew.component.html +++ b/src/Client/src/app/pages/main/jobs/new/jobnew.component.html @@ -58,22 +58,26 @@

Job Location

-
-
- - +
+
+
+ + +
+
+ + +
-
- - -
-
- - -
-
- - +
+
+ + +
+
+ + +
-- 2.52.0 From 266a051427c2bb54a7c21171aa9778e032ccf1df Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Fri, 25 Jul 2025 22:25:32 -0700 Subject: [PATCH 10/17] Edit auth -> Going to get removed soon --- src/Server/Program.cs | 2 +- src/Server/Services/jwt.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Server/Program.cs b/src/Server/Program.cs index 3109476..d5beb5c 100755 --- a/src/Server/Program.cs +++ b/src/Server/Program.cs @@ -6,8 +6,8 @@ using Stripe; using System.Security.Claims; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; -using System.Text; using System.IdentityModel.Tokens.Jwt; +using System.Text; var builder = WebApplication.CreateBuilder(args); diff --git a/src/Server/Services/jwt.cs b/src/Server/Services/jwt.cs index 876adb2..21dcf33 100644 --- a/src/Server/Services/jwt.cs +++ b/src/Server/Services/jwt.cs @@ -6,8 +6,8 @@ using Microsoft.IdentityModel.Tokens; namespace BoredCareers.Services { public class BoredCareersJWT { - public static string TokenAudience = "https://boredcareers.com/api"; - public static string TokenIssuer = "https://boredcareers.com"; + public static string TokenAudience = "mistox-llc-auth-token"; + public static string TokenIssuer = "https://auth.mistox.com"; public static string TokenSecretKey = ""; public static string TokenName = "mistox_session"; -- 2.52.0 From 5dd64a03fc6b62e06839ed588051fd7689ccc331 Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Fri, 25 Jul 2025 22:25:50 -0700 Subject: [PATCH 11/17] Fix checkbox breaking UI --- .../pages/main/jobs/new/jobnew.component.ts | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/src/Client/src/app/pages/main/jobs/new/jobnew.component.ts b/src/Client/src/app/pages/main/jobs/new/jobnew.component.ts index 793424d..62324e2 100644 --- a/src/Client/src/app/pages/main/jobs/new/jobnew.component.ts +++ b/src/Client/src/app/pages/main/jobs/new/jobnew.component.ts @@ -42,6 +42,13 @@ export class JobNewComponent { }; ngAfterViewInit(){ + this.formSteps.changes.subscribe(() => { + this.updateUI(); + }); + this.updateUI(); + } + + updateUI(){ this.formSteps.forEach((step: ElementRef, i: number) => { if (i === this.currentStep) { step.nativeElement.style.left = '0%'; @@ -55,28 +62,12 @@ export class JobNewComponent { nextStep(){ this.currentStep += 1; - this.formSteps.forEach((step: ElementRef, i: number) => { - if (i === this.currentStep) { - step.nativeElement.style.left = '0%'; - } else if (i < this.currentStep) { - step.nativeElement.style.left = '-100%'; - } else { - step.nativeElement.style.left = '100%'; - } - }); + this.updateUI(); } prevStep(){ this.currentStep -= 1; - this.formSteps.forEach((step: ElementRef, i: number) => { - if (i === this.currentStep) { - step.nativeElement.style.left = '0%'; - } else if (i < this.currentStep) { - step.nativeElement.style.left = '-100%'; - } else { - step.nativeElement.style.left = '100%'; - } - }); + this.updateUI(); } PostJobListing(jobListing: JobListing){ -- 2.52.0 From 985d02188826ed8268f2433929bbeadcd2eef06d Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Fri, 25 Jul 2025 22:26:09 -0700 Subject: [PATCH 12/17] Remove empty dropdown choices --- .../src/app/pages/main/jobs/new/jobnew.component.html | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Client/src/app/pages/main/jobs/new/jobnew.component.html b/src/Client/src/app/pages/main/jobs/new/jobnew.component.html index 93e290c..c519c73 100644 --- a/src/Client/src/app/pages/main/jobs/new/jobnew.component.html +++ b/src/Client/src/app/pages/main/jobs/new/jobnew.component.html @@ -9,11 +9,16 @@
+
@@ -36,7 +41,6 @@
@@ -54,45 +51,54 @@
-
-
- - -
-
- - +
+
+
+ + +
+
+ + +
+ + +
+ - -
-

Job Location

-
-
- - -
-
- - -
-
- - -
-
- - +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
@@ -105,6 +111,9 @@
+
@@ -142,6 +151,9 @@
+
\ No newline at end of file diff --git a/src/Client/src/app/pages/main/jobs/jobs.component.css b/src/Client/src/app/pages/main/jobs/jobs.component.css index 58f3098..6044df9 100644 --- a/src/Client/src/app/pages/main/jobs/jobs.component.css +++ b/src/Client/src/app/pages/main/jobs/jobs.component.css @@ -1,3 +1,21 @@ +button { + width: 150px; + border-radius: 5px; + margin: 10px; + text-align: center; + padding: 15px 0; + transition: .5s; + background-color: #0000; + border: 1px solid var(--Mistox-White); + color: var(--Mistox-White); + text-decoration: none; +} + + button:hover { + background-color: #00000044; + color: var(--Mistox-Light); + } + .full-width { display: block; width: 100%; @@ -5,14 +23,65 @@ } .tile-frame { - column-count: 4; + display: grid; + grid-template-columns: repeat(4, 1fr); column-gap: 20px; padding: 20px; width: calc(100% - 40px); } .tile{ - background-color: var(--Mistox-Dark)\); - height: 40px; + background-color: var(--Mistox-Dark); + color: var(--Mistox-White); break-inside: avoid; + padding: 20px; + border-radius: 20px; + margin-bottom: 20px; +} + +.jobs-frame { + width: 100%; + background-color: #8888; + border-top: 2px solid black; +} + +.post-job-frame { + display: flex; + justify-content: center; + padding: 10px 0; +} + +.tile-title { + text-align: center; + border-bottom: 1px solid; +} + +.tile-title h1 { + font-size: 40px; + margin: 5px 0; +} + +.tile-title h2 { + font-size: 14px; +} + +.tile-split { + columns: 2; + text-align: center; + padding: 10px 0; +} + +.tile-split h1 { + margin: 0; +} + +.tile-button { + display: flex; + width: 100%; + justify-content: center; +} + +.post-job-frame button { + border-color: var(--Mistox-Black); + color: var(--Mistox-Black); } \ No newline at end of file diff --git a/src/Client/src/app/pages/main/jobs/jobs.component.html b/src/Client/src/app/pages/main/jobs/jobs.component.html index f3c49a0..5e5ab3d 100644 --- a/src/Client/src/app/pages/main/jobs/jobs.component.html +++ b/src/Client/src/app/pages/main/jobs/jobs.component.html @@ -1,5 +1,5 @@ -
+

{{ cur.title }}

@@ -11,14 +11,13 @@

{{ cur.stateOrRegion }}

{{ cur.country }}

{{ cur.postalCode }}

-

{{ cur.description }}

Posted: {{ cur.createdTime }}

Modified: {{ cur.modifiedTime }}

-
+
@@ -26,17 +25,20 @@
-

{{ cur.title }}

-

{{ cur.jobType }}

-

Is Remote: {{ cur.remote }}

-

{{ cur.salaryMin }}

-

{{ cur.salaryMax }}

-

{{ cur.city }}

-

{{ cur.stateOrRegion }}

-

{{ cur.country }}

-

{{ cur.postalCode }}

-

{{ cur.description }}

-

Posted: {{ cur.createdTime }}

-

Modified: {{ cur.modifiedTime }}

+
+

{{ cur.title }}

+

${{ cur.salaryMax }} - ${{ cur.salaryMin }}

+
+
+

{{ cur.jobType }}

+

Remote

+
+
+

{{ cur.city }}

+

{{ cur.stateOrRegion }}

+
+
+ +
\ No newline at end of file diff --git a/src/Client/src/app/pages/main/jobs/new/jobnew.component.css b/src/Client/src/app/pages/main/jobs/new/jobnew.component.css index 3606281..4203dc9 100644 --- a/src/Client/src/app/pages/main/jobs/new/jobnew.component.css +++ b/src/Client/src/app/pages/main/jobs/new/jobnew.component.css @@ -14,7 +14,7 @@ form { .center { width: 100%; - display: flex; + display: grid; justify-content: center; } @@ -31,6 +31,15 @@ form { border-radius: 10px; padding: 40px; break-inside: avoid; + margin-bottom: 20px; +} + +.footer-frame { + background-color: #00000044; + border-radius: 10px; + padding: 10px; + break-inside: avoid; + margin-bottom: 20px; } .split { -- 2.52.0 From 08a833f261f8de1aab91d5a52d29f827b81b1a73 Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Fri, 25 Jul 2025 22:26:41 -0700 Subject: [PATCH 14/17] Update Todo --- ToDo.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ToDo.yaml b/ToDo.yaml index f1200a5..2493b07 100755 --- a/ToDo.yaml +++ b/ToDo.yaml @@ -9,9 +9,10 @@ Server: Client: jobs/new: - When remote job is check'd it still asks for location information Want to add Required skills to help with filtering - Need to fix some UI bugs. + When enter is pressed it tries to submit the form + Should run the whole carosel on enter before the submit is sent + Need to validate input before allowing next step Want to add completed job listing preview at end of carosel database: -- 2.52.0 From e70397477adea417260c7cce1a20b8043b169dac Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Sat, 26 Jul 2025 12:27:23 -0700 Subject: [PATCH 15/17] Fix that should have been done long ago --- .editorconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index 07820a4..e044e0c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,4 +13,5 @@ trim_trailing_whitespace = false csharp_new_line_before_open_brace = none csharp_new_line_before_catch = false csharp_new_line_before_finally = false -csharp_new_line_after_else = false \ No newline at end of file +csharp_new_line_after_else = false +csharp_new_line_before_else = false \ No newline at end of file -- 2.52.0 From 56f205fa4c695dc7c66f834d426612d4e86db019 Mon Sep 17 00:00:00 2001 From: Derek Holloway Date: Sun, 27 Jul 2025 20:53:52 -0700 Subject: [PATCH 16/17] Add lots of improvements to companyconnect --- .../connect/companyconnect.component.css | 18 ++++ .../connect/companyconnect.component.html | 24 ++--- .../connect/companyconnect.component.ts | 99 +++++++++++++++---- 3 files changed, 110 insertions(+), 31 deletions(-) diff --git a/src/Client/src/app/pages/main/company/connect/companyconnect.component.css b/src/Client/src/app/pages/main/company/connect/companyconnect.component.css index 4203dc9..afcf5dc 100644 --- a/src/Client/src/app/pages/main/company/connect/companyconnect.component.css +++ b/src/Client/src/app/pages/main/company/connect/companyconnect.component.css @@ -1,3 +1,21 @@ +button { + width: 150px; + border-radius: 5px; + margin: 10px; + text-align: center; + padding: 15px 0; + transition: .5s; + background-color: #0000; + border: 1px solid var(--Mistox-White); + color: var(--Mistox-White); + text-decoration: none; +} + + button:hover { + background-color: #00000044; + color: var(--Mistox-Light); + } + .title-text { width: 100%; text-align: center; diff --git a/src/Client/src/app/pages/main/company/connect/companyconnect.component.html b/src/Client/src/app/pages/main/company/connect/companyconnect.component.html index 30cdea5..9b71c56 100644 --- a/src/Client/src/app/pages/main/company/connect/companyconnect.component.html +++ b/src/Client/src/app/pages/main/company/connect/companyconnect.component.html @@ -7,7 +7,7 @@
- +