Skip to content

Commit

Permalink
Secure Stripe endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
e-wai committed Jan 15, 2023
1 parent 6c918f2 commit f3bfcf5
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 10 deletions.
10 changes: 7 additions & 3 deletions .github/actions/heroku-deploy/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ inputs:
stripe-secret-key:
description: "Stripe secret key for checkout flow"
required: true
stripe-endpoint-key:
description: "Stripe endpoint key for verifying webhook calls"
required: true
client-url:
description: "Client base URL for Stripe checkout result redirection"
required: true
Expand Down Expand Up @@ -96,9 +99,10 @@ runs:
heroku config:set MAILER_REFRESH_TOKEN="${{ inputs.mailer-refresh-token }}" -a $HEROKU_APP_NAME && \
heroku config:set STRIPE_PUBLISHABLE_TEST_KEY="${{ inputs.stripe-publishable-key }}" -a $HEROKU_APP_NAME && \
heroku config:set STRIPE_SECRET_TEST_KEY="${{ inputs.stripe-secret-key }}" -a $HEROKU_APP_NAME && \
heroku config:set PREVIEW_DEPLOY=$([ "${{inputs.deploy-branch}}" = "main" ] && echo "false" || echo "true") -a $HEROKU_APP_NAME
heroku config:set NODE_ENV="${{ inputs.node-env }}"
heroku config:set CLIENT_URL="${{ inputs.client-url }}"
heroku config:set STRIPE_ENDPOINT_KEY="${{ inputs.stripe-endpoint-key }}" -a $HEROKU_APP_NAME && \
heroku config:set PREVIEW_DEPLOY=$([ "${{inputs.deploy-branch}}" = "main" ] && echo "false" || echo "true") -a $HEROKU_APP_NAME && \
heroku config:set NODE_ENV="${{ inputs.node-env }}" -a $HEROKU_APP_NAME && \
heroku config:set CLIENT_URL="${{ inputs.client-url }}" -a $HEROKU_APP_NAME
env:
HEROKU_APP_NAME: "${{ inputs.heroku-app-name }}"
shell: bash
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/deploy-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,6 @@ jobs:
mailer-refresh-token: "${{ secrets.PRODUCTION_MAILER_REFRESH_TOKEN }}"
stripe-publishable-key: "${{ secrets.STRIPE_PUBLISHABLE_TEST_KEY }}"
stripe-secret-key: "${{ secrets.STRIPE_SECRET_TEST_KEY }}"
stripe-endpoint-key: "${{ secrets.STRIPE_ENDPOINT_KEY }}"
client-url: "${{ secrets.CLIENT_URL }}"
deploy-branch: "main"
1 change: 1 addition & 0 deletions .github/workflows/heroku-deploy-dev-ts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@ jobs:
mailer-refresh-token: "${{ secrets.MAILER_REFRESH_TOKEN }}"
stripe-publishable-key: "${{ secrets.STRIPE_PUBLISHABLE_TEST_KEY }}"
stripe-secret-key: "${{ secrets.STRIPE_SECRET_TEST_KEY }}"
stripe-endpoint-key: "${{ secrets.STRIPE_ENDPOINT_KEY }}"
client-url: "${{ secrets.CLIENT_URL }}"
deploy-branch: "dev"
22 changes: 15 additions & 7 deletions backend/typescript/rest/camperRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@ import {
WaitlistedCamperDTO,
} from "../types";
import { createWaitlistedCampersDtoValidator } from "../middlewares/validators/waitlistedCampersValidators";
import {
stripeKey,
verifyStripeWebhooksRequest,
} from "../utilities/stripeUtils";

const camperRouter: Router = Router();

const camperService: ICamperService = new CamperService();

// TODO: secure stripe keys
const STRIPE_ENDPOINT_KEY = process.env.STRIPE_ENDPOINT_SECRET || "";

// ROLES: Leaving unprotected as the registration flow probs needs this endpoint to register @dhruv
/* Create a camper */
camperRouter.post("/register", createCampersDtoValidator, async (req, res) => {
Expand Down Expand Up @@ -121,12 +122,19 @@ camperRouter.get("/:chargeId/:sessionId", async (req, res) => {
/* Initiated by Stripe webhook. On successful payment, mark camper as paid. */
camperRouter.post("/confirm-payment", async (req, res) => {
try {
const { body } = req;
const event = verifyStripeWebhooksRequest(
req.headers["stripe-signature"],
req.body,
);

if (!event) {
res.status(400).send("Webhook signature verification failed");
}

if (body.type === "checkout.session.completed") {
const chargeId = body.data.object.id;
if (event.type === "checkout.session.completed") {
const chargeId = event.data.object.id;

if (body.data.object.payment_status === "paid") {
if (event.data.object.payment_status === "paid") {
await camperService.confirmCamperPayment(
(chargeId as unknown) as string,
);
Expand Down
19 changes: 19 additions & 0 deletions backend/typescript/utilities/stripeUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ const stripe = new Stripe(process.env.STRIPE_SECRET_TEST_KEY ?? "", {
apiVersion: "2020-08-27",
});

const STRIPE_ENDPOINT_KEY = process.env.STRIPE_ENDPOINT_SECRET || "";

const dropoffProductName = "Early Drop Off Fees";
const pickupProductName = "Late Pick Up Fees";

Expand Down Expand Up @@ -146,3 +148,20 @@ export async function createStripeCheckoutSession(

return checkoutSession;
}

export const verifyStripeWebhooksRequest = (
signature: any,
body: any,
): Stripe.Event | undefined => {
try {
const event: Stripe.Event = stripe.webhooks.constructEvent(
body,
signature,
STRIPE_ENDPOINT_KEY,
);
return event;
} catch (err: any) {
console.log(`❌ Error message: ${err.message}`);
return undefined;
}
};

0 comments on commit f3bfcf5

Please sign in to comment.