From d33c24bd40b120890e812a2dded6ff53c7c92124 Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Sat, 30 Dec 2023 15:40:00 +0100 Subject: [PATCH] chore(test-project): Fix test-project generation script, and regenerate fixture (#9779) --- __fixtures__/test-project/README.md | 2 +- __fixtures__/test-project/api/package.json | 2 +- .../test-project/api/src/functions/auth.ts | 46 ++++++++++++------- .../test-project/api/src/functions/graphql.ts | 6 ++- __fixtures__/test-project/api/src/lib/auth.ts | 9 ++++ __fixtures__/test-project/web/package.json | 6 +-- __fixtures__/test-project/web/vite.config.ts | 8 ++-- tasks/test-project/codemods/models.js | 2 +- .../templates/api/context.test.ts.template | 2 +- tasks/test-project/tui-tasks.js | 35 ++++++++++---- tasks/test-project/util.js | 2 + 11 files changed, 83 insertions(+), 37 deletions(-) diff --git a/__fixtures__/test-project/README.md b/__fixtures__/test-project/README.md index 08f58865b056..60a38fe2c6ac 100644 --- a/__fixtures__/test-project/README.md +++ b/__fixtures__/test-project/README.md @@ -4,7 +4,7 @@ Welcome to [RedwoodJS](https://redwoodjs.com)! > **Prerequisites** > -> - Redwood requires [Node.js](https://nodejs.org/en/) (=18.x) and [Yarn](https://yarnpkg.com/) (>=1.15) +> - Redwood requires [Node.js](https://nodejs.org/en/) (=20.x) and [Yarn](https://yarnpkg.com/) > - Are you on Windows? For best results, follow our [Windows development setup](https://redwoodjs.com/docs/how-to/windows-development-setup) guide Start by installing dependencies: diff --git a/__fixtures__/test-project/api/package.json b/__fixtures__/test-project/api/package.json index 1fe562e03fbe..3184b65cbe96 100644 --- a/__fixtures__/test-project/api/package.json +++ b/__fixtures__/test-project/api/package.json @@ -4,7 +4,7 @@ "private": true, "dependencies": { "@redwoodjs/api": "6.0.7", - "@redwoodjs/auth-dbauth-api": "6.0.7", + "@redwoodjs/auth-dbauth-api": "7.0.0-canary.789", "@redwoodjs/graphql-server": "6.0.7" } } diff --git a/__fixtures__/test-project/api/src/functions/auth.ts b/__fixtures__/test-project/api/src/functions/auth.ts index ce2b4cdc4d57..d71b437e9802 100644 --- a/__fixtures__/test-project/api/src/functions/auth.ts +++ b/__fixtures__/test-project/api/src/functions/auth.ts @@ -3,6 +3,7 @@ import type { APIGatewayProxyEvent, Context } from 'aws-lambda' import { DbAuthHandler } from '@redwoodjs/auth-dbauth-api' import type { DbAuthHandlerOptions, UserType } from '@redwoodjs/auth-dbauth-api' +import { cookieName } from 'src/lib/auth' import { db } from 'src/lib/db' export const handler = async ( @@ -18,11 +19,20 @@ export const handler = async ( // https://example.com/reset-password?resetToken=${user.resetToken} // // Whatever is returned from this function will be returned from - // the `forgotPassword()` function that is destructured from `useAuth()` + // the `forgotPassword()` function that is destructured from `useAuth()`. // You could use this return value to, for example, show the email // address in a toast message so the user will know it worked and where // to look for the email. - handler: (user) => { + // + // Note that this return value is sent to the client in *plain text* + // so don't include anything you wouldn't want prying eyes to see. The + // `user` here has been sanitized to only include the fields listed in + // `allowedUserFields` so it should be safe to return as-is. + handler: (user, _resetToken) => { + // TODO: Send user an email/message with a link to reset their password, + // including the `resetToken`. The URL should look something like: + // `http://localhost:8910/reset-password?resetToken=${resetToken}` + return user }, @@ -115,12 +125,7 @@ export const handler = async ( // // If this returns anything else, it will be returned by the // `signUp()` function in the form of: `{ message: 'String here' }`. - handler: ({ - username, - hashedPassword, - salt, - userAttributes - }) => { + handler: ({ username, hashedPassword, salt, userAttributes }) => { return db.user.create({ data: { email: username, @@ -165,17 +170,26 @@ export const handler = async ( resetTokenExpiresAt: 'resetTokenExpiresAt', }, + // A list of fields on your user object that are safe to return to the + // client when invoking a handler that returns a user (like forgotPassword + // and signup). This list should be as small as possible to be sure not to + // leak any sensitive information to the client. + allowedUserFields: ['id', 'email'], + // Specifies attributes on the cookie that dbAuth sets in order to remember // who is logged in. See https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies cookie: { - HttpOnly: true, - Path: '/', - SameSite: 'Strict', - Secure: process.env.NODE_ENV !== 'development', - - // If you need to allow other domains (besides the api side) access to - // the dbAuth session cookie: - // Domain: 'example.com', + attributes: { + HttpOnly: true, + Path: '/', + SameSite: 'Strict', + Secure: process.env.NODE_ENV !== 'development', + + // If you need to allow other domains (besides the api side) access to + // the dbAuth session cookie: + // Domain: 'example.com', + }, + name: cookieName, }, forgotPassword: forgotPasswordOptions, diff --git a/__fixtures__/test-project/api/src/functions/graphql.ts b/__fixtures__/test-project/api/src/functions/graphql.ts index 5d8db6ab8f2a..e9c53e285fad 100644 --- a/__fixtures__/test-project/api/src/functions/graphql.ts +++ b/__fixtures__/test-project/api/src/functions/graphql.ts @@ -1,14 +1,16 @@ -import { authDecoder } from '@redwoodjs/auth-dbauth-api' +import { createAuthDecoder } from '@redwoodjs/auth-dbauth-api' import { createGraphQLHandler } from '@redwoodjs/graphql-server' import directives from 'src/directives/**/*.{js,ts}' import sdls from 'src/graphql/**/*.sdl.{js,ts}' import services from 'src/services/**/*.{js,ts}' -import { getCurrentUser } from 'src/lib/auth' +import { cookieName, getCurrentUser } from 'src/lib/auth' import { db } from 'src/lib/db' import { logger } from 'src/lib/logger' +const authDecoder = createAuthDecoder(cookieName) + export const handler = createGraphQLHandler({ authDecoder, getCurrentUser, diff --git a/__fixtures__/test-project/api/src/lib/auth.ts b/__fixtures__/test-project/api/src/lib/auth.ts index 84c450f086c1..4e8f9005ebe5 100644 --- a/__fixtures__/test-project/api/src/lib/auth.ts +++ b/__fixtures__/test-project/api/src/lib/auth.ts @@ -3,6 +3,15 @@ import { AuthenticationError, ForbiddenError } from '@redwoodjs/graphql-server' import { db } from './db' +/** + * The name of the cookie that dbAuth sets + * + * %port% will be replaced with the port the api server is running on. + * If you have multiple RW apps running on the same host, you'll need to + * make sure they all use unique cookie names + */ +export const cookieName = 'session_%port%' + /** * The session object sent in as the first argument to getCurrentUser() will * have a single key `id` containing the unique ID of the logged in user diff --git a/__fixtures__/test-project/web/package.json b/__fixtures__/test-project/web/package.json index c9eb5518fd81..24f597a88129 100644 --- a/__fixtures__/test-project/web/package.json +++ b/__fixtures__/test-project/web/package.json @@ -11,7 +11,7 @@ ] }, "dependencies": { - "@redwoodjs/auth-dbauth-web": "6.0.7", + "@redwoodjs/auth-dbauth-web": "7.0.0-canary.789", "@redwoodjs/forms": "6.0.7", "@redwoodjs/router": "6.0.7", "@redwoodjs/web": "6.0.7", @@ -25,8 +25,8 @@ "@types/react-dom": "18.2.15", "autoprefixer": "^10.4.16", "postcss": "^8.4.32", - "postcss-loader": "^7.3.3", + "postcss-loader": "^7.3.4", "prettier-plugin-tailwindcss": "0.4.1", - "tailwindcss": "^3.3.6" + "tailwindcss": "^3.4.0" } } diff --git a/__fixtures__/test-project/web/vite.config.ts b/__fixtures__/test-project/web/vite.config.ts index f7885f0a1336..54799ce1aa28 100644 --- a/__fixtures__/test-project/web/vite.config.ts +++ b/__fixtures__/test-project/web/vite.config.ts @@ -3,12 +3,12 @@ import dns from 'dns' import type { UserConfig } from 'vite' import { defineConfig } from 'vite' -// See: https://vitejs.dev/config/server-options.html#server-host -// So that Vite will load on local instead of 127.0.0.1 -dns.setDefaultResultOrder('verbatim') - import redwood from '@redwoodjs/vite' +// So that Vite will load on localhost instead of `127.0.0.1`. +// See: https://vitejs.dev/config/server-options.html#server-host. +dns.setDefaultResultOrder('verbatim') + const viteConfig: UserConfig = { plugins: [redwood()], } diff --git a/tasks/test-project/codemods/models.js b/tasks/test-project/codemods/models.js index 63104caf5098..3dcf3b1a863d 100644 --- a/tasks/test-project/codemods/models.js +++ b/tasks/test-project/codemods/models.js @@ -10,7 +10,7 @@ const post = `model Post { }` const contact = `model Contact { - id Int @id @default(autoincrement()) + id Int @id @default(autoincrement()) name String email String message String diff --git a/tasks/test-project/templates/api/context.test.ts.template b/tasks/test-project/templates/api/context.test.ts.template index 7be9e46d3294..972c4756e85d 100644 --- a/tasks/test-project/templates/api/context.test.ts.template +++ b/tasks/test-project/templates/api/context.test.ts.template @@ -10,5 +10,5 @@ test('Set a mock user on the context', async () => { }) test('Context is isolated between tests', () => { - expect(context).toStrictEqual({ currentUser: undefined }) + expect(context).toStrictEqual({}) }) diff --git a/tasks/test-project/tui-tasks.js b/tasks/test-project/tui-tasks.js index 2001faf64383..22d26ee08146 100644 --- a/tasks/test-project/tui-tasks.js +++ b/tasks/test-project/tui-tasks.js @@ -387,9 +387,9 @@ async function webTasks(outputPath, { linkWithLatestFwBuild }) { async function addModel(schema) { const path = `${OUTPUT_PATH}/api/db/schema.prisma` - const current = fs.readFileSync(path) + const current = fs.readFileSync(path, 'utf-8') - fs.writeFileSync(path, `${current}\n\n${schema}`) + fs.writeFileSync(path, `${current.trim()}\n\n${schema}\n`) } async function apiTasks(outputPath, { linkWithLatestFwBuild }) { @@ -406,6 +406,22 @@ async function apiTasks(outputPath, { linkWithLatestFwBuild }) { }, }) + // At an earlier step we run `yarn rwfw project:copy` which gives us + // auth-dbauth-setup@3.2.0 currently. We need that version to be a canary + // version for auth-dbauth-api and auth-dbauth-web package installations + // to work. So we update the package.json to make the setup use the latest + // canary version for the api and web sides + + const { stdout } = await exec( + `yarn npm info @redwoodjs/auth-dbauth-setup --fields versions --json`, + [], + execaOptions + ) + + const latestCanaryVersion = JSON.parse(stdout) + .versions.filter((version) => version.includes('canary')) + .at(-1) + const dbAuthSetupPath = path.join( outputPath, 'node_modules', @@ -413,13 +429,16 @@ async function apiTasks(outputPath, { linkWithLatestFwBuild }) { 'auth-dbauth-setup' ) - // At an earlier step we run `yarn rwfw project:copy` which gives us - // auth-dbauth-setup@3.2.0 currently. We need that version to be a canary - // version for auth-dbauth-api and auth-dbauth-web package installations - // to work. So we remove the current version and add a canary version - // instead. + const dbAuthSetupPackageJson = JSON.parse( + fs.readFileSync(path.join(dbAuthSetupPath, 'package.json'), 'utf-8') + ) + + dbAuthSetupPackageJson.version = latestCanaryVersion - fs.rmSync(dbAuthSetupPath, { recursive: true, force: true }) + fs.writeFileSync( + path.join(dbAuthSetupPath, 'package.json'), + JSON.stringify(dbAuthSetupPackageJson, null, 2) + ) await exec( 'yarn rw setup auth dbAuth --force --no-webauthn', diff --git a/tasks/test-project/util.js b/tasks/test-project/util.js index abacaabc0efc..a4dd2c105a8e 100644 --- a/tasks/test-project/util.js +++ b/tasks/test-project/util.js @@ -92,6 +92,8 @@ async function exec(...args) { if (exitCode !== 0) { throw new ExecaError({ stdout, stderr, exitCode }) } + + return { stdout, stderr, exitCode } }) .catch((error) => { if (error instanceof ExecaError) {