You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

72 lines
1.9 KiB

import { toByteArray } from "base64-js";
import { type ZodType, z } from "zod/v4";
export function makePskHelpers(allowedByteLengths: readonly number[]) {
const bitsLabel = allowedByteLengths.map((b) => b * 8).join(" | ");
const msgs = {
format: "formValidation.invalidFormat.key",
required: "formValidation.required.key",
length: `formValidation.pskLength.${bitsLabel.replace(/ \| /g, "_")}bit`,
} as const;
function tryParse(str: string): Uint8Array | null {
try {
return toByteArray(str);
} catch {
return null;
}
}
function isValidString(str: string): boolean {
const arr = tryParse(str);
return arr !== null && allowedByteLengths.includes(arr.byteLength);
}
function isValidKey(v: unknown): boolean {
if (typeof v === "string") {
return isValidString(v);
}
if (v instanceof Uint8Array) {
return allowedByteLengths.includes(v.byteLength);
}
return false;
}
const stringSchema = (optional = false) =>
z
.string()
.refine(
(s) =>
optional || s !== "" || (s === "" && allowedByteLengths.includes(0)),
{
message: msgs.required,
},
)
.refine((s) => s === "" || tryParse(s) !== null, { message: msgs.format })
.refine((s) => s === "" || isValidString(s), {
message: msgs.length,
params: { bits: bitsLabel },
});
const bytesSchema = (optional = false): ZodType<Uint8Array> =>
z
.instanceof(Uint8Array)
.refine(
(arr) =>
optional || arr.byteLength !== 0 || allowedByteLengths.includes(0),
{ message: msgs.required },
)
.refine(
(arr) => optional || allowedByteLengths.includes(arr.byteLength),
{ message: msgs.length, params: { bits: bitsLabel } },
);
return {
allowedByteLengths,
msgs,
tryParseStringKey: tryParse,
isValidKey,
stringSchema,
bytesSchema,
};
}