Skip to content
This repository has been archived by the owner on May 14, 2024. It is now read-only.

Commit

Permalink
Fix filter for non-ascii chars
Browse files Browse the repository at this point in the history
  • Loading branch information
jsumners committed Aug 16, 2023
1 parent 7876f8d commit e12ec04
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 45 deletions.
6 changes: 3 additions & 3 deletions lib/filter-string.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const { BerReader, BerWriter } = require('@ldapjs/asn1')

/**
* Baseline LDAP filter object. This exists solely to define the interface
* and basline properties and methods for actual LDAP filters.
* and baseline properties and methods for actual LDAP filters.
*/
class FilterString {
/**
Expand All @@ -22,7 +22,7 @@ class FilterString {
type = 'FilterString'

/**
* String value denoting which LDAP attribute the filter tagets. For example,
* String value denoting which LDAP attribute the filter targets. For example,
* in the filter `(&(cn=Foo Bar))`, the value would be "cn".
*/
attribute = ''
Expand All @@ -39,7 +39,7 @@ class FilterString {
*/

/**
* Creates a new filter object and sets the `attrbitute`.
* Creates a new filter object and sets the `attribute`.
*
* @param {FilterStringParams} input
*
Expand Down
33 changes: 24 additions & 9 deletions lib/filters/equality.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,15 +159,30 @@ tap.test('escape EqualityFilter inputs', async t => {
t.equal(f.toString(), '(\\28|\\28foo=\\c3\\b1)')
})

tap.test('encodes to BER correctly', async t => {
const expected = Buffer.from([
0xa3, 0x0a,
0x04, 0x03, 0x66, 0x6f, 0x6f, // OctetString "foo"
0x04, 0x03, 0x62, 0x61, 0x72 // OctetString "bar"
])
const f = new EqualityFilter({ attribute: 'foo', value: 'bar' })
const ber = f.toBer()
t.equal(expected.compare(ber.buffer), 0)
tap.test('encodes to BER correctly', t => {
t.test('basic ascii values', async t => {
const expected = Buffer.from([
0xa3, 0x0a,
0x04, 0x03, 0x66, 0x6f, 0x6f, // OctetString "foo"
0x04, 0x03, 0x62, 0x61, 0x72 // OctetString "bar"
])
const f = new EqualityFilter({ attribute: 'foo', value: 'bar' })
const ber = f.toBer()
t.equal(expected.compare(ber.buffer), 0)
})

t.test('values with non-ascii', async t => {
const expected = Buffer.from([
0xa3, 0x0b,
0x04, 0x03, 0x66, 0x6f, 0x6f, // OctetString "foo"
0x04, 0x04, 0xc3, 0xad, 0xc3, 0xb8 // OctetString "íø"
])
const f = new EqualityFilter({ attribute: 'foo', value: 'íø' })
const ber = f.toBer()
t.equal(expected.compare(ber.buffer), 0)
})

t.end()
})

tap.test('#parse', t => {
Expand Down
9 changes: 4 additions & 5 deletions lib/string-parsing/parse-expression.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ const LessThanEqualsFilter = require('../filters/less-than-equals')
const PresenceFilter = require('../filters/presence')
const SubstringFilter = require('../filters/substring')
const escapeSubstring = require('./escape-substring')
const escapeFilterValue = require('../utils/escape-filter-value')
const parseExtensibleFilterString = require('./parse-extensible-filter-string')

const attrRegex = /^[-_a-zA-Z0-9]+/
Expand Down Expand Up @@ -52,23 +51,23 @@ module.exports = function parseExpr (inputString) {
} else {
return new EqualityFilter({
attribute,
value: escapeFilterValue(remainder)
value: remainder
})
}
} else if (remainder[0] === '>' && remainder[1] === '=') {
return new GreaterThanEqualsFilter({
attribute,
value: escapeFilterValue(remainder.substring(2))
value: remainder.substring(2)
})
} else if (remainder[0] === '<' && remainder[1] === '=') {
return new LessThanEqualsFilter({
attribute,
value: escapeFilterValue(remainder.substring(2))
value: remainder.substring(2)
})
} else if (remainder[0] === '~' && remainder[1] === '=') {
return new ApproximateFilter({
attribute,
value: escapeFilterValue(remainder.substring(2))
value: remainder.substring(2)
})
}

Expand Down
18 changes: 18 additions & 0 deletions lib/string-parsing/parse-expression.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,21 @@ tap.test('ExtensibleFilter', t => {

t.end()
})

tap.test('parses filter with non-ascii characters', t => {
t.test('í', async t => {
const result = parse('cn=í')
t.type(result, EqualityFilter)
t.equal(result.value, 'í')
t.equal(result.toString(), '(cn=\\c3\\ad)')
})

t.test('ø', async t => {
const result = parse('cn=ø')
t.type(result, EqualityFilter)
t.equal(result.value, 'ø')
t.equal(result.toString(), '(cn=\\c3\\b8)')
})

t.end()
})
2 changes: 1 addition & 1 deletion lib/string-parsing/parse-string.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ module.exports = function parseString (inputString) {

let normalizedString = inputString
if (normalizedString.charAt(0) !== '(') {
// Wrap the filter in parantheticals since it is not already wrapped.
// Wrap the filter in parentheses since it is not already wrapped.
normalizedString = `(${normalizedString})`
}

Expand Down
63 changes: 36 additions & 27 deletions lib/string-parsing/parse-string.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,24 +83,27 @@ tap.test(') in filter', async t => {

tap.test('newlines in filter', async t => {
const v1 = '\\0a'
const v1Literal = '\n'
const v2 = 'bar\\0a'
const v2Literal = 'bar\n'
const v3 = '\\0abar'
const v3Literal = '\nbar'
checkFilters(t, [
{ str: '(foo=\n)', type: 'EqualityFilter', val: v1, output: '(foo=\\0a)' },
{ str: '(foo<=\n)', type: 'LessThanEqualsFilter', val: v1, output: '(foo<=\\0a)' },
{ str: '(foo>=\n)', type: 'GreaterThanEqualsFilter', val: v1, output: '(foo>=\\0a)' },
{ str: '(foo=\n)', type: 'EqualityFilter', val: v1Literal, output: '(foo=\\0a)' },
{ str: '(foo<=\n)', type: 'LessThanEqualsFilter', val: v1Literal, output: '(foo<=\\0a)' },
{ str: '(foo>=\n)', type: 'GreaterThanEqualsFilter', val: v1Literal, output: '(foo>=\\0a)' },
{ str: '(foo=\\0a)', type: 'EqualityFilter', val: v1, output: '(foo=\\0a)' },
{ str: '(foo<=\\0a)', type: 'LessThanEqualsFilter', val: v1, output: '(foo<=\\0a)' },
{ str: '(foo>=\\0a)', type: 'GreaterThanEqualsFilter', val: v1, output: '(foo>=\\0a)' },
{ str: '(foo=bar\n)', type: 'EqualityFilter', val: v2, output: '(foo=bar\\0a)' },
{ str: '(foo<=bar\n)', type: 'LessThanEqualsFilter', val: v2, output: '(foo<=bar\\0a)' },
{ str: '(foo>=bar\n)', type: 'GreaterThanEqualsFilter', val: v2, output: '(foo>=bar\\0a)' },
{ str: '(foo=bar\n)', type: 'EqualityFilter', val: v2Literal, output: '(foo=bar\\0a)' },
{ str: '(foo<=bar\n)', type: 'LessThanEqualsFilter', val: v2Literal, output: '(foo<=bar\\0a)' },
{ str: '(foo>=bar\n)', type: 'GreaterThanEqualsFilter', val: v2Literal, output: '(foo>=bar\\0a)' },
{ str: '(foo=bar\\0a)', type: 'EqualityFilter', val: v2, output: '(foo=bar\\0a)' },
{ str: '(foo<=bar\\0a)', type: 'LessThanEqualsFilter', val: v2, output: '(foo<=bar\\0a)' },
{ str: '(foo>=bar\\0a)', type: 'GreaterThanEqualsFilter', val: v2, output: '(foo>=bar\\0a)' },
{ str: '(foo=\nbar)', type: 'EqualityFilter', val: v3, output: '(foo=\\0abar)' },
{ str: '(foo<=\nbar)', type: 'LessThanEqualsFilter', val: v3, output: '(foo<=\\0abar)' },
{ str: '(foo>=\nbar)', type: 'GreaterThanEqualsFilter', val: v3, output: '(foo>=\\0abar)' },
{ str: '(foo=\nbar)', type: 'EqualityFilter', val: v3Literal, output: '(foo=\\0abar)' },
{ str: '(foo<=\nbar)', type: 'LessThanEqualsFilter', val: v3Literal, output: '(foo<=\\0abar)' },
{ str: '(foo>=\nbar)', type: 'GreaterThanEqualsFilter', val: v3Literal, output: '(foo>=\\0abar)' },
{ str: '(foo=\\0abar)', type: 'EqualityFilter', val: v3, output: '(foo=\\0abar)' },
{ str: '(foo<=\\0abar)', type: 'LessThanEqualsFilter', val: v3, output: '(foo<=\\0abar)' },
{ str: '(foo>=\\0abar)', type: 'GreaterThanEqualsFilter', val: v3, output: '(foo>=\\0abar)' }
Expand All @@ -109,24 +112,27 @@ tap.test('newlines in filter', async t => {

tap.test('carriage returns in filter', async t => {
const v1 = '\\0d'
const v1Literal = '\r'
const v2 = 'bar\\0d'
const v2Literal = 'bar\r'
const v3 = '\\0dbar'
const v3Literal = '\rbar'
checkFilters(t, [
{ str: '(foo=\r)', type: 'EqualityFilter', val: v1, output: '(foo=\\0d)' },
{ str: '(foo<=\r)', type: 'LessThanEqualsFilter', val: v1, output: '(foo<=\\0d)' },
{ str: '(foo>=\r)', type: 'GreaterThanEqualsFilter', val: v1, output: '(foo>=\\0d)' },
{ str: '(foo=\r)', type: 'EqualityFilter', val: v1Literal, output: '(foo=\\0d)' },
{ str: '(foo<=\r)', type: 'LessThanEqualsFilter', val: v1Literal, output: '(foo<=\\0d)' },
{ str: '(foo>=\r)', type: 'GreaterThanEqualsFilter', val: v1Literal, output: '(foo>=\\0d)' },
{ str: '(foo=\\0d)', type: 'EqualityFilter', val: v1, output: '(foo=\\0d)' },
{ str: '(foo<=\\0d)', type: 'LessThanEqualsFilter', val: v1, output: '(foo<=\\0d)' },
{ str: '(foo>=\\0d)', type: 'GreaterThanEqualsFilter', val: v1, output: '(foo>=\\0d)' },
{ str: '(foo=bar\r)', type: 'EqualityFilter', val: v2, output: '(foo=bar\\0d)' },
{ str: '(foo<=bar\r)', type: 'LessThanEqualsFilter', val: v2, output: '(foo<=bar\\0d)' },
{ str: '(foo>=bar\r)', type: 'GreaterThanEqualsFilter', val: v2, output: '(foo>=bar\\0d)' },
{ str: '(foo=bar\r)', type: 'EqualityFilter', val: v2Literal, output: '(foo=bar\\0d)' },
{ str: '(foo<=bar\r)', type: 'LessThanEqualsFilter', val: v2Literal, output: '(foo<=bar\\0d)' },
{ str: '(foo>=bar\r)', type: 'GreaterThanEqualsFilter', val: v2Literal, output: '(foo>=bar\\0d)' },
{ str: '(foo=bar\\0d)', type: 'EqualityFilter', val: v2, output: '(foo=bar\\0d)' },
{ str: '(foo<=bar\\0d)', type: 'LessThanEqualsFilter', val: v2, output: '(foo<=bar\\0d)' },
{ str: '(foo>=bar\\0d)', type: 'GreaterThanEqualsFilter', val: v2, output: '(foo>=bar\\0d)' },
{ str: '(foo=\rbar)', type: 'EqualityFilter', val: v3, output: '(foo=\\0dbar)' },
{ str: '(foo<=\rbar)', type: 'LessThanEqualsFilter', val: v3, output: '(foo<=\\0dbar)' },
{ str: '(foo>=\rbar)', type: 'GreaterThanEqualsFilter', val: v3, output: '(foo>=\\0dbar)' },
{ str: '(foo=\rbar)', type: 'EqualityFilter', val: v3Literal, output: '(foo=\\0dbar)' },
{ str: '(foo<=\rbar)', type: 'LessThanEqualsFilter', val: v3Literal, output: '(foo<=\\0dbar)' },
{ str: '(foo>=\rbar)', type: 'GreaterThanEqualsFilter', val: v3Literal, output: '(foo>=\\0dbar)' },
{ str: '(foo=\\0dbar)', type: 'EqualityFilter', val: v3, output: '(foo=\\0dbar)' },
{ str: '(foo<=\\0dbar)', type: 'LessThanEqualsFilter', val: v3, output: '(foo<=\\0dbar)' },
{ str: '(foo>=\\0dbar)', type: 'GreaterThanEqualsFilter', val: v3, output: '(foo>=\\0dbar)' }
Expand All @@ -135,24 +141,27 @@ tap.test('carriage returns in filter', async t => {

tap.test('tabs in filter', async t => {
const v1 = '\\09'
const v1Literal = '\t'
const v2 = 'bar\\09'
const v2Literal = 'bar\t'
const v3 = '\\09bar'
const v3Literal = '\tbar'
checkFilters(t, [
{ str: '(foo=\t)', type: 'EqualityFilter', val: v1, output: '(foo=\\09)' },
{ str: '(foo<=\t)', type: 'LessThanEqualsFilter', val: v1, output: '(foo<=\\09)' },
{ str: '(foo>=\t)', type: 'GreaterThanEqualsFilter', val: v1, output: '(foo>=\\09)' },
{ str: '(foo=\t)', type: 'EqualityFilter', val: v1Literal, output: '(foo=\\09)' },
{ str: '(foo<=\t)', type: 'LessThanEqualsFilter', val: v1Literal, output: '(foo<=\\09)' },
{ str: '(foo>=\t)', type: 'GreaterThanEqualsFilter', val: v1Literal, output: '(foo>=\\09)' },
{ str: '(foo=\\09)', type: 'EqualityFilter', val: v1, output: '(foo=\\09)' },
{ str: '(foo<=\\09)', type: 'LessThanEqualsFilter', val: v1, output: '(foo<=\\09)' },
{ str: '(foo>=\\09)', type: 'GreaterThanEqualsFilter', val: v1, output: '(foo>=\\09)' },
{ str: '(foo=bar\t)', type: 'EqualityFilter', val: v2, output: '(foo=bar\\09)' },
{ str: '(foo<=bar\t)', type: 'LessThanEqualsFilter', val: v2, output: '(foo<=bar\\09)' },
{ str: '(foo>=bar\t)', type: 'GreaterThanEqualsFilter', val: v2, output: '(foo>=bar\\09)' },
{ str: '(foo=bar\t)', type: 'EqualityFilter', val: v2Literal, output: '(foo=bar\\09)' },
{ str: '(foo<=bar\t)', type: 'LessThanEqualsFilter', val: v2Literal, output: '(foo<=bar\\09)' },
{ str: '(foo>=bar\t)', type: 'GreaterThanEqualsFilter', val: v2Literal, output: '(foo>=bar\\09)' },
{ str: '(foo=bar\\09)', type: 'EqualityFilter', val: v2, output: '(foo=bar\\09)' },
{ str: '(foo<=bar\\09)', type: 'LessThanEqualsFilter', val: v2, output: '(foo<=bar\\09)' },
{ str: '(foo>=bar\\09)', type: 'GreaterThanEqualsFilter', val: v2, output: '(foo>=bar\\09)' },
{ str: '(foo=\tbar)', type: 'EqualityFilter', val: v3, output: '(foo=\\09bar)' },
{ str: '(foo<=\tbar)', type: 'LessThanEqualsFilter', val: v3, output: '(foo<=\\09bar)' },
{ str: '(foo>=\tbar)', type: 'GreaterThanEqualsFilter', val: v3, output: '(foo>=\\09bar)' },
{ str: '(foo=\tbar)', type: 'EqualityFilter', val: v3Literal, output: '(foo=\\09bar)' },
{ str: '(foo<=\tbar)', type: 'LessThanEqualsFilter', val: v3Literal, output: '(foo<=\\09bar)' },
{ str: '(foo>=\tbar)', type: 'GreaterThanEqualsFilter', val: v3Literal, output: '(foo>=\\09bar)' },
{ str: '(foo=\\09bar)', type: 'EqualityFilter', val: v3, output: '(foo=\\09bar)' },
{ str: '(foo<=\\09bar)', type: 'LessThanEqualsFilter', val: v3, output: '(foo<=\\09bar)' },
{ str: '(foo>=\\09bar)', type: 'GreaterThanEqualsFilter', val: v3, output: '(foo>=\\09bar)' }
Expand Down

0 comments on commit e12ec04

Please sign in to comment.