Skip to content
This repository has been archived by the owner on Aug 19, 2022. It is now read-only.

Commit

Permalink
tsquery escaping
Browse files Browse the repository at this point in the history
  • Loading branch information
cianfoley-nearform committed May 17, 2018
1 parent 5643068 commit ec5707d
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 33 deletions.
2 changes: 1 addition & 1 deletion packages/udaru-core/lib/ops/policyOps.js
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,7 @@ function buildPolicyOps (db, config) {
SELECT *
FROM policies
WHERE (
to_tsvector(name) @@ to_tsquery(${query.split(' ').join(' & ') + ':*'})
to_tsvector(name) @@ to_tsquery(${utils.toTsQuery(query)})
OR name LIKE(${'%' + query + '%'})
)
`
Expand Down
4 changes: 2 additions & 2 deletions packages/udaru-core/lib/ops/teamOps.js
Original file line number Diff line number Diff line change
Expand Up @@ -1087,7 +1087,7 @@ function buildTeamOps (db, config) {
FROM teams
WHERE org_id=${organizationId}
AND (
to_tsvector(name) || to_tsvector(description) @@ to_tsquery(${query.split(' ').join(' & ') + ':*'})
to_tsvector(name) || to_tsvector(description) @@ to_tsquery(${utils.toTsQuery(query)})
OR name LIKE(${'%' + query + '%'})
)
ORDER BY id;
Expand Down Expand Up @@ -1125,7 +1125,7 @@ function buildTeamOps (db, config) {
AND mem.user_id = users.id
AND users.org_id = ${organizationId}
AND (
to_tsvector(name) @@ to_tsquery(${query.split(' ').join(' & ') + ':*'})
to_tsvector(name) @@ to_tsquery(${utils.toTsQuery(query)})
OR name ILIKE(${'%' + query + '%'})
OR id ILIKE(${'%' + query + '%'})
)
Expand Down
2 changes: 1 addition & 1 deletion packages/udaru-core/lib/ops/userOps.js
Original file line number Diff line number Diff line change
Expand Up @@ -913,7 +913,7 @@ function buildUserOps (db, config) {
FROM users
WHERE org_id=${organizationId}
AND (
to_tsvector(name) @@ to_tsquery(${query.split(' ').join(' & ') + ':*'})
to_tsvector(name) @@ to_tsquery(${utils.toTsQuery(query)})
OR name ILIKE(${'%' + query + '%'})
)
ORDER BY id;
Expand Down
12 changes: 11 additions & 1 deletion packages/udaru-core/lib/ops/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,15 @@ function checkOrg (db, organizationId, cb) {
})
}

function toTsQuery (query) {
let tsQuery = query.trim()

if (tsQuery !== '') {
tsQuery = "'" + tsQuery.replace(/ +/g, ' ').replace(/\\/g, '\\\\').replace(/'/g, "''").split(' ').join("':* & '") + "':*"
}
return tsQuery
}

function preparePolicy (policy) {
policy.variables = policy.variables || {}

Expand All @@ -105,5 +114,6 @@ module.exports = {
checkUsersOrg,
checkTeamsOrg,
checkUserOrg,
checkOrg
checkOrg,
toTsQuery
}
86 changes: 66 additions & 20 deletions packages/udaru-core/test/integration/teamOps.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1417,6 +1417,72 @@ lab.experiment('TeamOps', () => {
})
})

lab.test(': char search', (done) => {
let testTeam = {
id: 'ab-ba',
name: 'colon:team',
description: '"test&team\'s\\description"',
organizationId: 'WONKA'
}

udaru.teams.create(testTeam, function (err, result) {
expect(err).to.not.exist()
expect(result).to.exist()

udaru.teams.search({ query: 'colo:tea', organizationId: 'WONKA' }, (err, data, total) => {
expect(err).to.not.exist()

testTeam.path = 'ab-ba'
expect(data).to.contain(testTeam)
udaru.teams.delete({ id: result.id, organizationId: 'WONKA' }, done)
})
})
})

lab.test('quote team search', (done) => {
let testTeam = {
id: 'team-s',
name: 'team\'s name',
description: '"test&team\'s\\description"',
organizationId: 'WONKA'
}

udaru.teams.create(testTeam, function (err, result) {
expect(err).to.not.exist()
expect(result).to.exist()

udaru.teams.search({ query: 'tea\'s', organizationId: 'WONKA' }, (err, data, total) => {
expect(err).to.not.exist()

testTeam.path = 'team-s'
expect(data).to.contain(testTeam)
udaru.teams.delete({ id: result.id, organizationId: 'WONKA' }, done)
})
})
})

lab.test('backslash team search', (done) => {
let testTeam = {
id: 'team-b',
name: 'team\\backslash',
description: '"test&team\'s\\description"',
organizationId: 'WONKA'
}

udaru.teams.create(testTeam, function (err, result) {
expect(err).to.not.exist()
expect(result).to.exist()

udaru.teams.search({ query: 'tea\\backsla', organizationId: 'WONKA' }, (err, data, total) => {
expect(err).to.not.exist()

testTeam.path = 'team-b'
expect(data).to.contain(testTeam)
udaru.teams.delete({ id: result.id, organizationId: 'WONKA' }, done)
})
})
})

lab.test('Search for common words phrase', (done) => {
udaru.teams.search({ query: 'Managers', organizationId: 'WONKA' }, (err, data, total) => {
expect(err).to.not.exist()
Expand Down Expand Up @@ -1485,14 +1551,6 @@ lab.experiment('TeamOps', () => {
})
})

lab.test('Search sql injection query sanity check', (done) => {
udaru.teams.search({ query: 'Authors\'); drop database authorization;', organizationId: 'WONKA' }, (err, data, total) => {
expect(err).to.exist()

done()
})
})

lab.experiment('Team: search for users', () => {
lab.test('Search for Wonka', (done) => {
udaru.teams.searchUsers({ id: '4', query: 'wonka', organizationId: 'WONKA' }, (err, data, total) => {
Expand Down Expand Up @@ -1604,18 +1662,6 @@ lab.experiment('TeamOps', () => {
})
})

lab.test('Search sql injection query sanity check', (done) => {
udaru.teams.searchUsers({
id: '1',
query: 'Wonka\'); drop database authorization;',
organizationId: 'WONKA'
}, (err, data, total) => {
expect(err).to.exist()

done()
})
})

lab.test('Search sql injection id sanity check', (done) => {
udaru.teams.searchUsers({
id: '1\'); drop database authorization;',
Expand Down
8 changes: 0 additions & 8 deletions packages/udaru-core/test/integration/userOps.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1228,12 +1228,4 @@ lab.experiment('UserOps structure', () => {
done()
})
})

lab.test('Search sql injection query sanity check', (done) => {
udaru.users.search({ query: 'Charlie\');drop database authorization;', organizationId: 'WONKA' }, (err, data, total) => {
expect(err).to.exist()

done()
})
})
})
60 changes: 60 additions & 0 deletions packages/udaru-core/test/unit/utils.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
const Lab = require('lab')
const lab = exports.lab = Lab.script()
const expect = require('code').expect
const utils = require('../../lib/ops/utils.js')

lab.describe('tsquery tests', () => {
lab.test('empty string', done => {
const query = utils.toTsQuery('')
expect(query).to.equal(``)
done()
})

lab.test('single space', done => {
const query = utils.toTsQuery(' ')
expect(query).to.equal(``)
done()
})

lab.test('single phrase', done => {
const query = utils.toTsQuery('test')
expect(query).to.equal(`'test':*`)
done()
})

lab.test('multiple phrases', done => {
const query = utils.toTsQuery('this is a test')
expect(query).to.equal(`'this':* & 'is':* & 'a':* & 'test':*`)
done()
})

lab.test('multiple phrases with extra whitespace', done => {
const query = utils.toTsQuery('this is a test')
expect(query).to.equal(`'this':* & 'is':* & 'a':* & 'test':*`)
done()
})

lab.test('multiple phrases with in need of trim', done => {
const query = utils.toTsQuery(' this is a test ')
expect(query).to.equal(`'this':* & 'is':* & 'a':* & 'test':*`)
done()
})

lab.test('multiple phrases with quotes', done => {
const query = utils.toTsQuery("it's got quotes")
expect(query).to.equal(`'it''s':* & 'got':* & 'quotes':*`)
done()
})

lab.test('multiple phrases with backslash', done => {
const query = utils.toTsQuery('yes\\no maybe')
expect(query).to.equal(`'yes\\\\no':* & 'maybe':*`)
done()
})

lab.test('sql injection', done => {
const query = utils.toTsQuery('Wonka\'); drop database authorization;')
expect(query).to.equal(`'Wonka'');':* & 'drop':* & 'database':* & 'authorization;':*`)
done()
})
})
31 changes: 31 additions & 0 deletions packages/udaru-hapi-16-plugin/test/endToEnd/teams.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,37 @@ lab.experiment('Teams - search', () => {
udaru.teams.delete({ id: team.id, organizationId: team.organizationId }, done)
})
})

lab.test('searching for teams with colon in name', (done) => {
const options = utils.requestOptions({
method: 'GET',
url: `/authorization/teams/search?query=rubber:baby`
})

const team1Data = {
name: 'rubber:baby:buggy:bumpers',
description: 'This is a test team',
parentId: null,
organizationId: 'WONKA'
}

udaru.teams.create(team1Data, (err, team) => {
expect(err).to.not.exist()

server.inject(options, (response) => {
const result = response.result

expect(response.statusCode).to.equal(200)
expect(result.data[0].name).to.equal(team.name)
expect(result.total).to.exist()

expect(result.data.length).to.equal(1)
expect(result.total).to.equal(1)

udaru.teams.delete({ id: team.id, organizationId: team.organizationId }, done)
})
})
})
})

lab.test('searching for teams should handle server errors', (done) => {
Expand Down

0 comments on commit ec5707d

Please sign in to comment.