added xss protection, automatic links and, date middleware

This commit is contained in:
Grzegorz Leoniec 2018-10-28 18:47:24 +01:00
parent 6449d2a99c
commit 00cc53e045
10 changed files with 450 additions and 50 deletions

View File

@ -18,12 +18,16 @@
"apollo-link-http": "^1.5.4",
"apollo-server": "^2.0.4",
"bcryptjs": "^2.4.3",
"cheerio": "^1.0.0-rc.2",
"date-fns": "^2.0.0-alpha.24",
"dotenv": "^6.0.0",
"graphql-custom-directives": "^0.2.13",
"graphql-iso-date": "^3.6.1",
"graphql-middleware": "1.7.6",
"graphql-tag": "^2.9.2",
"graphql-yoga": "1.16.2",
"jsonwebtoken": "^8.3.0",
"linkifyjs": "^2.1.7",
"lodash": "^4.17.11",
"ms": "^2.1.1",
"neo4j-driver": "^1.6.1",
@ -31,6 +35,7 @@
"node-fetch": "^2.1.2",
"passport": "^0.4.0",
"passport-jwt": "^4.0.0",
"sanitize-html": "^1.19.1",
"slug": "^0.9.1",
"trunc-html": "^1.1.2"
},

View File

@ -0,0 +1,16 @@
import {
GraphQLLowerCaseDirective,
GraphQLTrimDirective,
GraphQLDefaultToDirective
} from 'graphql-custom-directives'
export default function applyDirectives(augmentedSchema) {
const directives = [
GraphQLLowerCaseDirective,
GraphQLTrimDirective,
GraphQLDefaultToDirective
]
augmentedSchema._directives.push.apply(augmentedSchema._directives, directives)
return augmentedSchema
}

13
src/bootstrap/scalars.js Normal file
View File

@ -0,0 +1,13 @@
import {
GraphQLDate,
GraphQLTime,
GraphQLDateTime
} from 'graphql-iso-date'
export default function applyScalars(augmentedSchema) {
augmentedSchema._typeMap.Date = GraphQLDate
augmentedSchema._typeMap.Time = GraphQLTime
augmentedSchema._typeMap.DateTime = GraphQLDateTime
return augmentedSchema
}

View File

