Disallow 2 old passwords
This commit is contained in:
@@ -178,12 +178,29 @@ namespace AceJobAgency.Controllers
|
|||||||
return BadRequest("Current password is incorrect.");
|
return BadRequest("Current password is incorrect.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (BCrypt.Net.BCrypt.Verify(request.NewPassword, user.Password))
|
||||||
|
{
|
||||||
|
new ActivityLogController(_context).LogUserActivity(user.Id, "Change password failed: Tried changing to the same password", ipAddress);
|
||||||
|
return BadRequest("New password can't be the same as the old password.");
|
||||||
|
}
|
||||||
|
|
||||||
if (!AccountManagement.IsPasswordComplex(request.NewPassword))
|
if (!AccountManagement.IsPasswordComplex(request.NewPassword))
|
||||||
{
|
{
|
||||||
new ActivityLogController(_context).LogUserActivity(user.Id, "Change password failed: Password not complex enough", ipAddress);
|
new ActivityLogController(_context).LogUserActivity(user.Id, "Change password failed: Password not complex enough", ipAddress);
|
||||||
return BadRequest("Password must be at least 12 characters long and include uppercase, lowercase, number, and special character.");
|
return BadRequest("Password must be at least 12 characters long and include uppercase, lowercase, number, and special character.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((!string.IsNullOrEmpty(user.Password) && BCrypt.Net.BCrypt.Verify(request.NewPassword, user.Password)) ||
|
||||||
|
(!string.IsNullOrEmpty(user.PreviousPassword1) && BCrypt.Net.BCrypt.Verify(request.NewPassword, user.PreviousPassword1)) ||
|
||||||
|
(!string.IsNullOrEmpty(user.PreviousPassword2) && BCrypt.Net.BCrypt.Verify(request.NewPassword, user.PreviousPassword2)))
|
||||||
|
{
|
||||||
|
new ActivityLogController(_context).LogUserActivity(user.Id, "Change password failed: New password matches one of the previous passwords", ipAddress);
|
||||||
|
return BadRequest("New password cannot be one of the last two passwords.");
|
||||||
|
}
|
||||||
|
|
||||||
|
user.PreviousPassword2 = user.PreviousPassword1;
|
||||||
|
user.PreviousPassword1 = user.Password;
|
||||||
|
|
||||||
user.Password = BCrypt.Net.BCrypt.HashPassword(request.NewPassword);
|
user.Password = BCrypt.Net.BCrypt.HashPassword(request.NewPassword);
|
||||||
user.UpdatedAt = DateTime.Now;
|
user.UpdatedAt = DateTime.Now;
|
||||||
_context.Users.Update(user);
|
_context.Users.Update(user);
|
||||||
|
|||||||
@@ -57,5 +57,13 @@ namespace AceJobAgency.Entities
|
|||||||
|
|
||||||
[DataType(DataType.DateTime)]
|
[DataType(DataType.DateTime)]
|
||||||
public DateTime? LockoutEndTime { get; set; }
|
public DateTime? LockoutEndTime { get; set; }
|
||||||
|
|
||||||
|
[DataType(DataType.Password)]
|
||||||
|
[MaxLength(128)]
|
||||||
|
public string PreviousPassword1 { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[DataType(DataType.Password)]
|
||||||
|
[MaxLength(128)]
|
||||||
|
public string PreviousPassword2 { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
139
AceJobAgency/Migrations/20250211015120_AddedTwoPasswordHistories.Designer.cs
generated
Normal file
139
AceJobAgency/Migrations/20250211015120_AddedTwoPasswordHistories.Designer.cs
generated
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using AceJobAgency.Data;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace AceJobAgency.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DataContext))]
|
||||||
|
[Migration("20250211015120_AddedTwoPasswordHistories")]
|
||||||
|
partial class AddedTwoPasswordHistories
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "8.0.2")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||||
|
|
||||||
|
MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("AceJobAgency.Entities.ActivityLog", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasMaxLength(36)
|
||||||
|
.HasColumnType("varchar(36)");
|
||||||
|
|
||||||
|
b.Property<string>("Activity")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(255)
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("IpAddress")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(15)
|
||||||
|
.HasColumnType("varchar(15)");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(36)
|
||||||
|
.HasColumnType("varchar(36)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("ActivityLogs");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("AceJobAgency.Entities.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasMaxLength(36)
|
||||||
|
.HasColumnType("varchar(36)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("DateOfBirth")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("varchar(128)");
|
||||||
|
|
||||||
|
b.Property<int>("FailedLoginAttempts")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("FirstName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(50)
|
||||||
|
.HasColumnType("varchar(50)");
|
||||||
|
|
||||||
|
b.Property<int>("Gender")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("IsActive")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<bool>("IsLockedOut")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<string>("LastName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(50)
|
||||||
|
.HasColumnType("varchar(50)");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("LockoutEndTime")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("NationalRegistrationIdentityCardNumber")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(255)
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("Password")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("varchar(128)");
|
||||||
|
|
||||||
|
b.Property<string>("PreviousPassword1")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("varchar(128)");
|
||||||
|
|
||||||
|
b.Property<string>("PreviousPassword2")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("varchar(128)");
|
||||||
|
|
||||||
|
b.Property<string>("ResumeName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("varchar(128)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UpdatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("WhoAmI")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(2048)
|
||||||
|
.HasColumnType("varchar(2048)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace AceJobAgency.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddedTwoPasswordHistories : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "PreviousPassword1",
|
||||||
|
table: "Users",
|
||||||
|
type: "varchar(128)",
|
||||||
|
maxLength: 128,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "")
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "PreviousPassword2",
|
||||||
|
table: "Users",
|
||||||
|
type: "varchar(128)",
|
||||||
|
maxLength: 128,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "")
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "PreviousPassword1",
|
||||||
|
table: "Users");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "PreviousPassword2",
|
||||||
|
table: "Users");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -103,6 +103,16 @@ namespace AceJobAgency.Migrations
|
|||||||
.HasMaxLength(128)
|
.HasMaxLength(128)
|
||||||
.HasColumnType("varchar(128)");
|
.HasColumnType("varchar(128)");
|
||||||
|
|
||||||
|
b.Property<string>("PreviousPassword1")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("varchar(128)");
|
||||||
|
|
||||||
|
b.Property<string>("PreviousPassword2")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(128)
|
||||||
|
.HasColumnType("varchar(128)");
|
||||||
|
|
||||||
b.Property<string>("ResumeName")
|
b.Property<string>("ResumeName")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasMaxLength(128)
|
.HasMaxLength(128)
|
||||||
|
|||||||
Reference in New Issue
Block a user