Switch to Cap invisible widget, add form drafts to middleware, and improve OTP

validation

Use the Cap client widget in the contact UI with status icons and auto-solve,
replacing the capwidget element. Normalize and tighten phone validation by
splitting
normalizePhone and isValidPhone in the Otp lib and use it in contact action
validation. Replace loose text validation with a character-stripper helper.
Also bump several dependencies and adjust middleware to save and restore form
data for
form actions.
This commit is contained in:
badblocks 2026-01-27 09:49:06 -08:00
parent f7bdfd3cb8
commit 8e35387841
No known key found for this signature in database
7 changed files with 261 additions and 222 deletions

View file

@ -29,33 +29,36 @@ function getUserSecret(phoneNumber: string, salt: string): string {
.digest("hex");
}
export function validatePhoneNumber(unsafePhoneNum: string) {
if (typeof unsafePhoneNum !== "string") {
return { success: false, message: "Invalid phone number." };
export function normalizePhone(phone: string) {
const result = phone.replace(/[^\d]/g, "").trim().startsWith("1")
? phone.substring(1)
: phone;
if (result.length !== 10) {
throw new Error("Invalid phone number.");
}
unsafePhoneNum = unsafePhoneNum.replace(/[^0-9]/g, "").trim();
const cleanedNumber = unsafePhoneNum.startsWith("1")
? unsafePhoneNum.substring(1)
: unsafePhoneNum;
return result;
}
const isValidFormat = /^[2-7][0-8][0-9][2-9][0-9]{6}$/.test(cleanedNumber);
const isNotAllSameDigit = !/^(.)\1{9}$/.test(cleanedNumber);
const isNot911Number = !/^[0-9]{3}911[0-9]{4}$/.test(cleanedNumber);
const isNot555Number = !/^[0-9]{3}555[0-9]{4}$/.test(cleanedNumber);
const isNotPopSongNumber = !/^[0-9]{3}8675309$/.test(cleanedNumber);
export function isValidPhone(phone: string): boolean {
phone = normalizePhone(phone);
const match = phone.match(/(\d{3})(\d{3})(\d{4})/);
const [, prefix, exchange, station] = match ?? [];
const isValidNANPFormat =
/^[2-7][0-8][0-9]$/.test(prefix) && /^[2-9][0-9]{2}$/.test(exchange);
const isNotAllSameDigit = !/^(.)\1{6}$/.test(exchange + station);
const isNot911Number = prefix !== "911" && exchange !== "911";
const isNot555Number = prefix !== "555" && exchange !== "555";
const isNotPopSongNumber = exchange !== "867" && station !== "5309";
if (
isValidFormat &&
return (
isValidNANPFormat &&
isNotAllSameDigit &&
isNot911Number &&
isNot555Number &&
isNotPopSongNumber
) {
return { success: true, validatedPhoneNumber: cleanedNumber };
}
return { success: false, validatedPhoneNumber: undefined };
);
}
export function generateOtp(phoneNumber: string, salt: string): string {
@ -141,7 +144,8 @@ export function recordOtpRequest(phoneNumber: string) {
}
export default {
validatePhoneNumber,
normalizePhone,
isValidPhone,
generateOtp,
verifyOtp,
getOtpStep,