Migrate filter extensions (#809)

* Replace presence filter

* Replace equality filter

* Remove TODO

* Fix integration tests

* Replace approximate filter

* Replace extensible filter

* Replace greater-than-equals filter

* Replace less-than-equals filter

* Replace remaining filters

* Remove debug code

* Remove transition code

* Remove unnecessry isFilter

* Remove unused code

* Use LDAP filter string parsing from @ldapjs/filter

* Move BER filter parsing to @ldapjs/filter

* Fully replace internal filters module with @ldapjs/filter
This commit is contained in:
James Sumners 2022-06-26 16:59:35 -04:00
parent 5bab39f58e
commit 9de9c703ab
32 changed files with 27 additions and 1837 deletions

View File

@ -23,7 +23,7 @@ const SearchPager = require('./search_pager')
const Protocol = require('@ldapjs/protocol')
const dn = require('../dn')
const errors = require('../errors')
const filters = require('../filters')
const filters = require('@ldapjs/filter')
const messages = require('../messages')
const url = require('../url')
const CorkedEmitter = require('../corked_emitter')
@ -572,7 +572,7 @@ Client.prototype.search = function search (base,
options.filter = filters.parseString(options.filter)
} else if (!options.filter) {
options.filter = new PresenceFilter({ attribute: 'objectclass' })
} else if (!filters.isFilter(options.filter)) {
} else if (Object.prototype.toString.call(options.filter) !== '[object FilterString]') {
throw new TypeError('options.filter (Filter) required')
}
if (typeof (controls) === 'function') {

View File

@ -1,27 +0,0 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
const assert = require('assert')
const util = require('util')
const parents = require('@ldapjs/filter')
const Filter = require('./filter')
/// --- API
function AndFilter (options) {
parents.AndFilter.call(this, options)
}
util.inherits(AndFilter, parents.AndFilter)
Filter.mixin(AndFilter)
module.exports = AndFilter
AndFilter.prototype._toBer = function (ber) {
assert.ok(ber)
this.filters.forEach(function (f) {
ber = f.toBer(ber)
})
return ber
}

View File

@ -1,35 +0,0 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
const assert = require('assert')
const util = require('util')
const parents = require('@ldapjs/filter')
const Filter = require('./filter')
/// --- API
function ApproximateFilter (options) {
parents.ApproximateFilter.call(this, options)
}
util.inherits(ApproximateFilter, parents.ApproximateFilter)
Filter.mixin(ApproximateFilter)
module.exports = ApproximateFilter
ApproximateFilter.prototype.parse = function (ber) {
assert.ok(ber)
this.attribute = ber.readString().toLowerCase()
this.value = ber.readString()
return true
}
ApproximateFilter.prototype._toBer = function (ber) {
assert.ok(ber)
ber.writeString(this.attribute)
ber.writeString(this.value)
return ber
}

View File

@ -1,66 +0,0 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
const assert = require('assert-plus')
const util = require('util')
const ASN1 = require('@ldapjs/asn1').Ber
const parents = require('@ldapjs/filter')
const Filter = require('./filter')
/// --- API
function EqualityFilter (options) {
parents.EqualityFilter.call(this, options)
}
util.inherits(EqualityFilter, parents.EqualityFilter)
Filter.mixin(EqualityFilter)
module.exports = EqualityFilter
EqualityFilter.prototype.matches = function (target, strictAttrCase) {
assert.object(target, 'target')
const tv = parents.getAttrValue({ sourceObject: target, attributeName: this.attribute, strictCase: strictAttrCase })
let value = this.value
if (this.attribute.toLowerCase() === 'objectclass') {
/*
* Perform case-insensitive match for objectClass since nearly every LDAP
* implementation behaves in this manner.
*/
value = value.toLowerCase()
return parents.testValues({
rule: function (v) {
return value === v.toLowerCase()
},
value: tv
})
} else {
return parents.testValues({
rule: function (v) {
return value === v
},
value: tv
})
}
}
EqualityFilter.prototype.parse = function (ber) {
assert.ok(ber)
this.attribute = ber.readString().toLowerCase()
this.value = ber.readString(ASN1.OctetString, true)
if (this.attribute === 'objectclass') { this.value = this.value.toLowerCase() }
return true
}
EqualityFilter.prototype._toBer = function (ber) {
assert.ok(ber)
ber.writeString(this.attribute)
ber.writeBuffer(this.raw, ASN1.OctetString)
return ber
}

View File

@ -1,44 +0,0 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
/**
* RFC 2254 Escaping of filter strings
*
* Raw Escaped
* (o=Parens (R Us)) (o=Parens \28R Us\29)
* (cn=star*) (cn=star\2A)
* (filename=C:\MyFile) (filename=C:\5cMyFile)
*
* Use substr_filter to avoid having * ecsaped.
*
* @author [Austin King](https://github.com/ozten)
*/
exports.escape = function (inp) {
if (typeof (inp) === 'string') {
let esc = ''
for (let i = 0; i < inp.length; i++) {
switch (inp[i]) {
case '*':
esc += '\\2a'
break
case '(':
esc += '\\28'
break
case ')':
esc += '\\29'
break
case '\\':
esc += '\\5c'
break
case '\0':
esc += '\\00'
break
default:
esc += inp[i]
break
}
}
return esc
} else {
return inp
}
}

View File

@ -1,59 +0,0 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
const assert = require('assert')
const util = require('util')
const parents = require('@ldapjs/filter')
const Filter = require('./filter')
// THIS IS A STUB!
//
// ldapjs does not support server side extensible matching.
// This class exists only for the client to send them.
/// --- API
function ExtensibleFilter (options) {
parents.ExtensibleFilter.call(this, options)
}
util.inherits(ExtensibleFilter, parents.ExtensibleFilter)
Filter.mixin(ExtensibleFilter)
module.exports = ExtensibleFilter
ExtensibleFilter.prototype.parse = function (ber) {
const end = ber.offset + ber.length
while (ber.offset < end) {
const tag = ber.peek()
switch (tag) {
case 0x81:
this.rule = ber.readString(tag)
break
case 0x82:
this.matchType = ber.readString(tag)
break
case 0x83:
this.value = ber.readString(tag)
break
case 0x84:
this.dnAttributes = ber.readBoolean(tag)
break
default:
throw new Error('Invalid ext_match filter type: 0x' + tag.toString(16))
}
}
return true
}
ExtensibleFilter.prototype._toBer = function (ber) {
assert.ok(ber)
if (this.rule) { ber.writeString(this.rule, 0x81) }
if (this.matchType) { ber.writeString(this.matchType, 0x82) }
ber.writeString(this.value, 0x83)
if (this.dnAttributes) { ber.writeBoolean(this.dnAttributes, 0x84) }
return ber
}

View File

@ -1,60 +0,0 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
// var assert = require('assert')
const Protocol = require('@ldapjs/protocol')
/// --- Globals
const TYPES = {
and: Protocol.search.FILTER_AND,
or: Protocol.search.FILTER_OR,
not: Protocol.search.FILTER_NOT,
equal: Protocol.search.FILTER_EQUALITY,
substring: Protocol.search.FILTER_SUBSTRINGS,
ge: Protocol.search.FILTER_GE,
le: Protocol.search.FILTER_LE,
present: Protocol.search.FILTER_PRESENT,
approx: Protocol.search.FILTER_APPROX,
ext: Protocol.search.FILTER_EXT
}
/// --- API
function isFilter (filter) {
if (!filter || typeof (filter) !== 'object') {
return false
}
// Do our best to duck-type it
if (typeof (filter.toBer) === 'function' &&
typeof (filter.matches) === 'function' &&
TYPES[filter.type] !== undefined) {
return true
}
return false
}
function isBerWriter (ber) {
return Boolean(
ber &&
typeof (ber) === 'object' &&
typeof (ber.startSequence) === 'function' &&
typeof (ber.endSequence) === 'function'
)
}
function mixin (target) {
target.prototype.toBer = function toBer (ber) {
if (isBerWriter(ber) === false) { throw new TypeError('ber (BerWriter) required') }
ber.startSequence(TYPES[this.type])
ber = this._toBer(ber)
ber.endSequence()
return ber
}
}
module.exports = {
isFilter: isFilter,
mixin: mixin
}

View File

@ -1,35 +0,0 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
const assert = require('assert')
const util = require('util')
const parents = require('@ldapjs/filter')
const Filter = require('./filter')
/// --- API
function GreaterThanEqualsFilter (options) {
parents.GreaterThanEqualsFilter.call(this, options)
}
util.inherits(GreaterThanEqualsFilter, parents.GreaterThanEqualsFilter)
Filter.mixin(GreaterThanEqualsFilter)
module.exports = GreaterThanEqualsFilter
GreaterThanEqualsFilter.prototype.parse = function (ber) {
assert.ok(ber)
this.attribute = ber.readString().toLowerCase()
this.value = ber.readString()
return true
}
GreaterThanEqualsFilter.prototype._toBer = function (ber) {
assert.ok(ber)
ber.writeString(this.attribute)
ber.writeString(this.value)
return ber
}

View File

@ -1,208 +0,0 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
const assert = require('assert')
const asn1 = require('@ldapjs/asn1')
const parents = require('@ldapjs/filter')
const Protocol = require('@ldapjs/protocol')
const Filter = require('./filter')
const AndFilter = require('./and_filter')
const ApproximateFilter = require('./approx_filter')
const EqualityFilter = require('./equality_filter')
const ExtensibleFilter = require('./ext_filter')
const GreaterThanEqualsFilter = require('./ge_filter')
const LessThanEqualsFilter = require('./le_filter')
const NotFilter = require('./not_filter')
const OrFilter = require('./or_filter')
const PresenceFilter = require('./presence_filter')
const SubstringFilter = require('./substr_filter')
/// --- Globals
const BerReader = asn1.BerReader
/// --- Internal Parsers
/*
* A filter looks like this coming in:
* Filter ::= CHOICE {
* and [0] SET OF Filter,
* or [1] SET OF Filter,
* not [2] Filter,
* equalityMatch [3] AttributeValueAssertion,
* substrings [4] SubstringFilter,
* greaterOrEqual [5] AttributeValueAssertion,
* lessOrEqual [6] AttributeValueAssertion,
* present [7] AttributeType,
* approxMatch [8] AttributeValueAssertion,
* extensibleMatch [9] MatchingRuleAssertion --v3 only
* }
*
* SubstringFilter ::= SEQUENCE {
* type AttributeType,
* SEQUENCE OF CHOICE {
* initial [0] IA5String,
* any [1] IA5String,
* final [2] IA5String
* }
* }
*
* The extensibleMatch was added in LDAPv3:
*
* MatchingRuleAssertion ::= SEQUENCE {
* matchingRule [1] MatchingRuleID OPTIONAL,
* type [2] AttributeDescription OPTIONAL,
* matchValue [3] AssertionValue,
* dnAttributes [4] BOOLEAN DEFAULT FALSE
* }
*/
function _parse (ber) {
assert.ok(ber)
function parseSet (f) {
const end = ber.offset + ber.length
while (ber.offset < end) { f.addFilter(_parse(ber)) }
}
let f
const type = ber.readSequence()
switch (type) {
case Protocol.search.FILTER_AND:
f = new AndFilter()
parseSet(f)
break
case Protocol.search.FILTER_APPROX:
f = new ApproximateFilter()
f.parse(ber)
break
case Protocol.search.FILTER_EQUALITY:
f = new EqualityFilter()
f.parse(ber)
return f
case Protocol.search.FILTER_EXT:
f = new ExtensibleFilter()
f.parse(ber)
return f
case Protocol.search.FILTER_GE:
f = new GreaterThanEqualsFilter()
f.parse(ber)
return f
case Protocol.search.FILTER_LE:
f = new LessThanEqualsFilter()
f.parse(ber)
return f
case Protocol.search.FILTER_NOT:
f = new NotFilter({
filter: _parse(ber)
})
break
case Protocol.search.FILTER_OR:
f = new OrFilter()
parseSet(f)
break
case Protocol.search.FILTER_PRESENT:
f = new PresenceFilter()
f.parse(ber)
break
case Protocol.search.FILTER_SUBSTRINGS:
f = new SubstringFilter()
f.parse(ber)
break
default:
throw new Error('Invalid search filter type: 0x' + type.toString(16))
}
assert.ok(f)
return f
}
function cloneFilter (input) {
let child
if (input.type === 'and' || input.type === 'or') {
child = input.filters.map(cloneFilter)
} else if (input.type === 'not') {
child = cloneFilter(input.filter)
}
switch (input.type) {
case 'and':
return new AndFilter({ filters: child })
case 'or':
return new OrFilter({ filters: child })
case 'not':
return new NotFilter({ filter: child })
case 'equal':
return new EqualityFilter(input)
case 'substring':
return new SubstringFilter(input)
case 'ge':
return new GreaterThanEqualsFilter(input)
case 'le':
return new LessThanEqualsFilter(input)
case 'present':
return new PresenceFilter(input)
case 'approx':
return new ApproximateFilter(input)
case 'ext':
return new ExtensibleFilter(input)
default:
throw new Error('invalid filter type:' + input.type)
}
}
function escapedToHex (str) {
return str.replace(/\\([0-9a-f](?![0-9a-f])|[^0-9a-f]|$)/gi, function (match, p1) {
if (!p1) {
return '\\5c'
}
const hexCode = p1.charCodeAt(0).toString(16)
return '\\' + hexCode
})
}
function parseString (str) {
const hexStr = escapedToHex(str)
const generic = parents.parse(hexStr)
// The filter object(s) return from ldap-filter.parse lack the toBer/parse
// decoration that native ldapjs filter possess. cloneFilter adds that back.
return cloneFilter(generic)
}
/// --- API
module.exports = {
parse: function (ber) {
if (!ber || !(ber instanceof BerReader)) { throw new TypeError('ber (BerReader) required') }
return _parse(ber)
},
parseString: parseString,
isFilter: Filter.isFilter,
AndFilter: AndFilter,
ApproximateFilter: ApproximateFilter,
EqualityFilter: EqualityFilter,
ExtensibleFilter: ExtensibleFilter,
GreaterThanEqualsFilter: GreaterThanEqualsFilter,
LessThanEqualsFilter: LessThanEqualsFilter,
NotFilter: NotFilter,
OrFilter: OrFilter,
PresenceFilter: PresenceFilter,
SubstringFilter: SubstringFilter
}

View File

@ -1,35 +0,0 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
const assert = require('assert')
const util = require('util')
const parents = require('@ldapjs/filter')
const Filter = require('./filter')
/// --- API
function LessThanEqualsFilter (options) {
parents.LessThanEqualsFilter.call(this, options)
}
util.inherits(LessThanEqualsFilter, parents.LessThanEqualsFilter)
Filter.mixin(LessThanEqualsFilter)
module.exports = LessThanEqualsFilter
LessThanEqualsFilter.prototype.parse = function (ber) {
assert.ok(ber)
this.attribute = ber.readString().toLowerCase()
this.value = ber.readString()
return true
}
LessThanEqualsFilter.prototype._toBer = function (ber) {
assert.ok(ber)
ber.writeString(this.attribute)
ber.writeString(this.value)
return ber
}

View File

@ -1,23 +0,0 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
const assert = require('assert')
const util = require('util')
const parents = require('@ldapjs/filter')
const Filter = require('./filter')
/// --- API
function NotFilter (options) {
parents.NotFilter.call(this, options)
}
util.inherits(NotFilter, parents.NotFilter)
Filter.mixin(NotFilter)
module.exports = NotFilter
NotFilter.prototype._toBer = function (ber) {
assert.ok(ber)
return this.filter.toBer(ber)
}

View File

@ -1,27 +0,0 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
const assert = require('assert')
const util = require('util')
const parents = require('@ldapjs/filter')
const Filter = require('./filter')
/// --- API
function OrFilter (options) {
parents.OrFilter.call(this, options)
}
util.inherits(OrFilter, parents.OrFilter)
Filter.mixin(OrFilter)
module.exports = OrFilter
OrFilter.prototype._toBer = function (ber) {
assert.ok(ber)
this.filters.forEach(function (f) {
ber = f.toBer(ber)
})
return ber
}

View File

@ -1,36 +0,0 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
const assert = require('assert')
const util = require('util')
const parents = require('@ldapjs/filter')
const Filter = require('./filter')
/// --- API
function PresenceFilter (options) {
parents.PresenceFilter.call(this, options)
}
util.inherits(PresenceFilter, parents.PresenceFilter)
Filter.mixin(PresenceFilter)
module.exports = PresenceFilter
PresenceFilter.prototype.parse = function (ber) {
assert.ok(ber)
this.attribute =
ber.buffer.slice(0, ber.length).toString('utf8').toLowerCase()
ber._offset += ber.length
return true
}
PresenceFilter.prototype._toBer = function (ber) {
assert.ok(ber)
for (let i = 0; i < this.attribute.length; i++) { ber.writeByte(this.attribute.charCodeAt(i)) }
return ber
}

View File

@ -1,70 +0,0 @@
// Copyright 2011 Mark Cavage, Inc. All rights reserved.
const assert = require('assert')
const util = require('util')
const parents = require('@ldapjs/filter')
const Filter = require('./filter')
/// --- API
function SubstringFilter (options) {
parents.SubstringFilter.call(this, options)
}
util.inherits(SubstringFilter, parents.SubstringFilter)
Filter.mixin(SubstringFilter)
module.exports = SubstringFilter
SubstringFilter.prototype.parse = function (ber) {
assert.ok(ber)
this.attribute = ber.readString().toLowerCase()
ber.readSequence()
const end = ber.offset + ber.length
while (ber.offset < end) {
const tag = ber.peek()
switch (tag) {
case 0x80: // Initial
this.initial = ber.readString(tag)
if (this.attribute === 'objectclass') { this.initial = this.initial.toLowerCase() }
break
case 0x81: { // Any
let anyVal = ber.readString(tag)
if (this.attribute === 'objectclass') { anyVal = anyVal.toLowerCase() }
this.any.push(anyVal)
break
}
case 0x82: // Final
this.final = ber.readString(tag)
if (this.attribute === 'objectclass') { this.final = this.final.toLowerCase() }
break
default:
throw new Error('Invalid substrings filter type: 0x' + tag.toString(16))
}
}
return true
}
SubstringFilter.prototype._toBer = function (ber) {
assert.ok(ber)
ber.writeString(this.attribute)
ber.startSequence()
if (this.initial) { ber.writeString(this.initial, 0x80) }
if (this.any && this.any.length) {
this.any.forEach(function (s) {
ber.writeString(s, 0x81)
})
}
if (this.final) { ber.writeString(this.final, 0x82) }
ber.endSequence()
return ber
}

View File

@ -12,7 +12,7 @@ const controls = require('./controls')
const persistentSearch = require('./persistent_search')
const dn = require('./dn')
const errors = require('./errors')
const filters = require('./filters')
const filters = require('@ldapjs/filter')
const messages = require('./messages')
const url = require('./url')

View File

@ -8,7 +8,7 @@ const asn1 = require('@ldapjs/asn1')
const LDAPMessage = require('./message')
// var LDAPResult = require('./result')
const dn = require('../dn')
const filters = require('../filters')
const filters = require('@ldapjs/filter')
const Protocol = require('@ldapjs/protocol')
/// --- Globals
@ -90,7 +90,7 @@ SearchRequest.prototype._parse = function (ber) {
this.timeLimit = ber.readInt()
this.typesOnly = ber.readBoolean()
this.filter = filters.parse(ber)
this.filter = filters.parseBer(ber)
// look for attributes
if (ber.peek() === 0x30) {
@ -119,7 +119,8 @@ SearchRequest.prototype._toBer = function (ber) {
ber.writeBoolean(this.typesOnly)
const f = this.filter || new filters.PresenceFilter({ attribute: 'objectclass' })
ber = f.toBer(ber)
const filterBer = f.toBer(ber)
ber.appendBuffer(filterBer.buffer)
ber.startSequence(Ber.Sequence | Ber.Constructor)
if (this.attributes && this.attributes.length) {

View File

@ -3,7 +3,7 @@
const querystring = require('querystring')
const url = require('url')
const dn = require('./dn')
const filter = require('./filters/')
const filter = require('@ldapjs/filter')
module.exports = {

View File

@ -17,9 +17,9 @@
"node": ">=10.13.0"
},
"dependencies": {
"@ldapjs/asn1": "^1.0.0",
"@ldapjs/asn1": "1.2.0",
"@ldapjs/controls": "^1.0.0",
"@ldapjs/filter": "^1.0.0-rc.1",
"@ldapjs/filter": "1.0.0",
"@ldapjs/protocol": "^1.0.0",
"abstract-logging": "^2.0.0",
"assert-plus": "^1.0.0",

View File

@ -48,9 +48,9 @@ tap.test('whois works correctly (issue #370)', t => {
client.exop('1.3.6.1.4.1.4203.1.11.3', (err, value, res) => {
t.error(err)
t.ok(value)
t.is(value, 'dn:cn=Philip J. Fry,ou=people,dc=planetexpress,dc=com')
t.equal(value, 'dn:cn=Philip J. Fry,ou=people,dc=planetexpress,dc=com')
t.ok(res)
t.is(res.status, 0)
t.equal(res.status, 0)
client.unbind(t.end)
})
@ -74,15 +74,15 @@ tap.test('can access large groups (issue #582)', t => {
})
response.on('error', t.error)
response.on('end', (result) => {
t.is(result.status, 0)
t.is(results.length === 1, true)
t.equal(result.status, 0)
t.equal(results.length === 1, true)
t.ok(results[0].attributes)
const memberAttr = results[0].attributes.find(a => a.type === 'member')
t.ok(memberAttr)
t.ok(memberAttr.vals)
t.type(memberAttr.vals, Array)
t.is(memberAttr.vals.length, 2000)
t.equal(memberAttr.vals.length, 2000)
client.unbind(t.end)
})

View File

@ -1,54 +0,0 @@
'use strict'
const { test } = require('tap')
const { filters: { EqualityFilter, AndFilter } } = require('../../lib')
test('Construct no args', function (t) {
t.ok(new AndFilter())
t.end()
})
test('Construct args', function (t) {
const f = new AndFilter()
f.addFilter(new EqualityFilter({
attribute: 'foo',
value: 'bar'
}))
f.addFilter(new EqualityFilter({
attribute: 'zig',
value: 'zag'
}))
t.ok(f)
t.equal(f.toString(), '(&(foo=bar)(zig=zag))')
t.end()
})
test('match true', function (t) {
const f = new AndFilter()
f.addFilter(new EqualityFilter({
attribute: 'foo',
value: 'bar'
}))
f.addFilter(new EqualityFilter({
attribute: 'zig',
value: 'zag'
}))
t.ok(f)
t.ok(f.matches({ foo: 'bar', zig: 'zag' }))
t.end()
})
test('match false', function (t) {
const f = new AndFilter()
f.addFilter(new EqualityFilter({
attribute: 'foo',
value: 'bar'
}))
f.addFilter(new EqualityFilter({
attribute: 'zig',
value: 'zag'
}))
t.ok(f)
t.ok(!f.matches({ foo: 'bar', zig: 'zonk' }))
t.end()
})

View File

@ -1,85 +0,0 @@
'use strict'
const { test } = require('tap')
const { BerReader, BerWriter } = require('@ldapjs/asn1')
const { filters: { ApproximateFilter } } = require('../../lib')
test('Construct no args', function (t) {
const f = new ApproximateFilter()
t.ok(f)
t.ok(!f.attribute)
t.ok(!f.value)
t.end()
})
test('Construct args', function (t) {
const f = new ApproximateFilter({
attribute: 'foo',
value: 'bar'
})
t.ok(f)
t.equal(f.attribute, 'foo')
t.equal(f.value, 'bar')
t.equal(f.toString(), '(foo~=bar)')
t.end()
})
test('GH-109 = escape value only in toString()', function (t) {
const f = new ApproximateFilter({
attribute: 'foo',
value: 'ba(r)'
})
t.ok(f)
t.equal(f.attribute, 'foo')
t.equal(f.value, 'ba(r)')
t.equal(f.toString(), '(foo~=ba\\28r\\29)')
t.end()
})
test('parse ok', function (t) {
const writer = new BerWriter()
writer.writeString('foo')
writer.writeString('bar')
const f = new ApproximateFilter()
t.ok(f)
t.ok(f.parse(new BerReader(writer.buffer)))
t.end()
})
test('parse bad', function (t) {
const writer = new BerWriter()
writer.writeString('foo')
writer.writeInt(20)
const f = new ApproximateFilter()
t.ok(f)
try {
f.parse(new BerReader(writer.buffer))
t.fail('Should have thrown InvalidAsn1Error')
} catch (e) {
t.equal(e.name, 'InvalidAsn1Error')
}
t.end()
})
test('GH-109 = to ber uses plain values', function (t) {
let f = new ApproximateFilter({
attribute: 'foo',
value: 'ba(r)'
})
t.ok(f)
const writer = new BerWriter()
f.toBer(writer)
f = new ApproximateFilter()
t.ok(f)
const reader = new BerReader(writer.buffer)
reader.readSequence()
t.ok(f.parse(reader))
t.equal(f.attribute, 'foo')
t.equal(f.value, 'ba(r)')
t.end()
})

View File

@ -1,167 +0,0 @@
'use strict'
const { test } = require('tap')
const { BerReader, BerWriter } = require('@ldapjs/asn1')
const { filters: { EqualityFilter } } = require('../../lib')
test('Construct no args', function (t) {
const f = new EqualityFilter()
t.ok(f)
t.ok(!f.attribute)
t.ok(!f.value)
t.end()
})
test('Construct args', function (t) {
const f = new EqualityFilter({
attribute: 'foo',
value: 'bar'
})
t.ok(f)
t.equal(f.attribute, 'foo')
t.equal(f.value, 'bar')
t.equal(f.toString(), '(foo=bar)')
t.end()
})
test('GH-109 = escape value only in toString()', function (t) {
const f = new EqualityFilter({
attribute: 'foo',
value: 'ba(r)'
})
t.ok(f)
t.equal(f.attribute, 'foo')
t.equal(f.value, 'ba(r)')
t.equal(f.toString(), '(foo=ba\\28r\\29)')
t.end()
})
test('match true', function (t) {
const f = new EqualityFilter({
attribute: 'foo',
value: 'bar'
})
t.ok(f)
t.ok(f.matches({ foo: 'bar' }))
t.end()
})
test('match multiple', function (t) {
const f = new EqualityFilter({
attribute: 'foo',
value: 'bar'
})
t.ok(f)
t.ok(f.matches({ foo: ['plop', 'bar'] }))
t.end()
})
test('match false', function (t) {
const f = new EqualityFilter({
attribute: 'foo',
value: 'bar'
})
t.ok(f)
t.ok(!f.matches({ foo: 'baz' }))
t.end()
})
test('parse ok', function (t) {
const writer = new BerWriter()
writer.writeString('foo')
writer.writeString('bar')
const f = new EqualityFilter()
t.ok(f)
t.ok(f.parse(new BerReader(writer.buffer)))
t.ok(f.matches({ foo: 'bar' }))
t.equal(f.attribute, 'foo')
t.equal(f.value, 'bar')
t.end()
})
test('escape EqualityFilter inputs', function (t) {
const f = new EqualityFilter({
attribute: '(|(foo',
value: 'bar))('
})
t.equal(f.attribute, '(|(foo')
t.equal(f.value, 'bar))(')
t.equal(f.toString(), '(\\28|\\28foo=bar\\29\\29\\28)')
t.end()
})
test('parse bad', function (t) {
const writer = new BerWriter()
writer.writeString('foo')
writer.writeInt(20)
const f = new EqualityFilter()
t.ok(f)
try {
f.parse(new BerReader(writer.buffer))
t.fail('Should have thrown InvalidAsn1Error')
} catch (e) {
t.equal(e.name, 'InvalidAsn1Error')
}
t.end()
})
test('GH-109 = to ber uses plain values', function (t) {
let f = new EqualityFilter({
attribute: 'foo',
value: 'ba(r)'
})
t.ok(f)
const writer = new BerWriter()
f.toBer(writer)
f = new EqualityFilter()
t.ok(f)
const reader = new BerReader(writer.buffer)
reader.readSequence()
t.ok(f.parse(reader))
t.equal(f.attribute, 'foo')
t.equal(f.value, 'ba(r)')
t.end()
})
test('handle values passed via buffer', function (t) {
const b = Buffer.from([32, 64, 128, 254])
const f = new EqualityFilter({
attribute: 'foo',
value: b
})
t.ok(f)
const writer = new BerWriter()
f.toBer(writer)
const reader = new BerReader(writer.buffer)
reader.readSequence()
const f2 = new EqualityFilter()
t.ok(f2.parse(reader))
t.equal(f2.value, b.toString())
t.equal(f2.raw.length, b.length)
for (let i = 0; i < b.length; i++) {
t.equal(f2.raw[i], b[i])
}
t.end()
})
test('GH-277 objectClass should be case-insensitive', function (t) {
const f = new EqualityFilter({
attribute: 'objectClass',
value: 'CaseInsensitiveObj'
})
t.ok(f)
t.ok(f.matches({ objectClass: 'CaseInsensitiveObj' }))
t.ok(f.matches({ OBJECTCLASS: 'CASEINSENSITIVEOBJ' }))
t.ok(f.matches({ objectclass: 'caseinsensitiveobj' }))
t.ok(!f.matches({ objectclass: 'matchless' }))
t.end()
})

View File

@ -1,82 +0,0 @@
'use strict'
const { test } = require('tap')
const { filters: { parseString, ExtensibleFilter } } = require('../../lib')
test('Construct no args', function (t) {
const f = new ExtensibleFilter()
t.ok(f)
t.end()
})
test('Construct args', function (t) {
const f = new ExtensibleFilter({
matchType: 'foo',
value: 'bar'
})
t.ok(f)
t.equal(f.matchType, 'foo')
t.equal(f.value, 'bar')
t.equal(f.toString(), '(foo:=bar)')
t.end()
})
test('parse RFC example 1', function (t) {
const f = parseString('(cn:caseExactMatch:=Fred Flintstone)')
t.ok(f)
t.equal(f.matchType, 'cn')
t.equal(f.matchingRule, 'caseExactMatch')
t.equal(f.matchValue, 'Fred Flintstone')
t.notOk(f.dnAttributes)
t.end()
})
test('parse RFC example 2', function (t) {
const f = parseString('(cn:=Betty Rubble)')
t.ok(f)
t.equal(f.matchType, 'cn')
t.equal(f.matchValue, 'Betty Rubble')
t.notOk(f.dnAttributes)
t.notOk(f.matchingRule)
t.end()
})
test('parse RFC example 3', function (t) {
const f = parseString('(sn:dn:2.4.6.8.10:=Barney Rubble)')
t.ok(f)
t.equal(f.matchType, 'sn')
t.equal(f.matchingRule, '2.4.6.8.10')
t.equal(f.matchValue, 'Barney Rubble')
t.ok(f.dnAttributes)
t.end()
})
test('parse RFC example 3', function (t) {
const f = parseString('(o:dn:=Ace Industry)')
t.ok(f)
t.equal(f.matchType, 'o')
t.notOk(f.matchingRule)
t.equal(f.matchValue, 'Ace Industry')
t.ok(f.dnAttributes)
t.end()
})
test('parse RFC example 4', function (t) {
const f = parseString('(:1.2.3:=Wilma Flintstone)')
t.ok(f)
t.notOk(f.matchType)
t.equal(f.matchingRule, '1.2.3')
t.equal(f.matchValue, 'Wilma Flintstone')
t.notOk(f.dnAttributes)
t.end()
})
test('parse RFC example 5', function (t) {
const f = parseString('(:DN:2.4.6.8.10:=Dino)')
t.ok(f)
t.notOk(f.matchType)
t.equal(f.matchingRule, '2.4.6.8.10')
t.equal(f.matchValue, 'Dino')
t.ok(f.dnAttributes)
t.end()
})

View File

@ -1,116 +0,0 @@
'use strict'
const { test } = require('tap')
const { BerReader, BerWriter } = require('@ldapjs/asn1')
const { filters: { GreaterThanEqualsFilter } } = require('../../lib')
test('Construct no args', function (t) {
const f = new GreaterThanEqualsFilter()
t.ok(f)
t.ok(!f.attribute)
t.ok(!f.value)
t.end()
})
test('Construct args', function (t) {
const f = new GreaterThanEqualsFilter({
attribute: 'foo',
value: 'bar'
})
t.ok(f)
t.equal(f.attribute, 'foo')
t.equal(f.value, 'bar')
t.equal(f.toString(), '(foo>=bar)')
t.end()
})
test('GH-109 = escape value only in toString()', function (t) {
const f = new GreaterThanEqualsFilter({
attribute: 'foo',
value: 'ba(r)'
})
t.ok(f)
t.equal(f.attribute, 'foo')
t.equal(f.value, 'ba(r)')
t.equal(f.toString(), '(foo>=ba\\28r\\29)')
t.end()
})
test('match true', function (t) {
const f = new GreaterThanEqualsFilter({
attribute: 'foo',
value: 'bar'
})
t.ok(f)
t.ok(f.matches({ foo: 'baz' }))
t.end()
})
test('match multiple', function (t) {
const f = new GreaterThanEqualsFilter({
attribute: 'foo',
value: 'bar'
})
t.ok(f)
t.ok(f.matches({ foo: ['beuha', 'baz'] }))
t.end()
})
test('match false', function (t) {
const f = new GreaterThanEqualsFilter({
attribute: 'foo',
value: 'bar'
})
t.ok(f)
t.ok(!f.matches({ foo: 'abc' }))
t.end()
})
test('parse ok', function (t) {
const writer = new BerWriter()
writer.writeString('foo')
writer.writeString('bar')
const f = new GreaterThanEqualsFilter()
t.ok(f)
t.ok(f.parse(new BerReader(writer.buffer)))
t.ok(f.matches({ foo: 'bar' }))
t.end()
})
test('parse bad', function (t) {
const writer = new BerWriter()
writer.writeString('foo')
writer.writeInt(20)
const f = new GreaterThanEqualsFilter()
t.ok(f)
try {
f.parse(new BerReader(writer.buffer))
t.fail('Should have thrown InvalidAsn1Error')
} catch (e) {
t.equal(e.name, 'InvalidAsn1Error')
}
t.end()
})
test('GH-109 = to ber uses plain values', function (t) {
let f = new GreaterThanEqualsFilter({
attribute: 'foo',
value: 'ba(r)'
})
t.ok(f)
const writer = new BerWriter()
f.toBer(writer)
f = new GreaterThanEqualsFilter()
t.ok(f)
const reader = new BerReader(writer.buffer)
reader.readSequence()
t.ok(f.parse(reader))
t.equal(f.attribute, 'foo')
t.equal(f.value, 'ba(r)')
t.end()
})

View File

@ -1,116 +0,0 @@
'use strict'
const { test } = require('tap')
const { BerReader, BerWriter } = require('@ldapjs/asn1')
const { filters: { LessThanEqualsFilter } } = require('../../lib')
test('Construct no args', function (t) {
const f = new LessThanEqualsFilter()
t.ok(f)
t.ok(!f.attribute)
t.ok(!f.value)
t.end()
})
test('Construct args', function (t) {
const f = new LessThanEqualsFilter({
attribute: 'foo',
value: 'bar'
})
t.ok(f)
t.equal(f.attribute, 'foo')
t.equal(f.value, 'bar')
t.equal(f.toString(), '(foo<=bar)')
t.end()
})
test('GH-109 = escape value only in toString()', function (t) {
const f = new LessThanEqualsFilter({
attribute: 'foo',
value: 'ba(r)'
})
t.ok(f)
t.equal(f.attribute, 'foo')
t.equal(f.value, 'ba(r)')
t.equal(f.toString(), '(foo<=ba\\28r\\29)')
t.end()
})
test('match true', function (t) {
const f = new LessThanEqualsFilter({
attribute: 'foo',
value: 'bar'
})
t.ok(f)
t.ok(f.matches({ foo: 'abc' }))
t.end()
})
test('match multiple', function (t) {
const f = new LessThanEqualsFilter({
attribute: 'foo',
value: 'bar'
})
t.ok(f)
t.ok(f.matches({ foo: ['abc', 'beuha'] }))
t.end()
})
test('match false', function (t) {
const f = new LessThanEqualsFilter({
attribute: 'foo',
value: 'bar'
})
t.ok(f)
t.ok(!f.matches({ foo: 'baz' }))
t.end()
})
test('parse ok', function (t) {
const writer = new BerWriter()
writer.writeString('foo')
writer.writeString('bar')
const f = new LessThanEqualsFilter()
t.ok(f)
t.ok(f.parse(new BerReader(writer.buffer)))
t.ok(f.matches({ foo: 'bar' }))
t.end()
})
test('parse bad', function (t) {
const writer = new BerWriter()
writer.writeString('foo')
writer.writeInt(20)
const f = new LessThanEqualsFilter()
t.ok(f)
try {
f.parse(new BerReader(writer.buffer))
t.fail('Should have thrown InvalidAsn1Error')
} catch (e) {
t.equal(e.name, 'InvalidAsn1Error')
}
t.end()
})
test('GH-109 = to ber uses plain values', function (t) {
let f = new LessThanEqualsFilter({
attribute: 'foo',
value: 'ba(r)'
})
t.ok(f)
const writer = new BerWriter()
f.toBer(writer)
f = new LessThanEqualsFilter()
t.ok(f)
const reader = new BerReader(writer.buffer)
reader.readSequence()
t.ok(f.parse(reader))
t.equal(f.attribute, 'foo')
t.equal(f.value, 'ba(r)')
t.end()
})

View File

@ -1,45 +0,0 @@
'use strict'
const { test } = require('tap')
const { filters: { EqualityFilter, NotFilter } } = require('../../lib')
test('Construct no args', function (t) {
t.ok(new NotFilter())
t.end()
})
test('Construct args', function (t) {
const f = new NotFilter({
filter: new EqualityFilter({
attribute: 'foo',
value: 'bar'
})
})
t.ok(f)
t.equal(f.toString(), '(!(foo=bar))')
t.end()
})
test('match true', function (t) {
const f = new NotFilter({
filter: new EqualityFilter({
attribute: 'foo',
value: 'bar'
})
})
t.ok(f)
t.ok(f.matches({ foo: 'baz' }))
t.end()
})
test('match false', function (t) {
const f = new NotFilter({
filter: new EqualityFilter({
attribute: 'foo',
value: 'bar'
})
})
t.ok(f)
t.ok(!f.matches({ foo: 'bar' }))
t.end()
})

View File

@ -1,54 +0,0 @@
'use strict'
const { test } = require('tap')
const { filters: { EqualityFilter, OrFilter } } = require('../../lib')
test('Construct no args', function (t) {
t.ok(new OrFilter())
t.end()
})
test('Construct args', function (t) {
const f = new OrFilter()
f.addFilter(new EqualityFilter({
attribute: 'foo',
value: 'bar'
}))
f.addFilter(new EqualityFilter({
attribute: 'zig',
value: 'zag'
}))
t.ok(f)
t.equal(f.toString(), '(|(foo=bar)(zig=zag))')
t.end()
})
test('match true', function (t) {
const f = new OrFilter()
f.addFilter(new EqualityFilter({
attribute: 'foo',
value: 'bar'
}))
f.addFilter(new EqualityFilter({
attribute: 'zig',
value: 'zag'
}))
t.ok(f)
t.ok(f.matches({ foo: 'bar', zig: 'zonk' }))
t.end()
})
test('match false', function (t) {
const f = new OrFilter()
f.addFilter(new EqualityFilter({
attribute: 'foo',
value: 'bar'
}))
f.addFilter(new EqualityFilter({
attribute: 'zig',
value: 'zag'
}))
t.ok(f)
t.ok(!f.matches({ foo: 'baz', zig: 'zonk' }))
t.end()
})

View File

@ -1,141 +0,0 @@
'use strict'
const { test } = require('tap')
const { parseFilter: parse } = require('../../lib')
test('GH-48 XML Strings in filter', function (t) {
const str = '(&(CentralUIEnrollments=\\<mydoc\\>*)(objectClass=User))'
const f = parse(str)
t.ok(f)
t.ok(f.filters)
t.equal(f.filters.length, 2)
f.filters.forEach(function (filter) {
t.ok(filter.attribute)
})
t.end()
})
test('GH-50 = in filter', function (t) {
const str = '(uniquemember=uuid=930896af-bf8c-48d4-885c-6573a94b1853, ' +
'ou=users, o=smartdc)'
const f = parse(str)
t.ok(f)
t.equal(f.attribute, 'uniquemember')
t.equal(f.value,
'uuid=930896af-bf8c-48d4-885c-6573a94b1853, ou=users, o=smartdc')
t.end()
})
test('convert to hex code', function (t) {
const str = 'foo=bar\\(abcd\\e\\fg\\h\\69\\a'
const f = parse(str)
t.ok(f)
t.equal(f.attribute, 'foo')
t.equal(f.value, 'bar(abcdefghia')
t.equal(f.toString(), '(foo=bar\\28abcdefghia)')
t.end()
})
test('( in filter', function (t) {
const str = '(foo=bar\\()'
const f = parse(str)
t.ok(f)
t.equal(f.attribute, 'foo')
t.equal(f.value, 'bar(')
t.equal(f.toString(), '(foo=bar\\28)')
t.end()
})
test(') in filter', function (t) {
const str = '(foo=bar\\))'
const f = parse(str)
t.ok(f)
t.equal(f.attribute, 'foo')
t.equal(f.value, 'bar)')
t.equal(f.toString(), '(foo=bar\\29)')
t.end()
})
test('\\ in filter', function (t) {
const str = '(foo=bar\\\\)'
const f = parse(str)
t.ok(f)
t.equal(f.attribute, 'foo')
t.equal(f.value, 'bar\\')
t.equal(f.toString(), '(foo=bar\\5c)')
t.end()
})
test('not escaped \\ at end of filter', function (t) {
const str = 'foo=bar\\'
const f = parse(str)
t.ok(f)
t.equal(f.attribute, 'foo')
t.equal(f.value, 'bar\\')
t.equal(f.toString(), '(foo=bar\\5c)')
t.end()
})
test('* in equality filter', function (t) {
const str = '(foo=bar\\*)'
const f = parse(str)
t.ok(f)
t.equal(f.attribute, 'foo')
t.equal(f.value, 'bar*')
t.equal(f.toString(), '(foo=bar\\2a)')
t.end()
})
test('* substr filter (prefix)', function (t) {
const str = '(foo=bar*)'
const f = parse(str)
t.ok(f)
t.equal(f.attribute, 'foo')
t.equal(f.initial, 'bar')
t.equal(f.toString(), '(foo=bar*)')
t.end()
})
test('GH-53 NotFilter', function (t) {
const str = '(&(objectClass=person)(!(objectClass=shadowAccount)))'
const f = parse(str)
t.ok(f)
t.equal(f.type, 'and')
t.equal(f.filters.length, 2)
t.equal(f.filters[0].type, 'equal')
t.equal(f.filters[1].type, 'not')
t.equal(f.filters[1].filter.type, 'equal')
t.equal(f.filters[1].filter.attribute, 'objectClass')
t.equal(f.filters[1].filter.value, 'shadowAccount')
t.end()
})
test('presence filter', function (t) {
const f = parse('(foo=*)')
t.ok(f)
t.equal(f.type, 'present')
t.equal(f.attribute, 'foo')
t.equal(f.toString(), '(foo=*)')
t.end()
})
test('bogus filter', function (t) {
t.throws(function () {
parse('foo>1')
})
t.end()
})
test('bogus filter !=', function (t) {
t.throws(function () {
parse('foo!=1')
})
t.end()
})
test('mismatched parens', function (t) {
t.throws(function () {
parse('(&(foo=bar)(!(state=done))')
})
t.end()
})

View File

@ -1,83 +0,0 @@
'use strict'
const { test } = require('tap')
const { BerReader, BerWriter } = require('@ldapjs/asn1')
const { filters: { PresenceFilter } } = require('../../lib')
test('Construct no args', function (t) {
const f = new PresenceFilter()
t.ok(f)
t.ok(!f.attribute)
t.end()
})
test('Construct args', function (t) {
const f = new PresenceFilter({
attribute: 'foo'
})
t.ok(f)
t.equal(f.attribute, 'foo')
t.equal(f.toString(), '(foo=*)')
t.end()
})
test('GH-109 = escape value only in toString()', function (t) {
const f = new PresenceFilter({
attribute: 'fo)o'
})
t.ok(f)
t.equal(f.attribute, 'fo)o')
t.equal(f.toString(), '(fo\\29o=*)')
t.end()
})
test('match true', function (t) {
const f = new PresenceFilter({
attribute: 'foo'
})
t.ok(f)
t.ok(f.matches({ foo: 'bar' }))
t.end()
})
test('match false', function (t) {
const f = new PresenceFilter({
attribute: 'foo'
})
t.ok(f)
t.ok(!f.matches({ bar: 'foo' }))
t.end()
})
test('parse ok', function (t) {
const writer = new BerWriter()
writer.writeString('foo', 0x87)
const f = new PresenceFilter()
t.ok(f)
const reader = new BerReader(writer.buffer)
reader.readSequence()
t.ok(f.parse(reader))
t.ok(f.matches({ foo: 'bar' }))
t.end()
})
test('GH-109 = to ber uses plain values', function (t) {
let f = new PresenceFilter({
attribute: 'f(o)o'
})
t.ok(f)
const writer = new BerWriter()
f.toBer(writer)
f = new PresenceFilter()
t.ok(f)
const reader = new BerReader(writer.buffer)
reader.readSequence()
t.ok(f.parse(reader))
t.equal(f.attribute, 'f(o)o')
t.end()
})

View File

@ -1,152 +0,0 @@
'use strict'
const { test } = require('tap')
const { BerReader, BerWriter } = require('@ldapjs/asn1')
const { filters: { SubstringFilter } } = require('../../lib')
test('Construct no args', function (t) {
const f = new SubstringFilter()
t.ok(f)
t.ok(!f.attribute)
t.ok(!f.value)
t.end()
})
test('Construct args', function (t) {
const f = new SubstringFilter({
attribute: 'foo',
initial: 'bar',
any: ['zig', 'zag'],
final: 'baz'
})
t.ok(f)
t.equal(f.attribute, 'foo')
t.equal(f.initial, 'bar')
t.equal(f.any.length, 2)
t.equal(f.any[0], 'zig')
t.equal(f.any[1], 'zag')
t.equal(f.final, 'baz')
t.equal(f.toString(), '(foo=bar*zig*zag*baz)')
t.end()
})
test('GH-109 = escape value only in toString()', function (t) {
const f = new SubstringFilter({
attribute: 'fo(o',
initial: 'ba(r)',
any: ['zi)g', 'z(ag'],
final: '(baz)'
})
t.ok(f)
t.equal(f.attribute, 'fo(o')
t.equal(f.initial, 'ba(r)')
t.equal(f.any.length, 2)
t.equal(f.any[0], 'zi)g')
t.equal(f.any[1], 'z(ag')
t.equal(f.final, '(baz)')
t.equal(f.toString(), '(fo\\28o=ba\\28r\\29*zi\\29g*z\\28ag*\\28baz\\29)')
t.end()
})
test('match true', function (t) {
const f = new SubstringFilter({
attribute: 'foo',
initial: 'bar',
any: ['zig', 'zag'],
final: 'baz'
})
t.ok(f)
t.ok(f.matches({ foo: 'barmoozigbarzagblahbaz' }))
t.end()
})
test('match false', function (t) {
const f = new SubstringFilter({
attribute: 'foo',
initial: 'bar',
foo: ['zig', 'zag'],
final: 'baz'
})
t.ok(f)
t.ok(!f.matches({ foo: 'bafmoozigbarzagblahbaz' }))
t.end()
})
test('match any', function (t) {
const f = new SubstringFilter({
attribute: 'foo',
initial: 'bar'
})
t.ok(f)
t.ok(f.matches({ foo: ['beuha', 'barista'] }))
t.end()
})
test('GH-109 = escape for regex in matches', function (t) {
const f = new SubstringFilter({
attribute: 'fo(o',
initial: 'ba(r)',
any: ['zi)g', 'z(ag'],
final: '(baz)'
})
t.ok(f)
t.ok(f.matches({ 'fo(o': ['ba(r)_zi)g-z(ag~(baz)'] }))
t.end()
})
test('parse ok', function (t) {
const writer = new BerWriter()
writer.writeString('foo')
writer.startSequence()
writer.writeString('bar', 0x80)
writer.writeString('bad', 0x81)
writer.writeString('baz', 0x82)
writer.endSequence()
const f = new SubstringFilter()
t.ok(f)
t.ok(f.parse(new BerReader(writer.buffer)))
t.ok(f.matches({ foo: 'bargoobadgoobaz' }))
t.end()
})
test('parse bad', function (t) {
const writer = new BerWriter()
writer.writeString('foo')
writer.writeInt(20)
const f = new SubstringFilter()
t.ok(f)
try {
f.parse(new BerReader(writer.buffer))
t.fail('Should have thrown InvalidAsn1Error')
} catch (e) {
}
t.end()
})
test('GH-109 = to ber uses plain values', function (t) {
let f = new SubstringFilter({
attribute: 'fo(o',
initial: 'ba(r)',
any: ['zi)g', 'z(ag'],
final: '(baz)'
})
t.ok(f)
const writer = new BerWriter()
f.toBer(writer)
f = new SubstringFilter()
t.ok(f)
const reader = new BerReader(writer.buffer)
reader.readSequence()
t.ok(f.parse(reader))
t.equal(f.attribute, 'fo(o')
t.equal(f.initial, 'ba(r)')
t.equal(f.any.length, 2)
t.equal(f.any[0], 'zi)g')
t.equal(f.any[1], 'z(ag')
t.equal(f.final, '(baz)')
t.end()
})

View File

@ -30,6 +30,10 @@ tap.beforeEach((t) => {
t.context.socketPath = getSock()
t.context.suffix = suffix
server.on('error', err => {
server.close(() => reject(err))
})
server.bind('cn=root', function (req, res, next) {
res.end()
return next()
@ -57,6 +61,9 @@ tap.beforeEach((t) => {
socketPath: t.context.socketPath
})
t.context.client.on('error', (err) => {
t.context.server.close(() => reject(err))
})
t.context.client.on('connectError', (err) => {
t.context.server.close(() => reject(err))
})
@ -80,7 +87,7 @@ tap.afterEach((t) => {
})
})
tap.test('Evolution search filter (GH-3)', function (t) {
tap.test('Evolution search filter (GH-3)', { only: true }, function (t) {
// This is what Evolution sends, when searching for a contact 'ogo'. Wow.
const filter =
'(|(cn=ogo*)(givenname=ogo*)(sn=ogo*)(mail=ogo*)(member=ogo*)' +

View File

@ -33,14 +33,16 @@ test('parse', function (t) {
value: 'foo@bar.com'
})
let ber = new BerWriter()
const ber = new BerWriter()
ber.writeString('cn=foo, o=test')
ber.writeEnumeration(0)
ber.writeEnumeration(0)
ber.writeInt(1)
ber.writeInt(2)
ber.writeBoolean(false)
ber = f.toBer(ber)
const eqBer = f.toBer()
ber.appendBuffer(eqBer.buffer)
const req = new SearchRequest()
t.ok(req._parse(new BerReader(ber.buffer)))