From b25eb17f541e3707feb8f099874470910a83c13c Mon Sep 17 00:00:00 2001 From: Bikash Date: Mon, 30 Sep 2024 14:20:35 +0545 Subject: [PATCH] added google recaptcha in auth --- Taskfile.yaml | 10 ++--- lib/app-setup/root.tsx | 1 + .../{components => helpers}/g-recaptcha.tsx | 4 +- src/apps/auth/components/footer.tsx | 8 ++-- src/apps/auth/consts.tsx | 1 + src/apps/auth/root.tsx | 37 +++++++++++++++++++ .../auth/routes/_main+/forgot-password.tsx | 7 ++++ src/apps/auth/routes/_providers+/login.tsx | 9 ++++- src/apps/auth/routes/_providers+/signup.tsx | 11 ++++-- src/design-system/index.css | 5 +++ 10 files changed, 78 insertions(+), 15 deletions(-) rename lib/client/{components => helpers}/g-recaptcha.tsx (89%) diff --git a/Taskfile.yaml b/Taskfile.yaml index 7f1e20127..f33ce8ae1 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -66,14 +66,14 @@ tasks: cp -r ./static/{{.app}}/. ./public/ case "{{.tscheck}}" in - "no") - GATEWAY_URL=$GATEWAY_URL URL_SUFFIX=$URL_SUFFIX APP={{.app}} PORT=$PORT BASE_URL=$BASE_URL REMIX_DEV_ORIGIN=$REMIX_DEV_ORIGIN DEVELOPER=$(whoami) pnpm dev - ;; - - *) + "yes") GATEWAY_URL=$GATEWAY_URL URL_SUFFIX=$URL_SUFFIX APP={{.app}} PORT=$PORT BASE_URL=$BASE_URL REMIX_DEV_ORIGIN=$REMIX_DEV_ORIGIN DEVELOPER=$(whoami) pnpm dev & pnpm typecheck ;; + *) + GATEWAY_URL=$GATEWAY_URL URL_SUFFIX=$URL_SUFFIX APP={{.app}} PORT=$PORT BASE_URL=$BASE_URL REMIX_DEV_ORIGIN=$REMIX_DEV_ORIGIN DEVELOPER=$(whoami) pnpm dev + ;; + esac diff --git a/lib/app-setup/root.tsx b/lib/app-setup/root.tsx index f959a4f38..1cd9ca13b 100644 --- a/lib/app-setup/root.tsx +++ b/lib/app-setup/root.tsx @@ -34,6 +34,7 @@ import Page404 from '~/components/organisms/page-404'; import { getClientEnv, getServerEnv } from '~/root/lib/configs/base-url.cjs'; import { useDataFromMatches } from '../client/hooks/use-custom-matches'; import { TooltipContainer } from '~/components/atoms/tooltipV2'; +import { RECAPTCHA_SITE_KEY } from '~/auth/consts'; export const links: LinksFunction = () => [ { rel: 'stylesheet', href: stylesUrl }, diff --git a/lib/client/components/g-recaptcha.tsx b/lib/client/helpers/g-recaptcha.tsx similarity index 89% rename from lib/client/components/g-recaptcha.tsx rename to lib/client/helpers/g-recaptcha.tsx index c83ef7547..06a8ac84a 100644 --- a/lib/client/components/g-recaptcha.tsx +++ b/lib/client/helpers/g-recaptcha.tsx @@ -2,7 +2,7 @@ declare global { interface Window { grecaptcha: { enterprise: { - ready: (callback: Promise) => void; + ready: (callback: () => Promise) => void; execute: ( sitekey: string, action: { @@ -14,7 +14,7 @@ declare global { } } -export const onReady = (callback: Promise) => { +export const onReady = (callback: () => Promise) => { if ( !window.grecaptcha || !window.grecaptcha.enterprise || diff --git a/src/apps/auth/components/footer.tsx b/src/apps/auth/components/footer.tsx index e1d8fd29d..7fa2105fb 100644 --- a/src/apps/auth/components/footer.tsx +++ b/src/apps/auth/components/footer.tsx @@ -36,15 +36,15 @@ const menu = [ }, { title: 'Changelog', - to: '/', + to: 'https://github.com/kloudlite/kloudlite/releases', }, { title: 'Pricing', - to: '/', + to: `${mainUrl}/pricing`, }, { title: 'Legal', - to: '/', + to: `${mainUrl}/legal/privacy-policy`, }, ]; @@ -71,7 +71,7 @@ const Footer = () => {
- + diff --git a/src/apps/auth/consts.tsx b/src/apps/auth/consts.tsx index 21fca516f..0f5ecd9c6 100644 --- a/src/apps/auth/consts.tsx +++ b/src/apps/auth/consts.tsx @@ -1 +1,2 @@ export const mainUrl = 'https://kloudlite.io'; +export const RECAPTCHA_SITE_KEY = '6LcxXUIqAAAAABtRW-S7Bov6z9PgUHhbNWjTLhND'; diff --git a/src/apps/auth/root.tsx b/src/apps/auth/root.tsx index 961134aa3..e4ce4ce3f 100644 --- a/src/apps/auth/root.tsx +++ b/src/apps/auth/root.tsx @@ -2,6 +2,10 @@ import Root, { links as baseLinks } from '~/lib/app-setup/root.jsx'; import { ChildrenProps } from '~/components/types'; import ThemeProvider from '~/root/lib/client/hooks/useTheme'; import authStylesUrl from './styles/index.css'; +import { RECAPTCHA_SITE_KEY } from './consts'; +import { useEffect } from 'react'; +import { useLocation } from '@remix-run/react'; +import grecaptcha from '~/root/lib/client/helpers/g-recaptcha'; export { loader } from '~/lib/app-setup/root.jsx'; export { shouldRevalidate } from '~/lib/app-setup/root.jsx'; @@ -13,6 +17,39 @@ export const links = () => { export { ErrorBoundary } from '~/lib/app-setup/root'; const Layout = ({ children }: ChildrenProps) => { + const { pathname, search } = useLocation(); + const hideCaptcha = () => { + let x = document.querySelector('.grecaptcha-badge') as HTMLDivElement; + if (x) { + if ( + (pathname.startsWith('/signup') && search === '?mode=email') || + (pathname.startsWith('/login') && search === '?mode=email') || + pathname.startsWith('/forgot-password') + ) { + x.style.setProperty('display', 'block', 'important'); + x.style.setProperty('visibility', 'visible'); + } else { + x.style.display = 'none'; + x.style.setProperty('visibility', 'hidden'); + } + } + }; + useEffect(() => { + const script = document.createElement('script'); + script.async = true; + script.src = `https://www.google.com/recaptcha/enterprise.js?render=${RECAPTCHA_SITE_KEY}`; + script.onload = () => { + grecaptcha.onReady(async () => { + hideCaptcha(); + }); + }; + document.head.appendChild(script); + }, []); + + useEffect(() => { + hideCaptcha(); + }, [pathname, search]); + return ( // // eslint-disable-next-line react/jsx-no-useless-fragment diff --git a/src/apps/auth/routes/_main+/forgot-password.tsx b/src/apps/auth/routes/_main+/forgot-password.tsx index 7a6b9b5f7..6f3422743 100644 --- a/src/apps/auth/routes/_main+/forgot-password.tsx +++ b/src/apps/auth/routes/_main+/forgot-password.tsx @@ -9,6 +9,8 @@ import { handleError } from '~/root/lib/utils/common'; import { useAuthApi } from '~/auth/server/gql/api-provider'; import { ArrowRight } from '~/components/icons'; import Container from '../../components/container'; +import grecaptcha from '~/root/lib/client/helpers/g-recaptcha'; +import { RECAPTCHA_SITE_KEY } from '~/auth/consts'; const ForgetPassword = () => { const api = useAuthApi(); @@ -21,8 +23,13 @@ const ForgetPassword = () => { }), onSubmit: async (val) => { try { + const token = await grecaptcha.execute(RECAPTCHA_SITE_KEY, { + action: 'login', + }); const { errors: e } = await api.requestResetPassword({ email: val.email, + //@ts-ignore + token, }); if (e) { throw e[0]; diff --git a/src/apps/auth/routes/_providers+/login.tsx b/src/apps/auth/routes/_providers+/login.tsx index 957771c1e..4687e54f8 100644 --- a/src/apps/auth/routes/_providers+/login.tsx +++ b/src/apps/auth/routes/_providers+/login.tsx @@ -20,6 +20,8 @@ import Yup from '~/root/lib/server/helpers/yup'; import { handleError } from '~/root/lib/utils/common'; import Container from '../../components/container'; import { IProviderContext } from './_layout'; +import grecaptcha from '~/root/lib/client/helpers/g-recaptcha'; +import { RECAPTCHA_SITE_KEY } from '~/auth/consts'; const CustomGoogleIcon = (props: any) => { return ; @@ -41,14 +43,19 @@ const LoginWithEmail = () => { }), onSubmit: async (v) => { try { + const token = await grecaptcha.execute(RECAPTCHA_SITE_KEY, { + action: 'login', + }); const { errors: _errors } = await api.login({ email: v.email, password: v.password, + //@ts-ignore + token, }); if (_errors) { throw _errors[0]; } - toast.success('logged in success fully'); + toast.success('Logged in successfully'); const callback = searchParams.get('callback'); if (callback) { diff --git a/src/apps/auth/routes/_providers+/signup.tsx b/src/apps/auth/routes/_providers+/signup.tsx index b37536703..72e9f8b60 100644 --- a/src/apps/auth/routes/_providers+/signup.tsx +++ b/src/apps/auth/routes/_providers+/signup.tsx @@ -19,9 +19,10 @@ import { useAPIClient } from '~/root/lib/client/hooks/api-provider'; import { handleError } from '~/root/lib/utils/common'; import { ArrowLeft, ArrowRight } from '~/components/icons'; import { cn } from '~/components/utils'; -import { mainUrl } from '~/auth/consts'; +import { RECAPTCHA_SITE_KEY, mainUrl } from '~/auth/consts'; import Container from '../../components/container'; import { IProviderContext } from './_layout'; +import grecaptcha from '~/root/lib/client/helpers/g-recaptcha'; const CustomGoogleIcon = (props: any) => { return ; @@ -47,10 +48,14 @@ const SignUpWithEmail = () => { }), onSubmit: async (v) => { try { + const token = await grecaptcha.execute(RECAPTCHA_SITE_KEY, { + action: 'login', + }); const { errors: _errors } = await api.signUpWithEmail({ email: v.email, name: v.name, password: v.password, + token, }); if (_errors) { throw _errors[0]; @@ -229,7 +234,7 @@ const Signup = () => {