QwikDev / qwik

Instant-loading web apps, without effort
https://qwik.dev
MIT License
20.83k stars 1.3k forks source link

[🐞]Uncaught (in promise) DOMException: The operation is insecure. #4921

Closed Maikpwwq closed 1 year ago

Maikpwwq commented 1 year ago

Which component is affected?

Qwik Runtime

Describe the bug

Static Qwik app, I use a function to perform some task in my MongoDB export const addCustomer = server$(async (data) => {... this when click in a Btn and everything works fine in development environment. <button onClick$={async () => {const resume = await addCustomer(customerRecord); ...}

So I pushed changes to production in Vercel host. Then when I send the information again, it Fails giving me this error in browser console. Uncaught (in promise) DOMException: The operation is insecure..

HELP!

Reproduction

I create a new Qwik app, with react and static adapters. Then I have in header a click link to visit Form route. Project Repository Vercel Deployment Vercel Project

Steps to reproduce

Get Code

git clone https://github.com/Maikpwwq/qwik-ssg-modular-forms.git
cd ./qwik-ssg-modular-forms
pnpm i
pnpm run start

Go to Form route through the Link, and tried to send Form.

System Info

...

Additional Information

No response

hamatoyogi commented 1 year ago

Could you please create a minimal reproduction?

Maikpwwq commented 1 year ago

@hamatoyogi Sure. I create a new Qwik app, with react and static adapters. In header click link to visit Form route.

Project Repository Vercel Deployment Vercel Project

When send form I am getting those issues on my Vercel Deployment

shairez commented 1 year ago

Thanks @Maikpwwq can you outline the steps to reproduce the issue in the repo that you shared (the more info the better, like which files to look at etc)

Maikpwwq commented 1 year ago

@shairez just clone the repo, run the app, navigate to the form and try to send it. It is not so difficult.

Maikpwwq commented 1 year ago

I am trying to implement a form, in my routes folder I created a folder called customer-form with a file Index.tsx. This fails to store my data when is deployed to Vercel with this in console:

Captura desde 2023-08-25 02-06-19

I have tried first with mongo, now with supabase the problem persist. My file Index.tsx

import { component$, $, useTask$ } from "@builder.io/qwik"; // , useSignal
import { isServer } from "@builder.io/qwik/build";
import { createClient } from "@supabase/supabase-js";
import { v4 as uuidv4 } from 'uuid'
import clsx from "clsx";
import {
  routeLoader$,
  z,
} from "@builder.io/qwik-city";
import type { InitialValues, SubmitHandler } from "@modular-forms/qwik"; //
import {
  useForm,
  formAction$,
  zodForm$,
  reset,
} from "@modular-forms/qwik";
import styles from "~/components/modular-forms/modularForm.module.css";
import { MUITypography, MUIPaper } from "~/integrations/react/mui";
import { TextInput } from "~/components/modular-forms/TextInput";

const SUPABASE_URL = `${import.meta.env.VITE_SUPABASE_URL}`;
const SUPABASE_KEY = `${import.meta.env.VITE_SUPABASE_KEY}`;

type LoginForm = {
  name: string;
  email: string;
  phone: string;
  issue: string;
  message: string;
};

const loginSchema = z.object({
  name: z.string().min(1, "Por favor introduzca su nombre."),
  email: z
    .string()
    .min(1, "Por favor introduzca su email.")
    .email("The email address is badly formatted."),
  phone: z
    .string()
    .min(1, "Por favor introduzca su teléfono.")
    .min(10, "Tu teléfono debe tener 10 caracteres o más."),
  issue: z.string().min(1, "Por favor introduzca su asunto."),
  message: z
    .string()
    .min(1, "Por favor introduzca su mensaje.")
    .min(8, "Tu mensaje debe tener 8 caracteres o más."),
});

// Also posible infer typos
// type LoginForm = z.infer<typeof loginSchema>;

// can only be declared in `layout.tsx`, `index.tsx` and `plugin.tsx` inside the src/routes directory
export const useFormLoader = routeLoader$<InitialValues<LoginForm>>(() => ({
  name: "",
  email: "",
  phone: "",
  issue: "",
  message: "",
}));

type ResponseData = {
  customerId: string;
};

export const useFormAction = formAction$<LoginForm, ResponseData>(
  async (values) => {
    // Runs on SERVER
    console.log("useFormAction", values);
    try {
      // Create a single supabase client for interacting with your database
      const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
      const { name, email, phone, issue, message } = values;
      const recordID : string = uuidv4();
      const hexNumber : number = 1; // parseInt(recordID.replace(/-/g, ''), 16);
      const { data: customer_form, error } = await supabase
        .from("customer_form")
        .insert([{ id: hexNumber, created_at: new Date(), name, email, phone, issue, message }])
        .select("*");

      console.log("supabase contact form", customer_form, error);
      if (customer_form) {
        console.log("Success supabase contact form", customer_form[0].id);
      }

      if (error) {
        console.log("Error supabase contact form", error);
      }

      return {
        status: "success",
        message: `Gracias, su mensaje ha sido recibido. ${recordID}`,
        data: { customerId: recordID },
      };
    } catch (error) {
      console.error(error);
      return {
        status: "error",
        message: `No se ha podido enviar su mensaje. ${error}`,
        data: { customerId: "" },
      };
    }
  },
  zodForm$(loginSchema),
); // valiForm$(LoginSchema)

export default component$(() => {
  // const nav = useNavigate();

  // , FieldArray
  const [loginForm, { Form, Field }] = useForm<LoginForm, ResponseData>({
    loader: useFormLoader(),
    action: useFormAction(),
    validate: zodForm$(loginSchema),
  });

  const handleSubmit = $<SubmitHandler<LoginForm>>(
    async (values: any, event: any) => {
      // Runs on CLIENT
      console.log("handleSubmit", values, event);
    },
  );

  const successData = $(async () => {
    console.log(
      "handleSubmitSuccess",
      loginForm.submitted,
      loginForm.submitting,
      loginForm.response,
    );
    alert(loginForm.response.message);
    reset(loginForm); // , useFormLoader
    // clearResponse(loginForm);
    // const value = getValue(form, name, options);
    // await nav("/");
  });

  const errorData = $(async () => {
    console.log(
      "handleSubmitError",
      loginForm.submitted,
      loginForm.submitting,
      loginForm.response,
    );
    alert(loginForm.response.message);
  });

  useTask$(({ track }) => {
    track(() => loginForm.response.status);
    if (isServer) {
      return; // Server guard
    }
    if (
      loginForm.submitted &&
      loginForm.submitting === false &&
      loginForm.response.status === "success"
    ) {
      successData();
    } else if (
      loginForm.submitted &&
      loginForm.submitting === false &&
      loginForm.response.status === "error"
    ) {
      errorData();
    }
  });

  return (
    <div class="container container-center flex justify-center" style={{}}>
      <MUIPaper className={styles.cardContactForm} elevation={16}>
        <div class={styles.sheetFormStyle}>
          <MUITypography
            variant="h6"
            color={"var(--qwik-dark-blue)"}
            align="center"
          >
            Formulario de contacto
          </MUITypography>
          <MUITypography variant="body1" className="pt-2 pb-4" align="center">
            Solicita información adicional o una presentación de nuestros
            servicios.
          </MUITypography>
          <Form
            class={styles.formFlex}
            onSubmit$={handleSubmit}
            // preventdefault:submit
            // reloadDocument={true}
          >
            <Field
              name="name"
            >
              {(field, props) => (
                <TextInput
                  {...props}
                  value={field.value}
                  error={field.error}
                  type="text"
                  label="Nombre:"
                  placeholder="Nombre"
                  required
                />
              )}
            </Field>
            <Field
              name="email"
            >
              {(field, props) => (
                <TextInput
                  {...props}
                  value={field.value}
                  error={field.error}
                  type="email"
                  label="Email:"
                  placeholder="Correo electrónico"
                  required
                />
              )}
            </Field>
            <Field
              name="phone"
            >
              {(field, props) => (
                <TextInput
                  {...props}
                  value={field.value}
                  error={field.error}
                  type="tel"
                  label="Teléfono:"
                  placeholder="+57"
                  required
                />
              )}
            </Field>
            <Field
              name="issue"
            >
              {(field, props) => (
                <TextInput
                  {...props}
                  value={field.value}
                  error={field.error}
                  type="text"
                  label="Asunto:"
                  placeholder="Asunto"
                  required
                />
              )}
            </Field>
            <Field
              name="message"
            >
              {(field, props) => (
                <TextInput
                  {...props}
                  value={field.value}
                  error={field.error}
                  type="text"
                  label="Mensaje:"
                  placeholder="Mensaje"
                  required
                />
              )}
            </Field>
            <button
              type="submit"
              class={clsx("mx-3 lg:mx-5", styles.btnStyle)}
            >
              Enviar
            </button>
          </Form>
        </div>
      </MUIPaper>
    </div>
  );
});
Maikpwwq commented 1 year ago

@gioboa I did it

Project Repository Vercel Deployment Vercel Project

Get Code

git clone https://github.com/Maikpwwq/qwik-ssg-modular-forms.git
cd ./qwik-ssg-modular-forms
pnpm i
pnpm run start

Go to Form route through the Link, and tried to send Form.

gioboa commented 1 year ago

Can you try to deploy you app in a different vendor please? eg. Cloudflare It's test is to verify if it's a specific issue of Vercel.

Maikpwwq commented 1 year ago

@gioboa take a look at the capture, the error is related with Qwik generated modules Captura desde 2023-08-25 02-06-19

gioboa commented 1 year ago

@gioboa I did it

Project Repository Vercel Deployment Vercel Project

Get Code

git clone https://github.com/Maikpwwq/qwik-ssg-modular-forms.git
cd ./qwik-ssg-modular-forms
pnpm i
pnpm run start

Go to Form route through the Link, and tried to send Form.

Thanks, anyway a simpler example with only the specific issue will be better. Btw in your repo you have .env vars and this can be a security issue for you, you should remove them

Maikpwwq commented 1 year ago

@gioboa This is a minimal reproduction, abstracted from my main project. I need to solve this issue then I can delete and restore my keys. How to use forms in Qwik? The documentation talks about @modular-forms/qwik I follow the configuration but it still fails. Really I have prove almost everything, serverless functions on Vercel, server$ functions on Qwik, now actions$ and I am a bit frustrated with this.

It works in development mode in production deploy continue failing.

gioboa commented 1 year ago

I will investigate in this issue. hold on

--- UPDATE ---

You are doing SSG. Did you try SSR with Vercel adapter?

mhevery commented 1 year ago

I am really sorry that you are running into issues.

Quick search on DOMException: The operation is insecure Shows this is an issue with FireFox, CORS and HTTPS.

If that is the case, it has nothing to do with Vercel.

The above is the reason why we always ask you to do a minimal reproduction. We get tens of issues every day, we can't look at them all, especially if the reproduction steps are complex involving creating Vercel deployments, only to later realize that it has nothing to do with Vercel and probably has to do with CORS and HTTPs.

We need a simpler reproduction (and I am going to guess that once you have simpler reproduction, you will realize it has nothing to do with Qwik.)

Maikpwwq commented 1 year ago

@gioboa Yes this site use Adapters for SSG. This because Vercel deploy only static content. I first tried with Vercel Edge Functions and also with Vercel server less functions, I couldn't get it to work using the correct URL to connect serverless functions in afetch call.

dev  http://localhost:8888/.netlify/functions/get_contacts/
prod  https://nexasoft.netlify.app/.netlify/functions/get_contacts/

I update minimal repository with changes, those works in preview but in deployed project fails.

mhevery commented 1 year ago

I think the issues you are running into are because you are trying to run server actions (server$ or routeAction$) but don't have an actual server environment that runs JS code.

I don't think this is an issue with Qwik but rather with your setup.

This issue is turning into technical support of your issue rather than a generic issue which would benefit all Qwik users.

Here is what we need from you to help you:

I am going to close this issue; once you have a minimal reproduction that shows a Qwik issue feel free to open a new one.

Maikpwwq commented 1 year ago

@mhevery currently I have created a minimal reproduction in a Qwik empty project, using the static adapter. Take a look first:

Github Project Repository Vercel Project

Get Code

git clone https://github.com/Maikpwwq/qwik-ssg-modular-forms.git
cd ./qwik-ssg-modular-forms
pnpm i
pnpm run start

Take into account I am trying to build just a simple Form in Qwik. I just need to sent it, that's because I am using my keys to access Mongo Or Supabase.

Maikpwwq commented 1 year ago

@mhevery you close it but have not take a look into the minimal reproduction first. Just is this fuck.. page. Is the reason why I ask you to install the dependecies first.

import { component$, $, useTask$ } from "@builder.io/qwik"; // , useSignal
import { isServer } from "@builder.io/qwik/build";
import { createClient } from "@supabase/supabase-js";
// import { v4 as uuidv4 } from 'uuid'
import clsx from "clsx";
import {
  routeLoader$,
  z,
} from "@builder.io/qwik-city";
import type { InitialValues, SubmitHandler } from "@modular-forms/qwik"; //
import {
  useForm,
  formAction$,
  zodForm$,
  reset,
} from "@modular-forms/qwik";
import styles from "~/components/modular-forms/modularForm.module.css";
import { MUITypography, MUIPaper } from "~/integrations/react/mui";
import { TextInput } from "~/components/modular-forms/TextInput";

const SUPABASE_URL = `${import.meta.env.VITE_SUPABASE_URL}`;
const SUPABASE_KEY = `${import.meta.env.VITE_SUPABASE_KEY}`;

type LoginForm = {
  name: string;
  email: string;
  phone: string;
  issue: string;
  message: string;
};

const loginSchema = z.object({
  name: z.string().min(1, "Por favor introduzca su nombre."),
  email: z
    .string()
    .min(1, "Por favor introduzca su email.")
    .email("The email address is badly formatted."),
  phone: z
    .string()
    .min(1, "Por favor introduzca su teléfono.")
    .min(10, "Tu teléfono debe tener 10 caracteres o más."),
  issue: z.string().min(1, "Por favor introduzca su asunto."),
  message: z
    .string()
    .min(1, "Por favor introduzca su mensaje.")
    .min(8, "Tu mensaje debe tener 8 caracteres o más."),
});

// Also posible infer typos
// type LoginForm = z.infer<typeof loginSchema>;

// can only be declared in `layout.tsx`, `index.tsx` and `plugin.tsx` inside the src/routes directory
export const useFormLoader = routeLoader$<InitialValues<LoginForm>>(() => ({
  name: "",
  email: "",
  phone: "",
  issue: "",
  message: "",
}));

type ResponseData = {
  customerId: string;
};

export const useFormAction = formAction$<LoginForm, ResponseData>(
  async (values) => {
    // Runs on SERVER
    console.log("useFormAction", values);
    try {
      // Create a single supabase client for interacting with your database
      const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
      const { name, email, phone, issue, message } = values;
      // const recordID : string = uuidv4();
      // Genera un número aleatorio entre 1 y 1000
      // const hexNumber : number = Math.floor(Math.random() * 1000) + 1; // parseInt(recordID.replace(/-/g, ''), 16);
      const { data: customer_form, error } = await supabase
        .from("customer_form")
        .insert([{ created_at: new Date(), name, email, phone, issue, message }])
        .select("*");

      console.log("supabase contact form", customer_form, error);

      if (error) {
        throw new Error(`Supabase contact: ${error}`);
      }

      if (customer_form) {
        console.log("Success supabase contact form", customer_form[0].id);
      }
      return {
        status: "success",
        message: `Gracias, su mensaje ha sido recibido. ${customer_form[0].id}`,
        data: { customerId: customer_form[0].id.toString() },
      };
    } catch (error) {
      console.error(error);
      return {
        status: "error",
        message: `No se ha podido enviar su mensaje. ${error}`,
        data: { customerId: "" },
      };
    }
  },
  zodForm$(loginSchema),
); // valiForm$(LoginSchema)

export default component$(() => {
  // const nav = useNavigate();

  // , FieldArray
  const [loginForm, { Form, Field }] = useForm<LoginForm, ResponseData>({
    loader: useFormLoader(),
    action: useFormAction(),
    validate: zodForm$(loginSchema),
  });

  const handleSubmit = $<SubmitHandler<LoginForm>>(
    async (values: any, event: any) => {
      // Runs on CLIENT
      console.log("handleSubmit", values, event);
    },
  );

  const successData = $(async () => {
    console.log(
      "handleSubmitSuccess",
      loginForm.submitted,
      loginForm.submitting,
      loginForm.response,
    );
    alert(loginForm.response.message);
    reset(loginForm); // , useFormLoader
    // clearResponse(loginForm);
    // const value = getValue(form, name, options);
    // await nav("/");
  });

  const errorData = $(async () => {
    console.log(
      "handleSubmitError",
      loginForm.submitted,
      loginForm.submitting,
      loginForm.response,
    );
    alert(loginForm.response.message);
  });

  useTask$(({ track }) => {
    track(() => loginForm.response.status);
    if (isServer) {
      return; // Server guard
    }
    if (
      loginForm.submitted &&
      loginForm.submitting === false &&
      loginForm.response.status === "success"
    ) {
      successData();
    } else if (
      loginForm.submitted &&
      loginForm.submitting === false &&
      loginForm.response.status === "error"
    ) {
      errorData();
    }
  });

  return (
    <div class="container container-center flex justify-center" style={{}}>
      <MUIPaper className={styles.cardContactForm} elevation={16}>
        <div class={styles.sheetFormStyle}>
          <MUITypography
            variant="h6"
            color={"var(--qwik-dark-blue)"}
            align="center"
          >
            Formulario de contacto
          </MUITypography>
          <MUITypography variant="body1" className="pt-2 pb-4" align="center">
            Solicita información adicional o una presentación de nuestros
            servicios.
          </MUITypography>
          <Form
            class={styles.formFlex}
            onSubmit$={handleSubmit}
            // preventdefault:submit
            // reloadDocument={true}
          >
            <Field
              name="name"
            >
              {(field, props) => (
                <TextInput
                  {...props}
                  value={field.value}
                  error={field.error}
                  type="text"
                  label="Nombre:"
                  placeholder="Nombre"
                  required
                />
              )}
            </Field>
            <Field
              name="email"
            >
              {(field, props) => (
                <TextInput
                  {...props}
                  value={field.value}
                  error={field.error}
                  type="email"
                  label="Email:"
                  placeholder="Correo electrónico"
                  required
                />
              )}
            </Field>
            <Field
              name="phone"
            >
              {(field, props) => (
                <TextInput
                  {...props}
                  value={field.value}
                  error={field.error}
                  type="tel"
                  label="Teléfono:"
                  placeholder="+57"
                  required
                />
              )}
            </Field>
            <Field
              name="issue"
            >
              {(field, props) => (
                <TextInput
                  {...props}
                  value={field.value}
                  error={field.error}
                  type="text"
                  label="Asunto:"
                  placeholder="Asunto"
                  required
                />
              )}
            </Field>
            <Field
              name="message"
            >
              {(field, props) => (
                <TextInput
                  {...props}
                  value={field.value}
                  error={field.error}
                  type="text"
                  label="Mensaje:"
                  placeholder="Mensaje"
                  required
                />
              )}
            </Field>
            <button
              type="submit"
              class={clsx("mx-3 lg:mx-5", styles.btnStyle)}
            >
              Enviar
            </button>
          </Form>
        </div>
      </MUIPaper>
    </div>
  );
});
mhevery commented 1 year ago

@Maikpwwq I am sorry you are having trouble with this. But please understand that we get a lot of requests and need to focus on actually fixing issues with Qwik.

(Here is an example of clear reproduction, few lines, no dependencies, stack blitz link.)

So I am really sorry, but we just don't have the time to debug your application.

Maikpwwq commented 1 year ago

@mhevery This in not a full application, just a starter template of Qwik, that tried to implement basically a Contact Form following the official documentation of Qwik and @modular-forms/qwik. then I am uploading credentials so is really easy to recreate just clone and run. Finally I update repository to disable SSG, replacing it with Vercel Edge Adapter. Again everything works in local but do not in production.

mhevery commented 1 year ago

If I go to https://vercel.com/maikpwwq/qwik-app I get 404. Where can I see the app running?

Maikpwwq commented 1 year ago

@mhevery try with https://qwik-app-psi-sable.vercel.app/

mhevery commented 1 year ago
  1. I navigated to https://qwik-app-psi-sable.vercel.app/customer-record/
  2. Filled out the form
  3. Hit submit

Everything worked, I saw no errors.

Maikpwwq commented 1 year ago

It throws not errors but doesn't complete my server call to supabase, as it does in my local. For that reason return that message: Gracias, su mensaje ha sido recibido. [object Promise] with [object Promise] instead value of the transaction id.

I can store data in my local correctly, but when I deploy doesn't works anymore.

mhevery commented 1 year ago

I think this may have resolved it. https://github.com/BuilderIO/qwik/pull/5041