From 937b58779ea1653b6ff127c1b98f8ce6f5415719 Mon Sep 17 00:00:00 2001 From: ladderschool Date: Sun, 20 Jul 2025 11:42:45 -0400 Subject: [PATCH 1/2] studio allow resync with trusted docs enabled --- .../src/plugins/useRedwoodTrustedDocuments.ts | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/packages/graphql-server/src/plugins/useRedwoodTrustedDocuments.ts b/packages/graphql-server/src/plugins/useRedwoodTrustedDocuments.ts index 6a60f93f0416..2e129b35b85e 100644 --- a/packages/graphql-server/src/plugins/useRedwoodTrustedDocuments.ts +++ b/packages/graphql-server/src/plugins/useRedwoodTrustedDocuments.ts @@ -26,6 +26,10 @@ export type RedwoodTrustedDocumentOptions = Omit< const REDWOOD__AUTH_GET_CURRENT_USER_QUERY = '{"query":"query __REDWOOD__AUTH_GET_CURRENT_USER { redwood { currentUser } }"}' +const REDWOOD__STUDIO_RESYNC_MAIL_RENDERERS_MUTATION = + '{"query":"mutation { resyncMailRenderers }"}' +const REDWOOD__STUDIO_TEMPLATE_MUTATION = + '{"query":"mutation { resyncMailTemplate }"}' /** * When using Redwood Auth, we want to allow the known, trusted `redwood.currentUser` query to be @@ -54,6 +58,27 @@ const allowRedwoodAuthCurrentUserQuery = async (request: Request) => { return hasAllowedHeaders && hasAllowedQuery } +/** + * When using RedwoodJS Studio, we want to allow the `resyncMailRenderers` and `resyncMailTemplate` mutations to be + * executed without a persisted operation. + * + * This is because the `resyncMailRenderers` mutation is a special case that is used by + * RedwoodJS Studio to sync mail renderers from the mailer configuration. + * + * This function checks if the request is for the `resyncMailRenderers` or `resyncMailTemplate` mutations and has the correct headers. + */ +const allowRedwoodStudioResyncMailMutations = async (request: Request) => { + const headers = request.headers + const hasContentType = headers.get('content-type') === 'application/json' + + const query = await request.text() + const hasAllowedQuery = + query === REDWOOD__STUDIO_RESYNC_MAIL_RENDERERS_MUTATION || + query === REDWOOD__STUDIO_TEMPLATE_MUTATION + + return hasContentType && hasAllowedQuery +} + export const useRedwoodTrustedDocuments = ( options: RedwoodTrustedDocumentOptions, ): Plugin => { @@ -80,7 +105,10 @@ export const useRedwoodTrustedDocuments = ( } } } - return allowRedwoodAuthCurrentUserQuery(request) + return ( + allowRedwoodAuthCurrentUserQuery(request) || + allowRedwoodStudioResyncMailMutations(request) + ) }, }) } From ec81f4777e200d03a3d9d7e8f8e2648cc7672c43 Mon Sep 17 00:00:00 2001 From: ladderschool Date: Wed, 23 Jul 2025 18:24:02 -0400 Subject: [PATCH 2/2] only circumvent trusted docs in dev mode --- .../src/plugins/useRedwoodTrustedDocuments.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/graphql-server/src/plugins/useRedwoodTrustedDocuments.ts b/packages/graphql-server/src/plugins/useRedwoodTrustedDocuments.ts index 2e129b35b85e..9f142fcc9227 100644 --- a/packages/graphql-server/src/plugins/useRedwoodTrustedDocuments.ts +++ b/packages/graphql-server/src/plugins/useRedwoodTrustedDocuments.ts @@ -60,7 +60,7 @@ const allowRedwoodAuthCurrentUserQuery = async (request: Request) => { /** * When using RedwoodJS Studio, we want to allow the `resyncMailRenderers` and `resyncMailTemplate` mutations to be - * executed without a persisted operation. + * executed without a persisted operation. This is only allowed in local development. * * This is because the `resyncMailRenderers` mutation is a special case that is used by * RedwoodJS Studio to sync mail renderers from the mailer configuration. @@ -68,6 +68,11 @@ const allowRedwoodAuthCurrentUserQuery = async (request: Request) => { * This function checks if the request is for the `resyncMailRenderers` or `resyncMailTemplate` mutations and has the correct headers. */ const allowRedwoodStudioResyncMailMutations = async (request: Request) => { + const isLocalDevelopment = process.env.NODE_ENV === 'development' + if (!isLocalDevelopment) { + return false + } + const headers = request.headers const hasContentType = headers.get('content-type') === 'application/json' @@ -76,7 +81,7 @@ const allowRedwoodStudioResyncMailMutations = async (request: Request) => { query === REDWOOD__STUDIO_RESYNC_MAIL_RENDERERS_MUTATION || query === REDWOOD__STUDIO_TEMPLATE_MUTATION - return hasContentType && hasAllowedQuery + return hasContentType && hasAllowedQuery && isLocalDevelopment } export const useRedwoodTrustedDocuments = (