Hi Peter and Thanks for your work !
It is always a pleasure to find a good code to start from. Sometimes modifications take longer that created from scratch, but the existing code is a kind of "seed", helping to write sometime something different. Free code on the Web is a good practice and I will not judge your code, it's a gift, no more no less.
But I want to share with you my enhancements.
I suppressed the "old fashioned" DataTable to use a collection of data (a special class storing analysis for each level). I suppressed the Level data (useless), the breaking description (a linq query can help to separate additions/deductions), I modified a bit some rules, refactor a bit too.
So my version is yours, written in a different style. I also separated bonus from malus, making the whole thing clearer.
Well, here is my version, hoping you'll like it :
(note that for security reasons this site is changing some symbols like "greather than", you'll have to reverb back to original symbols in order to compile)
public class PasswordChecker
{
private static readonly PasswordChecker current = new PasswordChecker();
private PasswordChecker()
{ }
public static PasswordChecker Current
{ get { return current; } }
private ObservableCollection<AnalysisItem> dtDetails;
private string password = string.Empty;
public string Password
{
get { return password; }
set
{
if (password == value) return;
password = value;
CheckPasswordWithDetails(password);
}
}
public int PasswordScore
{
get
{
return dtDetails != null ? dtDetails[0].Total : 0;
}
}
public int PasswordBonus
{
get
{
return dtDetails != null ? dtDetails[0].Bonus : 0;
}
}
public int PasswordMalus
{
get
{
return dtDetails != null ? dtDetails[0].Malus : 0;
}
}
public string PasswordStrength
{
get
{
return dtDetails != null ? dtDetails[0].Rate : "Unknown";
}
}
public ObservableCollection<AnalysisItem> StrengthDetails
{
get { return dtDetails; }
}
private void CheckPasswordWithDetails(string pwd)
{
var nMalus = 0;
var sComplexity = "";
var iUpperCase = 0;
var iLowerCase = 0;
var iDigit = 0;
var iSymbol = 0;
var iRepeated = 1;
var htRepeated = new Dictionary<char, int>();
var iMiddle = 0;
var iMiddleEx = 1;
var consecutiveMode = 0;
var iConsecutiveUpper = 0;
var iConsecutiveLower = 0;
var iConsecutiveDigit = 0;
const string sAlphas = "abcdefghijklmnopqrstuvwxyz";
const string sNumerics = "01234567890";
var nSeqAlpha = 0;
var nSeqNumber = 0;
CreateDetailsTable();
var drScore = dtDetails[0];
foreach (var ch in pwd.ToCharArray())
{
if (Char.IsDigit(ch))
{
iDigit++;
if (consecutiveMode == 3)
iConsecutiveDigit++;
consecutiveMode = 3;
}
if (Char.IsUpper(ch))
{
iUpperCase++;
if (consecutiveMode == 1)
iConsecutiveUpper++;
consecutiveMode = 1;
}
if (Char.IsLower(ch))
{
iLowerCase++;
if (consecutiveMode == 2)
iConsecutiveLower++;
consecutiveMode = 2;
}
if (Char.IsSymbol(ch) || Char.IsPunctuation(ch))
{
iSymbol++;
consecutiveMode = 0;
}
if (Char.IsLetter(ch))
{
if (htRepeated.ContainsKey(Char.ToLower(ch))) iRepeated++;
else htRepeated.Add(Char.ToLower(ch), 0);
if (iMiddleEx > 1)
iMiddle = iMiddleEx - 1;
}
if (iUpperCase > 0 || iLowerCase > 0)
{
if (Char.IsDigit(ch) || Char.IsSymbol(ch))
iMiddleEx++;
}
}
for (var s = 0; s < 23; s++)
{
var sFwd = sAlphas.Substring(s, 3);
var sRev = strReverse(sFwd);
if (pwd.ToLower().IndexOf(sFwd) == -1 && pwd.ToLower().IndexOf(sRev) == -1) continue;
nSeqAlpha++;
}
for (var s = 0; s < 8; s++)
{
var sFwd = sNumerics.Substring(s, 3);
var sRev = strReverse(sFwd);
if (pwd.ToLower().IndexOf(sFwd) == -1 && pwd.ToLower().IndexOf(sRev) == -1) continue;
nSeqNumber++;
}
var nScore = 4 * pwd.Length;
AddDetailsRow("Password Length", "(n*4)", pwd.Length, pwd.Length * 4, 0);
if (iUpperCase > 0)
{
nScore += ((pwd.Length - iUpperCase) * 2);
AddDetailsRow("Uppercase Letters", "+((len-n)*2)", iUpperCase, ((pwd.Length - iUpperCase) * 2), 0);
}
else
AddDetailsRow("Uppercase Letters", "+((len-n)*2)", iUpperCase, 0, 0);
if (iLowerCase > 0)
{
nScore += ((pwd.Length - iLowerCase) * 2);
AddDetailsRow("Lowercase Letters", "+((len-n)*2)", iLowerCase, ((pwd.Length - iLowerCase) * 2), 0);
}
else
AddDetailsRow("Lowercase Letters", "+((len-n)*2)", iLowerCase, 0, 0);
nScore += (iDigit * 4);
AddDetailsRow("Numbers", "+(n*4)", iDigit, (iDigit * 4), 0);
nScore += (iSymbol * 6);
AddDetailsRow("Symbols", "+(n*6)", iSymbol, (iSymbol * 6), 0);
nScore += (iMiddle * 2);
AddDetailsRow("Middle Numbers or Symbols", "+(n*2)", iMiddle, (iMiddle * 2), 0);
var requirments = 0;
if (pwd.Length >= 8) requirments++;
if (iUpperCase > 0) requirments++;
if (iLowerCase > 0) requirments++;
if (iDigit > 0) requirments++;
if (iSymbol > 0) requirments++;
if (pwd.Length>=8)
{
nScore += pwd.Length;
AddDetailsRow("Requirement. Length>8","+(n)",pwd.Length,pwd.Length,0);
}
if (iUpperCase>0)
{
nScore += iUpperCase*2;
AddDetailsRow("Requirement. Uppercase","+(n)",iUpperCase,iUpperCase,0);
}
if (iLowerCase>0)
{
nScore += iLowerCase;
AddDetailsRow("Requirement. Lowercase","+(n)",iLowerCase,iLowerCase,0);
}
if (iDigit>0)
{
nScore += iDigit;
AddDetailsRow("Requirement. Digit","+(n)",iDigit,iDigit,0);
}
if (iSymbol>0)
{
nScore += iSymbol*2;
AddDetailsRow("Requirement. Symbol","+(2n)",iSymbol,iSymbol*2,0);
}
if (requirments > 3)
{
nScore += (requirments * 2);
AddDetailsRow("3 or more requirments", "+(n*2)", requirments, (requirments * 2), 0);
}
else
AddDetailsRow("Less than 3 requirments", "-(5-n)*2", requirments, 0, (5-requirments)*2);
if (iDigit == 0 && iSymbol == 0)
{
nMalus += pwd.Length;
AddDetailsRow("Letters only", "-n", pwd.Length, 0, pwd.Length);
}
else
AddDetailsRow("Letters only", "-n", 0, 0, 0);
if (iDigit == pwd.Length)
{
nMalus += pwd.Length;
AddDetailsRow("Numbers only", "-n", pwd.Length, 0, pwd.Length);
}
else
AddDetailsRow("Numbers only", "-n", 0, 0, 0);
if (iRepeated > 1)
{
nMalus += (iRepeated * (iRepeated));
AddDetailsRow("Repeat Characters (Case Insensitive)", "-(n(n-1))", iRepeated, 0, iRepeated * (iRepeated));
}
nMalus += (iConsecutiveUpper * 2);
AddDetailsRow("Consecutive Uppercase Letters", "-(n*2)", iConsecutiveUpper, 0, iConsecutiveUpper * 2);
nMalus += (iConsecutiveLower * 2);
AddDetailsRow("Consecutive Lowercase Letters", "-(n*2)", iConsecutiveLower, 0, iConsecutiveLower * 2);
nMalus += (iConsecutiveDigit * 2);
AddDetailsRow("Consecutive Numbers", "-(n*2)", iConsecutiveDigit, 0, iConsecutiveDigit * 2);
nMalus += (nSeqAlpha * 3);
AddDetailsRow("Sequential Letters (3+)", "-(n*3)", nSeqAlpha, 0, nSeqAlpha * 3);
nMalus += (nSeqNumber * 3);
AddDetailsRow("Sequential Numbers (3+)", "-(n*3)", nSeqNumber, 0, nSeqNumber * 3);
var fScore = nScore - nMalus;
if (fScore > 100) { fScore = 100; } else if (fScore < 0) { fScore = 0; }
if (fScore >= 0 && fScore < 20) { sComplexity = "Very Weak"; }
else if (fScore >= 20 && fScore < 40) { sComplexity = "Weak"; }
else if (fScore >= 40 && fScore < 60) { sComplexity = "Good"; }
else if (fScore >= 60 && fScore < 80) { sComplexity = "Strong"; }
else if (fScore >= 80 && fScore <= 100) { sComplexity = "Very Strong"; }
drScore.Bonus = nScore;
drScore.Malus = nMalus;
drScore.Rate = sComplexity;
}
private void CreateDetailsTable()
{
dtDetails = new ObservableCollection<AnalysisItem>();
AddDetailsRow("Score", "", 0, 0, 0);
}
private void AddDetailsRow(string description, string rate, int count, int bonus, int malus)
{
var dr = new AnalysisItem
{
Description = description ?? "",
Rate = rate ?? "",
Count = count,
Bonus = bonus,
Malus = malus
};
dtDetails.Add(dr);
return;
}
private static String strReverse(IEnumerable<char> str)
{
return str.Aggregate("", (s, t) => t + s);
}
}
public class AnalysisItem
{
public string Description { get; set; }
public string Rate { get; set; }
public int Count { get; set; }
public int Bonus { get; set; }
public int Malus { get; set; }
public int Total
{
get { return Bonus - Malus; }
}
}
O.Dahan
www.e-naxos.com
|