Last active
April 26, 2023 14:25
-
-
Save HectorBlisS/d9ca9a64e42c356cb48a16e3ed950691 to your computer and use it in GitHub Desktop.
Youtube_forgot_password
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export const action: ActionFunction = async ({ request }) => { | |
const url = new URL(request.url); | |
const session = await getSession(request.headers.get("Cookie")); | |
const formData = await request.formData(); | |
const intent = formData.get("intent"); | |
const token = url.searchParams.get("token"); | |
const tokenResult = await verifyToken(token); | |
if (intent === "forgot-email") { | |
const email = formData.get("email") as string; | |
const exists = await db.user.findUnique({ | |
where: { | |
email, | |
}, | |
}); | |
if (!exists) { | |
return { ok: false, error: "Email not found" }; | |
} | |
// if so, send email with token | |
sendResetPassword(email as string); | |
return { ok: true, showEmailSent: true }; | |
} | |
if (intent === "update-password") { | |
if (!tokenResult.isValid || !tokenResult.email) { | |
return { | |
ok: false, | |
error: "Invalid or expired token. Get a new email", | |
errorCode: 666, | |
}; | |
} | |
const password = formData.get("password"); | |
if (!password) return { ok: false, error: "No password sent" }; | |
const validate = passwordSchema.safeParse(password); | |
if (!validate.success) return { ok: false, error: "Invalid password" }; | |
// hash password | |
const hash = await hashPass(password as string); | |
const user = await db.user.update({ | |
where: { | |
email: tokenResult.email, | |
}, | |
data: { | |
hashString: hash, | |
}, | |
}); | |
// save cookie // redirect to apps | |
session.set("userId", user.id); | |
return redirect("/apps", { | |
headers: { | |
"Set-Cookie": await commitSession(session, { | |
expires: new Date("2050-12-12"), | |
}), | |
}, | |
}); | |
} | |
return null; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var regularExpression = | |
/^(?=.*[0-9])(?=.*[!@#$%^&*])[a-zA-Z0-9!@#$%^&*]{6,16}$/; | |
const passwordSchema = z.string().regex(regularExpression); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export const EmailForm = ({ | |
isLoading, | |
error, | |
}: { | |
isLoading?: boolean; | |
error?: string | null; | |
}) => ( | |
<section> | |
<FeedbugDialog | |
isOpen={true} | |
onClose={() => false} | |
footer={null} | |
title={ | |
<> | |
<img | |
alt="logo" | |
src={`/assets/logo-sticky.png`} | |
className="w-[50%] rounded-lg mb-8 mx-auto" | |
/> | |
<h2 className="text-[#333333] text-4xl font-bold my-4"> | |
<strong className="text-[#4966f6]">Enter your</strong> email | |
</h2> | |
<p className="text-[#888888] text-xl font-thin mb-8"> | |
Get the instructions in your email. | |
</p> | |
</> | |
} | |
> | |
<Form method="post" className="flex flex-col"> | |
<TextField | |
isDisabled={false} | |
name="email" | |
type="email" | |
placeholder="Email" | |
/> | |
<p className="text-red-500 text-sm px-4 mb-2">{error}</p> | |
<FormButton | |
isLoading={isLoading} | |
name="intent" | |
value="forgot-email" | |
type="submit" | |
> | |
Restore my password | |
</FormButton> | |
</Form> | |
<Link | |
to="/" | |
className="text-center text-xs pt-4 block text-brand-500 hover:text-brand-400 " | |
> | |
Did you remember your password? | |
</Link> | |
</FeedbugDialog> | |
</section> | |
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export default function Forgot() { | |
const { show } = useLoaderData<loaderData>(); | |
const actionData = useActionData(); | |
const transition = useTransition(); | |
const [error, setError] = useState(null); | |
useEffect(() => { | |
console.log("Action", actionData); | |
if (actionData?.error) { | |
setError(actionData.error); | |
} | |
}, [actionData]); | |
const form = | |
show === "input" ? ( | |
<> | |
<PasswordForm isLoading={transition.state !== "idle"} error={error} /> | |
</> | |
) : ( | |
<EmailForm isLoading={transition.state !== "idle"} error={error} /> | |
); | |
return ( | |
<> | |
<section className="flex min-h-screen bg-gradient-to-r from-brand-500 to-violet-500"></section> | |
{actionData?.showEmailSent ? <SentMessage /> : form} | |
</> | |
); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
type LoaderFunction, | |
type ActionFunction, | |
redirect, | |
} from "@remix-run/node"; | |
import { | |
Form, | |
Link, | |
useActionData, | |
useLoaderData, | |
useTransition, | |
} from "@remix-run/react"; | |
import { useState, type FormEventHandler, useEffect } from "react"; | |
import { z } from "zod"; | |
import Dialog from "Cualquier dialog que tu ocupes yo uso el de headless ui"; | |
import { FormButton, TextField } from "Estos componentes también son mios pero cualquier input y form funcionan"; | |
import { db } from "~/db/db.server"; | |
import { hashPass, verifyToken } from "~/utils/tokens <= Estas funciónes también te la regalo"; | |
import { commitSession, getSession } from "~/sessions"; | |
import { sendResetPassword } from "~/utils/emailSenders"; // este es mi email sender, también te lo regalo | |
import bcrypt from "bcrypt"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type loaderData = { | |
show: "input" | "email"; | |
ok?: boolean; | |
}; | |
export const loader: LoaderFunction = async ({ request, params }) => { | |
const url = new URL(request.url); | |
const token = url.searchParams.get("token"); | |
// validate token | |
const result = await verifyToken(token); | |
if (result.isValid) { | |
return { | |
ok: true, | |
show: "input", | |
}; | |
} | |
return { show: "email" }; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export const SentMessage = () => ( | |
<FeedbugDialog | |
isOpen={true} | |
onClose={() => false} | |
footer={null} | |
title={ | |
<> | |
<img | |
alt="logo" | |
src={`/assets/logo-sticky.png`} | |
className="w-[50%] rounded-lg mb-8 mx-auto" | |
/> | |
<h2 className="text-[#333333] text-4xl font-bold my-4"> | |
<strong className="text-[#4966f6]">Check your </strong>email | |
</h2> | |
<p className="text-[#888888] text-lg font-thin mb-8"> | |
We've sent the instructions to reset your password to your email | |
</p> | |
</> | |
} | |
> | |
<Link | |
to="/" | |
className="text-center text-xs pt-4 block text-brand-500 hover:text-brand-400 " | |
> | |
Go back | |
</Link> | |
</FeedbugDialog> | |
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export const PasswordForm = ({ | |
onSubmit, | |
isLoading, | |
error, | |
}: { | |
isLoading?: boolean; | |
error?: string | null; | |
onSubmit?: (arg0: FormEventHandler<HTMLFormElement>) => void; | |
}) => ( | |
<section> | |
<FeedbugDialog | |
isOpen={true} | |
onClose={() => false} | |
footer={null} | |
title={ | |
<> | |
<img | |
alt="logo" | |
src={`/assets/logo-sticky.png`} | |
className="w-[50%] rounded-lg mb-8 mx-auto" | |
/> | |
<h2 className="text-[#333333] text-4xl font-bold my-4"> | |
<strong className="text-[#4966f6]">Enter your new</strong> password | |
</h2> | |
<p className="text-[#888888] text-lg font-thin mb-8"> | |
Remember to use 6 characters 1 number, 1 special character and 1 | |
case letter. | |
</p> | |
</> | |
} | |
> | |
<Form method="post" className="flex flex-col"> | |
<TextField | |
isDisabled={false} | |
name="password" | |
type="password" | |
placeholder="New password" | |
/> | |
<p className="text-red-500 text-sm px-4 mb-2">{error}</p> | |
<FormButton isLoading={isLoading} name="intent" value="update-password"> | |
Reset my password | |
</FormButton> | |
</Form> | |
<Link | |
to="/" | |
className="text-center text-xs pt-4 block text-brand-500 hover:text-brand-400 " | |
> | |
Did you remember your password? | |
</Link> | |
</FeedbugDialog> | |
</section> | |
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import jwt from "jsonwebtoken"; | |
const KEY = process.env.TOKEN_SECRET ?? "fixtergeek.com"; | |
export const verifyToken = async ( | |
token: string | null | undefined | |
): Promise<{ isValid: boolean; error?: any; email?: string }> => { | |
if (!token) return { isValid: false }; | |
try { | |
return { | |
...jwt.verify(token, KEY), | |
isValid: true, | |
}; | |
} catch (e) { | |
return { isValid: false, error: e }; | |
} | |
}; | |
const compareHash = async (password: string, hash: string) => { | |
return await bcrypt.compare(password, hash); | |
}; | |
export const hashPass = async (password: string) => { | |
const saltRounds = 10; | |
return await bcrypt.hash(password, saltRounds); | |
}; | |
export const genTokenWithEmail = (email: string) => { | |
return jwt.sign( | |
{ | |
email, | |
}, | |
KEY, | |
{ expiresIn: "12h" } | |
); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment