diff --git a/lib/filter-string.js b/lib/filter-string.js index ee4ddae..78e2189 100644 --- a/lib/filter-string.js +++ b/lib/filter-string.js @@ -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 { /** @@ -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 = '' @@ -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 * diff --git a/lib/filters/equality.test.js b/lib/filters/equality.test.js index 2889239..193fbbe 100644 --- a/lib/filters/equality.test.js +++ b/lib/filters/equality.test.js @@ -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 => { diff --git a/lib/string-parsing/parse-expression.js b/lib/string-parsing/parse-expression.js index e077d0a..7ea3309 100644 --- a/lib/string-parsing/parse-expression.js +++ b/lib/string-parsing/parse-expression.js @@ -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]+/ @@ -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) }) } diff --git a/lib/string-parsing/parse-expression.test.js b/lib/string-parsing/parse-expression.test.js index 4d2dcd5..e90d33e 100644 --- a/lib/string-parsing/parse-expression.test.js +++ b/lib/string-parsing/parse-expression.test.js @@ -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() +}) diff --git a/lib/string-parsing/parse-string.js b/lib/string-parsing/parse-string.js index e2be988..2e45134 100644 --- a/lib/string-parsing/parse-string.js +++ b/lib/string-parsing/parse-string.js @@ -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})` } diff --git a/lib/string-parsing/parse-string.test.js b/lib/string-parsing/parse-string.test.js index 292f304..0f8947d 100644 --- a/lib/string-parsing/parse-string.test.js +++ b/lib/string-parsing/parse-string.test.js @@ -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)' } @@ -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)' } @@ -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)' }