Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ASUB-8193 Adding reCaptchav3 #1990

Closed
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions blocks/identity-block/_index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,35 @@
.b-login-form {
@include scss.block-components("login-form");
@include scss.block-properties("login-form");
&__bot-protection-section {
@include scss.block-components("login-form-bot-protection-section");
@include scss.block-properties("login-form-bot-protection-section");
}
&__privacy-statement {
@include scss.block-components("login-form-privacy-statement");
@include scss.block-properties("login-form-privacy-statement");
}
&__sign-up-div {
@include scss.block-components("login-form-sign-up-div");
@include scss.block-properties("login-form-sign-up-div");
}
&__sign-up-button {
@include scss.block-components("login-form-sign-up-button");
@include scss.block-properties("login-form-sign-up-button");
}
&__login-form-error {
@include scss.block-components("login-form-error");
@include scss.block-properties("login-form-error");
}
}

.b-login-links {
@include scss.block-components("login-links");
@include scss.block-properties("login-links");
&__inner-link {
@include scss.block-components("login-links-inner-link");
@include scss.block-properties("login-links-inner-link");
}
}

.b-reset-password {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from "react";
import { useIdentity } from "@wpmedia/arc-themes-components";
import useRecaptcha, { RECAPTCHA_V2, RECAPTCHA_V3 } from "../../utils/useRecaptcha";
import ReCAPTCHA from "react-google-recaptcha";
import { GoogleReCaptchaProvider } from "react-google-recaptcha-v3";
import RecaptchaV3 from "./reCaptchaV3";

const BotChallengeProtection = ({ challengeIn, setCaptchaToken, className, resetRecaptcha }) => {
const { isInitialized } = useIdentity();
const { recaptchaVersion, siteKey, isRecaptchaEnabled } = useRecaptcha(challengeIn);

const onChange = (value) => {
setCaptchaToken(value);
localStorage.setItem("captchaToken", value);
};

if (!isInitialized) {
return null;
}

if (isRecaptchaEnabled && !!siteKey && !!recaptchaVersion) {
if (recaptchaVersion === RECAPTCHA_V2) {
return (
<section
className={`${className}__bot-protection-section`}
data-testid="bot-challege-protection-container"
>
<ReCAPTCHA sitekey={siteKey} onChange={onChange} />
</section>
);
}
if (recaptchaVersion === RECAPTCHA_V3) {
return (
<GoogleReCaptchaProvider reCaptchaKey={siteKey} scriptProps={{ async: true }}>
<RecaptchaV3 setCaptchaToken={setCaptchaToken} resetRecaptcha={resetRecaptcha} />
</GoogleReCaptchaProvider>
);
}
} else {
return null;
}
};

export default BotChallengeProtection;
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { useEffect, useCallback } from "react";
import { useGoogleReCaptcha } from "react-google-recaptcha-v3";

const RecaptchaV3 = ({ setCaptchaToken, resetRecaptcha }) => {
const { executeRecaptcha } = useGoogleReCaptcha();

const handleReCaptcha3Verify = useCallback(async () => {
if (!executeRecaptcha) {
console.log("ArcXP - Execute recaptcha not yet available");
return;
}
const token = await executeRecaptcha();
setCaptchaToken(token);
localStorage.setItem("captchaToken", token);
}, [executeRecaptcha]);

useEffect(() => {
handleReCaptcha3Verify();
}, [executeRecaptcha, resetRecaptcha]);

return null;
};

export default RecaptchaV3;
4 changes: 2 additions & 2 deletions blocks/identity-block/features/login-links/default.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from "react";
import PropTypes from "@arc-fusion/prop-types";
import { useFusionContext } from "fusion:context";
import getTranslatedPhrases from "fusion:intl";
import { Link, Stack } from "@wpmedia/arc-themes-components";
import { Link, Paragraph, Stack } from "@wpmedia/arc-themes-components";

const BLOCK_CLASS_NAME = "b-login-links";
const defaultLoginURL = "/account/login/";
Expand Down Expand Up @@ -35,7 +35,7 @@ const LoginLinks = ({ customFields }) => {
<Link href={forgotURL}>{phrases.t("identity-block.login-links-forgot")}</Link>
) : null}
{showSignUp ? (
<Link href={signUpURL}>{phrases.t("identity-block.login-links-signup")}</Link>
<Paragraph>{phrases.t("identity-block.login-links-signup")}<Link href={signUpURL} className={`${BLOCK_CLASS_NAME}__inner-link`}>{phrases.t("identity-block.sign-up-natural")}</Link></Paragraph>
) : null}
</Stack>
);
Expand Down
68 changes: 54 additions & 14 deletions blocks/identity-block/features/login/default.jsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
import React, { useState, useEffect } from "react";
import React, { useState } from "react";
import PropTypes from "@arc-fusion/prop-types";
import { useFusionContext } from "fusion:context";
import getProperties from "fusion:properties";
import getTranslatedPhrases from "fusion:intl";
import { Input, useIdentity } from "@wpmedia/arc-themes-components";
import { Input, useIdentity, Paragraph } from "@wpmedia/arc-themes-components";
import HeadlinedSubmitForm from "../../components/headlined-submit-form";
import useLogin from "../../components/login";
import BotChallengeProtection from "../../components/bot-challenge-protection";
import useOIDCLogin from "../../utils/useOIDCLogin";
import validateURL from "../../utils/validate-redirect-url";
import { RECAPTCHA_LOGIN } from "../../utils/useRecaptcha";

