Skip to content

Commit

Permalink
[SOA-17] Sanitize posts text content (#18)
Browse files Browse the repository at this point in the history
* feat 🎸 (be): add save/update hook for basic post content sanitization

* test 🧪: added post model content parsing functional tests
  • Loading branch information
mariadriana-deemaze authored Nov 9, 2024
1 parent 550e3fb commit 72e213f
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 2 deletions.
10 changes: 8 additions & 2 deletions app/models/post.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { DateTime } from 'luxon'
import { BaseModel, belongsTo, column, computed } from '@adonisjs/lucid/orm'
import { BaseModel, beforeSave, beforeUpdate, belongsTo, column, computed } from '@adonisjs/lucid/orm'
import User from '#models/user'
import type { BelongsTo } from '@adonisjs/lucid/types/relations'
import type { UUID } from 'crypto'
import { extractFirstLink } from '#utils/index'
import { extractFirstLink, sanitizePostContent } from '#utils/index'

export default class Post extends BaseModel {
@column({ isPrimary: true })
Expand All @@ -28,4 +28,10 @@ export default class Post extends BaseModel {
get link(): string | null {
return extractFirstLink(this.content)
}

@beforeSave()
@beforeUpdate()
static sanitizeContent(post: Post) {
post.content = sanitizePostContent(post.content)
}
}
13 changes: 13 additions & 0 deletions app/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,16 @@ export function extractFirstLink(content: string): string | null {
const matches = content.match(urlRegex)
return matches ? matches[0] : null
}

/**
*
*/
export function sanitizePostContent(content: string): string {
const map = {
'&': '&',
'<': '&lt;',
'>': '&gt;',
}
// @ts-ignore
return content.replace(/[&<>]/g, (m) => map[m])
}
54 changes: 54 additions & 0 deletions tests/functional/posts/parsing.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { UserFactory } from '#database/factories/user_factory'
import Post from '#models/post'
import { faker } from '@faker-js/faker'
import { test } from '@japa/runner'

test.group('Posts content parsing', () => {
const link = 'https://www.youtube.com/watch?v=jEeQC6I8nlY'
const contentWithLink = faker.lorem.sentence() + ' ' + link

const contentWithScript = "<body onload=alert('test1')>"

test('Sucessfully parses the post content on create', async ({ assert }) => {
const user = await UserFactory.create()

const postWithScript = await Post.create({
userId: user.id,
content: contentWithScript,
})

const postWithLink = await Post.create({
userId: user.id,
content: contentWithLink,
})

assert.equal(postWithScript.content, "&lt;body onload=alert('test1')&gt;")
assert.equal(postWithLink.content, contentWithLink)
assert.equal(postWithLink.link, link)
})

test('Sucessfully parses the post content on update', async ({ assert }) => {
const user = await UserFactory.create()

const postWithScript = await Post.create({
userId: user.id,
content: faker.lorem.sentence(),
})

const postWithLink = await Post.create({
userId: user.id,
content: faker.lorem.sentence(),
})

postWithScript.content = contentWithScript

postWithLink.content = contentWithLink

await postWithScript.save()
await postWithLink.save()

assert.equal(postWithScript.content, "&amp;lt;body onload=alert('test1')&amp;gt;")
assert.equal(postWithLink.content, contentWithLink)
assert.equal(postWithLink.link, link)
})
})

0 comments on commit 72e213f

Please sign in to comment.