From dd9f8b362d4ce5dd74c3e3e49490f1a54179b22b Mon Sep 17 00:00:00 2001 From: Pranav Kanade Date: Tue, 8 Jun 2021 11:10:11 +0530 Subject: [PATCH] [Feature #3379] Added recaptcha for signup (#4701) * temp commit * using onsubmit to continue using action on form * added recaptcha site key to env example file * moved the recaptcha lib loading logic to signup page * removed unnecessary edit * handle the case where the recaptcha token is not provided as env var * added proper env var config for client * recaptcha config for ansible * recaptcha config for heroku * recaptcha config for k8s * updated app.json * fixed the typos * added more description for env vars * removed api key * minor typo fix --- .env.example | 7 ++- app.json | 15 ++++++ .../docker/templates/nginx-app.conf.template | 1 + app/client/netlify.toml | 1 + app/client/public/index.html | 3 +- app/client/src/configs/index.ts | 12 +++++ app/client/src/configs/types.ts | 4 ++ app/client/src/pages/UserAuth/SignUp.tsx | 47 ++++++++++++++++++- .../appsmith_playbook/appsmith-vars.yml | 3 ++ .../generate_template/templates/docker.env.j2 | 6 +++ .../templates/nginx-app.conf.j2 | 6 +++ deploy/heroku/README.MD | 4 ++ deploy/heroku/bootstrap.sh | 6 +++ deploy/heroku/default.conf.template | 3 ++ deploy/k8s/scripts/appsmith-configmap.yaml.sh | 3 ++ deploy/k8s/scripts/nginx-configmap.yaml | 3 ++ deploy/template/docker.env.sh | 6 +++ deploy/template/nginx_app.conf.sh | 6 +++ 18 files changed, 132 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index a98011bb3d..6dfdfab187 100644 --- a/.env.example +++ b/.env.example @@ -57,4 +57,9 @@ APPSMITH_MAIL_SMTP_TLS_ENABLED= #APPSMITH_SENTRY_ENVIRONMENT= # Configure cloud services -# APPSMITH_CLOUD_SERVICES_BASE_URL="https://release-cs.appsmith.com" \ No newline at end of file +# APPSMITH_CLOUD_SERVICES_BASE_URL="https://release-cs.appsmith.com" + +# Google Recaptcha Config +APPSMITH_RECAPTCHA_SITE_KEY= +APPSMITH_RECAPTCHA_SECRET_KEY= +APPSMITH_RECAPTCHA_ENABLED= \ No newline at end of file diff --git a/app.json b/app.json index d6bf73c26b..1a1fb89536 100644 --- a/app.json +++ b/app.json @@ -98,6 +98,21 @@ "value": "", "required": false }, + "APPSMITH_RECAPTCHA_SITE_KEY": { + "description" : "Google reCAPTCHA v3 site key, it is required if you wish to enable protection against spam/abusive users. Read more at: https://developers.google.com/recaptcha/docs/v3", + "value": "", + "required": false + }, + "APPSMITH_RECAPTCHA_SECRET_KEY": { + "description" : "Google reCAPTCHA v3 verification secret key, it is required if you wish to enable spam protection in your backend server.", + "value": "", + "required": false + }, + "APPSMITH_RECAPTCHA_ENABLED": { + "description" : "Boolean config to enable or disable Google reCAPTCHA v3 verification feature. If set to true, both site key and secret key should be provided.", + "value": "", + "required": false + }, "APPSMITH_DISABLE_TELEMETRY": { "description" : "We want to be transparent and request that you share anonymous usage data with us. This data is purely statistical in nature and helps us understand your needs & provide better support to your self-hosted instance. You can read more about what information is collected in our documentation https://docs.appsmith.com/v/v1.2.1/setup/telemetry", "value": "false" diff --git a/app/client/docker/templates/nginx-app.conf.template b/app/client/docker/templates/nginx-app.conf.template index 4b7c5fdf4e..6b8ed93474 100644 --- a/app/client/docker/templates/nginx-app.conf.template +++ b/app/client/docker/templates/nginx-app.conf.template @@ -48,6 +48,7 @@ server { sub_filter __APPSMITH_MAIL_ENABLED__ '${APPSMITH_MAIL_ENABLED}'; sub_filter __APPSMITH_DISABLE_TELEMETRY__ '${APPSMITH_DISABLE_TELEMETRY}'; sub_filter __APPSMITH_CLOUD_SERVICES_BASE_URL__ '${APPSMITH_CLOUD_SERVICES_BASE_URL}'; + sub_filter __APPSMITH_RECAPTCHA_SITE_KEY__ '${APPSMITH_RECAPTCHA_SITE_KEY}'; } location /f { diff --git a/app/client/netlify.toml b/app/client/netlify.toml index 3bb6abd265..9c900dc92d 100644 --- a/app/client/netlify.toml +++ b/app/client/netlify.toml @@ -8,6 +8,7 @@ REACT_APP_ALGOLIA_SEARCH_INDEX_NAME = "test_appsmith" REACT_APP_CLIENT_LOG_LEVEL = "debug" REACT_APP_GOOGLE_MAPS_API_KEY = "AIzaSyBOQFulljufGt3VDhBAwNjZN09KEFufVyg" + REACT_APP_GOOGLE_RECAPTCHA_SITE_KEY = "" REACT_APP_TNC_PP = "true" REACT_APP_CLOUD_HOSTING = "true" REACT_APP_INTERCOM_APP_ID = "y10e7138" diff --git a/app/client/public/index.html b/app/client/public/index.html index 8079bbba08..df6675bb58 100755 --- a/app/client/public/index.html +++ b/app/client/public/index.html @@ -204,7 +204,8 @@ intercomAppID: APP_ID, mailEnabled: parseConfig("__APPSMITH_MAIL_ENABLED__"), disableTelemetry: DISABLE_TELEMETRY === "" || DISABLE_TELEMETRY, - cloudServicesBaseUrl: parseConfig("__APPSMITH_CLOUD_SERVICES_BASE_URL__") || "https://cs.appsmith.com" + cloudServicesBaseUrl: parseConfig("__APPSMITH_CLOUD_SERVICES_BASE_URL__") || "https://cs.appsmith.com", + googleRecaptchaSiteKey: parseConfig("__APPSMITH_RECAPTCHA_SITE_KEY__"), }; diff --git a/app/client/src/configs/index.ts b/app/client/src/configs/index.ts index e4b2b60f9a..a50565f606 100644 --- a/app/client/src/configs/index.ts +++ b/app/client/src/configs/index.ts @@ -42,6 +42,7 @@ export type INJECTED_CONFIGS = { mailEnabled: boolean; disableTelemetry: boolean; cloudServicesBaseUrl: string; + googleRecaptchaSiteKey: string; onboardingFormEnabled: boolean; }; declare global { @@ -116,6 +117,8 @@ const getConfigsFromEnvVars = (): INJECTED_CONFIGS => { : false, disableTelemetry: true, cloudServicesBaseUrl: process.env.REACT_APP_CLOUD_SERVICES_BASE_URL || "", + googleRecaptchaSiteKey: + process.env.REACT_APP_GOOGLE_RECAPTCHA_SITE_KEY || "", onboardingFormEnabled: !!process.env.REACT_APP_SHOW_ONBOARDING_FORM, }; }; @@ -167,6 +170,11 @@ export const getAppsmithConfigs = (): AppsmithUIConfigs => { ); const google = getConfig(ENV_CONFIG.google, APPSMITH_FEATURE_CONFIGS.google); + const googleRecaptchaSiteKey = getConfig( + ENV_CONFIG.googleRecaptchaSiteKey, + APPSMITH_FEATURE_CONFIGS.googleRecaptchaSiteKey, + ); + // As the following shows, the config variables can be set using a combination // of env variables and injected configs const smartLook = getConfig( @@ -245,6 +253,10 @@ export const getAppsmithConfigs = (): AppsmithUIConfigs => { enabled: google.enabled, apiKey: google.value, }, + googleRecaptchaSiteKey: { + enabled: googleRecaptchaSiteKey.enabled, + apiKey: googleRecaptchaSiteKey.value, + }, enableRapidAPI: ENV_CONFIG.enableRapidAPI || APPSMITH_FEATURE_CONFIGS.enableRapidAPI, enableGithubOAuth: diff --git a/app/client/src/configs/types.ts b/app/client/src/configs/types.ts index fde3769c7c..41fde2417f 100644 --- a/app/client/src/configs/types.ts +++ b/app/client/src/configs/types.ts @@ -73,5 +73,9 @@ export type AppsmithUIConfigs = { cloudServicesBaseUrl: string; + googleRecaptchaSiteKey: { + enabled: boolean; + apiKey: string; + }; onboardingFormEnabled: boolean; }; diff --git a/app/client/src/pages/UserAuth/SignUp.tsx b/app/client/src/pages/UserAuth/SignUp.tsx index 97604e2671..74c74ebcbc 100644 --- a/app/client/src/pages/UserAuth/SignUp.tsx +++ b/app/client/src/pages/UserAuth/SignUp.tsx @@ -35,7 +35,6 @@ import { isEmail, isStrongPassword, isEmptyString } from "utils/formhelpers"; import { SignupFormValues } from "./helpers"; import AnalyticsUtil from "utils/AnalyticsUtil"; -import { getAppsmithConfigs } from "configs"; import { SIGNUP_SUBMIT_PATH } from "constants/ApiConstants"; import { connect } from "react-redux"; import { AppState } from "reducers"; @@ -45,6 +44,8 @@ import PerformanceTracker, { import { useIntiateOnboarding } from "components/editorComponents/Onboarding/utils"; import { SIGNUP_FORM_EMAIL_FIELD_NAME } from "constants/forms"; +import { getAppsmithConfigs } from "configs"; +import { useScript, ScriptStatus, AddScriptTo } from "utils/hooks/useScript"; const { enableGithubOAuth, enableGoogleOAuth } = getAppsmithConfigs(); const SocialLoginList: string[] = []; @@ -54,6 +55,13 @@ if (enableGithubOAuth) SocialLoginList.push(SocialLoginTypes.GITHUB); import { withTheme } from "styled-components"; import { Theme } from "constants/DefaultTheme"; +declare global { + interface Window { + grecaptcha: any; + } +} +const { googleRecaptchaSiteKey } = getAppsmithConfigs(); + const validate = (values: SignupFormValues) => { const errors: SignupFormValues = {}; if (!values.password || isEmptyString(values.password)) { @@ -82,6 +90,11 @@ export function SignUp(props: SignUpFormProps) { const location = useLocation(); const initiateOnboarding = useIntiateOnboarding(); + const recaptchaStatus = useScript( + `https://www.google.com/recaptcha/api.js?render=${googleRecaptchaSiteKey.apiKey}`, + AddScriptTo.HEAD, + ); + let showError = false; let errorMessage = ""; const queryParams = new URLSearchParams(location.search); @@ -118,7 +131,37 @@ export function SignUp(props: SignUpFormProps) { {SocialLoginList.length > 0 && ( )} - + { + e.preventDefault(); + const formElement: HTMLFormElement = document.getElementById( + "signup-form", + ) as HTMLFormElement; + if ( + googleRecaptchaSiteKey.enabled && + recaptchaStatus === ScriptStatus.READY + ) { + window.grecaptcha + .execute(googleRecaptchaSiteKey.apiKey, { + action: "submit", + }) + .then(function(token: any) { + formElement && + formElement.setAttribute( + "action", + `${signupURL}?recaptchaToken=${token}`, + ); + formElement && formElement.submit(); + }); + } else { + formElement && formElement.submit(); + } + return false; + }} + > /etc/nginx/conf.d/default.conf.template.1 envsubst "\$PORT" < /etc/nginx/conf.d/default.conf.template.1 > /etc/nginx/conf.d/default.conf diff --git a/deploy/heroku/default.conf.template b/deploy/heroku/default.conf.template index 8362ccc505..490cacb32d 100644 --- a/deploy/heroku/default.conf.template +++ b/deploy/heroku/default.conf.template @@ -32,6 +32,9 @@ server { sub_filter __APPSMITH_INTERCOM_APP_ID__ '${APPSMITH_INTERCOM_APP_ID}'; sub_filter __APPSMITH_MAIL_ENABLED__ '${APPSMITH_MAIL_ENABLED}'; sub_filter __APPSMITH_DISABLE_TELEMETRY__ '${APPSMITH_DISABLE_TELEMETRY}'; + sub_filter __APPSMITH_RECAPTCHA_SITE_KEY__ '${APPSMITH_RECAPTCHA_SITE_KEY}'; + sub_filter __APPSMITH_RECAPTCHA_SECRET_KEY__ '${APPSMITH_RECAPTCHA_SECRET_KEY}'; + sub_filter __APPSMITH_RECAPTCHA_ENABLED__ '${APPSMITH_RECAPTCHA_ENABLED}'; } location /f { diff --git a/deploy/k8s/scripts/appsmith-configmap.yaml.sh b/deploy/k8s/scripts/appsmith-configmap.yaml.sh index d664292f6f..bf7b314546 100644 --- a/deploy/k8s/scripts/appsmith-configmap.yaml.sh +++ b/deploy/k8s/scripts/appsmith-configmap.yaml.sh @@ -30,4 +30,7 @@ data: APPSMITH_REDIS_URL: redis://redis-service:6379 APPSMITH_MONGODB_URI: $mongo_protocol$encoded_mongo_root_user:$encoded_mongo_root_password@$mongo_host/$mongo_db?retryWrites=true&authSource=admin APPSMITH_DISABLE_TELEMETRY: "$disable_telemetry" + APPSMITH_RECAPTCHA_SITE_KEY= "" + APPSMITH_RECAPTCHA_SECRET_KEY= "" + APPSMITH_RECAPTCHA_ENABLED= "false" EOF diff --git a/deploy/k8s/scripts/nginx-configmap.yaml b/deploy/k8s/scripts/nginx-configmap.yaml index b9253d36bf..eef8665258 100644 --- a/deploy/k8s/scripts/nginx-configmap.yaml +++ b/deploy/k8s/scripts/nginx-configmap.yaml @@ -37,6 +37,9 @@ data: sub_filter __APPSMITH_MAIL_ENABLED__ '${APPSMITH_MAIL_ENABLED}'; sub_filter __APPSMITH_DISABLE_TELEMETRY__ '${APPSMITH_DISABLE_TELEMETRY}'; sub_filter __APPSMITH_CLOUD_SERVICES_BASE_URL__ '${APPSMITH_CLOUD_SERVICES_BASE_URL}'; + sub_filter __APPSMITH_RECAPTCHA_SITE_KEY__ '${APPSMITH_RECAPTCHA_SITE_KEY}'; + sub_filter __APPSMITH_RECAPTCHA_SECRET_KEY__ '${APPSMITH_RECAPTCHA_SECRET_KEY}'; + sub_filter __APPSMITH_RECAPTCHA_ENABLED__ '${APPSMITH_RECAPTCHA_ENABLED}'; } location /f { diff --git a/deploy/template/docker.env.sh b/deploy/template/docker.env.sh index 6bbeb5e901..d1561b8902 100644 --- a/deploy/template/docker.env.sh +++ b/deploy/template/docker.env.sh @@ -59,4 +59,10 @@ APPSMITH_DISABLE_TELEMETRY=$disable_telemetry # APPSMITH_CODEC_SIZE= # ******************************* +# ***** Google Recaptcha Config ****** +# APPSMITH_RECAPTCHA_SITE_KEY= +# APPSMITH_RECAPTCHA_SECRET_KEY= +# APPSMITH_RECAPTCHA_ENABLED= +# ************************************ + EOF diff --git a/deploy/template/nginx_app.conf.sh b/deploy/template/nginx_app.conf.sh index cb0a0928b4..8954753b82 100644 --- a/deploy/template/nginx_app.conf.sh +++ b/deploy/template/nginx_app.conf.sh @@ -49,6 +49,9 @@ $NGINX_SSL_CMNT server_name $custom_domain ; sub_filter __APPSMITH_INTERCOM_APP_ID__ '\${APPSMITH_INTERCOM_APP_ID}'; sub_filter __APPSMITH_MAIL_ENABLED__ '\${APPSMITH_MAIL_ENABLED}'; sub_filter __APPSMITH_DISABLE_TELEMETRY__ '\${APPSMITH_DISABLE_TELEMETRY}'; + sub_filter __APPSMITH_RECAPTCHA_SITE_KEY__ '\${APPSMITH_RECAPTCHA_SITE_KEY}'; + sub_filter __APPSMITH_RECAPTCHA_SECRET_KEY__ '\${APPSMITH_RECAPTCHA_SECRET_KEY}'; + sub_filter __APPSMITH_RECAPTCHA_ENABLED__ '\${APPSMITH_RECAPTCHA_ENABLED}'; } location /f { @@ -106,6 +109,9 @@ $NGINX_SSL_CMNT sub_filter __APPSMITH_VERSION_RELEASE_DATE__ '\${APPSMITH $NGINX_SSL_CMNT sub_filter __APPSMITH_INTERCOM_APP_ID__ '\${APPSMITH_INTERCOM_APP_ID}'; $NGINX_SSL_CMNT sub_filter __APPSMITH_MAIL_ENABLED__ '\${APPSMITH_MAIL_ENABLED}'; $NGINX_SSL_CMNT sub_filter __APPSMITH_DISABLE_TELEMETRY__ '\${APPSMITH_DISABLE_TELEMETRY}'; +$NGINX_SSL_CMNT sub_filter __APPSMITH_RECAPTCHA_SITE_KEY__ '\${APPSMITH_RECAPTCHA_SITE_KEY}; +$NGINX_SSL_CMNT sub_filter __APPSMITH_RECAPTCHA_SECRET_KEY__ '\${APPSMITH_RECAPTCHA_SECRET_KEY}; +$NGINX_SSL_CMNT sub_filter __APPSMITH_RECAPTCHA_ENABLED__ '\${APPSMITH_RECAPTCHA_ENABLED}'; $NGINX_SSL_CMNT } $NGINX_SSL_CMNT $NGINX_SSL_CMNT location /f {