const BLOCK_CLASS_NAME = "b-login-form";

export function definedMessageByCode(code) {
return errorCodes[code] || errorCodes["0"];
}

const errorCodes = {
100015: "identity-block.login-form-error.account-is-disabled",
130001: "identity-block.login-form-error.captcha-token-invalid",
130051: "identity-block.login-form-error.unverified-email-address",
100013: "identity-block.login-form-error.max-devices",
0: "identity-block.login-form-error.invalid-email-password",
};

const Login = ({ customFields }) => {
const { redirectURL, redirectToPreviousPage, loggedInPageLocation, OIDC } = customFields;

Expand All @@ -21,8 +35,13 @@ const Login = ({ customFields }) => {
const { locale } = getProperties(arcSite);
const phrases = getTranslatedPhrases(locale);

const isOIDC = OIDC && url.searchParams.get("client_id") && url.searchParams.get("response_type") === "code";
const isOIDC =
OIDC && url.searchParams.get("client_id") && url.searchParams.get("response_type") === "code";
const { Identity, isInitialized } = useIdentity();

const [captchaToken, setCaptchaToken] = useState();
const [resetRecaptcha, setResetRecaptcha] = useState(false);

const [error, setError] = useState();
const { loginRedirect } = useLogin({
isAdmin,
Expand All @@ -41,24 +60,35 @@ const Login = ({ customFields }) => {
<HeadlinedSubmitForm
buttonLabel={phrases.t("identity-block.log-in")}
className={BLOCK_CLASS_NAME}
formErrorText={error}
headline={phrases.t("identity-block.log-in")}
onSubmit={({ email, password }) =>
Identity.login(email, password, {rememberMe: true})
headline={phrases.t("identity-block.log-in-headline")}
onSubmit={({ email, password }) => {
Identity.login(email, password, {
rememberMe: true,
recaptchaToken: captchaToken,
})
.then(() => {
if (isOIDC) {
loginByOIDC();
} else {
const validatedURL = validateURL(loginRedirect);
window.location = validatedURL;
}
setResetRecaptcha(false);
})
.catch(() => setError(phrases.t("identity-block.login-form-error")))
}
.catch((error) => {
setError(phrases.t(definedMessageByCode(error.code)));
setResetRecaptcha(true);
});
}}
>
{error ? (
<div className={`${BLOCK_CLASS_NAME}__login-form-error`}>
<Paragraph>{error}</Paragraph>
</div>
) : null}
<Input
autoComplete="email"
label={phrases.t("identity-block.email")}
label={phrases.t("identity-block.email-label")}
name="email"
required
showDefaultError={false}
Expand All @@ -73,6 +103,15 @@ const Login = ({ customFields }) => {
showDefaultError={false}
type="password"
/>
<BotChallengeProtection
className={BLOCK_CLASS_NAME}
challengeIn={RECAPTCHA_LOGIN}
setCaptchaToken={setCaptchaToken}
resetRecaptcha={resetRecaptcha}
/>
<Paragraph className={`${BLOCK_CLASS_NAME}__privacy-statement`}>
{phrases.t("identity-block.privacy-statement")}
</Paragraph>
</HeadlinedSubmitForm>
);
};
Expand All @@ -98,10 +137,11 @@ Login.propTypes = {
"The URL to which a user would be redirected to if visiting a login page when already logged in.",
}),
OIDC: PropTypes.bool.tag({
name: 'Login with OIDC',
defaultValue: false,
description: 'Used when authenticating a third party site with OIDC PKCE flow. This will use an ArcXp Org as an auth provider',
}),
name: "Login with OIDC",
defaultValue: false,
description:
"Used when authenticating a third party site with OIDC PKCE flow. This will use an ArcXp Org as an auth provider",
}),
}),
};

Expand Down
29 changes: 28 additions & 1 deletion blocks/identity-block/intl.json
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@
"bn": "কোনো অ্যাকাউন্ট নেই?\nসাইন আপ করুন",
"bo": "ཁྱེད་ལ་དྲ་གྲངས་མེད་དམ། ཐོ་འགོད།",
"de": "Sign up for an account.",
"en": "Don't have an account? Sign up",
"en": "Need to create an account? ",
"es": "Sign up for an account.",
"fr": "Sign up for an account.",
"id": "Belum memiliki akun? Daftar",
Expand Down Expand Up @@ -1273,5 +1273,32 @@
"vi": "Tên người dùng",
"zh-CN": "用户名",
"zh-TW": "使用者名稱"
},
"identity-block.email-label": {
"en": "Email"
},
"identity-block.log-in-headline": {
"en": "Log in to your account"
},
"identity-block.login-form-error.account-is-disabled": {
"en": "Account is disabled."
},
"identity-block.login-form-error.captcha-token-invalid": {
"en": "Captcha token invalid."
},
"identity-block.login-form-error.unverified-email-address": {
"en": "Email Address is not verified."
},
"identity-block.login-form-error.max-devices": {
"en": "User account has reached the max number of devices."
},
"identity-block.login-form-error.invalid-email-password": {
"en": "Email or password is invalid. Try again."
},
"identity-block.privacy-statement": {
"en": "By creating an account, you agree to the Terms of Service and acknowledge our Privacy Policy."
},
"identity-block.sign-up-natural": {
"en": "Sign up"
}
}
Loading
Loading