Open stefnotch opened 3 hours ago
Here we go, a slightly horrifying golfed version
/*
ShangShield.ts by Alyx Shang.
Licensed under the FSL v1.
*/
/**
* A JSON interface to save information
* about the analysis of the strength of
* a password.
*/
export interface SecurityInfo {
password: string;
score: number;
cutOff: number;
isSecure: boolean;
}
const charValues = new Map(
"abcdefghijklmnopqrstuvwxyz"
.split("")
.map(
(c, i) => [c, (letterWeight: number) => letterWeight * (i + 1)] as const
)
.concat("0123456789".split("").map((c, i) => [c, () => i] as const))
);
/**
* This function reduces a character down to a number that mathematical
* operations can be conducted on.
* @param {string} char The character to reduce to a number entity.
* @param {number} letterWeight The weight assigned to normal alphabets.
* @param {number} specialCharWeight The weight assigned to special characters.
* @returns {number} The number the character has been reduced to is returned.
*/
function reduceCharactersToNumber(
char: string,
letterWeight: number,
specialCharWeight: number
): number {
return (
charValues.get(char.toLowerCase())?.(letterWeight) ?? specialCharWeight
);
}
/**
* This function calculates the security score of the supplied password
* using the supplied weights.
* @param {string} pwd The password to calculate the strength score of.
* @param {number} letterWeight The weight assigned to normal alphabets.
* @param {number} specialCharWeight The weight assigned to special characters.
* @returns {number} A number that reflects how secure a password is.
*/
export function securityScore(
pwd: string,
letterWeight: number,
specialCharWeight: number
): number {
const scores = pwd
.split("")
.map((char) =>
reduceCharactersToNumber(char, letterWeight, specialCharWeight)
);
if (scores.length === 0) {
return 0;
}
if (scores.length === 1) {
return scores[0];
}
const differences = scores
.map((score, i) => Math.abs(score - scores[i - 1]))
.slice(1);
differences[differences.length - 1] *= 2; // Double count the last score difference
return differences.reduce((a, b) => a + b, 0);
}
/**
* This function checks whether the security score of the supplied
* password is larger or smaller than the supplied "cutOff" value.
* @param {string} pwd The password to calculate the strength score of.
* @param {number} letterWeight The weight assigned to normal alphabets.
* @param {number} specialCharWeight The weight assigned to special characters.
* @param {number} cutOff The value that the calculated security score has to be
* smaller or larger than.
* @returns {boolean} Returns a boolean that reflects whether the calculated
* security score of the supplied password is larger or smaller than the
* supplied "cutOff" value.
*/
export function isSecure(
pwd: string,
letterWeight: number,
specialCharWeight: number,
cutOff: number
): boolean {
return shieldSummary(pwd, letterWeight, specialCharWeight, cutOff).isSecure;
}
/**
* This function runs the analysis functions for password strength
* analysis and adds the information to an instance of the "SecurityInfo"
* JSON interface. This instance is then returned.
* @param {string} password The password whose strength to analyze.
* @param {number} letterWeight The weight assigned to letters of the alphabet.
* @param {number} specialCharWeight The weight assigned to special characters.
* @param {number} cutOff The value that the calculated security score has to be
* larger or greater than for the password to be deemed secure.
* @returns {SecurityInfo} Returns an instance of the "SecurityInfo" JSON
* interface providing a summary of the analysis results.
*/
export function shieldSummary(
password: string,
letterWeight: number,
specialCharWeight: number,
cutOff: number
): SecurityInfo {
const score = securityScore(password, letterWeight, specialCharWeight);
return {
password,
score,
cutOff,
isSecure: score >= cutOff,
};
}
I was bored, so I figured I'd do a bit of code golf. While doing so, I noticed a bug. In this case, the implementation returns NaN.