Skip to content

Instantly share code, notes, and snippets.

@jdboachie
Created January 20, 2026 09:01
Show Gist options
  • Select an option

  • Save jdboachie/72e88c96abd8199878b9d915f6c803ca to your computer and use it in GitHub Desktop.

Select an option

Save jdboachie/72e88c96abd8199878b9d915f6c803ca to your computer and use it in GitHub Desktop.
interface ValidationResult {
passed: boolean;
violations: string[] | null;
}
type ValidatorFn = (input: string) => ValidationResult;
const validators: ValidatorFn[] = [];
const isDigit = (char: string) => {
return char >= "0" && char <= "9";
};
const isLower = (char: string) => {
return char >= "a" && char <= "z";
};
function registerValidators(validatorFns: ValidatorFn[]) {
for (const fn of validatorFns) {
validators.push(fn);
}
}
function hasOnlyOneColon(input: string): ValidationResult {
const passed = input.split(":").length == 2;
return {
passed,
violations: passed ? null : ["Missing or multiple separators"],
};
}
function validateUsername(input: string): ValidationResult {
try {
let splits = input.split(":");
if (!(splits.length === 2)) {
throw new Error();
}
input = splits[0] ?? "";
} catch {
return { passed: false, violations: null };
}
let passed: boolean = true;
let violations: string[] = [];
if (input.length < 5 || input.length > 15) {
passed = false;
violations.push("Username length/format error");
}
if (isDigit(input[0]!) || isDigit(input[-1]!)) {
passed = false;
violations.push("Username length/format error");
return {
passed,
violations,
};
}
for (const char of input) {
if (!isLower(char) && !isDigit(char)) {
passed = false;
violations.push("Username length/format error");
break;
}
}
return {
passed,
violations,
};
}
function validatePassword(input: string): ValidationResult {
try {
let splits = input.split(":");
if (!(splits.length === 2)) {
throw new Error();
}
input = splits[1] ?? "";
} catch {
return { passed: false, violations: null };
}
let passed: boolean = true;
let violations: string[] = [];
if (input.length < 8) {
passed = false;
violations.push("Password complexity error");
return {
passed,
violations,
};
}
let hasUppercaseChar = false;
let hasLowercaseChar = false;
let hasDigit = false;
let hasSpecialChar = false;
for (const char of input) {
if (isDigit(char)) {
hasDigit = true;
} else if (isLower(char)) {
hasLowercaseChar = true;
} else if (char >= "A" && char <= "Z") {
hasUppercaseChar = true;
} else if (["!", "@", "#", "$"].includes(char)) {
hasSpecialChar = true;
}
}
passed = hasUppercaseChar && hasLowercaseChar && hasDigit && hasSpecialChar;
if (!passed) {
violations.push("Password complexity error")
}
return {
passed,
violations,
};
}
registerValidators([hasOnlyOneColon, validateUsername, validatePassword]);
function validateCredentials(input: string) {
let passed: boolean = true;
let violations: string[] = [];
for (const v of validators) {
let res = v(input);
passed = passed ? res.passed : passed;
if (res.violations) {
violations.push(...res.violations);
}
}
console.log(passed ? "Secure" : "Insecure");
if (!passed) {
console.log("Reasons:", violations.join(", "));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment