* Add recaptcha handling with feature flag
This commit is contained in:
Pomax 2022-01-27 09:32:36 -08:00 коммит произвёл GitHub
Родитель 39433db492
Коммит 9c99295e43
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
7 изменённых файлов: 70 добавлений и 23 удалений

Просмотреть файл

@ -1,3 +1,14 @@
queue_rules:
- name: dependabot
conditions:
- "status-success=continuous-integration/travis-ci/pr"
- "status-success=continuous-integration/travis-ci/push"
- name: ready-to-merge
conditions:
- "status-success=continuous-integration/travis-ci/pr"
- "status-success=continuous-integration/travis-ci/push"
pull_request_rules: pull_request_rules:
- name: Automatic merge for dependabot PRs - name: Automatic merge for dependabot PRs
conditions: conditions:
@ -6,10 +17,10 @@ pull_request_rules:
- "status-success=continuous-integration/travis-ci/pr" - "status-success=continuous-integration/travis-ci/pr"
- "status-success=continuous-integration/travis-ci/push" - "status-success=continuous-integration/travis-ci/push"
actions: actions:
merge: queue:
method: squash method: squash
strict_method: rebase name: dependabot
strict: true
- name: Automatic merge for PRs labelled "ready to merge" - name: Automatic merge for PRs labelled "ready to merge"
conditions: conditions:
- "#approved-reviews-by>=1" - "#approved-reviews-by>=1"
@ -17,7 +28,6 @@ pull_request_rules:
- "status-success=continuous-integration/travis-ci/push" - "status-success=continuous-integration/travis-ci/push"
- "label=ready-to-merge" - "label=ready-to-merge"
actions: actions:
merge: queue:
method: squash method: squash
strict_method: rebase name: ready-to-merge
strict: true

Просмотреть файл