@ -6,17 +6,13 @@ import { v1 as neo4j } from 'neo4j-driver'
import dotenv from 'dotenv'
import mocks from './mocks'
import middleware from './middleware'
import applyDirectives from './bootstrap/directives'
import applyScalars from './bootstrap/scalars'
import passport from 'passport'
import jwtStrategy from './jwt/strategy'
import jwt from 'jsonwebtoken'
// import {
// GraphQLLowerCaseDirective,
// GraphQLTrimDirective,
// GraphQLDefaultToDirective
// } from 'graphql-custom-directives';
dotenv.config()
const schema = makeExecutableSchema({
@ -24,17 +20,6 @@ const schema = makeExecutableSchema({
resolvers
})
// augmentSchema will add auto generated mutations based on types in schema
// const augmentedSchema = augmentSchema(schema)
// add custom directives
// const directives = [
// GraphQLLowerCaseDirective,
// GraphQLTrimDirective,
// GraphQLDefaultToDirective
// ]
// augmentedSchema._directives.push.apply(augmentedSchema._directives, directives)
const driver = neo4j.driver(
process.env.NEO4J_URI || 'bolt://localhost:7687',
neo4j.auth.basic(
@ -46,6 +31,15 @@ const driver = neo4j.driver(
const MOCK = (process.env.MOCK === 'true')
console.log('MOCK:', MOCK)
const augumentedSchema = augmentSchema(schema, {
query: {
exclude: ['Statistics', 'LoggedInUser']
},
mutation: {
exclude: ['Statistics', 'LoggedInUser']
}
})
const server = new GraphQLServer({
context: async (req) => {
const payload = {
@ -60,15 +54,7 @@ const server = new GraphQLServer({
return payload
},
// schema: augmentSchema(schema),
schema: augmentSchema(schema, {
query: {
exclude: ['Statistics', 'LoggedInUser']
},
mutation: {
exclude: ['Statistics', 'LoggedInUser']
}
}),
schema: applyScalars(applyDirectives(augumentedSchema)),
tracing: true,
middlewares: middleware,
mocks: MOCK ? mocks : false
@ -79,18 +65,6 @@ server.express.use(passport.initialize())
server.express.post('/graphql', passport.authenticate(['jwt'], { session: false }))
// session middleware
// server.express.use(session({
// name: 'qid',
// secret: process.env.JWT_SECRET,
// resave: true,
// saveUninitialized: true,
// cookie: {
// secure: process.env.NODE_ENV === 'production',
// maxAge: ms('1d')
// }
// }))
const serverConfig = {
port: 4000
// cors: {

View File

@ -0,0 +1,54 @@
import format from 'date-fns/format'
export default {
Mutation: {
CreateUser: async (resolve, root, args, context, info) => {
args.createdAt = format(new Date())
args.disabled = false
args.deleted = false
const result = await resolve(root, args, context, info)
return result
},
CreatePost: async (resolve, root, args, context, info) => {
args.createdAt = format(new Date())
args.disabled = false
args.deleted = false
const result = await resolve(root, args, context, info)
return result
},
CreateComment: async (resolve, root, args, context, info) => {
args.createdAt = format(new Date())
args.disabled = false
args.deleted = false
const result = await resolve(root, args, context, info)
return result
},
CreateOrganization: async (resolve, root, args, context, info) => {
args.createdAt = format(new Date())
args.disabled = false
args.deleted = false
const result = await resolve(root, args, context, info)
return result
},
UpdateUser: async (resolve, root, args, context, info) => {
args.updatedAt = format(new Date())
const result = await resolve(root, args, context, info)
return result
},
UpdatePost: async (resolve, root, args, context, info) => {
args.updatedAt = format(new Date())
const result = await resolve(root, args, context, info)
return result
},
UpdateComment: async (resolve, root, args, context, info) => {
args.updatedAt = format(new Date())
const result = await resolve(root, args, context, info)
return result
},
UpdateOrganization: async (resolve, root, args, context, info) => {
args.updatedAt = format(new Date())
const result = await resolve(root, args, context, info)
return result
}
}
}

View File

@ -3,8 +3,12 @@ import softDeleteMiddleware from './softDeleteMiddleware'
import sluggifyMiddleware from './sluggifyMiddleware'
import fixImageUrlsMiddleware from './fixImageUrlsMiddleware'
import excerptMiddleware from './excerptMiddleware'
import dateTimeMiddleware from './dateTimeMiddleware';
import xssMiddleware from './xssMiddleware';
export default [
xssMiddleware,
dateTimeMiddleware,
passwordMiddleware,
sluggifyMiddleware,
excerptMiddleware,

View File

@ -0,0 +1,124 @@
import trunc from 'trunc-html'
// import { getByDot, setByDot, getItems, replaceItems } from 'feathers-hooks-common'
import sanitizeHtml from 'sanitize-html'
// import { isEmpty, intersection } from 'lodash'
import cheerio from 'cheerio'
import linkifyHtml from 'linkifyjs/html'
const embedToAnchor = (content) => {
const $ = cheerio.load(content)
$('div[data-url-embed]').each((i, el) => {
let url = el.attribs['data-url-embed']
let aTag = $(`<a href="${url}" target="_blank" data-url-embed="">${url}</a>`)
$(el).replaceWith(aTag)
})
return $('body').html()
}
function clean (dirty) {
if (!dirty) {
return dirty
}
// Convert embeds to a-tags
dirty = embedToAnchor(dirty)
dirty = linkifyHtml(dirty)
dirty = sanitizeHtml(dirty, {
allowedTags: ['iframe', 'img', 'p', 'br', 'b', 'i', 'em', 'strong', 'a', 'pre', 'ul', 'li', 'ol', 's', 'strike', 'span', 'blockquote'],
allowedAttributes: {
a: ['href', 'class', 'target', 'data-*' , 'contenteditable'],
span: ['contenteditable', 'class', 'data-*'],
img: ['src'],
iframe: ['src', 'class', 'frameborder', 'allowfullscreen']
},
allowedIframeHostnames: ['www.youtube.com', 'player.vimeo.com'],
parser: {
lowerCaseTags: true
},
transformTags: {
iframe: function (tagName, attribs) {
return {
tagName: 'a',
text: attribs.src,
attribs: {
href: attribs.src,
target: '_blank',
'data-url-embed': ''
}
}
},
i: 'em',
// a: function (tagName, attribs) {
// return {
// tagName: 'a',
// attribs: {
// href: attribs.href,
// target: '_blank',
// }
// }
// },
b: 'strong',
s: 'strike',
img: function (tagName, attribs) {
let src = attribs.src
// if (isEmpty(hook.result)) {
// const config = hook.app.get('thumbor')
// if (config && src.indexOf(config < 0)) {
// // download image
// // const ThumborUrlHelper = require('../helper/thumbor-helper')
// // const Thumbor = new ThumborUrlHelper(config.key || null, config.url || null)
// // src = Thumbor
// // .setImagePath(src)
// // .buildUrl('740x0')
// }
// }
return {
tagName: 'img',
attribs: {
src: `http://localhost:3050/images?url=${src}`
}
}
}
}
})
// remove empty html tags and duplicated returns
dirty = dirty
.replace(/<[a-z]>[\s]*<\/[a-z]>/igm, '')
.replace(/(<iframe(?!.*?src=(['"]).*?\2)[^>]*)(>)[^>]*\/*>/igm, '')
.replace(/<p>[\s]*(<br ?\/?>)+[\s]*<\/p>/igm, '<br />')
.replace(/(<br ?\/?>){2,}/igm, '<br />')
.replace(/[\n]{3,}/igm, '\n\n')
.replace(/(\r\n|\n\r|\r|\n)/g, '<br>$1')
.replace(/<p><br><\/p>/g, '')
return dirty
}
// iterate through all fields and clean the values
function cleanAll (result, key, recursive, fields = ['content', 'contentExcerpt']) {
if (result && typeof result === 'string' && fields.includes(key)) {
result = clean(result)
} else if (result && Array.isArray(result)) {
result.forEach((res, index) => {
result[index] = cleanAll(result[index], index, true, fields)
})
} else if (result && typeof result === 'object') {
Object.keys(result).forEach(key => {
result[key] = cleanAll(result[key], key, true, fields)
})
}
return result
}
export default {
Mutation: async (resolve, root, args, context, info) => {
args = cleanAll(args)
const result = await resolve(root, args, context, info)
return result
},
Query: async (resolve, root, args, context, info) => {
const result = await resolve(root, args, context, info)
return cleanAll(result)
}
}

View File

View File

@ -28,6 +28,10 @@ type Statistics {
countShouts: Int!
}
scalar Date
scalar Time
scalar DateTime
enum VisibilityEnum {
public
friends
@ -65,6 +69,8 @@ type User {
deleted: Boolean
disabled: Boolean
role: UserGroupEnum
createdAt: String
updatedAt: String
friends: [User]! @relation(name: "FRIENDS", direction: "BOTH")
friendsCount: Int! @cypher(statement: "MATCH (this)<-[:FRIENDS]->(r:User) RETURN COUNT(r)")

228
yarn.lock
View File

@ -490,6 +490,10 @@ array-flatten@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
array-uniq@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
array-unique@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
@ -1090,6 +1094,10 @@ body-parser@1.18.3, body-parser@^1.18.2, body-parser@^1.18.3:
raw-body "2.3.3"
type-is "~1.6.16"
boolbase@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
boxen@^1.2.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b"
@ -1202,7 +1210,7 @@ chalk@^1.1.3:
strip-ansi "^3.0.0"
supports-color "^2.0.0"
chalk@^2.0.1:
chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
dependencies:
@ -1210,6 +1218,17 @@ chalk@^2.0.1:
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
cheerio@^1.0.0-rc.2:
version "1.0.0-rc.2"
resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.2.tgz#4b9f53a81b27e4d5dac31c0ffd0cfa03cc6830db"
dependencies:
css-select "~1.2.0"
dom-serializer "~0.1.0"
entities "~1.1.1"
htmlparser2 "^3.9.1"
lodash "^4.15.0"
parse5 "^3.0.1"
chokidar@^1.6.1:
version "1.7.0"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
@ -1379,6 +1398,23 @@ crypto-random-string@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
css-select@~1.2.0:
version "1.2.0"
resolved "http://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858"
dependencies:
boolbase "~1.0.0"
css-what "2.1"
domutils "1.5.1"
nth-check "~1.0.1"
css-what@2.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.2.tgz#c0876d9d0480927d7d4920dcd72af3595649554d"
date-fns@^2.0.0-alpha.24:
version "2.0.0-alpha.24"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.0.0-alpha.24.tgz#2988c137c72275af29d7d21cc53eb52b3a8c2586"
debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
@ -1457,6 +1493,45 @@ dicer@0.2.5:
readable-stream "1.1.x"
streamsearch "0.1.2"
dom-serializer@0, dom-serializer@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
dependencies:
domelementtype "~1.1.1"
entities "~1.1.1"
domelementtype@1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.2.1.tgz#578558ef23befac043a1abb0db07635509393479"
domelementtype@^1.3.0:
version "1.3.0"
resolved "http://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2"
domelementtype@~1.1.1:
version "1.1.3"
resolved "http://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b"
domhandler@^2.3.0:
version "2.4.2"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803"
dependencies:
domelementtype "1"
domutils@1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf"
dependencies:
dom-serializer "0"
domelementtype "1"
domutils@^1.5.1:
version "1.7.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a"
dependencies:
dom-serializer "0"
domelementtype "1"
dot-prop@^4.1.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57"
@ -1497,6 +1572,10 @@ encodeurl@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
entities@^1.1.1, entities@~1.1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
es-abstract@^1.5.1:
version "1.12.0"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165"
@ -1898,6 +1977,10 @@ graphql-import@^0.6.0:
dependencies:
lodash "^4.17.4"
graphql-iso-date@^3.6.1:
version "3.6.1"
resolved "https://registry.yarnpkg.com/graphql-iso-date/-/graphql-iso-date-3.6.1.tgz#bd2d0dc886e0f954cbbbc496bbf1d480b57ffa96"
graphql-middleware@1.6.6:
version "1.6.6"
resolved "https://registry.yarnpkg.com/graphql-middleware/-/graphql-middleware-1.6.6.tgz#f40f4e836ced479df718dbc1869ea4cd3b64027b"
@ -2071,6 +2154,17 @@ home-or-tmp@^2.0.0:
os-homedir "^1.0.0"
os-tmpdir "^1.0.1"
htmlparser2@^3.9.0, htmlparser2@^3.9.1:
version "3.10.0"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.0.tgz#5f5e422dcf6119c0d983ed36260ce9ded0bee464"
dependencies:
domelementtype "^1.3.0"
domhandler "^2.3.0"
domutils "^1.5.1"
entities "^1.1.1"
inherits "^2.0.1"
readable-stream "^3.0.6"
http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3:
version "1.6.3"
resolved "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
@ -2389,6 +2483,10 @@ jmespath@0.15.0:
version "0.15.0"
resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217"
jquery@^3.3.1:
version "3.3.1"
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca"
"js-tokens@^3.0.0 || ^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@ -2471,10 +2569,26 @@ latest-version@^3.0.0:
dependencies:
package-json "^4.0.0"
linkifyjs@^2.1.7:
version "2.1.7"
resolved "https://registry.yarnpkg.com/linkifyjs/-/linkifyjs-2.1.7.tgz#e5d68d2ae30b9c055e1d74cc40f9a31d3abb4012"
optionalDependencies:
jquery "^3.3.1"
react "^16.4.2"
react-dom "^16.4.2"
lodash.clonedeep@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
lodash.debounce@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
lodash.escaperegexp@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347"
lodash.includes@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f"
@ -2499,11 +2613,15 @@ lodash.isstring@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
lodash.mergewith@^4.6.0:
version "4.6.1"
resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz#639057e726c3afbdb3e7d42741caa8d6e4335927"
lodash.once@^4.0.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5:
lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5:
version "4.17.11"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
@ -2511,7 +2629,7 @@ long@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28"
loose-envify@^1.0.0:
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
dependencies:
@ -2800,6 +2918,12 @@ npmlog@^4.0.2:
gauge "~2.7.3"
set-blocking "~2.0.0"
nth-check@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c"
dependencies:
boolbase "~1.0.0"
number-is-nan@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
@ -2808,7 +2932,7 @@ numeral@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/numeral/-/numeral-2.0.6.tgz#4ad080936d443c2561aed9f2197efffe25f4e506"
object-assign@^4, object-assign@^4.1.0:
object-assign@^4, object-assign@^4.1.0, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
@ -2917,6 +3041,12 @@ parse-glob@^3.0.4:
is-extglob "^1.0.0"
is-glob "^2.0.0"
parse5@^3.0.1:
version "3.0.3"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c"
dependencies:
"@types/node" "*"
parseurl@~1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3"
@ -2981,6 +3111,14 @@ posix-character-classes@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
postcss@^6.0.14:
version "6.0.23"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324"
dependencies:
chalk "^2.4.1"
source-map "^0.6.1"
supports-color "^5.4.0"
prepend-http@^1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
@ -2997,6 +3135,13 @@ process-nextick-args@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
prop-types@^15.6.2:
version "15.6.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
dependencies:
loose-envify "^1.3.1"
object-assign "^4.1.1"
protobufjs@^6.8.6:
version "6.8.8"
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.8.8.tgz#c8b4f1282fd7a90e6f5b109ed11c84af82908e7c"
@ -3084,6 +3229,24 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7:
minimist "^1.2.0"
strip-json-comments "~2.0.1"
react-dom@^16.4.2:
version "16.6.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.6.0.tgz#6375b8391e019a632a89a0988bce85f0cc87a92f"
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
prop-types "^15.6.2"
scheduler "^0.10.0"
react@^16.4.2:
version "16.6.0"
resolved "https://registry.yarnpkg.com/react/-/react-16.6.0.tgz#b34761cfaf3e30f5508bc732fb4736730b7da246"
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
prop-types "^15.6.2"
scheduler "^0.10.0"
readable-stream@1.1.x:
version "1.1.14"
resolved "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
@ -3105,6 +3268,14 @@ readable-stream@^2.0.2, readable-stream@^2.0.6:
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
readable-stream@^3.0.6:
version "3.0.6"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.0.6.tgz#351302e4c68b5abd6a2ed55376a7f9a25be3057a"
dependencies:
inherits "^2.0.3"
string_decoder "^1.1.1"
util-deprecate "^1.0.1"
readdirp@^2.0.0:
version "2.2.1"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525"
@ -3231,6 +3402,21 @@ safe-regex@^1.1.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
sanitize-html@^1.19.1:
version "1.19.1"
resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-1.19.1.tgz#e8b33c69578054d6ee4f57ea152d6497f3f6fb7d"
dependencies:
chalk "^2.3.0"
htmlparser2 "^3.9.0"
lodash.clonedeep "^4.5.0"
lodash.escaperegexp "^4.1.2"
lodash.isplainobject "^4.0.6"
lodash.isstring "^4.0.1"
lodash.mergewith "^4.6.0"
postcss "^6.0.14"
srcset "^1.0.0"
xtend "^4.0.0"
sax@1.2.1:
version "1.2.1"
resolved "http://registry.npmjs.org/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a"
@ -3239,6 +3425,13 @@ sax@>=0.6.0, sax@^1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
scheduler@^0.10.0:
version "0.10.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.10.0.tgz#7988de90fe7edccc774ea175a783e69c40c521e1"
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
semver-diff@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36"
@ -3384,7 +3577,7 @@ source-map@^0.5.6, source-map@^0.5.7:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
source-map@^0.6.0:
source-map@^0.6.0, source-map@^0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
@ -3404,6 +3597,13 @@ sprintf-js@~1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
srcset@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/srcset/-/srcset-1.0.0.tgz#a5669de12b42f3b1d5e83ed03c71046fc48f41ef"
dependencies:
array-uniq "^1.0.2"
number-is-nan "^1.0.0"
static-extend@^0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
@ -3445,16 +3645,16 @@ string-width@^1.0.1:
is-fullwidth-code-point "^2.0.0"
strip-ansi "^4.0.0"
string_decoder@~0.10.x:
version "0.10.31"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
string_decoder@~1.1.1:
string_decoder@^1.1.1, string_decoder@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
dependencies:
safe-buffer "~5.1.0"
string_decoder@~0.10.x:
version "0.10.31"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
strip-ansi@^3.0.0, strip-ansi@^3.0.1:
version "3.0.1"
resolved "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
@ -3489,7 +3689,7 @@ supports-color@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
supports-color@^5.2.0, supports-color@^5.3.0:
supports-color@^5.2.0, supports-color@^5.3.0, supports-color@^5.4.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
dependencies:
@ -3670,7 +3870,7 @@ user-home@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190"
util-deprecate@~1.0.1:
util-deprecate@^1.0.1, util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
@ -3758,6 +3958,10 @@ xmlbuilder@~9.0.1:
version "9.0.7"
resolved "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d"
xtend@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
yallist@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"