diff --git a/api-server/server/boot/donate.js b/api-server/server/boot/donate.js index de445ffc3e..e1866a3c31 100644 --- a/api-server/server/boot/donate.js +++ b/api-server/server/boot/donate.js @@ -12,18 +12,12 @@ import { import { durationKeysConfig, donationOneTimeConfig, - donationSubscriptionConfig, - paypalConfig + donationSubscriptionConfig } from '../../../config/donation-settings'; import keys from '../../../config/secrets'; const log = debug('fcc:boot:donate'); -const paypalWebhookId = - process.env.FREECODECAMP_NODE_ENV === 'production' - ? paypalConfig.production.webhookId - : paypalConfig.development.webhookId; - export default function donateBoot(app, done) { let stripe = false; const api = app.loopback.Router(); @@ -255,6 +249,7 @@ export default function donateBoot(app, done) { .send({ error: 'Donation failed due to a server error.' }) ); } + function addDonation(req, res) { const { user, body } = req; @@ -284,7 +279,7 @@ export default function donateBoot(app, done) { return Promise.resolve(req) .then(verifyWebHookType) .then(getAsyncPaypalToken) - .then(token => verifyWebHook(headers, body, token, paypalWebhookId)) + .then(token => verifyWebHook(headers, body, token, keys.paypal.webhookId)) .then(hookBody => updateUser(hookBody, app)) .then(() => res.status(200).json({ message: 'received hook' })) .catch(err => { @@ -310,37 +305,21 @@ export default function donateBoot(app, done) { !hmacKey || hmacKey === 'secret_key_from_servicebot_dashboard'; const paypalInvalid = paypalPublicInvalid || paypalSecretInvalid; const stripeInvalid = stripeSecretInvalid || stripPublicInvalid; - if (stripeInvalid) { + + if (stripeInvalid || paypalInvalid || hmacKeyInvalid) { if (process.env.FREECODECAMP_NODE_ENV === 'production') { - throw new Error('Stripe API keys are required to boot the server!'); + throw new Error('Donation API keys are required to boot the server!'); } - console.info('No Stripe API keys were found, moving on...'); + log('Donation disabled in development unless ALL test keys are provided'); + done(); } else { api.post('/charge-stripe', createStripeDonation); api.post('/create-hmac-hash', createHmacHash); - } - if (paypalInvalid) { - if (process.env.FREECODECAMP_NODE_ENV === 'production') { - throw new Error('PayPal API keys are required to boot the server!'); - } - console.info('No PayPal API keys were found, moving on...'); - } else { - api.post('/update-paypal', updatePaypal); api.post('/add-donation', addDonation); - } - if (hmacKeyInvalid) { - if (process.env.FREECODECAMP_NODE_ENV === 'production') { - throw new Error('Servicebot HMAC key is required to boot the server!'); - } - console.info('No servicebot HMAC key was found, moving on...'); - } - donateRouter.use('/donate', api); - app.use(donateRouter); - app.use('/internal', donateRouter); - - if (stripeInvalid) { - done(); - } else { + api.post('/update-paypal', updatePaypal); + donateRouter.use('/donate', api); + app.use(donateRouter); + app.use('/internal', donateRouter); connectToStripe().then(done); } } diff --git a/api-server/server/utils/donation.js b/api-server/server/utils/donation.js index 822c7d95c3..763b82df1b 100644 --- a/api-server/server/utils/donation.js +++ b/api-server/server/utils/donation.js @@ -5,14 +5,14 @@ import keys from '../../../config/secrets'; const log = debug('fcc:boot:donate'); -const sandBoxSubdomain = - process.env.FREECODECAMP_NODE_ENV === 'production' ? '' : 'sandbox.'; - -const verificationUrl = `https://api.${sandBoxSubdomain}paypal.com/v1/notifications/verify-webhook-signature`; -const tokenUrl = `https://api.${sandBoxSubdomain}paypal.com/v1/oauth2/token`; +const paypalverifyWebhookURL = + keys.paypal.verifyWebhookURL || + `https://api.sandbox.paypal.com/v1/notifications/verify-webhook-signature`; +const paypalTokenURL = + keys.paypal.tokenUrl || `https://api.sandbox.paypal.com/v1/oauth2/token`; export async function getAsyncPaypalToken() { - const res = await axios.post(tokenUrl, null, { + const res = await axios.post(paypalTokenURL, null, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, @@ -48,7 +48,7 @@ export async function verifyWebHook(headers, body, token, webhookId) { webhook_event: webhookEventBody }; - const response = await axios.post(verificationUrl, payload, { + const response = await axios.post(paypalverifyWebhookURL, payload, { headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` diff --git a/api-server/server/utils/donation-uttils.test.js b/api-server/server/utils/donation.test.js similarity index 94% rename from api-server/server/utils/donation-uttils.test.js rename to api-server/server/utils/donation.test.js index 7342b036d6..e53e67a976 100644 --- a/api-server/server/utils/donation-uttils.test.js +++ b/api-server/server/utils/donation.test.js @@ -22,11 +22,8 @@ import { jest.mock('axios'); -const sandBoxSubdomain = - process.env.FREECODECAMP_NODE_ENV === 'production' ? '' : 'sandbox.'; - -const verificationUrl = `https://api.${sandBoxSubdomain}paypal.com/v1/notifications/verify-webhook-signature`; -const tokenUrl = `https://api.${sandBoxSubdomain}paypal.com/v1/oauth2/token`; +const verificationUrl = `https://api.sandbox.paypal.com/v1/notifications/verify-webhook-signature`; +const tokenUrl = `https://api.sandbox.paypal.com/v1/oauth2/token`; const { body: activationHookBody, headers: activationHookHeaders diff --git a/client/src/components/Donation/PaypalButton.js b/client/src/components/Donation/PaypalButton.js index 898624f36f..d224055246 100644 --- a/client/src/components/Donation/PaypalButton.js +++ b/client/src/components/Donation/PaypalButton.js @@ -1,5 +1,4 @@ /* eslint-disable camelcase */ -/* global ENVIRONMENT */ import React, { Component } from 'react'; import PropTypes from 'prop-types'; @@ -11,16 +10,13 @@ import { verifySubscriptionPaypal } from '../../utils/ajax'; import { paypalConfig } from '../../../../config/donation-settings'; import { signInLoadingSelector, userSelector, executeGA } from '../../redux'; -const paypalDurationPlans = - ENVIRONMENT === 'production' - ? paypalConfig.production.durationPlans - : paypalConfig.development.durationPlans; +const { durationPlans } = paypalConfig; export class PaypalButton extends Component { constructor(...props) { super(...props); this.state = { - planId: paypalDurationPlans.month['500'].planId + planId: durationPlans.month['500'].planId }; this.handleApproval = this.handleApproval.bind(this); } diff --git a/config/donation-settings.js b/config/donation-settings.js index 32243571f4..ee7b5386d2 100644 --- a/config/donation-settings.js +++ b/config/donation-settings.js @@ -1,3 +1,5 @@ +require('dotenv').config(); + // Configuration for client side const durationsConfig = { year: 'yearly', @@ -40,9 +42,8 @@ const donationSubscriptionConfig = { }; // Shared paypal configuration -const paypalConfig = { - production: { - webhookId: '8AM40465WC915574A', +const paypalConfigTypes = { + live: { durationPlans: { month: { '500': { @@ -51,8 +52,7 @@ const paypalConfig = { } } }, - development: { - webhookId: '2UL63757DN298592C', + staging: { durationPlans: { month: { '500': { @@ -63,6 +63,10 @@ const paypalConfig = { } }; +const paypalConfig = process.env.DEPLOYMENT_ENV + ? paypalConfigTypes['live'] + : paypalConfigTypes['staging']; + module.exports = { durationsConfig, amountsConfig, diff --git a/config/secrets.js b/config/secrets.js index 6a2b8242dc..890dd6b4f5 100644 --- a/config/secrets.js +++ b/config/secrets.js @@ -37,7 +37,10 @@ const { SERVICEBOT_HMAC_SECRET_KEY, PAYPAL_CLIENT_ID, - PAYPAL_SECRET + PAYPAL_SECRET, + PAYPAL_VERIFY_WEBHOOK_URL, + PAYPAL_API_TOKEN_URL, + PAYPAL_WEBHOOK_ID } = process.env; module.exports = { @@ -104,7 +107,10 @@ module.exports = { paypal: { client: PAYPAL_CLIENT_ID, - secret: PAYPAL_SECRET + secret: PAYPAL_SECRET, + verifyWebhookURL: PAYPAL_VERIFY_WEBHOOK_URL, + tokenUrl: PAYPAL_API_TOKEN_URL, + webhookId: PAYPAL_WEBHOOK_ID }, servicebot: { diff --git a/sample.env b/sample.env index cf4740d902..0f7fd41739 100644 --- a/sample.env +++ b/sample.env @@ -23,8 +23,13 @@ SERVICEBOT_ID=servicebot_id_from_servicebot_dashboard SERVICEBOT_HMAC_SECRET_KEY=secret_key_from_servicebot_dashboard PAYPAL_SUPPORTERS=1703 + PAYPAL_CLIENT_ID=id_from_paypal_dashboard PAYPAL_SECRET=secret_from_paypal_dashboard +PAYPAL_VERIFY_WEBHOOK_URL='https://api.sandbox.paypal.com/v1/notifications/verify-webhook-signature' +PAYPAL_API_TOKEN_URL='https://api.sandbox.paypal.com/v1/oauth2/token' +PAYPAL_WEBHOOK_ID=webhook_id_from_paypal_dashboard +DEPLOYMENT_ENV='staging' PEER=stuff DEBUG=true