Skip to content

Commit

Permalink
fix(gatsby-transformer-remark): Disallow JS frontmatter by default (#…
Browse files Browse the repository at this point in the history
…37244)

(cherry picked from commit 77b8ccd)
  • Loading branch information
LekoArts authored and pieh committed Dec 20, 2022
1 parent 2cc9eaf commit 79c2884
Show file tree
Hide file tree
Showing 3 changed files with 154 additions and 73 deletions.
141 changes: 85 additions & 56 deletions packages/gatsby-transformer-remark/README.md
Expand Up @@ -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`
Expand All @@ -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: `<!-- end -->`
}
},
],
}
```

## Parsing algorithm

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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": `<!-- end -->`
}
}
```

Any file that does not have the given `excerpt_separator` will fall back to the default pruning method.

## Troubleshooting
Expand All @@ -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": `<!-- endexcerpt -->`
}
```js:title=gatsby-config.js
module.exports = {
plugins: [
{
resolve: `gatsby-transformer-remark`,
options: {
excerpt_separator: `<!-- endexcerpt -->`
},
},
],
}
```

Expand Down
45 changes: 28 additions & 17 deletions packages/gatsby-transformer-remark/src/__tests__/gatsby-node.js
Expand Up @@ -7,32 +7,43 @@ 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 } = await testPluginOptionsSchema(pluginOptionsSchema, {
footnotes: `this should be a boolean`,
gfm: `this should be a boolean`,
plugins: `this should be an array`,
})
const { errors, isValid } = await testPluginOptionsSchema(
pluginOptionsSchema,
{
footnotes: `this should be a boolean`,
gfm: `this should be a boolean`,
plugins: `this should be an array`,
jsFrontmatterEngine: `this should be a boolean`,
}
)

expect(isValid).toBe(false)
expect(errors).toEqual(expectedErrors)
})

it(`should validate the schema`, async () => {
const { isValid } = await testPluginOptionsSchema(pluginOptionsSchema, {
footnotes: false,
gfm: false,
plugins: [
`gatsby-remark-copy-linked-files`,
{
resolve: `gatsby-remark-images`,
options: {
maxWidth: 756,
const { isValid, errors } = await testPluginOptionsSchema(
pluginOptionsSchema,
{
footnotes: false,
gfm: false,
plugins: [
`gatsby-remark-copy-linked-files`,
{
resolve: `gatsby-remark-images`,
options: {
maxWidth: 756,
},
},
},
],
})
],
jsFrontmatterEngine: true,
}
)

expect(isValid).toBe(true)
expect(errors).toEqual([])
})
})
41 changes: 41 additions & 0 deletions packages/gatsby-transformer-remark/src/gatsby-node.js
Expand Up @@ -7,6 +7,9 @@ exports.unstable_shouldOnCreateNode = unstable_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(
Expand All @@ -21,5 +24,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,
},
}
})
}

0 comments on commit 79c2884

Please sign in to comment.