From 2d0634cdc3d00b3e55cf773ff03c7dc841112d36 Mon Sep 17 00:00:00 2001 From: Joe Carstairs <65492573+Sycamost@users.noreply.github.com> Date: Thu, 21 Dec 2023 21:22:47 +0000 Subject: 33 / Users can sign up and log in with WebAuthn (#39) * Installs @vercel/postgres * Installs @simplewebauthn/server * Installs @simplewebauthn/browser * Git-ignores all files starting with .env * Reorganises folders in API * Defines User type * Defines Subscription type * Defines Authenticator type * Sets up table definition file * Can get user from database * Can add user to database * Can get user's current challenge * Can set user's current challenge * Can get user's authenticators from database * Can get authenticator by ID from database * Can add user authenticator to database * Can update authenticator in database * Defines Relying Party information * Can generate registration options * Can verify registration response * Defines registration API endpoint * Defines user API endpoint * Reorganises API functions on frontend * Can access authentication API functions on frontend * Can generate authentication options * Can verify authentication response * Documents the registration flow * Fix dev_csso * Form styling * WIP adds sign up page --- api/_paypal.ts | 115 --------------------------------------------------------- 1 file changed, 115 deletions(-) delete mode 100644 api/_paypal.ts (limited to 'api/_paypal.ts') diff --git a/api/_paypal.ts b/api/_paypal.ts deleted file mode 100644 index 5abb198..0000000 --- a/api/_paypal.ts +++ /dev/null @@ -1,115 +0,0 @@ -import type Order from './_Order'; -import env from './_env'; - -export async function paypalCreateOrder(order: Order) { - const accessToken = await getLazyAccessToken(); - const url = `${PAYPAL_URL}/v2/checkout/orders`; - const response = await fetch(url, { - method: 'POST', - headers: paypalCreateOrderRequestHeaders(accessToken), - body: paypalCreateOrderRequestBody(order), - }); - return await handle(response); -} - -export async function paypalCaptureOrder(orderId: string) { - const accessToken = await getLazyAccessToken(); - const url = `${PAYPAL_URL}/v2/checkout/orders/${orderId}/capture`; - const response = await fetch(url, { - method: 'POST', - headers: paypalCaptureOrderRequestHeaders(accessToken), - }); - return await handle(response); -} - -async function handle(response: Response) { - if (response.ok) { - return await response.json(); - } - throw new Error('Failed to communicate with PayPal. ' + await response.text()); -} - -function paypalCreateOrderRequestBody(order: Order) { - const body = JSON.stringify({ - intent: 'CAPTURE', - purchase_units: [ - { - description: order.productDescription, - soft_descriptor: order.shortDescription, - amount: { - currency_code: 'GBP', - value: order.totalPrice, - }, - }, - ], - }); - return body; -} - -function paypalCreateOrderRequestHeaders(accessToken: string) { - return { - 'Content-Type': 'application/json', - Authorization: `Bearer ${accessToken}`, - }; -} - -function paypalCaptureOrderRequestHeaders(accessToken: string) { - return { - 'Content-Type': 'application/json', - Authorization: `Bearer ${accessToken}`, - }; -} - -const getLazyAccessToken = (() => { - let accessToken: string; - let timeRequested: number; - let timeExpires: number; - return async function (): Promise { - const isNearlyExpired = timeExpires - Date.now() < 10_000; - if (!accessToken || isNearlyExpired) { - timeRequested = Date.now(); - let secondsUntilExpires: number; - ({ accessToken, secondsUntilExpires } = await generateAccessToken()); - const msUntilExpires = secondsUntilExpires * 1000; - timeExpires = timeRequested + msUntilExpires; - } - return accessToken; - }; -})(); - -async function generateAccessToken(): Promise { - const auth = Buffer.from(PAYPAL_CLIENT_ID + ':' + PAYPAL_SECRET).toString('base64'); - const response = await fetch(`${PAYPAL_URL}/v1/oauth2/token`, { - method: 'POST', - body: 'grant_type=client_credentials', - headers: { - Authorization: `Basic ${auth}`, - }, - }); - const { access_token, expires_in } = await response.json(); - if (access_token && expires_in) { - return { - accessToken: access_token, - secondsUntilExpires: expires_in, - }; - } - throw new Error('Could not fetch access token from PayPal.'); -} - -type AccessTokenResponse = { - accessToken: string; - secondsUntilExpires: number; -}; - -const PAYPAL_CLIENT_ID = - env.ENVIRONMENT === 'prod' - ? env.PAYPAL_LIVE_CLIENT_ID - : env.PAYPAL_SANDBOX_CLIENT_ID; -const PAYPAL_SECRET = - env.ENVIRONMENT === 'prod' - ? env.PAYPAL_LIVE_SECRET - : env.PAYPAL_SANDBOX_SECRET; -const PAYPAL_URL = - env.ENVIRONMENT === 'prod' - ? 'https://api-m.paypal.com' - : 'https://api-m.sandbox.paypal.com' \ No newline at end of file -- cgit v1.2.3