Skip to content

Commit 73dc3cf

Browse files
authored
Sanitise URLs in document field fields.url on input (#9686)
Co-authored-by: Daniel Cousens <dcousens@users.noreply.github.com>
1 parent b07145a commit 73dc3cf

11 files changed

Lines changed: 43 additions & 25 deletions

File tree

.changeset/fix-document-uris.mx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
"@keystone-6/fields-document": patch
2+
"@keystone-6/fields-document": major
33
---
44

5-
Use `new URL` rather than `encodeURI` when validating, and sanitize user input
5+
Changes `fields.url` and document links to sanitise and `encodeURI` on blur

docs/components/docs/Heading.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
'use client'
44

55
import slugify from '@sindresorhus/slugify'
6-
import { type ReactNode } from 'react'
6+
import type { ReactNode } from 'react'
77

88
import { HeadingIdLink } from './CopyToClipboard'
99

packages/core/src/admin-ui/components/Logo.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { type SVGAttributes } from 'react'
1+
import type { SVGAttributes } from 'react'
22
import Link from 'next/link'
3+
34
import { css, tokenSchema } from '@keystar/ui/style'
45
import { Heading } from '@keystar/ui/typography'
56

packages/core/src/fields/types/calendarDay/index.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
1-
import type { SimpleFieldTypeInfo } from '../../../types'
1+
import type {
2+
GArg,
3+
GInputObjectType,
4+
GList,
5+
GNonNull,
6+
InferValueFromInputType,
7+
} from '@graphql-ts/schema'
8+
9+
import { g } from '../../..'
210
import {
311
type BaseListTypeInfo,
412
type CommonFieldConfig,
513
type FieldTypeFunc,
14+
type SimpleFieldTypeInfo,
615
fieldType,
716
orderDirectionEnum,
817
} from '../../../types'
9-
import { type CalendarDayFieldMeta } from './views'
10-
import { g } from '../../..'
1118
import { filters } from '../../filters'
12-
import { makeValidateHook, defaultIsRequired } from '../../non-null-graphql'
13-
import type {
14-
GInputObjectType,
15-
GArg,
16-
GList,
17-
GNonNull,
18-
InferValueFromInputType,
19-
} from '@graphql-ts/schema'
19+
import { defaultIsRequired, makeValidateHook } from '../../non-null-graphql'
20+
import type { CalendarDayFieldMeta } from './views'
2021

2122
export type CalendarDayFieldConfig<ListTypeInfo extends BaseListTypeInfo> = CommonFieldConfig<
2223
ListTypeInfo,

packages/core/src/fields/types/relationship/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { g } from '../../..'
22
import { type ListMetaSource, getAdminMetaForRelationshipField } from '../../../lib/admin-meta'
3-
import type { JSONValue } from '../../../types'
43
import {
54
type BaseListTypeInfo,
65
type CommonFieldConfig,
76
type FieldTypeFunc,
7+
type JSONValue,
88
fieldType,
99
} from '../../../types'
1010
import type { controller } from './views'

packages/fields-document/src/DocumentEditor/component-blocks/api.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ export const fields = {
110110
label: string
111111
defaultValue?: string
112112
}): FormField<string, undefined> {
113+
// TODO: use zod?
113114
const validate = (value: unknown) => {
114115
return typeof value === 'string' && (value === '' || isValidURL(value))
115116
}

packages/fields-document/src/DocumentEditor/component-blocks/fields-ui.tsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { TextField } from '@keystar/ui/text-field'
1111
import { VStack } from '@keystar/ui/layout'
1212
import { TagGroup } from '@keystar/ui/tag'
1313
import { Text } from '@keystar/ui/typography'
14+
import { sanitizeUrl } from '@braintree/sanitize-url'
1415

1516
export { TextField, TextArea } from '@keystar/ui/text-field'
1617
export { Text } from '@keystar/ui/typography'
@@ -44,12 +45,25 @@ export function makeUrlFieldInput(opts: {
4445
}): FormField<string, unknown>['Input'] {
4546
return function UrlFieldInput({ autoFocus, forceValidation, onChange, value }) {
4647
const [isDirty, setDirty] = useState(false)
48+
49+
function onBlur() {
50+
const sanitisedHref = encodeURI(sanitizeUrl(value))
51+
if (value !== sanitisedHref && sanitisedHref !== 'about:blank') {
52+
onChange(sanitisedHref)
53+
}
54+
setDirty(true)
55+
}
56+
4757
return (
4858
<TextField
4959
autoFocus={autoFocus}
5060
label={opts.label}
51-
errorMessage={(forceValidation || isDirty) && !opts.validate(value) ? 'Invalid URL' : null}
52-
onBlur={() => setDirty(true)}
61+
errorMessage={
62+
(forceValidation || isDirty) && !opts.validate(value)
63+
? 'This type of URL is not accepted'
64+
: null
65+
}
66+
onBlur={onBlur}
5367
onChange={x => onChange?.(x)}
5468
value={value}
5569
/>

packages/fields-document/src/DocumentEditor/heading.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { type RenderElementProps } from 'slate-react'
1+
import type { RenderElementProps } from 'slate-react'
22

33
export function HeadingElement({
44
attributes,

packages/fields-document/src/DocumentEditor/lists.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useMemo } from 'react'
2-
import { type Element, type Node } from 'slate'
2+
import type { Element, Node } from 'slate'
33

44
import { useToolbarState } from './toolbar-state'
55
import { toggleList } from './lists-shared'

packages/fields-document/src/DocumentEditor/pasting/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { type Text } from 'slate'
2-
import { type Mark } from '../utils'
1+
import type { Text } from 'slate'
2+
import type { Mark } from '../utils'
33

44
// a v important note
55
// marks in the markdown ast/html are represented quite differently to how they are in slate

0 commit comments

Comments
 (0)