commit 01e654fb51de21d40e33dcc0166a3dd172c26bf3
parent fb0b62a145694a0a05fa22731a9e9634ad965cde
Author: Sebastian <sebasjm@gmail.com>
Date: Thu, 6 Feb 2025 16:33:27 -0300
validation defined on design
Diffstat:
4 files changed, 124 insertions(+), 213 deletions(-)
diff --git a/packages/aml-backoffice-ui/src/pages/CreateAccount.tsx b/packages/aml-backoffice-ui/src/pages/CreateAccount.tsx
@@ -36,38 +36,11 @@ type FormType = {
password: string;
repeat: string;
};
-function createFormValidator(
+
+const createAccountForm = (
i18n: InternationalizationAPI,
allowInsecurePassword: boolean,
-) {
- return function check(
- state: RecursivePartial<FormValues<FormType>>,
- ): FormErrors<FormType> | undefined {
- return undefinedIfEmpty<FormErrors<FormType>>({
- password: !state.password
- ? i18n.str`required`
- : allowInsecurePassword
- ? undefined
- : state.password.length < 8
- ? i18n.str`should have at least 8 characters`
- : !state.password.match(/[a-z]/) && state.password.match(/[A-Z]/)
- ? i18n.str`should have lowercase and uppercase characters`
- : !state.password.match(/\d/)
- ? i18n.str`should have numbers`
- : !state.password.match(/[^a-zA-Z\d]/)
- ? i18n.str`should have at least one character which is not a number or letter`
- : undefined,
-
- repeat: !state.repeat
- ? i18n.str`required`
- : state.password !== state.repeat
- ? i18n.str`doesn't match`
- : undefined,
- });
- };
-}
-
-const createAccountForm = (i18n: InternationalizationAPI): FormDesign => ({
+): FormDesign => ({
type: "single-column",
fields: [
{
@@ -75,12 +48,34 @@ const createAccountForm = (i18n: InternationalizationAPI): FormDesign => ({
type: "secret",
label: i18n.str`Password`,
required: true,
+ validator(value) {
+ return !value
+ ? i18n.str`required`
+ : allowInsecurePassword
+ ? undefined
+ : value.length < 8
+ ? i18n.str`should have at least 8 characters`
+ : !value.match(/[a-z]/) && value.match(/[A-Z]/)
+ ? i18n.str`should have lowercase and uppercase characters`
+ : !value.match(/\d/)
+ ? i18n.str`should have numbers`
+ : !value.match(/[^a-zA-Z\d]/)
+ ? i18n.str`should have at least one character which is not a number or letter`
+ : undefined;
+ },
},
{
id: "repeat" as UIHandlerId,
type: "secret",
label: i18n.str`Repeat password`,
required: true,
+ validator(value) {
+ return value
+ ? i18n.str`required`
+ : // : state.password !== value
+ // ? i18n.str`doesn't match`
+ undefined;
+ },
},
],
});
@@ -92,7 +87,7 @@ export function CreateAccount(): VNode {
const [notification, withErrorHandler] = useLocalNotificationHandler();
- const design = createAccountForm(i18n);
+ const design = createAccountForm(i18n, settings.allowInsecurePassword);
const { handler, status } = useForm<FormType>(
design,
@@ -100,7 +95,7 @@ export function CreateAccount(): VNode {
password: undefined,
repeat: undefined,
},
- createFormValidator(i18n, settings.allowInsecurePassword),
+ // createFormValidator(i18n, settings.allowInsecurePassword),
);
const createAccountHandler =
diff --git a/packages/aml-backoffice-ui/src/pages/NewMeasure.tsx b/packages/aml-backoffice-ui/src/pages/NewMeasure.tsx
@@ -51,13 +51,13 @@ export function NewMeasure({}: {}): VNode {
})),
};
- const design = formDesign(i18n, names.programs, names.checks);
-
const summary =
!measures || measures instanceof TalerError || measures.type === "fail"
? undefined
: measures.body;
+ const design = formDesign(i18n, names.programs, names.checks, summary);
+
const form = useForm<FormType>(
design,
{
@@ -71,38 +71,38 @@ export function NewMeasure({}: {}): VNode {
},
],
},
- (f) => {
- if (!summary) return undefined;
- return undefinedIfEmpty<FormErrors<FormType>>({
- name: !f.name
- ? i18n.str`required`
- : summary.roots[f.name]
- ? i18n.str`already exist`
- : undefined,
- program: !f.program
- ? i18n.str`required`
- : programAndCheckMatch(i18n, summary, f.program, f.check) ??
- undefined,
- check: checkAndcontextMatch(
- i18n,
- summary,
- f.check,
- (f.context ?? []) as {
- key: string;
- value: string;
- }[],
- ),
- context: checkAndcontextMatch(
- i18n,
- summary,
- f.check,
- (f.context ?? []) as {
- key: string;
- value: string;
- }[],
- ) as any,
- });
- },
+ // (f) => {
+ // if (!summary) return undefined;
+ // return undefinedIfEmpty<FormErrors<FormType>>({
+ // // name: !f.name
+ // // ? i18n.str`required`
+ // // : summary.roots[f.name]
+ // // ? i18n.str`already exist`
+ // // : undefined,
+ // // program: !f.program
+ // // ? i18n.str`required`
+ // // : programAndCheckMatch(i18n, summary, f.program, f.check) ??
+ // // undefined,
+ // // check: checkAndcontextMatch(
+ // // i18n,
+ // // summary,
+ // // f.check,
+ // // (f.context ?? []) as {
+ // // key: string;
+ // // value: string;
+ // // }[],
+ // // ),
+ // // context: checkAndcontextMatch(
+ // // i18n,
+ // // summary,
+ // // f.check,
+ // // (f.context ?? []) as {
+ // // key: string;
+ // // value: string;
+ // // }[],
+ // // ) as any,
+ // });
+ // },
);
function addNewRule(nr: FormType) {
@@ -330,6 +330,7 @@ const formDesign = (
i18n: InternationalizationAPI,
programs: { key: string; value: AmlProgramRequirement }[],
checks: { key: string; value: KycCheckInformation }[],
+ summary: AvailableMeasureSummary | undefined,
): FormDesign<KycRule> => ({
type: "single-column",
fields: [
@@ -338,6 +339,13 @@ const formDesign = (
type: "text",
required: true,
label: i18n.str`Name`,
+ validator(value) {
+ return !value
+ ? i18n.str`required`
+ : summary && summary.roots[value]
+ ? i18n.str`already exist`
+ : undefined;
+ },
},
{
type: "selectOne",
@@ -349,6 +357,13 @@ const formDesign = (
label: m.key,
};
}),
+ validator(value) {
+ // FIXME: cross validation
+ return !value
+ ? i18n.str`required`
+ : // : !summary ? undefined : programAndCheckMatch(i18n, summary, value, f.check) ??
+ undefined;
+ },
},
{
type: "selectOne",
@@ -360,6 +375,19 @@ const formDesign = (
label: m.key,
};
}),
+ validator(value) {
+ // FIXME: cross validation
+ return undefined;
+ // return checkAndcontextMatch(
+ // i18n,
+ // summary!,
+ // f.check,
+ // (f.context ?? []) as {
+ // key: string;
+ // value: string;
+ // }[],
+ // )
+ },
},
{
type: "array",
diff --git a/packages/aml-backoffice-ui/src/pages/Search.tsx b/packages/aml-backoffice-ui/src/pages/Search.tsx
@@ -67,7 +67,7 @@ export function Search() {
const paytoForm = useForm<FormPayto>(
design,
{ paytoType: "iban" },
- createFormValidator(i18n),
+ // createFormValidator(i18n),
);
if (officer.state !== "ready") {
@@ -307,7 +307,7 @@ function XTalerBankForm({
const form = useForm<PaytoUriTalerBankForm>(
design,
{},
- createTalerBankPaytoValidator(i18n),
+ // createTalerBankPaytoValidator(i18n),
);
const paytoUri =
form.status.status === "fail"
@@ -340,6 +340,7 @@ function XTalerBankForm({
</form>
);
}
+
function IbanForm({
onSearch,
}: {
@@ -353,7 +354,7 @@ function IbanForm({
const form = useForm<PaytoUriIBANForm>(
design,
{},
- createIbanPaytoValidator(i18n),
+ // createIbanPaytoValidator(i18n),
);
const paytoUri =
form.status.status === "fail"
@@ -398,7 +399,7 @@ function WalletForm({
{
exchange: getURLHostnamePortPath(config.keys.base_url),
},
- createTalerPaytoValidator(i18n),
+ // createTalerPaytoValidator(i18n),
);
const paytoUri =
form.status.status === "fail"
@@ -445,7 +446,7 @@ function GenericForm({
const form = useForm<PaytoUriGenericForm>(
design,
{},
- createGenericPaytoValidator(i18n),
+ // createGenericPaytoValidator(i18n),
);
const paytoUri =
form.status.status === "fail"
@@ -477,80 +478,23 @@ interface FormPayto {
paytoType: "generic" | "iban" | "x-taler-bank" | "wallet";
}
-function createFormValidator(i18n: InternationalizationAPI) {
- return function check(
- state: RecursivePartial<FormValues<FormPayto>>,
- ): FormErrors<FormPayto> | undefined {
- return undefinedIfEmpty<FormErrors<FormPayto>>({
- paytoType: !state?.paytoType ? i18n.str`required` : undefined,
- });
- };
-}
-
interface PaytoUriGenericForm {
payto: string;
}
-function createGenericPaytoValidator(i18n: InternationalizationAPI) {
- return function check(
- state: RecursivePartial<FormValues<PaytoUriGenericForm>>,
- ): FormErrors<PaytoUriGenericForm> | undefined {
- return undefinedIfEmpty<FormErrors<PaytoUriGenericForm>>({
- payto: !state.payto
- ? i18n.str`required`
- : parsePaytoUri(state.payto) === undefined
- ? i18n.str`invalid`
- : undefined,
- });
- };
-}
-
interface PaytoUriIBANForm {
account: string;
}
-function createIbanPaytoValidator(i18n: InternationalizationAPI) {
- return function check(
- state: RecursivePartial<FormValues<PaytoUriIBANForm>>,
- ): FormErrors<PaytoUriIBANForm> | undefined {
- return undefinedIfEmpty<FormErrors<PaytoUriIBANForm>>({
- account: !state.account ? i18n.str`required` : undefined,
- });
- };
-}
interface PaytoUriTalerBankForm {
hostname: string;
account: string;
}
-function createTalerBankPaytoValidator(i18n: InternationalizationAPI) {
- return function check(
- state: RecursivePartial<FormValues<PaytoUriTalerBankForm>>,
- ): FormErrors<PaytoUriTalerBankForm> | undefined {
- return undefinedIfEmpty<FormErrors<PaytoUriTalerBankForm>>({
- account: !state.account ? i18n.str`required` : undefined,
- hostname: !state.hostname ? i18n.str`required` : undefined,
- });
- };
-}
interface PaytoUriTalerForm {
exchange: string;
reservePub: string;
}
-function createTalerPaytoValidator(i18n: InternationalizationAPI) {
- return function check(
- state: RecursivePartial<FormValues<PaytoUriTalerForm>>,
- ): FormErrors<PaytoUriTalerForm> | undefined {
- return undefinedIfEmpty<FormErrors<PaytoUriTalerForm>>({
- exchange: !state.exchange ? i18n.str`required` : undefined,
- reservePub: !state.reservePub
- ? i18n.str`required`
- : state.reservePub.length !== 16
- ? i18n.str`Should be 16 charaters`
- : undefined,
- });
- };
-}
const paytoTypeField: (
i18n: InternationalizationAPI,
@@ -581,17 +525,6 @@ const paytoTypeField: (
},
];
-const receiverName: (i18n: InternationalizationAPI) => UIFormElementConfig = (
- i18n,
-) => ({
- id: "name" as UIHandlerId,
- type: "text",
- required: true,
- label: i18n.str`Owner's name`,
- help: i18n.str`It should match the bank account name.`,
- placeholder: i18n.str`John Doe`,
-});
-
const genericFields: (
i18n: InternationalizationAPI,
) => UIFormElementConfig[] = (i18n) => [
@@ -602,6 +535,9 @@ const genericFields: (
label: i18n.str`Payto URI`,
help: i18n.str`As defined by RFC 8905`,
placeholder: i18n.str`payto://`,
+ validator(value) {
+ return parsePaytoUri(value) === undefined ? i18n.str`invalid` : undefined;
+ },
},
];
const ibanFields: (i18n: InternationalizationAPI) => UIFormElementConfig[] = (
@@ -614,39 +550,8 @@ const ibanFields: (i18n: InternationalizationAPI) => UIFormElementConfig[] = (
label: i18n.str`IBAN`,
help: i18n.str`International Bank Account Number`,
placeholder: i18n.str`DE1231231231`,
- // validator: (value) => validateIBAN(value, i18n),
+ validator: (value) => validateIBAN(value, i18n),
},
- // receiverName(i18n),
- // {
- // id: "bic" as UIHandlerId,
- // type: "text",
- // label: i18n.str`Bank`,
- // help: i18n.str`Business Identifier Code`,
- // placeholder: i18n.str`GENODEM1GLS`,
- // // validator: (value) => validateIBAN(value, i18n),
- // },
-];
-const paytoHashFields: (
- i18n: InternationalizationAPI,
-) => UIFormElementConfig[] = (i18n) => [
- {
- id: "account" as UIHandlerId,
- type: "text",
- required: true,
- label: i18n.str`ID`,
- help: i18n.str`Normalized payto:// hash`,
- placeholder: i18n.str`ABC123`,
- // validator: (value) => validateIBAN(value, i18n),
- },
- // receiverName(i18n),
- // {
- // id: "bic" as UIHandlerId,
- // type: "text",
- // label: i18n.str`Bank`,
- // help: i18n.str`Business Identifier Code`,
- // placeholder: i18n.str`GENODEM1GLS`,
- // // validator: (value) => validateIBAN(value, i18n),
- // },
];
const walletFields: (i18n: InternationalizationAPI) => UIFormElementConfig[] = (
@@ -659,7 +564,9 @@ const walletFields: (i18n: InternationalizationAPI) => UIFormElementConfig[] = (
label: i18n.str`Host`,
help: i18n.str`Exchange hostname`,
placeholder: i18n.str`exchange.taler.net`,
- // validator: (value) => validateIBAN(value, i18n),
+ validator(value) {
+ return !DOMAIN_REGEX.test(value) ? i18n.str`Invalid hostname` : undefined;
+ },
},
{
id: "reservePub" as UIHandlerId,
@@ -668,17 +575,12 @@ const walletFields: (i18n: InternationalizationAPI) => UIFormElementConfig[] = (
label: i18n.str`ID`,
help: i18n.str`Wallet reserve public key`,
placeholder: i18n.str`abcdef1235`,
- // validator: (value) => validateIBAN(value, i18n),
+ validator(value) {
+ return value.length !== 16
+ ? i18n.str`Should be 16 characters`
+ : undefined;
+ },
},
- // receiverName(i18n),
- // {
- // id: "bic" as UIHandlerId,
- // type: "text",
- // label: i18n.str`Bank`,
- // help: i18n.str`Business Identifier Code`,
- // placeholder: i18n.str`GENODEM1GLS`,
- // // validator: (value) => validateIBAN(value, i18n),
- // },
];
const talerBankFields: (
@@ -699,9 +601,9 @@ const talerBankFields: (
label: i18n.str`Hostname`,
help: i18n.str`Without the scheme, may include subpath: bank.com, bank.com/path/`,
placeholder: i18n.str`bank.demo.taler.net`,
- // validator: (value) => validateTalerBank(value, i18n),
+ validator: (value) =>
+ !DOMAIN_REGEX.test(value) ? i18n.str`Invalid hostname` : undefined,
},
- // receiverName(i18n),
];
function validateIBAN(
@@ -733,35 +635,21 @@ function validateIBAN(
})
.join("");
- function calculate_iban_checksum(str: string): number {
- const numberStr = str.substr(0, 5);
- const rest = str.substr(5);
- const number = parseInt(numberStr, 10);
- const result = number % 97;
- if (rest.length > 0) {
- return calculate_iban_checksum(`${result}${rest}`);
- }
- return result;
- }
-
const checksum = calculate_iban_checksum(step3);
if (checksum !== 1)
return i18n.str`IBAN number is invalid, checksum is wrong`;
return undefined;
}
+function calculate_iban_checksum(str: string): number {
+ const numberStr = str.substr(0, 5);
+ const rest = str.substr(5);
+ const number = parseInt(numberStr, 10);
+ const result = number % 97;
+ if (rest.length > 0) {
+ return calculate_iban_checksum(`${result}${rest}`);
+ }
+ return result;
+}
const DOMAIN_REGEX =
/^[a-zA-Z0-9][a-zA-Z0-9-_]{1,61}[a-zA-Z0-9-_](?:\.[a-zA-Z0-9-_]{2,})+(:[0-9]+)?(\/[a-zA-Z0-9-.]+)*\/?$/;
-
-function validateTalerBank(
- addr: string,
- i18n: InternationalizationAPI,
-): TranslatedString | undefined {
- try {
- const valid = DOMAIN_REGEX.test(addr);
- if (valid) return undefined;
- } catch (e) {
- console.log(e);
- }
- return i18n.str`This is not a valid host.`;
-}
diff --git a/packages/aml-backoffice-ui/src/pages/UnlockAccount.tsx b/packages/aml-backoffice-ui/src/pages/UnlockAccount.tsx
@@ -58,11 +58,11 @@ export function UnlockAccount(): VNode {
{
password: undefined,
},
- (state) => {
- return undefinedIfEmpty<FormErrors<FormType>>({
- password: !state.password ? i18n.str`required` : undefined,
- });
- },
+ // (state) => {
+ // return undefinedIfEmpty<FormErrors<FormType>>({
+ // password: !state.password ? i18n.str`required` : undefined,
+ // });
+ // },
);
const unlockHandler =