diff --git a/package.json b/package.json index 35bfcbc..c9bbeed 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,9 @@ "Titus Wormer (https://wooorm.com)", "Jason Switzer " ], + "types": "types/index.d.ts", "files": [ + "types/index.d.ts", "lib", "index.js" ], @@ -36,8 +38,9 @@ "devDependencies": { "browserify": "^16.0.0", "deepmerge": "^4.0.0", + "dtslint": "^3.6.12", "hast-util-to-html": "^7.0.0", - "hastscript": "^5.0.0", + "hastscript": "^6.0.0", "nyc": "^15.0.0", "prettier": "^2.0.0", "remark-cli": "^8.0.0", @@ -54,7 +57,8 @@ "build": "npm run build-bundle && npm run build-mangle", "test-api": "node test", "test-coverage": "nyc --reporter lcov tape test.js", - "test": "npm run format && npm run build && npm run test-coverage" + "test-types": "dtslint types", + "test": "npm run format && npm run build && npm run test-coverage && npm run test-types" }, "nyc": { "check-coverage": true, diff --git a/types/hast-util-sanitize-tests.ts b/types/hast-util-sanitize-tests.ts new file mode 100644 index 0000000..fae0780 --- /dev/null +++ b/types/hast-util-sanitize-tests.ts @@ -0,0 +1,204 @@ +import h = require('hastscript') +import u = require('unist-builder') +import merge = require('deepmerge') +import sanitize = require('hast-util-sanitize') + +// Taken from Readme +const tree = h('div', {onmouseover: 'alert("alpha")'}, [ + h( + 'a', + {href: 'jAva script:alert("bravo")', onclick: 'alert("charlie")'}, + 'delta' + ), + u('text', '\n'), + h('script', 'alert("charlie")'), + u('text', '\n'), + h('img', {src: 'x', onerror: 'alert("delta")'}), + u('text', '\n'), + // eslint-disable-next-line no-script-url + h('iframe', {src: 'javascript:alert("echo")'}), + u('text', '\n'), + h('math', h('mi', {'xlink:href': 'data:x,'})) +]) + +const gh: sanitize.Schema = { + strip: ['script'], + clobberPrefix: 'user-content-', + clobber: ['name', 'id'], + ancestors: { + tbody: ['table'], + tfoot: ['table'], + thead: ['table'], + td: ['table'], + th: ['table'], + tr: ['table'] + }, + protocols: { + href: ['http', 'https', 'mailto', 'xmpp', 'irc', 'ircs'], + cite: ['http', 'https'], + src: ['http', 'https'], + longDesc: ['http', 'https'] + }, + tagNames: [ + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'br', + 'b', + 'i', + 'strong', + 'em', + 'a', + 'pre', + 'code', + 'img', + 'tt', + 'div', + 'ins', + 'del', + 'sup', + 'sub', + 'p', + 'ol', + 'ul', + 'table', + 'thead', + 'tbody', + 'tfoot', + 'blockquote', + 'dl', + 'dt', + 'dd', + 'kbd', + 'q', + 'samp', + 'var', + 'hr', + 'ruby', + 'rt', + 'rp', + 'li', + 'tr', + 'td', + 'th', + 's', + 'strike', + 'summary', + 'details', + 'caption', + 'figure', + 'figcaption', + 'abbr', + 'bdo', + 'cite', + 'dfn', + 'mark', + 'small', + 'span', + 'time', + 'wbr', + 'input' + ], + attributes: { + a: ['href'], + img: ['src', 'longDesc'], + input: [ + ['type', 'checkbox'], + ['disabled', true] + ], + li: [['className', 'task-list-item']], + div: ['itemScope', 'itemType'], + blockquote: ['cite'], + del: ['cite'], + ins: ['cite'], + q: ['cite'], + '*': [ + 'abbr', + 'accept', + 'acceptCharset', + 'accessKey', + 'action', + 'align', + 'alt', + 'ariaDescribedBy', + 'ariaHidden', + 'ariaLabel', + 'ariaLabelledBy', + 'axis', + 'border', + 'cellPadding', + 'cellSpacing', + 'char', + 'charOff', + 'charSet', + 'checked', + 'clear', + 'cols', + 'colSpan', + 'color', + 'compact', + 'coords', + 'dateTime', + 'dir', + 'disabled', + 'encType', + 'htmlFor', + 'frame', + 'headers', + 'height', + 'hrefLang', + 'hSpace', + 'isMap', + 'id', + 'label', + 'lang', + 'maxLength', + 'media', + 'method', + 'multiple', + 'name', + 'noHref', + 'noShade', + 'noWrap', + 'open', + 'prompt', + 'readOnly', + 'rel', + 'rev', + 'rows', + 'rowSpan', + 'rules', + 'scope', + 'selected', + 'shape', + 'size', + 'span', + 'start', + 'summary', + 'tabIndex', + 'target', + 'title', + 'type', + 'useMap', + 'vAlign', + 'value', + 'vSpace', + 'width', + 'itemProp' + ] + }, + required: { + input: { + type: 'checkbox', + disabled: true + } + } +} + +const schema = merge(gh, {attributes: {'*': ['className']}}) + +sanitize(tree) +sanitize(tree, schema) diff --git a/types/index.d.ts b/types/index.d.ts new file mode 100644 index 0000000..aded122 --- /dev/null +++ b/types/index.d.ts @@ -0,0 +1,77 @@ +import {Node} from 'unist' + +declare namespace sanitize { + /** + * Possible HTML attribute values + */ + type HTMLValue = string | number | boolean + + /** + * Sanitization configuration + */ + interface Schema { + /** + * Map of tag names to allowed property names + * + * The special '*' key defines property names allowed on all elements + */ + attributes?: { + [key: string]: Array + } + + /** + * Map of tag names to required property names and their default property value + */ + required?: {[key: string]: {[key: string]: HTMLValue}} + + /** + * List of allowed tag names + */ + tagNames?: string[] + + /** + * Map of protocols to allow in property values + */ + protocols?: {[key: string]: string[]} + + /** + * Map of tag names to their required ancestor elements + */ + ancestors?: {[key: string]: string[]} + + /** + * List of allowed property names which can clobber + */ + clobber?: string[] + + /** + * Prefix to use before potentially clobbering property names + */ + clobberPrefix?: string + + /** + * Names of elements to strip from the tree + */ + strip?: string[] + + /** + * Whether to allow comments + */ + allowComments?: boolean + + /** + * Whether to allow doctypes + */ + allowDoctypes?: boolean + } +} + +/** + * Hast utility to sanitize a tree + * + * @param tree Hast tree to sanitize + * @param schema Schema defining how to sanitize - defaults to Github style sanitation + */ +declare function sanitize(tree: Node, schema?: sanitize.Schema): Node + +export = sanitize diff --git a/types/tsconfig.json b/types/tsconfig.json new file mode 100644 index 0000000..3cecfb1 --- /dev/null +++ b/types/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "lib": ["es2015"], + "strict": true, + "baseUrl": ".", + "resolveJsonModule": true, + "paths": { + "hast-util-sanitize": ["index.d.ts"] + } + } +} diff --git a/types/tslint.json b/types/tslint.json new file mode 100644 index 0000000..70c4494 --- /dev/null +++ b/types/tslint.json @@ -0,0 +1,7 @@ +{ + "extends": "dtslint/dtslint.json", + "rules": { + "semicolon": false, + "whitespace": false + } +}