From 9a18046a4786ed7dfe32ef28bfd39bd09e617a59 Mon Sep 17 00:00:00 2001 From: Lennart Date: Thu, 15 Dec 2022 08:37:35 +0100 Subject: [PATCH] fix(gatsby-transformer-remark): Disallow JS frontmatter by default (#37244) (cherry picked from commit 77b8ccdf764790d027c75b6f62bab15a30e30a2b) --- packages/gatsby-transformer-remark/README.md | 141 +++++++++++------- .../src/__tests__/gatsby-node.js | 3 + .../src/gatsby-node.js | 41 +++++ 3 files changed, 129 insertions(+), 56 deletions(-) diff --git a/packages/gatsby-transformer-remark/README.md b/packages/gatsby-transformer-remark/README.md index 6c012fe738ebe..e780d4a802f37 100644 --- a/packages/gatsby-transformer-remark/README.md +++ b/packages/gatsby-transformer-remark/README.md @@ -4,25 +4,46 @@ Parses Markdown files using [remark](http://remark.js.org/). ## Install -`npm install gatsby-transformer-remark` - -## How to use - -```javascript -// In your gatsby-config.js -plugins: [ - { - resolve: `gatsby-transformer-remark`, - options: { - // Footnotes mode (default: true) - footnotes: true, - // GitHub Flavored Markdown mode (default: true) - gfm: true, - // Plugins configs - plugins: [], +Install the plugin to your site: + +```shell +npm install gatsby-transformer-remark +``` + +Add it to your `gatsby-config`: + +```js:title=gatsby-config.js +module.exports = { + plugins: [ + { + resolve: `gatsby-transformer-remark`, + options: {}, }, - }, -], + ], +} +``` + +## Options + +```js:title=gatsby-config.js +module.exports = { + plugins: [ + { + resolve: `gatsby-transformer-remark`, + options: { + // Footnotes mode (default: true) + footnotes: true, + // GitHub Flavored Markdown mode (default: true) + gfm: true, + // Add your gatsby-remark-* plugins here + plugins: [], + // Enable JS for https://github.com/jonschlinkert/gray-matter#optionsengines (default: false) + // It's not advised to set this to "true" and this option will likely be removed in the future + jsFrontmatterEngine: false, + }, + }, + ], +} ``` The following parts of `options` enable the `remark-footnotes` and `remark-gfm` @@ -31,10 +52,30 @@ plugins: - `options.footnotes` - `options.gfm` -A full explanation of how to use markdown in Gatsby can be found here: -[Adding Markdown Pages](https://www.gatsbyjs.com/docs/how-to/routing/adding-markdown-pages/) +A full explanation of how to use markdown in Gatsby can be found here: [Adding Markdown Pages](https://www.gatsbyjs.com/docs/how-to/routing/adding-markdown-pages/) + +There are many `gatsby-remark-*` plugins which you can install to customize how Markdown is processed. Check out the [source code for using-remark](https://github.com/gatsbyjs/gatsby/tree/master/examples/using-remark) as an example. + +### `gray-matter` options + +`gatsby-transformer-remark` uses [gray-matter](https://github.com/jonschlinkert/gray-matter) to parse Markdown frontmatter, so you can specify any of the options mentioned [in its README](https://github.com/jonschlinkert/gray-matter#options) in the `options` key of the plugin. -There are many Gatsby Remark plugins which you can install to customize how Markdown is processed. Many of them are demoed at https://using-remark.gatsbyjs.org/. See also the [source code for using-remark](https://github.com/gatsbyjs/gatsby/tree/master/examples/using-remark). +**Example: Excerpts** + +If you don't want to use `pruneLength` for excerpts but a custom separator, you can specify an `excerpt_separator`: + +```js:title=gatsby-config.js +module.exports = { + plugins: [ + { + resolve: `gatsby-transformer-remark`, + options: { + excerpt_separator: `` + } + }, + ], +} +``` ## Parsing algorithm @@ -120,19 +161,20 @@ By default, `absolute` is set to `false`, generating a relative path. If you'd l To pass default options to the plugin generating the `tableOfContents`, configure it in `gatsby-config.js` as shown below. The options shown below are the defaults used by the plugin. -```javascript -// In your gatsby-config.js -plugins: [ - { - resolve: `gatsby-transformer-remark`, - options: { - tableOfContents: { - heading: null, - maxDepth: 6, +```js:title=gatsby-config.js +module.exports = { + plugins: [ + { + resolve: `gatsby-transformer-remark`, + options: { + tableOfContents: { + heading: null, + maxDepth: 6, + }, }, }, - }, -] + ], +} ``` ### Excerpts @@ -198,23 +240,6 @@ You can also get excerpts in Markdown format. } ``` -## `gray-matter` options - -`gatsby-transformer-remark` uses [gray-matter](https://github.com/jonschlinkert/gray-matter) to parse Markdown frontmatter, so you can specify any of the options mentioned [here](https://github.com/jonschlinkert/gray-matter#options) in the `gatsby-config.js` file. - -### Example: Excerpts - -If you don't want to use `pruneLength` for excerpts but a custom separator, you can specify an `excerpt_separator` in the `gatsby-config.js` file: - -```javascript -{ - "resolve": `gatsby-transformer-remark`, - "options": { - "excerpt_separator": `` - } -} -``` - Any file that does not have the given `excerpt_separator` will fall back to the default pruning method. ## Troubleshooting @@ -237,14 +262,18 @@ If that is the case, you can set `truncate` option on `excerpt` field, like: If your Markdown file contains HTML, `excerpt` will not return a value. -In that case, you can set an `excerpt_separator` in the `gatsby-config.js` file: +In that case, you can set an `excerpt_separator` in the `gatsby-config`: -```javascript -{ - "resolve": `gatsby-transformer-remark`, - "options": { - "excerpt_separator": `` - } +```js:title=gatsby-config.js +module.exports = { + plugins: [ + { + resolve: `gatsby-transformer-remark`, + options: { + excerpt_separator: `` + }, + }, + ], } ``` diff --git a/packages/gatsby-transformer-remark/src/__tests__/gatsby-node.js b/packages/gatsby-transformer-remark/src/__tests__/gatsby-node.js index 7e4ff8648b75d..4e7de171b5b49 100644 --- a/packages/gatsby-transformer-remark/src/__tests__/gatsby-node.js +++ b/packages/gatsby-transformer-remark/src/__tests__/gatsby-node.js @@ -7,6 +7,7 @@ describe(`gatsby-node.js`, () => { `"footnotes" must be a boolean`, `"gfm" must be a boolean`, `"plugins" must be an array`, + `"jsFrontmatterEngine" must be a boolean`, ] const { errors, isValid } = await testPluginOptionsSchema( @@ -15,6 +16,7 @@ describe(`gatsby-node.js`, () => { footnotes: `this should be a boolean`, gfm: `this should be a boolean`, plugins: `this should be an array`, + jsFrontmatterEngine: `this should be a boolean`, } ) @@ -37,6 +39,7 @@ describe(`gatsby-node.js`, () => { }, }, ], + jsFrontmatterEngine: true, } ) diff --git a/packages/gatsby-transformer-remark/src/gatsby-node.js b/packages/gatsby-transformer-remark/src/gatsby-node.js index 2a40b7ab837e5..8353ef6d824dd 100644 --- a/packages/gatsby-transformer-remark/src/gatsby-node.js +++ b/packages/gatsby-transformer-remark/src/gatsby-node.js @@ -4,6 +4,9 @@ exports.shouldOnCreateNode = shouldOnCreateNode exports.createSchemaCustomization = require(`./create-schema-customization`) exports.setFieldsOnGraphQLNodeType = require(`./extend-node-type`) +// Dedupe warning +let warnedAboutJSFrontmatterEngine = false + exports.pluginOptionsSchema = function ({ Joi }) { return Joi.object({ footnotes: Joi.boolean().description( @@ -18,5 +21,43 @@ exports.pluginOptionsSchema = function ({ Joi }) { plugins: Joi.subPlugins().description( `A list of remark plugins. See also: https://github.com/gatsbyjs/gatsby/tree/master/examples/using-remark for examples` ), + // TODO(v6): Remove and disallow any custom engines (including JS) + jsFrontmatterEngine: Joi.boolean() + .default(false) + .description( + `Enable JS for https://github.com/jonschlinkert/gray-matter#optionsengines` + ), + }).custom(value => { + const { jsFrontmatterEngine, engines = {} } = value || {} + + if (jsFrontmatterEngine) { + // show this warning only once in main process + if (!process.env.GATSBY_WORKER_ID) { + console.warn( + `JS frontmatter engine is enabled in gatsby-transformer-remark (via jsFrontmatterEngine: true). This can cause a security risk, see https://github.com/gatsbyjs/gatsby/security/advisories/GHSA-7ch4-rr99-cqcw. If you are not relying on this feature we strongly suggest disabling it via the "jsFrontmatterEngine: false" plugin option. If you rely on this feature make sure to properly secure or sanitize your content source.` + ) + } + return value + } + + const js = () => { + if (!warnedAboutJSFrontmatterEngine) { + console.warn( + `You have frontmatter declared with "---js" or "---javascript" that is not parsed by default to mitigate a security risk (see https://github.com/gatsbyjs/gatsby/security/advisories/GHSA-7ch4-rr99-cqcw). If you require this feature it can be enabled by setting "jsFrontmatterEngine: true" in the plugin options of gatsby-transformer-remark.` + ) + warnedAboutJSFrontmatterEngine = true + } + // we still have to return a frontmatter, so we just stub it with empty object + return {} + } + + return { + ...value, + engines: { + ...engines, + js, + javascript: js, + }, + } }) }