diff --git a/.husky/pre-commit b/.husky/pre-commit index 4002971e7..6c50066bb 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -3,4 +3,4 @@ . "$(dirname "$0")/_/husky.sh" -npx lint-staged +yarn lint-staged diff --git a/packages/server/modules/comments/graph/resolvers/comments.js b/packages/server/modules/comments/graph/resolvers/comments.js index e82889dd2..6fd05f342 100644 --- a/packages/server/modules/comments/graph/resolvers/comments.js +++ b/packages/server/modules/comments/graph/resolvers/comments.js @@ -13,7 +13,8 @@ const { viewComment, archiveComment, editComment, - streamResourceCheck + streamResourceCheck, + formatCommentText } = require('@/modules/comments/services') const authorizeStreamAccess = async ({ streamId, userId, auth }) => { @@ -60,6 +61,9 @@ module.exports = { limit: args.limit, cursor: args.cursor }) + }, + text(parent) { + return formatCommentText(parent) } }, Stream: { diff --git a/packages/server/modules/comments/services/index.js b/packages/server/modules/comments/services/index.js index 5adc37256..7066f90c2 100644 --- a/packages/server/modules/comments/services/index.js +++ b/packages/server/modules/comments/services/index.js @@ -1,12 +1,22 @@ 'use strict' const crs = require('crypto-random-string') const knex = require('@/db/knex') +const sanitizeHtml = require('sanitize-html') const Comments = () => knex('comments') const CommentLinks = () => knex('comment_links') const CommentViews = () => knex('comment_views') module.exports = { + /** + * Format comment text field (e.g. for returning to frontend or saving to DB) + * @param {Object} comment + * @returns {string} + */ + formatCommentText(comment) { + if (!comment || !comment.text) return '' + return sanitizeHtml(comment.text) + }, async streamResourceCheck({ streamId, resources }) { // this itches - a for loop with queries... but okay let's hit the road now for (const res of resources) { @@ -74,6 +84,7 @@ module.exports = { comment.id = crs({ length: 10 }) comment.authorId = userId + comment.text = module.exports.formatCommentText(comment) await Comments().insert(comment) try { @@ -105,6 +116,8 @@ module.exports = { streamId, parentComment: parentCommentId } + comment.text = module.exports.formatCommentText(comment) + await Comments().insert(comment) try { const commentLink = { resourceId: parentCommentId, resourceType: 'comment' } diff --git a/packages/server/modules/comments/tests/comments.spec.js b/packages/server/modules/comments/tests/comments.spec.js index 7c0891645..6b490d995 100644 --- a/packages/server/modules/comments/tests/comments.spec.js +++ b/packages/server/modules/comments/tests/comments.spec.js @@ -78,6 +78,22 @@ describe('Comments @comments', () => { }) }) + it('Should not accept complex HTML in the comment text', async () => { + const commentId = await createComment({ + userId: user.id, + input: { + streamId: stream.id, + resources: [{ resourceId: stream.id, resourceType: 'stream' }], + text: 'Some epic cool text!', + data: { justSome: crs({ length: 10 }) } + } + }) + + const comment = await getComment({ id: commentId }) + expect(comment).to.be.ok + expect((comment.text.match(/alert/) || []).length).to.equal(0) + }) + it('Should not be allowed to comment without specifying at least one target resource', async () => { await createComment({ userId: user.id, diff --git a/packages/server/package.json b/packages/server/package.json index 3255b12cd..fc9e24893 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -67,7 +67,7 @@ "prom-client": "^14.0.1", "redis": "^3.1.1", "response-time": "^2.3.2", - "sanitize-html": "^2.4.0", + "sanitize-html": "^2.7.0", "sharp": "^0.29.3", "string-pixel-width": "^1.10.0", "subscriptions-transport-ws": "0.9.0", diff --git a/yarn.lock b/yarn.lock index d435b936e..969d3167d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3047,7 +3047,7 @@ __metadata: prom-client: ^14.0.1 redis: ^3.1.1 response-time: ^2.3.2 - sanitize-html: ^2.4.0 + sanitize-html: ^2.7.0 sharp: ^0.29.3 string-pixel-width: ^1.10.0 subscriptions-transport-ws: 0.9.0 @@ -20645,7 +20645,7 @@ __metadata: languageName: node linkType: hard -"sanitize-html@npm:^2.4.0": +"sanitize-html@npm:^2.7.0": version: 2.7.0 resolution: "sanitize-html@npm:2.7.0" dependencies: