Public Function BCrypt_CheckPassword(ByVal Password As String, ByVal HashedPassword As String) As Boolean
Validates a BCrypt-hash with the specified password. Returns True if matching. Note: This function is slow by-design to prevent brute force attacks
Const mcMaxFailedLogins = 8
Private Function CheckPassword(pContext, pUserName As String, pPassword As String, ByRef pErrorMessage As String) As Boolean
If pUserName = "" Then
pErrorMessage = "No Username"
Else
Using GetApplicationDataConnector(pContext).OpenDynamicRecordSet(@"SELECT * FROM WebUsers WHERE UserName = {pUserName}")
If .Eof Then
pErrorMessage = "User not found"
ElseIf .Fields("Locked").Value Then
pErrorMessage = "User locked"
ElseIf .Fields("PasswordHash").Value ?? "" = "" Then
pErrorMessage = "User has no password set"
ElseIf .Fields("FailedLogins").Value >= mcMaxFailedLogins Then
pErrorMessage = "Too many failed logins."
ElseIf Not BCrypt_CheckPassword(pPassword, .Fields("PasswordHash").Value) Then
pErrorMessage = "Invalid Password"
.Fields("FailedLogins").Value = .Fields("FailedLogins").Value + 1
.Fields("LastFailedLogin").Value = SystemTime
.Update
Return False
Else
.Fields("FailedLogins").Value = 0
.Fields("LastSuccessfulLogin").Value = SystemTime
Return True
End If
End Using
End If
Return False
End Function