From ad8e93745427c198b103feabbd7671dbfa0f9e83 Mon Sep 17 00:00:00 2001 From: Nate Moore Date: Mon, 28 Jun 2021 11:48:00 -0400 Subject: [PATCH] fix: use 403 error for unpublished docs --- packages/astro/src/build/page.ts | 2 +- packages/astro/src/dev.ts | 19 +++++++++++++++++++ packages/astro/src/runtime.ts | 17 +++++++++-------- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/packages/astro/src/build/page.ts b/packages/astro/src/build/page.ts index 240d05291..b21897aa4 100644 --- a/packages/astro/src/build/page.ts +++ b/packages/astro/src/build/page.ts @@ -92,7 +92,7 @@ export async function buildStaticPage({ astroConfig, buildState, filepath, runti const { pages: pagesRoot } = astroConfig; const url = filepath.pathname.replace(pagesRoot.pathname, '/').replace(/(index)?\.(astro|md)$/, ''); const result = await runtime.load(url); - if (result.statusCode === 404 && result.error.message === 'Unpublished document') return; + if (result.statusCode === 403) return; if (result.statusCode !== 200) throw new Error((result as any).error); const outFile = path.posix.join(url, '/index.html'); buildState[outFile] = { diff --git a/packages/astro/src/dev.ts b/packages/astro/src/dev.ts index f6a765ba4..2829ec15d 100644 --- a/packages/astro/src/dev.ts +++ b/packages/astro/src/dev.ts @@ -50,6 +50,25 @@ export default async function dev(astroConfig: AstroConfig) { res.end(); break; } + case 403: { + const fullurl = new URL(req.url || '/', astroConfig.buildOptions.site || `http://localhost${astroConfig.devOptions.port}`); + const reqPath = decodeURI(fullurl.pathname); + error(logging, 'static', 'Forbidden', reqPath); + res.statusCode = 403; + + const fourOhThreeResult = await runtime.load('/403'); + if (fourOhThreeResult.statusCode === 200) { + if (fourOhThreeResult.contentType) { + res.setHeader('Content-Type', fourOhThreeResult.contentType); + } + res.write(fourOhThreeResult.contents); + } else { + res.setHeader('Content-Type', 'text/plain'); + res.write(`Forbidden: ${result.error.message}`); + } + res.end(); + break; + } case 404: { const fullurl = new URL(req.url || '/', astroConfig.buildOptions.site || `http://localhost${astroConfig.devOptions.port}`); const reqPath = decodeURI(fullurl.pathname); diff --git a/packages/astro/src/runtime.ts b/packages/astro/src/runtime.ts index 6909dce77..a719bb497 100644 --- a/packages/astro/src/runtime.ts +++ b/packages/astro/src/runtime.ts @@ -46,11 +46,12 @@ type LoadResultSuccess = { contents: string | Buffer; contentType?: string | false; }; +type LoadResultForbidden = { statusCode: 403; error: Error; collectionInfo?: CollectionInfo }; type LoadResultNotFound = { statusCode: 404; error: Error; collectionInfo?: CollectionInfo }; type LoadResultRedirect = { statusCode: 301 | 302; location: string; collectionInfo?: CollectionInfo }; type LoadResultError = { statusCode: 500 } & ({ type: 'parse-error'; error: CompileError } | { type: 'not-found'; error: CompileError } | { type: 'unknown'; error: Error }); -export type LoadResult = (LoadResultSuccess | LoadResultNotFound | LoadResultRedirect | LoadResultError) & { collectionInfo?: CollectionInfo }; +export type LoadResult = (LoadResultSuccess | LoadResultForbidden | LoadResultNotFound | LoadResultRedirect | LoadResultError) & { collectionInfo?: CollectionInfo }; // Disable snowpack from writing to stdout/err. configureSnowpackLogger(snowpackLogger); @@ -108,16 +109,16 @@ async function load(config: RuntimeConfig, rawPathname: string | undefined): Pro if (mod.exports.__content) { const hasDraftAttribute = mod.exports.__content.hasOwnProperty('draft'); const hasPublishAttribute = mod.exports.__content.hasOwnProperty('published'); - if(hasPublishAttribute && mod.exports.__content['published'] === false) { + if (hasPublishAttribute && mod.exports.__content['published'] === false) { return { - statusCode: 404, - error: new Error('Unpublished document') + statusCode: 403, + error: new Error('Document is not published') }; } - if(hasDraftAttribute && mod.exports.__content['draft'] === true && !buildOptions.draft && config.mode === 'production') { + if (hasDraftAttribute && mod.exports.__content['draft'] === true && !buildOptions.draft && config.mode === 'production') { return { - statusCode: 404, - error: new Error('Unpublished document') + statusCode: 403, + error: new Error('Document is not published') }; } } @@ -155,7 +156,7 @@ async function load(config: RuntimeConfig, rawPathname: string | undefined): Pro if (!data) throw new Error(`[createCollection] \`data()\` returned nothing (empty data)"`); if (!Array.isArray(data)) data = [data]; // note: this is supposed to be a little friendlier to the user, but should we error out instead? data = data.filter(entry => !entry.hasOwnProperty('published') || (entry.hasOwnProperty('published') && entry.published)); - if(!buildOptions.draft && config.mode === "production") { + if (!buildOptions.draft && config.mode === "production") { data = data.filter(entry => !entry.hasOwnProperty('draft') || (entry.hasOwnProperty('draft') && !entry.draft)); }