From 8be01616d4d8f5ed85b8daac582eaf66e8d8c57c Mon Sep 17 00:00:00 2001 From: Benson Cho <100653148+bcho892@users.noreply.github.com> Date: Sat, 23 Mar 2024 18:05:33 +1300 Subject: [PATCH 01/12] Prettier workflow (#183) * add check on ci for prettier * add files * change readme * rename workflow --- .github/workflows/prettier.yml | 17 +++++++++++++++++ README.md | 1 + package.json | 1 + 3 files changed, 19 insertions(+) create mode 100644 .github/workflows/prettier.yml diff --git a/.github/workflows/prettier.yml b/.github/workflows/prettier.yml new file mode 100644 index 000000000..7726b2b36 --- /dev/null +++ b/.github/workflows/prettier.yml @@ -0,0 +1,17 @@ +name: Prettier +on: + pull_request: + push: + branches: + - master +jobs: + Prettier: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Enable corepack + run: corepack enable + + - run: sudo yarn + - run: yarn prettier:ci diff --git a/README.md b/README.md index f71f4f0f4..94ba964ac 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ Project initiated by WDCC in 2023. - Eddie Wang (Project Manager) ## 2024 Team Members + - Kartik Malik - Logan Bellingham - Aziz Patel diff --git a/package.json b/package.json index 3fca38501..ae7bc4808 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "lint": "eslint", "lint-all": "eslint .", "prettier": "prettier . --write", + "prettier:ci": "prettier . --check", "vsc-setup": "code --install-extension dbaeumer.vscode-eslint && code --install-extension esbenp.prettier-vscode && code install-extension bradlc.vscode-tailwindcss", "postinstall": "husky", "lint-and-fix": "eslint . --fix", From 425ac421a94704c8db384ff7d5e32685cd6d4fa1 Mon Sep 17 00:00:00 2001 From: Benson Cho <100653148+bcho892@users.noreply.github.com> Date: Sat, 23 Mar 2024 20:24:25 +1300 Subject: [PATCH 02/12] Pre push instead of pre commit (#184) * dont run checks on EVERY commit, do it on pushes * test * run linters instead of lint-staged * fix command * fix induced lint error --- .husky/pre-commit | 1 - .husky/pre-push | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) delete mode 100644 .husky/pre-commit create mode 100644 .husky/pre-push diff --git a/.husky/pre-commit b/.husky/pre-commit deleted file mode 100644 index 1a1f1f060..000000000 --- a/.husky/pre-commit +++ /dev/null @@ -1 +0,0 @@ -yarn lint-staged \ No newline at end of file diff --git a/.husky/pre-push b/.husky/pre-push new file mode 100644 index 000000000..1fcee5fba --- /dev/null +++ b/.husky/pre-push @@ -0,0 +1,2 @@ +yarn lint-all +yarn prettier:ci \ No newline at end of file From 307599dd365f79e11a33cacbcfe70e62f29de2db Mon Sep 17 00:00:00 2001 From: Benson Cho <100653148+bcho892@users.noreply.github.com> Date: Tue, 26 Mar 2024 20:32:10 +1300 Subject: [PATCH 03/12] add command for testing firestore on server (#185) --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index ae7bc4808..789a860fa 100644 --- a/package.json +++ b/package.json @@ -51,9 +51,10 @@ "dev-client": "yarn workspace client start", "dev-server": "yarn workspace server start", "storybook": "yarn workspace client storybook", - "test-server": "firebase emulators:exec --only firestore \"node --experimental-vm-modules --dns-result-order=ipv4first ./node_modules/jest/bin/jest.js --setupFiles dotenv/config --passWithNoTests --detectOpenHandles --forceExit --testPathPattern=server/src\"", + "test-server": "yarn firestore-test \"node --experimental-vm-modules --dns-result-order=ipv4first ./node_modules/jest/bin/jest.js --setupFiles dotenv/config --passWithNoTests --detectOpenHandles --forceExit --testPathPattern=server/src\"", "test-client": "jest --setupFiles dotenv/config --passWithNoTests --detectOpenHandles --forceExit --testPathPattern=server/client", - "test": "yarn test-client && yarn test-server" + "test": "yarn test-client && yarn test-server", + "firestore-test": "firebase emulators:exec --only firestore" }, "eslintConfig": { "extends": [ From bbe53930d4d3882103cd0b7ede7c036a9b5199a5 Mon Sep 17 00:00:00 2001 From: Jefffplays2005 Date: Thu, 28 Mar 2024 12:57:38 +1300 Subject: [PATCH 04/12] Push developement files --- client/package.json | 2 +- .../services/StripeWebhook.test.ts | 18 +++++++++ server/src/middleware/__generated__/routes.ts | 2 + .../controllers/StripeWebhook.ts | 37 +++++++++++++++++++ .../request-models/StripeWebhook.ts | 15 ++++++++ yarn.lock | 10 ++--- 6 files changed, 78 insertions(+), 6 deletions(-) create mode 100644 server/src/business-layer/services/StripeWebhook.test.ts create mode 100644 server/src/service-layer/controllers/StripeWebhook.ts create mode 100644 server/src/service-layer/request-models/StripeWebhook.ts diff --git a/client/package.json b/client/package.json index 71fc4c5e0..b404858a8 100644 --- a/client/package.json +++ b/client/package.json @@ -33,7 +33,7 @@ "react-router-dom": "^6.10.0", "react-sweet-state": "^2.7.1", "scheduler": "^0.23.0", - "stripe": "^13.7.0", + "stripe": "^14.22.0", "vite": "^4.1.0-beta.0", "vite-tsconfig-paths": "^4.2.3", "web-vitals": "^2.1.4" diff --git a/server/src/business-layer/services/StripeWebhook.test.ts b/server/src/business-layer/services/StripeWebhook.test.ts new file mode 100644 index 000000000..f09a78bf5 --- /dev/null +++ b/server/src/business-layer/services/StripeWebhook.test.ts @@ -0,0 +1,18 @@ +import StripeService from "./StripeService" + +jest.mock("stripe", () => { + const stripe = jest.requireActual("stripe") + jest + .spyOn(stripe.resources.Customers.prototype, "post") + .mockImplementation(() => { + Promise.resolve({ id: "stripe-test-id" }) + }) + return stripe +}) + +describe("Stripe Service", () => { + it("should do this", async () => { + const customer = new StripeService().getCustomer("eufhgeufh38g") + expect(customer).toEqual(customerMock) + }) +}) diff --git a/server/src/middleware/__generated__/routes.ts b/server/src/middleware/__generated__/routes.ts index 8ca1bfb00..9ae7e70ae 100644 --- a/server/src/middleware/__generated__/routes.ts +++ b/server/src/middleware/__generated__/routes.ts @@ -4,6 +4,8 @@ import { Controller, ValidationService, FieldErrors, ValidateError, TsoaRoute, HttpStatusCodeLiteral, TsoaResponse, fetchMiddlewares } from '@tsoa/runtime'; // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa import { UsersController } from './../../service-layer/controllers/UserController'; +// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa +import { StripeWebhook } from './../../service-layer/controllers/StripeWebhook'; import { expressAuthentication } from './../../business-layer/security/Authentication'; // @ts-ignore - no great way to install types from subpackage import type { RequestHandler, Router } from 'express'; diff --git a/server/src/service-layer/controllers/StripeWebhook.ts b/server/src/service-layer/controllers/StripeWebhook.ts new file mode 100644 index 000000000..33a58dde4 --- /dev/null +++ b/server/src/service-layer/controllers/StripeWebhook.ts @@ -0,0 +1,37 @@ +import { StripeWebhookHeader } from "service-layer/request-models/StripeWebhook" +import { Controller, SuccessResponse, Route, Post, Body, Header } from "tsoa" +import Stripe from "stripe" +const stripe = new Stripe(process.env.STRIPE_API_KEY) + +@Post() +@Route("webhook") +export class StripeWebhook extends Controller { + @SuccessResponse(200, "Webhook post received") + // public + public async receiveWebhook( + @Header() requestHeader: StripeWebhookHeader, + @Body() requestBody: any + ): Promise { + try { + const event: Stripe.Event = stripe.webhooks.constructEvent( + requestBody, + requestHeader["stripe-signature"], + process.env.STRIPE_API_SECRET + ) + switch (event.type) { + case "payment_intent.succeeded": + console.log("payment_intent.succeeded") + break + case "payment_method.attached": + console.log("payment_method.attached") + break + default: + console.log(`Unhandled event type ${event.type}.`) + } + return this.setStatus(200) // set status to 200 as success + } catch (err) { + // set status to 400 due to bad request + return this.setStatus(400) + } + } +} diff --git a/server/src/service-layer/request-models/StripeWebhook.ts b/server/src/service-layer/request-models/StripeWebhook.ts new file mode 100644 index 000000000..11eb5cc44 --- /dev/null +++ b/server/src/service-layer/request-models/StripeWebhook.ts @@ -0,0 +1,15 @@ +export interface StripeWebhookBody { + id: string + object: string + type: string + data: { + object: { + id: string + } + } + pending_webhooks: integer +} + +export interface StripeWebhookHeader { + "stripe-signature": string +} diff --git a/yarn.lock b/yarn.lock index 217b30384..c952d810a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7753,7 +7753,7 @@ __metadata: react-sweet-state: "npm:^2.7.1" scheduler: "npm:^0.23.0" storybook: "npm:^7.6.17" - stripe: "npm:^13.7.0" + stripe: "npm:^14.22.0" tailwindcss: "npm:^3.4.1" typescript: "npm:^5.3.3" vite: "npm:^4.1.0-beta.0" @@ -17137,13 +17137,13 @@ __metadata: languageName: node linkType: hard -"stripe@npm:^13.7.0": - version: 13.11.0 - resolution: "stripe@npm:13.11.0" +"stripe@npm:^14.22.0": + version: 14.22.0 + resolution: "stripe@npm:14.22.0" dependencies: "@types/node": "npm:>=8.1.0" qs: "npm:^6.11.0" - checksum: 10c0/ea9ad9397a4b5464bf5e2cc3a65683d14e035161c5db0146061370f2316851e6b919e4fe2be97ec0dc72a2856b09cceab69e7afcb4a86f9e3361ed630f2fbad2 + checksum: 10c0/befb3a1d517c7bfcbf6cf9bebdebd6d86e3ba1d0f581a4634ff622d95f63c37f0e85266cb35897a0f1f4ac6e6aa6485ac2ffc85a6e66bf85759704ea345f4ebf languageName: node linkType: hard From 4c25e4e0022459d084493a0a8741a6eff5c6e1d1 Mon Sep 17 00:00:00 2001 From: Jefffplays2005 Date: Thu, 28 Mar 2024 17:06:30 +1300 Subject: [PATCH 05/12] Update to accept post requests, payload issues now --- client/src/models/__generated__/schema.d.ts | 11 +++++++ server/src/middleware/__generated__/routes.ts | 25 ++++++++++++++++ .../src/middleware/__generated__/swagger.json | 12 ++++++++ .../controllers/StripeWebhook.ts | 29 ++++++++++--------- .../request-models/StripeWebhook.ts | 15 ---------- 5 files changed, 64 insertions(+), 28 deletions(-) delete mode 100644 server/src/service-layer/request-models/StripeWebhook.ts diff --git a/client/src/models/__generated__/schema.d.ts b/client/src/models/__generated__/schema.d.ts index 55ad7010b..4e58c9f10 100644 --- a/client/src/models/__generated__/schema.d.ts +++ b/client/src/models/__generated__/schema.d.ts @@ -17,6 +17,9 @@ export interface paths { "/users/bulk-edit": { patch: operations["EditUsers"]; }; + "/webhook": { + post: operations["ReceiveWebhook"]; + }; } export type webhooks = Record; @@ -141,4 +144,12 @@ export interface operations { }; }; }; + ReceiveWebhook: { + responses: { + /** @description Webhook post received */ + 200: { + content: never; + }; + }; + }; } diff --git a/server/src/middleware/__generated__/routes.ts b/server/src/middleware/__generated__/routes.ts index 9ae7e70ae..42b8f1ac7 100644 --- a/server/src/middleware/__generated__/routes.ts +++ b/server/src/middleware/__generated__/routes.ts @@ -188,6 +188,31 @@ export function RegisterRoutes(app: Router) { } }); // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + app.post('/webhook', + ...(fetchMiddlewares(StripeWebhook)), + ...(fetchMiddlewares(StripeWebhook.prototype.receiveWebhook)), + + function StripeWebhook_receiveWebhook(request: any, response: any, next: any) { + const args = { + request: {"in":"request","name":"request","required":true,"dataType":"object"}, + }; + + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + + let validatedArgs: any[] = []; + try { + validatedArgs = getValidatedArgs(args, request, response); + + const controller = new StripeWebhook(); + + + const promise = controller.receiveWebhook.apply(controller, validatedArgs as any); + promiseHandler(controller, promise, response, 200, next); + } catch (err) { + return next(err); + } + }); + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa diff --git a/server/src/middleware/__generated__/swagger.json b/server/src/middleware/__generated__/swagger.json index 3442d1460..9e472181f 100644 --- a/server/src/middleware/__generated__/swagger.json +++ b/server/src/middleware/__generated__/swagger.json @@ -285,6 +285,18 @@ } } } + }, + "/webhook": { + "post": { + "operationId": "ReceiveWebhook", + "responses": { + "200": { + "description": "Webhook post received" + } + }, + "security": [], + "parameters": [] + } } }, "servers": [ diff --git a/server/src/service-layer/controllers/StripeWebhook.ts b/server/src/service-layer/controllers/StripeWebhook.ts index 33a58dde4..17f200239 100644 --- a/server/src/service-layer/controllers/StripeWebhook.ts +++ b/server/src/service-layer/controllers/StripeWebhook.ts @@ -1,22 +1,24 @@ -import { StripeWebhookHeader } from "service-layer/request-models/StripeWebhook" -import { Controller, SuccessResponse, Route, Post, Body, Header } from "tsoa" +// import { StripeWebhookHeader } from "service-layer/request-models/StripeWebhook" +import { Controller, SuccessResponse, Route, Post, Request } from "tsoa" import Stripe from "stripe" -const stripe = new Stripe(process.env.STRIPE_API_KEY) -@Post() @Route("webhook") export class StripeWebhook extends Controller { @SuccessResponse(200, "Webhook post received") - // public - public async receiveWebhook( - @Header() requestHeader: StripeWebhookHeader, - @Body() requestBody: any - ): Promise { + @Post() + public async receiveWebhook(@Request() request: any): Promise { + const stripe = new Stripe(process.env.STRIPE_API_KEY) + + const endPointSecret = process.env.STRIPE_LOCAL + + console.log("webhook received") try { - const event: Stripe.Event = stripe.webhooks.constructEvent( - requestBody, - requestHeader["stripe-signature"], - process.env.STRIPE_API_SECRET + const event = stripe.webhooks.constructEvent( + // const event: Stripe.Event = stripe.webhooks.constructEvent( + request.body, + request.headers["stripe-signature"], + endPointSecret + // process.env.STRIPE_API_SECRET ) switch (event.type) { case "payment_intent.succeeded": @@ -30,6 +32,7 @@ export class StripeWebhook extends Controller { } return this.setStatus(200) // set status to 200 as success } catch (err) { + console.log(err) // set status to 400 due to bad request return this.setStatus(400) } diff --git a/server/src/service-layer/request-models/StripeWebhook.ts b/server/src/service-layer/request-models/StripeWebhook.ts deleted file mode 100644 index 11eb5cc44..000000000 --- a/server/src/service-layer/request-models/StripeWebhook.ts +++ /dev/null @@ -1,15 +0,0 @@ -export interface StripeWebhookBody { - id: string - object: string - type: string - data: { - object: { - id: string - } - } - pending_webhooks: integer -} - -export interface StripeWebhookHeader { - "stripe-signature": string -} From 86ad171ebe9b0871cc31d89f2bd195dd5fd1fa96 Mon Sep 17 00:00:00 2001 From: Jefffplays2005 Date: Thu, 28 Mar 2024 21:24:54 +1300 Subject: [PATCH 06/12] Allows stripe webhook receival. Open to new services being added. Updated README.md to describe how local testing can be performed on the Stripe webhook. Updated index.ts to allow for the keeping of the raw body during requests. Plans to change this to only enable for the /webhook endpoint. --- server/src/index.ts | 13 +++++++++++- .../src/service-layer/controllers/README.md | 6 ++++++ .../controllers/StripeWebhook.ts | 20 +++++++++---------- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/server/src/index.ts b/server/src/index.ts index f846c654c..1dae915e3 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -15,8 +15,19 @@ const importSwaggerJson = async () => { const app: Express = express() +function keepRawBody( + req: any, + res: any, + buf: Buffer, + encoding: BufferEncoding +) { + if (buf && buf.length) { + req.rawBody = buf + } +} + app.use(helmet()) -app.use(express.json()) +app.use(express.json({ verify: keepRawBody })) app.use(cors()) app.use("/api-docs", swaggerUi.serve, async (_req: Request, res: Response) => { diff --git a/server/src/service-layer/controllers/README.md b/server/src/service-layer/controllers/README.md index eee197126..ffd3f144d 100644 --- a/server/src/service-layer/controllers/README.md +++ b/server/src/service-layer/controllers/README.md @@ -3,3 +3,9 @@ Controller methods convert requests coming from the routes and convert to HTTP responses See the [tsoa docs](https://tsoa-community.github.io/docs/examples.html) for how to write controllers (These will automatically be converted to routes) + +## Stripe Webhook + +For local testing, ensure that your .env file has a STRIPE_LOCAL key, which stores the stripe local webhook key for testing purposes. + +Follow the current [link](https://docs.stripe.com/webhooks#test-webhook) for local testing. diff --git a/server/src/service-layer/controllers/StripeWebhook.ts b/server/src/service-layer/controllers/StripeWebhook.ts index 17f200239..ca0671266 100644 --- a/server/src/service-layer/controllers/StripeWebhook.ts +++ b/server/src/service-layer/controllers/StripeWebhook.ts @@ -1,24 +1,21 @@ -// import { StripeWebhookHeader } from "service-layer/request-models/StripeWebhook" import { Controller, SuccessResponse, Route, Post, Request } from "tsoa" import Stripe from "stripe" @Route("webhook") export class StripeWebhook extends Controller { - @SuccessResponse(200, "Webhook post received") @Post() + @SuccessResponse(200, "Webhook post received") public async receiveWebhook(@Request() request: any): Promise { - const stripe = new Stripe(process.env.STRIPE_API_KEY) + console.log("webhook received") - const endPointSecret = process.env.STRIPE_LOCAL + const stripe = new Stripe(process.env.STRIPE_API_KEY) - console.log("webhook received") try { - const event = stripe.webhooks.constructEvent( - // const event: Stripe.Event = stripe.webhooks.constructEvent( - request.body, + const event: Stripe.Event = stripe.webhooks.constructEvent( + request.rawBody, request.headers["stripe-signature"], - endPointSecret - // process.env.STRIPE_API_SECRET + // process.env.STRIPE_LOCAL // test local api secret + process.env.STRIPE_API_SECRET ) switch (event.type) { case "payment_intent.succeeded": @@ -30,9 +27,10 @@ export class StripeWebhook extends Controller { default: console.log(`Unhandled event type ${event.type}.`) } + return this.setStatus(200) // set status to 200 as success } catch (err) { - console.log(err) + console.error(err) // set status to 400 due to bad request return this.setStatus(400) } From 255a99115c0e684eac072766256e3a6bfef659da Mon Sep 17 00:00:00 2001 From: Jefffplays2005 Date: Thu, 28 Mar 2024 21:31:33 +1300 Subject: [PATCH 07/12] Removed the stripewebhook test, using manual local testing. --- .../services/StripeWebhook.test.ts | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 server/src/business-layer/services/StripeWebhook.test.ts diff --git a/server/src/business-layer/services/StripeWebhook.test.ts b/server/src/business-layer/services/StripeWebhook.test.ts deleted file mode 100644 index f09a78bf5..000000000 --- a/server/src/business-layer/services/StripeWebhook.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import StripeService from "./StripeService" - -jest.mock("stripe", () => { - const stripe = jest.requireActual("stripe") - jest - .spyOn(stripe.resources.Customers.prototype, "post") - .mockImplementation(() => { - Promise.resolve({ id: "stripe-test-id" }) - }) - return stripe -}) - -describe("Stripe Service", () => { - it("should do this", async () => { - const customer = new StripeService().getCustomer("eufhgeufh38g") - expect(customer).toEqual(customerMock) - }) -}) From 8e2cb4e5063fd77dab7695c86bc7ca040baad6bb Mon Sep 17 00:00:00 2001 From: Jefffplays2005 Date: Thu, 28 Mar 2024 21:47:48 +1300 Subject: [PATCH 08/12] Removed StripeWebhook.test.ts as testing is manual and local. Removed README.md documentations as moved the testing steps to the github wiki. Updated server workspace Stripe version. Reverted changes to client workspace back to master. Needing to move helper function out of index.ts --- client/package.json | 2 +- server/package.json | 1 + .../services/StripeWebhook.test.ts | 18 ----------------- server/src/index.ts | 13 +++++++++++- .../controllers/StripeWebhook.ts | 20 +++++++++---------- yarn.lock | 13 +++++++++++- 6 files changed, 35 insertions(+), 32 deletions(-) delete mode 100644 server/src/business-layer/services/StripeWebhook.test.ts diff --git a/client/package.json b/client/package.json index b404858a8..71fc4c5e0 100644 --- a/client/package.json +++ b/client/package.json @@ -33,7 +33,7 @@ "react-router-dom": "^6.10.0", "react-sweet-state": "^2.7.1", "scheduler": "^0.23.0", - "stripe": "^14.22.0", + "stripe": "^13.7.0", "vite": "^4.1.0-beta.0", "vite-tsconfig-paths": "^4.2.3", "web-vitals": "^2.1.4" diff --git a/server/package.json b/server/package.json index cd5045f29..9edcb4293 100644 --- a/server/package.json +++ b/server/package.json @@ -10,6 +10,7 @@ "express": "^4.18.2", "firebase-admin": "^12.0.0", "helmet": "^7.1.0", + "stripe": "^14.22.0", "supertest": "^6.3.4", "swagger-jsdoc": "^6.2.8", "swagger-ui-express": "^5.0.0", diff --git a/server/src/business-layer/services/StripeWebhook.test.ts b/server/src/business-layer/services/StripeWebhook.test.ts deleted file mode 100644 index f09a78bf5..000000000 --- a/server/src/business-layer/services/StripeWebhook.test.ts +++ /dev/null @@ -1,18 +0,0 @@ -import StripeService from "./StripeService" - -jest.mock("stripe", () => { - const stripe = jest.requireActual("stripe") - jest - .spyOn(stripe.resources.Customers.prototype, "post") - .mockImplementation(() => { - Promise.resolve({ id: "stripe-test-id" }) - }) - return stripe -}) - -describe("Stripe Service", () => { - it("should do this", async () => { - const customer = new StripeService().getCustomer("eufhgeufh38g") - expect(customer).toEqual(customerMock) - }) -}) diff --git a/server/src/index.ts b/server/src/index.ts index f846c654c..d0e6e7e6f 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -14,9 +14,20 @@ const importSwaggerJson = async () => { } const app: Express = express() +function keepRawBody( + req: any, + res: any, + buf: Buffer, + encoding: BufferEncoding +) { + if (buf && buf.length) { + req.rawBody = buf + } +} +}) app.use(helmet()) -app.use(express.json()) +app.use(express.json({ verify: keepRawBody })) app.use(cors()) app.use("/api-docs", swaggerUi.serve, async (_req: Request, res: Response) => { diff --git a/server/src/service-layer/controllers/StripeWebhook.ts b/server/src/service-layer/controllers/StripeWebhook.ts index 17f200239..ca0671266 100644 --- a/server/src/service-layer/controllers/StripeWebhook.ts +++ b/server/src/service-layer/controllers/StripeWebhook.ts @@ -1,24 +1,21 @@ -// import { StripeWebhookHeader } from "service-layer/request-models/StripeWebhook" import { Controller, SuccessResponse, Route, Post, Request } from "tsoa" import Stripe from "stripe" @Route("webhook") export class StripeWebhook extends Controller { - @SuccessResponse(200, "Webhook post received") @Post() + @SuccessResponse(200, "Webhook post received") public async receiveWebhook(@Request() request: any): Promise { - const stripe = new Stripe(process.env.STRIPE_API_KEY) + console.log("webhook received") - const endPointSecret = process.env.STRIPE_LOCAL + const stripe = new Stripe(process.env.STRIPE_API_KEY) - console.log("webhook received") try { - const event = stripe.webhooks.constructEvent( - // const event: Stripe.Event = stripe.webhooks.constructEvent( - request.body, + const event: Stripe.Event = stripe.webhooks.constructEvent( + request.rawBody, request.headers["stripe-signature"], - endPointSecret - // process.env.STRIPE_API_SECRET + // process.env.STRIPE_LOCAL // test local api secret + process.env.STRIPE_API_SECRET ) switch (event.type) { case "payment_intent.succeeded": @@ -30,9 +27,10 @@ export class StripeWebhook extends Controller { default: console.log(`Unhandled event type ${event.type}.`) } + return this.setStatus(200) // set status to 200 as success } catch (err) { - console.log(err) + console.error(err) // set status to 400 due to bad request return this.setStatus(400) } diff --git a/yarn.lock b/yarn.lock index c952d810a..80c4c2482 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7753,7 +7753,7 @@ __metadata: react-sweet-state: "npm:^2.7.1" scheduler: "npm:^0.23.0" storybook: "npm:^7.6.17" - stripe: "npm:^14.22.0" + stripe: "npm:^13.7.0" tailwindcss: "npm:^3.4.1" typescript: "npm:^5.3.3" vite: "npm:^4.1.0-beta.0" @@ -16503,6 +16503,7 @@ __metadata: firebase-admin: "npm:^12.0.0" helmet: "npm:^7.1.0" nodemon: "npm:^3.1.0" + stripe: "npm:^14.22.0" supertest: "npm:^6.3.4" swagger-jsdoc: "npm:^6.2.8" swagger-ui-express: "npm:^5.0.0" @@ -17137,6 +17138,16 @@ __metadata: languageName: node linkType: hard +"stripe@npm:^13.7.0": + version: 13.11.0 + resolution: "stripe@npm:13.11.0" + dependencies: + "@types/node": "npm:>=8.1.0" + qs: "npm:^6.11.0" + checksum: 10c0/ea9ad9397a4b5464bf5e2cc3a65683d14e035161c5db0146061370f2316851e6b919e4fe2be97ec0dc72a2856b09cceab69e7afcb4a86f9e3361ed630f2fbad2 + languageName: node + linkType: hard + "stripe@npm:^14.22.0": version: 14.22.0 resolution: "stripe@npm:14.22.0" From 37be1839eacda06bdb62ca643ee5485c010489a7 Mon Sep 17 00:00:00 2001 From: Jefffplays2005 Date: Thu, 28 Mar 2024 21:54:37 +1300 Subject: [PATCH 09/12] Fixed duplicate functions and removed documentation in README.md file --- server/src/index.ts | 12 ------------ server/src/service-layer/controllers/README.md | 6 ------ 2 files changed, 18 deletions(-) diff --git a/server/src/index.ts b/server/src/index.ts index 651538722..641644366 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -14,18 +14,6 @@ const importSwaggerJson = async () => { } const app: Express = express() -function keepRawBody( - req: any, - res: any, - buf: Buffer, - encoding: BufferEncoding -) { - if (buf && buf.length) { - req.rawBody = buf - } -} -}) - function keepRawBody( req: any, res: any, diff --git a/server/src/service-layer/controllers/README.md b/server/src/service-layer/controllers/README.md index ffd3f144d..eee197126 100644 --- a/server/src/service-layer/controllers/README.md +++ b/server/src/service-layer/controllers/README.md @@ -3,9 +3,3 @@ Controller methods convert requests coming from the routes and convert to HTTP responses See the [tsoa docs](https://tsoa-community.github.io/docs/examples.html) for how to write controllers (These will automatically be converted to routes) - -## Stripe Webhook - -For local testing, ensure that your .env file has a STRIPE_LOCAL key, which stores the stripe local webhook key for testing purposes. - -Follow the current [link](https://docs.stripe.com/webhooks#test-webhook) for local testing. From 23d3b717cc0e16254ef8d3ff442b77c40a109c5e Mon Sep 17 00:00:00 2001 From: Benson Cho <100653148+bcho892@users.noreply.github.com> Date: Thu, 28 Mar 2024 22:30:32 +1300 Subject: [PATCH 10/12] add stripe env variables to server deployment (#193) * update workflows * change --env format * disable on prs --- .github/workflows/deploy-server.production.yml | 2 +- .github/workflows/deploy-server.staging.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy-server.production.yml b/.github/workflows/deploy-server.production.yml index 400b3f34e..888f8f325 100644 --- a/.github/workflows/deploy-server.production.yml +++ b/.github/workflows/deploy-server.production.yml @@ -20,6 +20,6 @@ jobs: steps: - uses: actions/checkout@v3 - uses: superfly/flyctl-actions/setup-flyctl@master - - run: flyctl deploy --remote-only --config fly.production.toml --env "GOOGLE_SERVICE_ACCOUNT_JSON=$(echo ${{ secrets.PROD_SERVER_SERVICE_ACCOUNT }} | base64 --decode)" + - run: flyctl deploy --remote-only --config fly.production.toml --env "GOOGLE_SERVICE_ACCOUNT_JSON=$(echo ${{ secrets.PROD_SERVER_SERVICE_ACCOUNT }} | base64 --decode) STRIPE_API_SECRET=${{ secrets.PROD_SERVER_STRIPE_API_SECRET }} STRIPE_API_KEY=${{ secrets.PROD_SERVER_STRIPE_API_KEY }}" env: FLY_API_TOKEN: ${{ secrets.FLY_API_PRODUCTION_API_TOKEN }} diff --git a/.github/workflows/deploy-server.staging.yml b/.github/workflows/deploy-server.staging.yml index 8eb12de09..e4d0c79aa 100644 --- a/.github/workflows/deploy-server.staging.yml +++ b/.github/workflows/deploy-server.staging.yml @@ -23,6 +23,6 @@ jobs: steps: - uses: actions/checkout@v3 - uses: superfly/flyctl-actions/setup-flyctl@master - - run: flyctl deploy --remote-only --config fly.staging.toml --env "GOOGLE_SERVICE_ACCOUNT_JSON=$(echo ${{ secrets.STAGING_SERVER_SERVICE_ACCOUNT }} | base64 --decode)" + - run: flyctl deploy --remote-only --config fly.staging.toml --env "GOOGLE_SERVICE_ACCOUNT_JSON=$(echo ${{ secrets.STAGING_SERVER_SERVICE_ACCOUNT }} | base64 --decode) STRIPE_API_SECRET=${{ secrets.STAGING_SERVER_STRIPE_API_SECRET }} STRIPE_API_KEY=${{ secrets.STAGING_SERVER_STRIPE_API_KEY }}" env: FLY_API_TOKEN: ${{ secrets.FLY_API_STAGING_API_TOKEN }} From b6a5db9c52f060aa36ada593dcb325455b83ba1f Mon Sep 17 00:00:00 2001 From: Benson Cho <100653148+bcho892@users.noreply.github.com> Date: Thu, 28 Mar 2024 23:00:07 +1300 Subject: [PATCH 11/12] Fix env in workflow (#194) * update workflows * disable on prs * specify --env multiple times --- .github/workflows/deploy-server.production.yml | 2 +- .github/workflows/deploy-server.staging.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy-server.production.yml b/.github/workflows/deploy-server.production.yml index 888f8f325..6db57de2a 100644 --- a/.github/workflows/deploy-server.production.yml +++ b/.github/workflows/deploy-server.production.yml @@ -20,6 +20,6 @@ jobs: steps: - uses: actions/checkout@v3 - uses: superfly/flyctl-actions/setup-flyctl@master - - run: flyctl deploy --remote-only --config fly.production.toml --env "GOOGLE_SERVICE_ACCOUNT_JSON=$(echo ${{ secrets.PROD_SERVER_SERVICE_ACCOUNT }} | base64 --decode) STRIPE_API_SECRET=${{ secrets.PROD_SERVER_STRIPE_API_SECRET }} STRIPE_API_KEY=${{ secrets.PROD_SERVER_STRIPE_API_KEY }}" + - run: flyctl deploy --remote-only --config fly.production.toml --env "GOOGLE_SERVICE_ACCOUNT_JSON=$(echo ${{ secrets.PROD_SERVER_SERVICE_ACCOUNT }} | base64 --decode)" --env "STRIPE_API_SECRET=${{ secrets.PROD_SERVER_STRIPE_API_SECRET }}" --env "STRIPE_API_KEY=${{ secrets.PROD_SERVER_STRIPE_API_KEY }}" env: FLY_API_TOKEN: ${{ secrets.FLY_API_PRODUCTION_API_TOKEN }} diff --git a/.github/workflows/deploy-server.staging.yml b/.github/workflows/deploy-server.staging.yml index e4d0c79aa..2e8d6ca2a 100644 --- a/.github/workflows/deploy-server.staging.yml +++ b/.github/workflows/deploy-server.staging.yml @@ -23,6 +23,6 @@ jobs: steps: - uses: actions/checkout@v3 - uses: superfly/flyctl-actions/setup-flyctl@master - - run: flyctl deploy --remote-only --config fly.staging.toml --env "GOOGLE_SERVICE_ACCOUNT_JSON=$(echo ${{ secrets.STAGING_SERVER_SERVICE_ACCOUNT }} | base64 --decode) STRIPE_API_SECRET=${{ secrets.STAGING_SERVER_STRIPE_API_SECRET }} STRIPE_API_KEY=${{ secrets.STAGING_SERVER_STRIPE_API_KEY }}" + - run: flyctl deploy --remote-only --config fly.staging.toml --env "GOOGLE_SERVICE_ACCOUNT_JSON=$(echo ${{ secrets.STAGING_SERVER_SERVICE_ACCOUNT }} | base64 --decode)" --env "STRIPE_API_SECRET=${{ secrets.STAGING_SERVER_STRIPE_API_SECRET }}" --env "STRIPE_API_KEY=${{ secrets.STAGING_SERVER_STRIPE_API_KEY }}" env: FLY_API_TOKEN: ${{ secrets.FLY_API_STAGING_API_TOKEN }} From d34c7d42709db10d5a32260e9ff6a416c51e801c Mon Sep 17 00:00:00 2001 From: Benson Cho <100653148+bcho892@users.noreply.github.com> Date: Fri, 29 Mar 2024 12:03:04 +1300 Subject: [PATCH 12/12] get storybook working for signup form (#195) --- .../composite/SignUpForm/SignUpForm.story.tsx | 8 +++++ .../composite/SignUpForm/SignUpForm.tsx | 29 ------------------- 2 files changed, 8 insertions(+), 29 deletions(-) diff --git a/client/src/components/composite/SignUpForm/SignUpForm.story.tsx b/client/src/components/composite/SignUpForm/SignUpForm.story.tsx index bc8bbb0e7..6f06e10ad 100644 --- a/client/src/components/composite/SignUpForm/SignUpForm.story.tsx +++ b/client/src/components/composite/SignUpForm/SignUpForm.story.tsx @@ -2,6 +2,7 @@ import type { Meta, StoryObj } from "@storybook/react" import SignUpForm from "./SignUpForm" +import { BrowserRouter } from "react-router-dom" // 👇 This default export determines where your story goes in the story list const meta: Meta = { @@ -12,6 +13,13 @@ export default meta type Story = StoryObj export const FirstStory: Story = { + decorators: [ + (Story) => ( + + + + ) + ], args: { // 👇 The args you need here will depend on your component } diff --git a/client/src/components/composite/SignUpForm/SignUpForm.tsx b/client/src/components/composite/SignUpForm/SignUpForm.tsx index 2b7e4f142..392db8fe6 100644 --- a/client/src/components/composite/SignUpForm/SignUpForm.tsx +++ b/client/src/components/composite/SignUpForm/SignUpForm.tsx @@ -1,12 +1,5 @@ import React, { useState } from "react" -import { - getAuth, - createUserWithEmailAndPassword, - updateProfile -} from "firebase/auth" import { useNavigate } from "react-router-dom" -import { db } from "../../../firebase" -import { setDoc, doc } from "firebase/firestore" import Button from "@mui/material/Button" import TextField from "@mui/material/TextField" import Snackbar from "@mui/material/Snackbar" @@ -62,7 +55,6 @@ const SignUpForm = () => { setOpen(false) } - const auth = getAuth() const navigate = useNavigate() const handleSubmit = async (event: any) => { @@ -106,29 +98,8 @@ const SignUpForm = () => { } try { - const { user } = await createUserWithEmailAndPassword( - auth, - email, - password - ) console.log("User created") - await updateProfile(user, { displayName: `${firstName} ${lastName}` }) - console.log("Profile updated") - - await setDoc(doc(db, "users", user.uid), { - uid: user.uid, - firstName, - lastName, - email, - phoneNumber, - dob, - studentId, - yearLevel, - faculty, - sportType, - interestedInRacing - }) console.log("Document set in Firestore") setOpen(true)