58 lines
1.4 KiB
TypeScript
58 lines
1.4 KiB
TypeScript
interface OtpServiceEntity {
|
|
length?: number;
|
|
}
|
|
|
|
export class OtpService {
|
|
private readonly otpLength: number;
|
|
|
|
constructor({ length = 4 }: OtpServiceEntity) {
|
|
this.otpLength = Math.max(length, 4); // Minimum of 4 digits
|
|
}
|
|
|
|
private hasSequentialDigits(str: string): boolean {
|
|
for (let i = 0; i < str.length - 1; i++) {
|
|
const current = parseInt(str[i], 10);
|
|
const next = parseInt(str[i + 1], 10);
|
|
if (next === current + 1 || next === current - 1) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private hasRepeatedDigits(str: string): boolean {
|
|
return str.split('').every((char) => char === str[0]);
|
|
}
|
|
|
|
private isPalindrome(str: string): boolean {
|
|
return str === str.split('').reverse().join('');
|
|
}
|
|
|
|
private hasPartiallyRepeatedDigits(str: string): boolean {
|
|
const counts: Record<string, number> = {};
|
|
for (const char of str) {
|
|
counts[char] = (counts[char] || 0) + 1;
|
|
}
|
|
|
|
// Reject if any digit appears more than twice
|
|
return Object.values(counts).some((count) => count > 2);
|
|
}
|
|
|
|
public generateSecureOTP(): string {
|
|
let otp: string;
|
|
|
|
do {
|
|
otp = Array.from({ length: this.otpLength }, () =>
|
|
Math.floor(Math.random() * 10).toString(),
|
|
).join('');
|
|
} while (
|
|
this.hasSequentialDigits(otp) ||
|
|
this.hasRepeatedDigits(otp) ||
|
|
this.isPalindrome(otp) ||
|
|
this.hasPartiallyRepeatedDigits(otp)
|
|
);
|
|
|
|
return otp;
|
|
}
|
|
}
|