diff --git a/apps/console/src/providers/RelayProviders.tsx b/apps/console/src/providers/RelayProviders.tsx index 3d0696bb7..dc986ba10 100644 --- a/apps/console/src/providers/RelayProviders.tsx +++ b/apps/console/src/providers/RelayProviders.tsx @@ -58,6 +58,18 @@ export class ForbiddenError extends Error { } } +export class InvalidError extends Error { + field?: string; + cause?: string; + + constructor(message?: string, field?: string, cause?: string) { + super(message || "INVALID"); + this.name = "InvalidError"; + this.field = field; + this.cause = cause; + } +} + export function buildEndpoint(path: string): string { const host = import.meta.env.VITE_API_URL; @@ -91,6 +103,9 @@ const hasUnauthorizedError = (error: GraphQLError) => const hasForbiddenError = (error: GraphQLError) => error.extensions?.code == "FORBIDDEN"; +const hasInvalidError = (error: GraphQLError) => + error.extensions?.code == "INVALID_REQUEST"; + const fetchRelay: FetchFunction = async ( request, variables, @@ -183,6 +198,15 @@ const fetchRelay: FetchFunction = async ( if (forbiddenError) { throw new ForbiddenError(forbiddenError.message); } + + const invalidError = errors.find(hasInvalidError); + if (invalidError) { + throw new InvalidError( + invalidError.message, + invalidError.extensions.field as string ?? "", + invalidError.extensions.cause as string ?? "", + ); + } } return json; diff --git a/apps/trust/src/components/RequestAccessDialog.tsx b/apps/trust/src/components/RequestAccessDialog.tsx index 8731dacd7..52a357898 100644 --- a/apps/trust/src/components/RequestAccessDialog.tsx +++ b/apps/trust/src/components/RequestAccessDialog.tsx @@ -17,6 +17,7 @@ import { useMutationWithToasts } from "/hooks/useMutationWithToast"; import { useTrustCenter } from "/hooks/useTrustCenter"; import { type FormEventHandler, type PropsWithChildren } from "react"; import { useIsAuthenticated } from "/hooks/useIsAuthenticated.ts"; +import { InvalidError } from "/providers/RelayProviders"; type Props = PropsWithChildren<{ documentId?: string; @@ -40,7 +41,7 @@ export function RequestAccessDialog({ const trustCenter = useTrustCenter(); const { toast } = useToast(); const { __ } = useTranslate(); - const { handleSubmit, register } = useFormWithSchema(schema, { + const { handleSubmit, register, setError, formState } = useFormWithSchema(schema, { defaultValues: { name: "", email: "", @@ -62,7 +63,11 @@ export function RequestAccessDialog({ dialogRef.current?.close(); }) .catch((error) => { - console.error(error); + if (error instanceof InvalidError) { + if (error.field === "email") { + setError(error.field, {message: error.message}) + } + } toast({ title: __("Error"), description: __("Cannot request access"), @@ -109,6 +114,7 @@ export function RequestAccessDialog({ placeholder="john.doe@acme.com" {...register("email")} type="email" + error={formState.errors.email?.message} /> )} diff --git a/apps/trust/src/providers/RelayProviders.tsx b/apps/trust/src/providers/RelayProviders.tsx index ea4ad1e63..23cf17d85 100644 --- a/apps/trust/src/providers/RelayProviders.tsx +++ b/apps/trust/src/providers/RelayProviders.tsx @@ -16,6 +16,18 @@ export class UnAuthenticatedError extends Error { } } +export class InvalidError extends Error { + field?: string; + cause?: string; + + constructor(message?: string, field?: string, cause?: string) { + super(message || "INVALID"); + this.name = "InvalidError"; + this.field = field; + this.cause = cause; + } +} + export class InternalServerError extends Error { constructor() { super("INTERNAL_SERVER_ERROR"); @@ -47,6 +59,9 @@ export function buildEndpoint(path: string): string { const hasUnauthenticatedError = (error: GraphQLError) => error.extensions?.code == "UNAUTHENTICATED"; +const hasInvalidError = (error: GraphQLError) => + error.extensions?.code == "INVALID_REQUEST"; + const fetchRelay: FetchFunction = async ( request, variables, @@ -125,6 +140,15 @@ const fetchRelay: FetchFunction = async ( throw new UnAuthenticatedError(); } + const invalidError = errors.find(hasInvalidError); + if (invalidError) { + throw new InvalidError( + invalidError.message, + invalidError.extensions.field as string ?? "", + invalidError.extensions.cause as string ?? "", + ); + } + throw new Error(`Error fetching GraphQL query '${request.name}'`); } diff --git a/pkg/trust/trust_center_access_service.go b/pkg/trust/trust_center_access_service.go index fb34eb911..35d91985c 100644 --- a/pkg/trust/trust_center_access_service.go +++ b/pkg/trust/trust_center_access_service.go @@ -58,9 +58,9 @@ const ( func (tcar *TrustCenterAccessRequest) Validate() error { v := validator.New() - v.Check(tcar.Email, "email", validator.NotOneOfSlice([]string{})) + v.Check(tcar.Email, "email", validator.NotBlacklisted()) - return nil + return v.Error() } func (s TrustCenterAccessService) ValidateToken( @@ -88,7 +88,7 @@ func (s TrustCenterAccessService) Request( req *TrustCenterAccessRequest, ) (*coredata.TrustCenterAccess, error) { if err := req.Validate(); err != nil { - return nil, fmt.Errorf("invalid request arguments") + return nil, fmt.Errorf("invalid request arguments: %w", err) } now := time.Now() diff --git a/pkg/validator/validator_email.go b/pkg/validator/validator_email.go index f653069f9..287b6e595 100644 --- a/pkg/validator/validator_email.go +++ b/pkg/validator/validator_email.go @@ -37,7 +37,7 @@ func NotBlacklisted() ValidatorFunc { if err == nil { return newValidationError( - ErrorCodeInvalidEnum, + ErrorCodeInvalidEmail, "must not be blacklisted", ) }