@ -54,6 +54,8 @@ This starts a few image optimization scripts.
`PULSE_API` | Default: `https://pulse-api.mofostaging.net/api/pulse`<br><br>URL to Pulse API. e.g., `http://test.example.com:8000/api/pulse`. <br>To set up a local instance of Pulse API, follow instructions on [Pulse API README doc](https://github.com/mozilla/network-pulse-api/blob/master/README.md). `PULSE_API` | Default: `https://pulse-api.mofostaging.net/api/pulse`<br><br>URL to Pulse API. e.g., `http://test.example.com:8000/api/pulse`. <br>To set up a local instance of Pulse API, follow instructions on [Pulse API README doc](https://github.com/mozilla/network-pulse-api/blob/master/README.md).
`PULSE_LOGIN_URL` | Default: `https://pulse-api.mofostaging.net/accounts/login/`<br><br>URL to use to login to Pulse. This needs to be a Pulse API login url. `PULSE_LOGIN_URL` | Default: `https://pulse-api.mofostaging.net/accounts/login/`<br><br>URL to use to login to Pulse. This needs to be a Pulse API login url.
`PULSE_LOGOUT_URL` | Default: `https://pulse-api.mofostaging.net/accounts/logout/`<br><br>URL to use to logout of Pulse. This needs to be a Pulse API logout url. `PULSE_LOGOUT_URL` | Default: `https://pulse-api.mofostaging.net/accounts/logout/`<br><br>URL to use to logout of Pulse. This needs to be a Pulse API logout url.
`USE_RECAPTCHA` | Default: `true`<br><br>Whether or not to have recaptcha securing the sign up/sign in action.
`RECAPTCHA_KEY` | Default: empty string<br><br>The recaptcha site key to use, when recaptcha is enabled.
`PROJECT_BATCH_SIZE`| Default: `24`<br><br>Number of projects you want to display as a batch. Make sure this number is divisible by 2 AND 3 so rows display evenly for different screen sizes. `PROJECT_BATCH_SIZE`| Default: `24`<br><br>Number of projects you want to display as a batch. Make sure this number is divisible by 2 AND 3 so rows display evenly for different screen sizes.
`PROFILE_BATCH_SIZE`| Default: `10`<br><br>Number of profiles you want to display as a batch. `PROFILE_BATCH_SIZE`| Default: `10`<br><br>Number of profiles you want to display as a batch.
`LEARN_MORE_LINK` | Default: `https://www.mozillapulse.org/entry/120`<br><br>Link to learn more about what Pulse project is about. `LEARN_MORE_LINK` | Default: `https://www.mozillapulse.org/entry/120`<br><br>Link to learn more about what Pulse project is about.
@ -62,6 +64,7 @@ This starts a few image optimization scripts.
`HEROKU_APP_NAME` | Default: `""`<br><br>The name of the review app (generated by Heroku). `HEROKU_APP_NAME` | Default: `""`<br><br>The name of the review app (generated by Heroku).
`GITHUB_TOKEN` | Default: `""`<br><br>GitHub token used by the review app slack webhook. `GITHUB_TOKEN` | Default: `""`<br><br>GitHub token used by the review app slack webhook.
`SLACK_WEBHOOK` | Default: `""`<br><br>Webhook of the Slack channel where the bot is posting. `SLACK_WEBHOOK` | Default: `""`<br><br>Webhook of the Slack channel where the bot is posting.
## Deployment ## Deployment
### Staging ### Staging

Просмотреть файл

@ -84,12 +84,18 @@ class NavBar extends React.Component {
handleSignInBtnClick(event) { handleSignInBtnClick(event) {
event.preventDefault(); event.preventDefault();
Analytics.ReactGA.event({ try {
category: `Account`, Analytics.ReactGA.event({
action: `Login`, category: `Account`,
label: `Login ${window.location.pathname}`, action: `Login`,
transport: `beacon`, label: `Login ${window.location.pathname}`,
}); transport: `beacon`,
});
} catch (err) {
// This does not need to succeed, but we also
// don't want a throw to prevent the actual
// login from happening.
}
user.login(utility.getCurrentURL()); user.login(utility.getCurrentURL());
} }

Просмотреть файл

@ -3,6 +3,8 @@ import env from "./env-client";
import localstorage from "./localstorage.js"; import localstorage from "./localstorage.js";
import Service from "./service.js"; import Service from "./service.js";
const useRecaptcha = env.USE_RECAPTCHA;
const recaptchaKey = env.RECAPTCHA_KEY;
const loginUrl = env.PULSE_LOGIN_URL; const loginUrl = env.PULSE_LOGIN_URL;
/** /**
@ -14,8 +16,11 @@ const Login = {
/* /*
* Generates the oauth url for logging a user in, with a redirect-when-finished URL * Generates the oauth url for logging a user in, with a redirect-when-finished URL
*/ */
getLoginURL(redirectUrl) { getLoginURL(redirectUrl, recaptchaToken) {
return `${loginUrl}?next=${encodeURIComponent(redirectUrl)}`; const trailing = loginUrl.endsWith(`/`) ? `` : `/`;
const next = `?next=${encodeURIComponent(redirectUrl)}`;
const token = recaptchaToken ? `&token=${recaptchaToken}` : ``;
return [loginUrl, trailing, next, token].join(``);
}, },
/* /*
@ -113,13 +118,23 @@ class User {
} }
login(redirectUrl) { login(redirectUrl) {
// we record that the user started a login in localStorage, const performLogin = (token) => {
// then the app gets closed and oauth happens. Once the // we record that the user started a login in localStorage,
// oauth callback drops the user back at a URL that loads // then the app gets closed and oauth happens. Once the
// the app again, pages can run `user.verify` to finalise // oauth callback drops the user back at a URL that loads
// the login process. // the app again, pages can run `user.verify` to finalise
localstorage.setItem(`pulse:user:attemptingLogin`, `True`); // the login process.
window.location = Login.getLoginURL(redirectUrl); localstorage.setItem(`pulse:user:attemptingLogin`, `True`);
window.location = Login.getLoginURL(redirectUrl, token);
};
if (useRecaptcha) {
grecaptcha.ready(() =>
grecaptcha
.execute(recaptchaKey, { action: "submit" })
.then((recaptcha_response) => performLogin(recaptcha_response))
);
} else performLogin();
} }
verify(location, history) { verify(location, history) {

Просмотреть файл

@ -6,7 +6,7 @@ import dotenv from "dotenv";
dotenv.config(); dotenv.config();
// load default.env so that anything didn't get set in .env or the host environment will get a default value // load default.env so that anything didn't get set in .env or the host environment will get a default value
dotenv.config({ path: `config/default.env` }); dotenv.config({ path: `./config/default.env` });
let envUtilities = { let envUtilities = {
serializeSafeEnvAsJSON: () => { serializeSafeEnvAsJSON: () => {
@ -24,6 +24,8 @@ let envUtilities = {
PULSE_API: process.env.PULSE_API, PULSE_API: process.env.PULSE_API,
PULSE_LOGIN_URL: process.env.PULSE_LOGIN_URL, PULSE_LOGIN_URL: process.env.PULSE_LOGIN_URL,
PULSE_LOGOUT_URL: process.env.PULSE_LOGOUT_URL, PULSE_LOGOUT_URL: process.env.PULSE_LOGOUT_URL,
USE_RECAPTCHA: process.env.USE_RECAPTCHA,
RECAPTCHA_KEY: process.env.RECAPTCHA_KEY,
}; };
return JSON.stringify(config); return JSON.stringify(config);

Просмотреть файл

@ -10,12 +10,15 @@ export default {
`https://platform.twitter.com/widgets.js`, `https://platform.twitter.com/widgets.js`,
`https://www.googletagmanager.com/gtm.js`, `https://www.googletagmanager.com/gtm.js`,
`https://www.googletagmanager.com/debug/bootstrap`, `https://www.googletagmanager.com/debug/bootstrap`,
`https://www.google.com/recaptcha/api.js`,
`https://www.gstatic.com/recaptcha/releases/`,
], ],
fontSrc: [ fontSrc: [
`'self'`, `'self'`,
`https://code.cdn.mozilla.net`, `https://code.cdn.mozilla.net`,
`https://fonts.gstatic.com`, `https://fonts.gstatic.com`,
], ],
frameSrc: [`https://www.google.com/`],
styleSrc: [ styleSrc: [
`'self'`, `'self'`,
`'unsafe-inline'`, `'unsafe-inline'`,
@ -28,6 +31,8 @@ export default {
url.parse(env.PULSE_API).host || url.parse(env.PULSE_API).host ||
`https://network-pulse-api-staging.herokuapp.com/`, `https://network-pulse-api-staging.herokuapp.com/`,
`https://www.mozilla.org/en-US/newsletter/`, `https://www.mozilla.org/en-US/newsletter/`,
`https://www.google.com/recaptcha/api.js`,
`https://www.gstatic.com/recaptcha/releases/`,
], ],
childSrc: [ childSrc: [
`https://syndication.twitter.com`, `https://syndication.twitter.com`,

Просмотреть файл

@ -137,6 +137,11 @@ function renderPage(appHtml, reactHelmet, canonicalUrl) {
? `<meta name="googlebot" content="noindex, nofollow, noarchive" />` ? `<meta name="googlebot" content="noindex, nofollow, noarchive" />`
: ``; : ``;
let recaptcha = ``;
if (env.USE_RECAPTCHA) {
recaptcha = `<script src="https://www.google.com/recaptcha/api.js?render=${env.RECAPTCHA_KEY}" async></script>`;
}
return ` return `
<!doctype html> <!doctype html>
<html> <html>
@ -148,7 +153,7 @@ function renderPage(appHtml, reactHelmet, canonicalUrl) {
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
${twitterCard} ${twitterCard}
${ogTags} ${ogTags}
<script type="text/javascript" async src="https://platform.twitter.com/widgets.js"></script> <script src="https://platform.twitter.com/widgets.js" async defer></script>
<link rel="apple-touch-icon" type="image/png" sizes="180x180" href="/assets/favicons/apple-touch-icon-180x180@2x.png"> <link rel="apple-touch-icon" type="image/png" sizes="180x180" href="/assets/favicons/apple-touch-icon-180x180@2x.png">
<link rel="icon" type="image/png" sizes="196x196" href="/assets/favicons/favicon-196x196@2x.png"> <link rel="icon" type="image/png" sizes="196x196" href="/assets/favicons/favicon-196x196@2x.png">
<link rel="shortcut icon" href="/assets/favicons/favicon.ico"> <link rel="shortcut icon" href="/assets/favicons/favicon.ico">
@ -164,6 +169,7 @@ function renderPage(appHtml, reactHelmet, canonicalUrl) {
${reactHelmet.title.toString()} ${reactHelmet.title.toString()}
<meta name="ga-identifier" content="UA-87658599-4"> <meta name="ga-identifier" content="UA-87658599-4">
<meta name="gtm-identifier" content="GTM-KHLX47C"> <meta name="gtm-identifier" content="GTM-KHLX47C">
${recaptcha}
</head> </head>
<body> <body>
<div id="app">${appHtml}</div> <div id="app">${appHtml}</div>